xref: /haiku/src/add-ons/translators/jpeg/JPEGTranslator.cpp (revision dbc936ac13c9ec220e33e278cc2bb48fb741940b)
19949213aSStephan Aßmus /*
29949213aSStephan Aßmus 
39949213aSStephan Aßmus Copyright (c) 2002-2003, Marcin 'Shard' Konicki
49949213aSStephan Aßmus All rights reserved.
59949213aSStephan Aßmus 
69949213aSStephan Aßmus Redistribution and use in source and binary forms, with or without
79949213aSStephan Aßmus modification, are permitted provided that the following conditions are met:
89949213aSStephan Aßmus 
99949213aSStephan Aßmus     * Redistributions of source code must retain the above copyright notice,
109949213aSStephan Aßmus       this list of conditions and the following disclaimer.
119949213aSStephan Aßmus     * Redistributions in binary form must reproduce the above copyright notice,
129949213aSStephan Aßmus       this list of conditions and the following disclaimer in the documentation and/or
139949213aSStephan Aßmus       other materials provided with the distribution.
149949213aSStephan Aßmus     * Name "Marcin Konicki", "Shard" or any combination of them,
159949213aSStephan Aßmus       must not be used to endorse or promote products derived from this
169949213aSStephan Aßmus       software without specific prior written permission from Marcin Konicki.
179949213aSStephan Aßmus 
189949213aSStephan Aßmus THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
199949213aSStephan Aßmus ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
209949213aSStephan Aßmus THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
219949213aSStephan Aßmus ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
229949213aSStephan Aßmus BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
239949213aSStephan Aßmus OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
249949213aSStephan Aßmus PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
259949213aSStephan Aßmus OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
269949213aSStephan Aßmus WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
279949213aSStephan Aßmus OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
289949213aSStephan Aßmus EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
299949213aSStephan Aßmus 
309949213aSStephan Aßmus */
319949213aSStephan Aßmus 
329949213aSStephan Aßmus 
339949213aSStephan Aßmus #include "JPEGTranslator.h"
349949213aSStephan Aßmus 
3552e8f46aSAxel Dörfler #include "exif_parser.h"
3652e8f46aSAxel Dörfler 
378687ff64SAxel Dörfler #include <TabView.h>
388687ff64SAxel Dörfler 
399949213aSStephan Aßmus 
4052e8f46aSAxel Dörfler #define MARKER_EXIF	0xe1
4152e8f46aSAxel Dörfler 
429949213aSStephan Aßmus // Set these accordingly
439949213aSStephan Aßmus #define JPEG_ACRONYM "JPEG"
449949213aSStephan Aßmus #define JPEG_FORMAT 'JPEG'
459949213aSStephan Aßmus #define JPEG_MIME_STRING "image/jpeg"
469949213aSStephan Aßmus #define JPEG_DESCRIPTION "JPEG image"
479949213aSStephan Aßmus 
489949213aSStephan Aßmus // The translation kit's native file type
499949213aSStephan Aßmus #define B_TRANSLATOR_BITMAP_MIME_STRING "image/x-be-bitmap"
509949213aSStephan Aßmus #define B_TRANSLATOR_BITMAP_DESCRIPTION "Be Bitmap image"
519949213aSStephan Aßmus 
529949213aSStephan Aßmus // Translation Kit required globals
53109d4881SStephan Aßmus char translatorName[] = "JPEG Images";
548687ff64SAxel Dörfler char translatorInfo[] =
558687ff64SAxel Dörfler 	"©2002-2003, Marcin Konicki\n"
56f13b5de6SAxel Dörfler 	"©2005-2007, Haiku\n"
57758b1d0eSIngo Weinhold 	"\n"
588687ff64SAxel Dörfler 	"Based on IJG library © 1991-1998, Thomas G. Lane\n"
59758b1d0eSIngo Weinhold 	"          http://www.ijg.org/files/\n"
60758b1d0eSIngo Weinhold 	"with \"Lossless\" encoding support patch by Ken Murchison\n"
61758b1d0eSIngo Weinhold 	"          http://www.oceana.com/ftp/ljpeg/\n"
62758b1d0eSIngo Weinhold 	"\n"
63758b1d0eSIngo Weinhold 	"With some colorspace conversion routines by Magnus Hellman\n"
648687ff64SAxel Dörfler 	"          http://www.bebits.com/app/802\n";
65d8e2fb50SAxel Dörfler 
66f13b5de6SAxel Dörfler int32 translatorVersion = 0x120;
679949213aSStephan Aßmus 
689949213aSStephan Aßmus // Define the formats we know how to read
699949213aSStephan Aßmus translation_format inputFormats[] = {
709949213aSStephan Aßmus 	{ JPEG_FORMAT, B_TRANSLATOR_BITMAP, 0.5, 0.5,
719949213aSStephan Aßmus 		JPEG_MIME_STRING, JPEG_DESCRIPTION },
729949213aSStephan Aßmus 	{ B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.5, 0.5,
739949213aSStephan Aßmus 		B_TRANSLATOR_BITMAP_MIME_STRING, B_TRANSLATOR_BITMAP_DESCRIPTION },
74d8e2fb50SAxel Dörfler 	{}
759949213aSStephan Aßmus };
769949213aSStephan Aßmus 
779949213aSStephan Aßmus // Define the formats we know how to write
789949213aSStephan Aßmus translation_format outputFormats[] = {
799949213aSStephan Aßmus 	{ JPEG_FORMAT, B_TRANSLATOR_BITMAP, 0.5, 0.5,
809949213aSStephan Aßmus 		JPEG_MIME_STRING, JPEG_DESCRIPTION },
819949213aSStephan Aßmus 	{ B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.5, 0.5,
829949213aSStephan Aßmus 		B_TRANSLATOR_BITMAP_MIME_STRING, B_TRANSLATOR_BITMAP_DESCRIPTION },
83d8e2fb50SAxel Dörfler 	{}
849949213aSStephan Aßmus };
859949213aSStephan Aßmus 
8652e8f46aSAxel Dörfler // Main functions of translator :)
8752e8f46aSAxel Dörfler static status_t Copy(BPositionIO *in, BPositionIO *out);
8852e8f46aSAxel Dörfler static status_t Compress(BPositionIO *in, BPositionIO *out);
8952e8f46aSAxel Dörfler static status_t Decompress(BPositionIO *in, BPositionIO *out, BMessage* ioExtension);
9052e8f46aSAxel Dörfler static status_t Error(j_common_ptr cinfo, status_t error = B_ERROR);
9152e8f46aSAxel Dörfler 
92d8e2fb50SAxel Dörfler 
93d8e2fb50SAxel Dörfler bool gAreSettingsRunning = false;
949949213aSStephan Aßmus 
959949213aSStephan Aßmus 
96d8e2fb50SAxel Dörfler //!	Make settings to defaults
97d8e2fb50SAxel Dörfler void
98d8e2fb50SAxel Dörfler LoadDefaultSettings(jpeg_settings *settings)
99d8e2fb50SAxel Dörfler {
100d8e2fb50SAxel Dörfler 	settings->Smoothing = 0;
101d8e2fb50SAxel Dörfler 	settings->Quality = 95;
102d8e2fb50SAxel Dörfler 	settings->Progressive = true;
103d8e2fb50SAxel Dörfler 	settings->OptimizeColors = true;
104d8e2fb50SAxel Dörfler 	settings->SmallerFile = false;
105d8e2fb50SAxel Dörfler 	settings->B_GRAY1_as_B_RGB24 = false;
106d8e2fb50SAxel Dörfler 	settings->Always_B_RGB32 = true;
107d8e2fb50SAxel Dörfler 	settings->PhotoshopCMYK = true;
108d8e2fb50SAxel Dörfler 	settings->ShowReadWarningBox = true;
109d8e2fb50SAxel Dörfler }
1109949213aSStephan Aßmus 
111d8e2fb50SAxel Dörfler 
112d8e2fb50SAxel Dörfler //!	Save settings to config file
113d8e2fb50SAxel Dörfler void
114d8e2fb50SAxel Dörfler SaveSettings(jpeg_settings *settings)
115d8e2fb50SAxel Dörfler {
116d8e2fb50SAxel Dörfler 	// Make path to settings file
117d8e2fb50SAxel Dörfler 	BPath path;
118117da2d7SAxel Dörfler 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path, true) != B_OK)
119117da2d7SAxel Dörfler 		return;
120117da2d7SAxel Dörfler 
121d8e2fb50SAxel Dörfler 	path.Append(SETTINGS_FILE);
122d8e2fb50SAxel Dörfler 
123d8e2fb50SAxel Dörfler 	// Open settings file (create it if there's no file) and write settings
124d8e2fb50SAxel Dörfler 	FILE *file = NULL;
125d8e2fb50SAxel Dörfler 	if ((file = fopen(path.Path(), "wb+"))) {
126d8e2fb50SAxel Dörfler 		fwrite(settings, sizeof(jpeg_settings), 1, file);
127d8e2fb50SAxel Dörfler 		fclose(file);
128d8e2fb50SAxel Dörfler 	}
129d8e2fb50SAxel Dörfler }
130d8e2fb50SAxel Dörfler 
131d8e2fb50SAxel Dörfler 
132d8e2fb50SAxel Dörfler //!	Return true if settings were run, false if not
133d8e2fb50SAxel Dörfler bool
134d8e2fb50SAxel Dörfler SettingsChangedAlert()
135d8e2fb50SAxel Dörfler {
136d8e2fb50SAxel Dörfler 	// If settings view wasn't already initialized (settings not running)
137d8e2fb50SAxel Dörfler 	// and user wants to run settings
138d8e2fb50SAxel Dörfler 	if (!gAreSettingsRunning
139d8e2fb50SAxel Dörfler 		&& (new BAlert("Different settings file",
140d8e2fb50SAxel Dörfler 				"JPEG settings were set to default because of incompatible settings file.",
141d8e2fb50SAxel Dörfler 				"Configure settings", "OK", NULL, B_WIDTH_AS_USUAL,
142d8e2fb50SAxel Dörfler 				B_WARNING_ALERT))->Go() == 0) {
143d8e2fb50SAxel Dörfler 		// Create settings window (with no quit on close!), launch
144d8e2fb50SAxel Dörfler 		// it and wait until it's closed
145d8e2fb50SAxel Dörfler 		TranslatorWindow *window = new TranslatorWindow(false);
146d8e2fb50SAxel Dörfler 		window->Show();
147c016311bSAxel Dörfler 
148c016311bSAxel Dörfler 		status_t err;
149d8e2fb50SAxel Dörfler 		wait_for_thread(window->Thread(), &err);
150d8e2fb50SAxel Dörfler 		return true;
151d8e2fb50SAxel Dörfler 	}
152d8e2fb50SAxel Dörfler 
153d8e2fb50SAxel Dörfler 	return false;
154d8e2fb50SAxel Dörfler }
155d8e2fb50SAxel Dörfler 
156d8e2fb50SAxel Dörfler 
157d8e2fb50SAxel Dörfler /*!
158d8e2fb50SAxel Dörfler 	Load settings from config file
159d8e2fb50SAxel Dörfler 	If can't find it make them default and try to save
160d8e2fb50SAxel Dörfler */
161d8e2fb50SAxel Dörfler void
162d8e2fb50SAxel Dörfler LoadSettings(jpeg_settings *settings)
163d8e2fb50SAxel Dörfler {
164d8e2fb50SAxel Dörfler 	// Make path to settings file
165d8e2fb50SAxel Dörfler 	BPath path;
166d8e2fb50SAxel Dörfler 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) {
167117da2d7SAxel Dörfler 		LoadDefaultSettings(settings);
168117da2d7SAxel Dörfler 		return;
169117da2d7SAxel Dörfler 	}
170117da2d7SAxel Dörfler 
171d8e2fb50SAxel Dörfler 	path.Append(SETTINGS_FILE);
172d8e2fb50SAxel Dörfler 
173d8e2fb50SAxel Dörfler 	// Open settings file (create it if there's no file) and write settings
174d8e2fb50SAxel Dörfler 	FILE *file = NULL;
175c016311bSAxel Dörfler 	if ((file = fopen(path.Path(), "rb")) != NULL) {
176d8e2fb50SAxel Dörfler 		if (!fread(settings, sizeof(jpeg_settings), 1, file)) {
177d8e2fb50SAxel Dörfler 			// settings struct has changed size
178d8e2fb50SAxel Dörfler 			// Load default settings, and Save them
179d8e2fb50SAxel Dörfler 			fclose(file);
180d8e2fb50SAxel Dörfler 			LoadDefaultSettings(settings);
181d8e2fb50SAxel Dörfler 			SaveSettings(settings);
182d8e2fb50SAxel Dörfler 			// Tell user settings were changed to default, and ask to run settings panel or not
183d8e2fb50SAxel Dörfler 			if (SettingsChangedAlert())
184d8e2fb50SAxel Dörfler 				// User configured settings, load them again
185d8e2fb50SAxel Dörfler 				LoadSettings(settings);
186d8e2fb50SAxel Dörfler 		} else
187d8e2fb50SAxel Dörfler 			fclose(file);
188c016311bSAxel Dörfler 	} else if ((file = fopen(path.Path(), "wb+")) != NULL) {
189d8e2fb50SAxel Dörfler 		LoadDefaultSettings(settings);
190d8e2fb50SAxel Dörfler 		fwrite(settings, sizeof(jpeg_settings), 1, file);
191d8e2fb50SAxel Dörfler 		fclose(file);
192d8e2fb50SAxel Dörfler 	}
193d8e2fb50SAxel Dörfler }
194d8e2fb50SAxel Dörfler 
195d8e2fb50SAxel Dörfler 
1969e34f742SAxel Dörfler static bool
1979e34f742SAxel Dörfler x_flipped(int32 orientation)
1989e34f742SAxel Dörfler {
1999e34f742SAxel Dörfler 	return orientation == 2 || orientation == 3
2009e34f742SAxel Dörfler 		|| orientation == 6 || orientation == 7;
2019e34f742SAxel Dörfler }
2029e34f742SAxel Dörfler 
2039e34f742SAxel Dörfler 
2049e34f742SAxel Dörfler static bool
2059e34f742SAxel Dörfler y_flipped(int32 orientation)
2069e34f742SAxel Dörfler {
2079e34f742SAxel Dörfler 	return orientation == 3 || orientation == 4
2089e34f742SAxel Dörfler 		|| orientation == 7 || orientation == 8;
2099e34f742SAxel Dörfler }
2109e34f742SAxel Dörfler 
2119e34f742SAxel Dörfler 
2129e34f742SAxel Dörfler static int32
2139e34f742SAxel Dörfler dest_index(uint32 width, uint32 height, uint32 x, uint32 y, int32 orientation)
2149e34f742SAxel Dörfler {
2159e34f742SAxel Dörfler 	if (orientation > 4) {
2169e34f742SAxel Dörfler 		uint32 temp = x;
2179e34f742SAxel Dörfler 		x = y;
2189e34f742SAxel Dörfler 		y = temp;
2199e34f742SAxel Dörfler 	}
2209e34f742SAxel Dörfler 	if (y_flipped(orientation))
2219e34f742SAxel Dörfler 		y = height - 1 - y;
2229e34f742SAxel Dörfler 	if (x_flipped(orientation))
2239e34f742SAxel Dörfler 		x = width - 1 - x;
2249e34f742SAxel Dörfler 
2259e34f742SAxel Dörfler 	return y * width + x;
2269e34f742SAxel Dörfler }
2279e34f742SAxel Dörfler 
2289e34f742SAxel Dörfler 
2299e34f742SAxel Dörfler //	#pragma mark - conversion for compression
230d8e2fb50SAxel Dörfler 
231d8e2fb50SAxel Dörfler 
232d8e2fb50SAxel Dörfler inline void
2339e34f742SAxel Dörfler convert_from_gray1_to_gray8(uint8* in, uint8* out, int32 inRowBytes)
234d8e2fb50SAxel Dörfler {
235d8e2fb50SAxel Dörfler 	int32 index = 0;
236d8e2fb50SAxel Dörfler 	int32 index2 = 0;
2379e34f742SAxel Dörfler 	while (index < inRowBytes) {
238d8e2fb50SAxel Dörfler 		unsigned char c = in[index++];
239d8e2fb50SAxel Dörfler 		for (int b = 128; b; b = b>>1) {
240d8e2fb50SAxel Dörfler 			unsigned char color;
241d8e2fb50SAxel Dörfler 			if (c & b)
242d8e2fb50SAxel Dörfler 				color = 0;
243d8e2fb50SAxel Dörfler 			else
244d8e2fb50SAxel Dörfler 				color = 255;
245d8e2fb50SAxel Dörfler 			out[index2++] = color;
246d8e2fb50SAxel Dörfler 		}
247d8e2fb50SAxel Dörfler 	}
248d8e2fb50SAxel Dörfler }
249d8e2fb50SAxel Dörfler 
250d8e2fb50SAxel Dörfler 
251d8e2fb50SAxel Dörfler inline void
2529e34f742SAxel Dörfler convert_from_gray1_to_24(uint8* in, uint8* out, int32 inRowBytes)
253d8e2fb50SAxel Dörfler {
254d8e2fb50SAxel Dörfler 	int32 index = 0;
255d8e2fb50SAxel Dörfler 	int32 index2 = 0;
2569e34f742SAxel Dörfler 	while (index < inRowBytes) {
257d8e2fb50SAxel Dörfler 		unsigned char c = in[index++];
258d8e2fb50SAxel Dörfler 		for (int b = 128; b; b = b>>1) {
259d8e2fb50SAxel Dörfler 			unsigned char color;
260d8e2fb50SAxel Dörfler 			if (c & b)
261d8e2fb50SAxel Dörfler 				color = 0;
262d8e2fb50SAxel Dörfler 			else
263d8e2fb50SAxel Dörfler 				color = 255;
264d8e2fb50SAxel Dörfler 			out[index2++] = color;
265d8e2fb50SAxel Dörfler 			out[index2++] = color;
266d8e2fb50SAxel Dörfler 			out[index2++] = color;
267d8e2fb50SAxel Dörfler 		}
268d8e2fb50SAxel Dörfler 	}
269d8e2fb50SAxel Dörfler }
270d8e2fb50SAxel Dörfler 
271d8e2fb50SAxel Dörfler 
272d8e2fb50SAxel Dörfler inline void
2739e34f742SAxel Dörfler convert_from_cmap8_to_24(uint8* in, uint8* out, int32 inRowBytes)
274d8e2fb50SAxel Dörfler {
275d8e2fb50SAxel Dörfler 	const color_map * map = system_colors();
276d8e2fb50SAxel Dörfler 	int32 index = 0;
277d8e2fb50SAxel Dörfler 	int32 index2 = 0;
2789e34f742SAxel Dörfler 	while (index < inRowBytes) {
279d8e2fb50SAxel Dörfler 		rgb_color color = map->color_list[in[index++]];
280d8e2fb50SAxel Dörfler 
281d8e2fb50SAxel Dörfler 		out[index2++] = color.red;
282d8e2fb50SAxel Dörfler 		out[index2++] = color.green;
283d8e2fb50SAxel Dörfler 		out[index2++] = color.blue;
284d8e2fb50SAxel Dörfler 	}
285d8e2fb50SAxel Dörfler }
286d8e2fb50SAxel Dörfler 
287d8e2fb50SAxel Dörfler 
288d8e2fb50SAxel Dörfler inline void
2899e34f742SAxel Dörfler convert_from_15_to_24(uint8* in, uint8* out, int32 inRowBytes)
290d8e2fb50SAxel Dörfler {
291d8e2fb50SAxel Dörfler 	int32 index = 0;
292d8e2fb50SAxel Dörfler 	int32 index2 = 0;
293d8e2fb50SAxel Dörfler 	int16 in_pixel;
2949e34f742SAxel Dörfler 	while (index < inRowBytes) {
295d8e2fb50SAxel Dörfler 		in_pixel = in[index] | (in[index+1] << 8);
296d8e2fb50SAxel Dörfler 		index += 2;
297d8e2fb50SAxel Dörfler 
298d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x7c00)) >> 7) | (((in_pixel & 0x7c00)) >> 12);
299d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x3e0)) >> 2) | (((in_pixel & 0x3e0)) >> 7);
300d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2);
301d8e2fb50SAxel Dörfler 	}
302d8e2fb50SAxel Dörfler }
303d8e2fb50SAxel Dörfler 
304d8e2fb50SAxel Dörfler 
305d8e2fb50SAxel Dörfler inline void
3069e34f742SAxel Dörfler convert_from_15b_to_24(uint8* in, uint8* out, int32 inRowBytes)
307d8e2fb50SAxel Dörfler {
308d8e2fb50SAxel Dörfler 	int32 index = 0;
309d8e2fb50SAxel Dörfler 	int32 index2 = 0;
310d8e2fb50SAxel Dörfler 	int16 in_pixel;
3119e34f742SAxel Dörfler 	while (index < inRowBytes) {
312d8e2fb50SAxel Dörfler 		in_pixel = in[index+1] | (in[index] << 8);
313d8e2fb50SAxel Dörfler 		index += 2;
314d8e2fb50SAxel Dörfler 
315d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x7c00)) >> 7) | (((in_pixel & 0x7c00)) >> 12);
316d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x3e0)) >> 2) | (((in_pixel & 0x3e0)) >> 7);
317d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2);
318d8e2fb50SAxel Dörfler 	}
319d8e2fb50SAxel Dörfler }
320d8e2fb50SAxel Dörfler 
321d8e2fb50SAxel Dörfler 
322d8e2fb50SAxel Dörfler inline void
3239e34f742SAxel Dörfler convert_from_16_to_24(uint8* in, uint8* out, int32 inRowBytes)
324d8e2fb50SAxel Dörfler {
325d8e2fb50SAxel Dörfler 	int32 index = 0;
326d8e2fb50SAxel Dörfler 	int32 index2 = 0;
327d8e2fb50SAxel Dörfler 	int16 in_pixel;
3289e34f742SAxel Dörfler 	while (index < inRowBytes) {
329d8e2fb50SAxel Dörfler 		in_pixel = in[index] | (in[index+1] << 8);
330d8e2fb50SAxel Dörfler 		index += 2;
331d8e2fb50SAxel Dörfler 
332d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0xf800)) >> 8) | (((in_pixel & 0xf800)) >> 13);
333d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x7e0)) >> 3) | (((in_pixel & 0x7e0)) >> 9);
334d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2);
335d8e2fb50SAxel Dörfler 	}
336d8e2fb50SAxel Dörfler }
337d8e2fb50SAxel Dörfler 
338d8e2fb50SAxel Dörfler 
339d8e2fb50SAxel Dörfler inline void
3409e34f742SAxel Dörfler convert_from_16b_to_24(uint8* in, uint8* out, int32 inRowBytes)
341d8e2fb50SAxel Dörfler {
342d8e2fb50SAxel Dörfler 	int32 index = 0;
343d8e2fb50SAxel Dörfler 	int32 index2 = 0;
344d8e2fb50SAxel Dörfler 	int16 in_pixel;
3459e34f742SAxel Dörfler 	while (index < inRowBytes) {
346d8e2fb50SAxel Dörfler 		in_pixel = in[index+1] | (in[index] << 8);
347d8e2fb50SAxel Dörfler 		index += 2;
348d8e2fb50SAxel Dörfler 
349d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0xf800)) >> 8) | (((in_pixel & 0xf800)) >> 13);
350d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x7e0)) >> 3) | (((in_pixel & 0x7e0)) >> 9);
351d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2);
352d8e2fb50SAxel Dörfler 	}
353d8e2fb50SAxel Dörfler }
354d8e2fb50SAxel Dörfler 
355d8e2fb50SAxel Dörfler 
356d8e2fb50SAxel Dörfler inline void
3579e34f742SAxel Dörfler convert_from_24_to_24(uint8* in, uint8* out, int32 inRowBytes)
358d8e2fb50SAxel Dörfler {
359d8e2fb50SAxel Dörfler 	int32 index = 0;
360d8e2fb50SAxel Dörfler 	int32 index2 = 0;
3619e34f742SAxel Dörfler 	while (index < inRowBytes) {
362d8e2fb50SAxel Dörfler 		out[index2++] = in[index+2];
363d8e2fb50SAxel Dörfler 		out[index2++] = in[index+1];
364d8e2fb50SAxel Dörfler 		out[index2++] = in[index];
365d8e2fb50SAxel Dörfler 		index+=3;
366d8e2fb50SAxel Dörfler 	}
367d8e2fb50SAxel Dörfler }
368d8e2fb50SAxel Dörfler 
369d8e2fb50SAxel Dörfler 
370d8e2fb50SAxel Dörfler inline void
3719e34f742SAxel Dörfler convert_from_32_to_24(uint8* in, uint8* out, int32 inRowBytes)
372d8e2fb50SAxel Dörfler {
37351623681SAxel Dörfler 	inRowBytes /= 4;
37451623681SAxel Dörfler 
3759e34f742SAxel Dörfler 	for (int32 i = 0; i < inRowBytes; i++) {
3769e34f742SAxel Dörfler 		out[0] = in[2];
3779e34f742SAxel Dörfler 		out[1] = in[1];
3789e34f742SAxel Dörfler 		out[2] = in[0];
3799e34f742SAxel Dörfler 
3809e34f742SAxel Dörfler 		in += 4;
3819e34f742SAxel Dörfler 		out += 3;
382d8e2fb50SAxel Dörfler 	}
383d8e2fb50SAxel Dörfler }
384d8e2fb50SAxel Dörfler 
385d8e2fb50SAxel Dörfler 
386d8e2fb50SAxel Dörfler inline void
3879e34f742SAxel Dörfler convert_from_32b_to_24(uint8* in, uint8* out, int32 inRowBytes)
388d8e2fb50SAxel Dörfler {
38951623681SAxel Dörfler 	inRowBytes /= 4;
39051623681SAxel Dörfler 
3919e34f742SAxel Dörfler 	for (int32 i = 0; i < inRowBytes; i++) {
39251623681SAxel Dörfler 		out[0] = in[1];
39351623681SAxel Dörfler 		out[1] = in[2];
39451623681SAxel Dörfler 		out[2] = in[3];
3959e34f742SAxel Dörfler 
3969e34f742SAxel Dörfler 		in += 4;
3979e34f742SAxel Dörfler 		out += 3;
398d8e2fb50SAxel Dörfler 	}
399d8e2fb50SAxel Dörfler }
400d8e2fb50SAxel Dörfler 
401d8e2fb50SAxel Dörfler 
4029e34f742SAxel Dörfler //	#pragma mark - conversion for decompression
4039e34f742SAxel Dörfler 
4049e34f742SAxel Dörfler 
405d8e2fb50SAxel Dörfler inline void
4069e34f742SAxel Dörfler convert_from_CMYK_to_32_photoshop(uint8* in, uint8* out, int32 inRowBytes, int32 xStep)
407d8e2fb50SAxel Dörfler {
4089e34f742SAxel Dörfler 	for (int32 i = 0; i < inRowBytes; i += 4) {
4099e34f742SAxel Dörfler 		int32 black = in[3];
4109e34f742SAxel Dörfler 		out[0] = in[2] * black / 255;
4119e34f742SAxel Dörfler 		out[1] = in[1] * black / 255;
4129e34f742SAxel Dörfler 		out[2] = in[0] * black / 255;
4139e34f742SAxel Dörfler 		out[3] = 255;
4149e34f742SAxel Dörfler 
4159e34f742SAxel Dörfler 		in += 4;
4169e34f742SAxel Dörfler 		out += xStep;
417d8e2fb50SAxel Dörfler 	}
418d8e2fb50SAxel Dörfler }
419d8e2fb50SAxel Dörfler 
420d8e2fb50SAxel Dörfler 
421d8e2fb50SAxel Dörfler //!	!!! UNTESTED !!!
422d8e2fb50SAxel Dörfler inline void
4239e34f742SAxel Dörfler convert_from_CMYK_to_32(uint8* in, uint8* out, int32 inRowBytes, int32 xStep)
424d8e2fb50SAxel Dörfler {
4259e34f742SAxel Dörfler 	for (int32 i = 0; i < inRowBytes; i += 4) {
4269e34f742SAxel Dörfler 		int32 black = 255 - in[3];
4279e34f742SAxel Dörfler 		out[0] = ((255 - in[2]) * black) / 255;
4289e34f742SAxel Dörfler 		out[1] = ((255 - in[1]) * black) / 255;
4299e34f742SAxel Dörfler 		out[2] = ((255 - in[0]) * black) / 255;
4309e34f742SAxel Dörfler 		out[3] = 255;
4319e34f742SAxel Dörfler 
4329e34f742SAxel Dörfler 		in += 4;
4339e34f742SAxel Dörfler 		out += xStep;
434d8e2fb50SAxel Dörfler 	}
435d8e2fb50SAxel Dörfler }
436d8e2fb50SAxel Dörfler 
437d8e2fb50SAxel Dörfler 
438d8e2fb50SAxel Dörfler //!	RGB24 8:8:8 to xRGB 8:8:8:8
439d8e2fb50SAxel Dörfler inline void
4409e34f742SAxel Dörfler convert_from_24_to_32(uint8* in, uint8* out, int32 inRowBytes, int32 xStep)
441d8e2fb50SAxel Dörfler {
4429e34f742SAxel Dörfler 	for (int32 i = 0; i < inRowBytes; i += 3) {
4439e34f742SAxel Dörfler 		out[0] = in[2];
4449e34f742SAxel Dörfler 		out[1] = in[1];
4459e34f742SAxel Dörfler 		out[2] = in[0];
4469e34f742SAxel Dörfler 		out[3] = 255;
4479e34f742SAxel Dörfler 
4489e34f742SAxel Dörfler 		in += 3;
4499e34f742SAxel Dörfler 		out += xStep;
4509e34f742SAxel Dörfler 	}
4519e34f742SAxel Dörfler }
4529e34f742SAxel Dörfler 
4539e34f742SAxel Dörfler 
4549e34f742SAxel Dörfler //! 8-bit to 8-bit, only need when rotating the image
4559e34f742SAxel Dörfler void
4569e34f742SAxel Dörfler translate_8(uint8* in, uint8* out, int32 inRowBytes, int32 xStep)
4579e34f742SAxel Dörfler {
4589e34f742SAxel Dörfler 	for (int32 i = 0; i < inRowBytes; i++) {
4599e34f742SAxel Dörfler 		out[0] = in[0];
4609e34f742SAxel Dörfler 
4619e34f742SAxel Dörfler 		in++;
4629e34f742SAxel Dörfler 		out += xStep;
463d8e2fb50SAxel Dörfler 	}
464d8e2fb50SAxel Dörfler }
465d8e2fb50SAxel Dörfler 
466d8e2fb50SAxel Dörfler 
4678687ff64SAxel Dörfler //	#pragma mark - SView
4688687ff64SAxel Dörfler 
4698687ff64SAxel Dörfler 
4708687ff64SAxel Dörfler SView::SView(const char *name, float x, float y)
4718687ff64SAxel Dörfler 	: BView(BRect(x, y, x, y), name, B_FOLLOW_NONE, B_WILL_DRAW)
4728687ff64SAxel Dörfler {
4738687ff64SAxel Dörfler 	fPreferredWidth = 0;
4748687ff64SAxel Dörfler 	fPreferredHeight = 0;
4758687ff64SAxel Dörfler 
4768687ff64SAxel Dörfler 	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
4778687ff64SAxel Dörfler 	SetLowColor(ViewColor());
4788687ff64SAxel Dörfler 
4798687ff64SAxel Dörfler 	SetFont(be_plain_font);
4808687ff64SAxel Dörfler }
4818687ff64SAxel Dörfler 
4828687ff64SAxel Dörfler 
4838687ff64SAxel Dörfler void
4848687ff64SAxel Dörfler SView::GetPreferredSize(float* _width, float* _height)
4858687ff64SAxel Dörfler {
4868687ff64SAxel Dörfler 	if (_width)
4878687ff64SAxel Dörfler 		*_width = fPreferredWidth;
4888687ff64SAxel Dörfler 	if (_height)
4898687ff64SAxel Dörfler 		*_height = fPreferredHeight;
4908687ff64SAxel Dörfler }
4918687ff64SAxel Dörfler 
4928687ff64SAxel Dörfler 
4938687ff64SAxel Dörfler void
4948687ff64SAxel Dörfler SView::ResizeToPreferred()
4958687ff64SAxel Dörfler {
4968687ff64SAxel Dörfler 	ResizeTo(fPreferredWidth, fPreferredHeight);
4978687ff64SAxel Dörfler }
4988687ff64SAxel Dörfler 
4998687ff64SAxel Dörfler 
5008687ff64SAxel Dörfler void
5018687ff64SAxel Dörfler SView::ResizePreferredBy(float width, float height)
5028687ff64SAxel Dörfler {
5038687ff64SAxel Dörfler 	fPreferredWidth += width;
5048687ff64SAxel Dörfler 	fPreferredHeight += height;
5058687ff64SAxel Dörfler }
5068687ff64SAxel Dörfler 
5078687ff64SAxel Dörfler 
5088687ff64SAxel Dörfler void
509f9810471SAxel Dörfler SView::AddChild(BView *child, BView *before)
5108687ff64SAxel Dörfler {
5118687ff64SAxel Dörfler 	BView::AddChild(child, before);
5128687ff64SAxel Dörfler 	child->ResizeToPreferred();
5138687ff64SAxel Dörfler 	BRect frame = child->Frame();
5148687ff64SAxel Dörfler 
5158687ff64SAxel Dörfler 	if (frame.right > fPreferredWidth)
5168687ff64SAxel Dörfler 		fPreferredWidth = frame.right;
5178687ff64SAxel Dörfler 	if (frame.bottom > fPreferredHeight)
5188687ff64SAxel Dörfler 		fPreferredHeight = frame.bottom;
5198687ff64SAxel Dörfler }
5208687ff64SAxel Dörfler 
5218687ff64SAxel Dörfler 
522d8e2fb50SAxel Dörfler //	#pragma mark -
523d8e2fb50SAxel Dörfler 
524d8e2fb50SAxel Dörfler 
525d8e2fb50SAxel Dörfler SSlider::SSlider(BRect frame, const char *name, const char *label,
526d8e2fb50SAxel Dörfler 		BMessage *message, int32 minValue, int32 maxValue, orientation posture,
527d8e2fb50SAxel Dörfler 		thumb_style thumbType, uint32 resizingMode, uint32 flags)
528d8e2fb50SAxel Dörfler 	: BSlider(frame, name, label, message, minValue, maxValue,
529d8e2fb50SAxel Dörfler 		posture, thumbType, resizingMode, flags)
5309949213aSStephan Aßmus {
5318687ff64SAxel Dörfler 	rgb_color barColor = { 0, 0, 229, 255 };
5328687ff64SAxel Dörfler 	UseFillColor(true, &barColor);
5339949213aSStephan Aßmus }
5349949213aSStephan Aßmus 
5358687ff64SAxel Dörfler 
5368687ff64SAxel Dörfler //!	Update status string - show actual value
5379949213aSStephan Aßmus char*
5389949213aSStephan Aßmus SSlider::UpdateText() const
5399949213aSStephan Aßmus {
5408687ff64SAxel Dörfler 	snprintf(fStatusLabel, sizeof(fStatusLabel), "%ld", Value());
5418687ff64SAxel Dörfler 	return fStatusLabel;
5429949213aSStephan Aßmus }
5439949213aSStephan Aßmus 
5448687ff64SAxel Dörfler 
5458687ff64SAxel Dörfler //!	BSlider::ResizeToPreferred + Resize width if it's too small to show label and status
5469949213aSStephan Aßmus void
5479949213aSStephan Aßmus SSlider::ResizeToPreferred()
5489949213aSStephan Aßmus {
5499949213aSStephan Aßmus 	int32 width = (int32)ceil(StringWidth(Label()) + StringWidth("9999"));
5508687ff64SAxel Dörfler 	if (width < 230)
5518687ff64SAxel Dörfler 		width = 230;
5528687ff64SAxel Dörfler 
5539949213aSStephan Aßmus 	float w, h;
5549949213aSStephan Aßmus 	GetPreferredSize(&w, &h);
5559949213aSStephan Aßmus 	ResizeTo(width, h);
5569949213aSStephan Aßmus }
5579949213aSStephan Aßmus 
5589949213aSStephan Aßmus 
559d8e2fb50SAxel Dörfler //	#pragma mark -
5609949213aSStephan Aßmus 
561d8e2fb50SAxel Dörfler 
562d8e2fb50SAxel Dörfler TranslatorReadView::TranslatorReadView(const char *name, jpeg_settings *settings,
563d8e2fb50SAxel Dörfler 		float x, float y)
5649949213aSStephan Aßmus 	: SView(name, x, y),
565d8e2fb50SAxel Dörfler 	fSettings(settings)
5669949213aSStephan Aßmus {
5678687ff64SAxel Dörfler 	fAlwaysRGB32 = new BCheckBox(BRect(10, GetPreferredHeight(), 10,
568d8e2fb50SAxel Dörfler 		GetPreferredHeight()), "alwaysrgb32", VIEW_LABEL_ALWAYSRGB32,
569d8e2fb50SAxel Dörfler 		new BMessage(VIEW_MSG_SET_ALWAYSRGB32));
5708687ff64SAxel Dörfler 	fAlwaysRGB32->SetFont(be_plain_font);
571d8e2fb50SAxel Dörfler 	if (fSettings->Always_B_RGB32)
5728687ff64SAxel Dörfler 		fAlwaysRGB32->SetValue(1);
5739949213aSStephan Aßmus 
5748687ff64SAxel Dörfler 	AddChild(fAlwaysRGB32);
5759949213aSStephan Aßmus 
5768687ff64SAxel Dörfler 	fPhotoshopCMYK = new BCheckBox(BRect(10, GetPreferredHeight(), 10,
5778687ff64SAxel Dörfler 		GetPreferredHeight()), "photoshopCMYK", VIEW_LABEL_PHOTOSHOPCMYK,
5788687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_PHOTOSHOPCMYK));
5798687ff64SAxel Dörfler 	fPhotoshopCMYK->SetFont(be_plain_font);
580d8e2fb50SAxel Dörfler 	if (fSettings->PhotoshopCMYK)
5818687ff64SAxel Dörfler 		fPhotoshopCMYK->SetValue(1);
5829949213aSStephan Aßmus 
5838687ff64SAxel Dörfler 	AddChild(fPhotoshopCMYK);
5849949213aSStephan Aßmus 
5858687ff64SAxel Dörfler 	fShowErrorBox = new BCheckBox(BRect(10, GetPreferredHeight(), 10,
5868687ff64SAxel Dörfler 		GetPreferredHeight()), "error", VIEW_LABEL_SHOWREADERRORBOX,
5878687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_SHOWREADERRORBOX));
5888687ff64SAxel Dörfler 	fShowErrorBox->SetFont(be_plain_font);
589d8e2fb50SAxel Dörfler 	if (fSettings->ShowReadWarningBox)
5908687ff64SAxel Dörfler 		fShowErrorBox->SetValue(1);
5919949213aSStephan Aßmus 
5928687ff64SAxel Dörfler 	AddChild(fShowErrorBox);
5939949213aSStephan Aßmus 
5949949213aSStephan Aßmus 	ResizeToPreferred();
5959949213aSStephan Aßmus }
5969949213aSStephan Aßmus 
5978687ff64SAxel Dörfler 
5989949213aSStephan Aßmus void
5999949213aSStephan Aßmus TranslatorReadView::AttachedToWindow()
6009949213aSStephan Aßmus {
6018687ff64SAxel Dörfler 	fAlwaysRGB32->SetTarget(this);
6028687ff64SAxel Dörfler 	fPhotoshopCMYK->SetTarget(this);
6038687ff64SAxel Dörfler 	fShowErrorBox->SetTarget(this);
6049949213aSStephan Aßmus }
6059949213aSStephan Aßmus 
6068687ff64SAxel Dörfler 
6079949213aSStephan Aßmus void
6089949213aSStephan Aßmus TranslatorReadView::MessageReceived(BMessage* message)
6099949213aSStephan Aßmus {
6108687ff64SAxel Dörfler 	switch (message->what) {
6119949213aSStephan Aßmus 		case VIEW_MSG_SET_ALWAYSRGB32:
6129949213aSStephan Aßmus 		{
6139949213aSStephan Aßmus 			int32 value;
6149949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
615d8e2fb50SAxel Dörfler 				fSettings->Always_B_RGB32 = value;
616d8e2fb50SAxel Dörfler 				SaveSettings(fSettings);
6179949213aSStephan Aßmus 			}
6189949213aSStephan Aßmus 			break;
6199949213aSStephan Aßmus 		}
6209949213aSStephan Aßmus 		case VIEW_MSG_SET_PHOTOSHOPCMYK:
6219949213aSStephan Aßmus 		{
6229949213aSStephan Aßmus 			int32 value;
6239949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
624d8e2fb50SAxel Dörfler 				fSettings->PhotoshopCMYK = value;
625d8e2fb50SAxel Dörfler 				SaveSettings(fSettings);
6269949213aSStephan Aßmus 			}
6279949213aSStephan Aßmus 			break;
6289949213aSStephan Aßmus 		}
6299949213aSStephan Aßmus 		case VIEW_MSG_SET_SHOWREADERRORBOX:
6309949213aSStephan Aßmus 		{
6319949213aSStephan Aßmus 			int32 value;
6329949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
633d8e2fb50SAxel Dörfler 				fSettings->ShowReadWarningBox = value;
634d8e2fb50SAxel Dörfler 				SaveSettings(fSettings);
6359949213aSStephan Aßmus 			}
6369949213aSStephan Aßmus 			break;
6379949213aSStephan Aßmus 		}
6389949213aSStephan Aßmus 		default:
6399949213aSStephan Aßmus 			BView::MessageReceived(message);
6409949213aSStephan Aßmus 			break;
6419949213aSStephan Aßmus 	}
6429949213aSStephan Aßmus }
6439949213aSStephan Aßmus 
6449949213aSStephan Aßmus 
6458687ff64SAxel Dörfler //	#pragma mark - TranslatorWriteView
6469949213aSStephan Aßmus 
6478687ff64SAxel Dörfler 
6488687ff64SAxel Dörfler TranslatorWriteView::TranslatorWriteView(const char *name, jpeg_settings *settings,
6498687ff64SAxel Dörfler 		float x, float y)
6509949213aSStephan Aßmus 	: SView(name, x, y),
651d8e2fb50SAxel Dörfler 	fSettings(settings)
6529949213aSStephan Aßmus {
6538687ff64SAxel Dörfler 	fQualitySlider = new SSlider(BRect(10, GetPreferredHeight(), 10,
6548687ff64SAxel Dörfler 		GetPreferredHeight()), "quality", VIEW_LABEL_QUALITY,
6558687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_QUALITY), 0, 100);
6568687ff64SAxel Dörfler 	fQualitySlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
6578687ff64SAxel Dörfler 	fQualitySlider->SetHashMarkCount(10);
6588687ff64SAxel Dörfler 	fQualitySlider->SetLimitLabels("Low", "High");
6598687ff64SAxel Dörfler 	fQualitySlider->SetFont(be_plain_font);
6608687ff64SAxel Dörfler 	fQualitySlider->SetValue(fSettings->Quality);
6618687ff64SAxel Dörfler 	AddChild(fQualitySlider);
6629949213aSStephan Aßmus 
6638687ff64SAxel Dörfler 	fSmoothingSlider = new SSlider(BRect(10, GetPreferredHeight()+10, 10,
6648687ff64SAxel Dörfler 		GetPreferredHeight()), "smoothing", VIEW_LABEL_SMOOTHING,
6658687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_SMOOTHING), 0, 100);
6668687ff64SAxel Dörfler 	fSmoothingSlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
6678687ff64SAxel Dörfler 	fSmoothingSlider->SetHashMarkCount(10);
6688687ff64SAxel Dörfler 	fSmoothingSlider->SetLimitLabels("None", "High");
6698687ff64SAxel Dörfler 	fSmoothingSlider->SetFont(be_plain_font);
6708687ff64SAxel Dörfler 	fSmoothingSlider->SetValue(fSettings->Smoothing);
6718687ff64SAxel Dörfler 	AddChild(fSmoothingSlider);
6729949213aSStephan Aßmus 
6738687ff64SAxel Dörfler 	fProgress = new BCheckBox(BRect(10, GetPreferredHeight()+10, 10,
6748687ff64SAxel Dörfler 		GetPreferredHeight()), "progress", VIEW_LABEL_PROGRESSIVE,
6758687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_PROGRESSIVE));
6768687ff64SAxel Dörfler 	fProgress->SetFont(be_plain_font);
677d8e2fb50SAxel Dörfler 	if (fSettings->Progressive)
6788687ff64SAxel Dörfler 		fProgress->SetValue(1);
6799949213aSStephan Aßmus 
6808687ff64SAxel Dörfler 	AddChild(fProgress);
6819949213aSStephan Aßmus 
6828687ff64SAxel Dörfler 	fOptimizeColors = new BCheckBox(BRect(10, GetPreferredHeight()+5, 10,
6838687ff64SAxel Dörfler 		GetPreferredHeight() + 5), "optimizecolors", VIEW_LABEL_OPTIMIZECOLORS,
6848687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_OPTIMIZECOLORS));
6858687ff64SAxel Dörfler 	fOptimizeColors->SetFont(be_plain_font);
686d8e2fb50SAxel Dörfler 	if (fSettings->OptimizeColors)
6878687ff64SAxel Dörfler 		fOptimizeColors->SetValue(1);
6889949213aSStephan Aßmus 
6898687ff64SAxel Dörfler 	AddChild(fOptimizeColors);
6909949213aSStephan Aßmus 
6918687ff64SAxel Dörfler 	fSmallerFile = new BCheckBox(BRect(25, GetPreferredHeight()+5, 25,
6928687ff64SAxel Dörfler 		GetPreferredHeight() + 5), "smallerfile", VIEW_LABEL_SMALLERFILE,
6938687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_SMALLERFILE));
6948687ff64SAxel Dörfler 	fSmallerFile->SetFont(be_plain_font);
695d8e2fb50SAxel Dörfler 	if (fSettings->SmallerFile)
6968687ff64SAxel Dörfler 		fSmallerFile->SetValue(1);
697d8e2fb50SAxel Dörfler 	if (!fSettings->OptimizeColors)
6988687ff64SAxel Dörfler 		fSmallerFile->SetEnabled(false);
6999949213aSStephan Aßmus 
7008687ff64SAxel Dörfler 	AddChild(fSmallerFile);
7019949213aSStephan Aßmus 
7028687ff64SAxel Dörfler 	fGrayAsRGB24 = new BCheckBox(BRect(10, GetPreferredHeight()+5, 25,
7038687ff64SAxel Dörfler 		GetPreferredHeight()+5), "gray1asrgb24", VIEW_LABEL_GRAY1ASRGB24,
7048687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_GRAY1ASRGB24));
7058687ff64SAxel Dörfler 	fGrayAsRGB24->SetFont(be_plain_font);
706d8e2fb50SAxel Dörfler 	if (fSettings->B_GRAY1_as_B_RGB24)
7078687ff64SAxel Dörfler 		fGrayAsRGB24->SetValue(1);
7089949213aSStephan Aßmus 
7098687ff64SAxel Dörfler 	AddChild(fGrayAsRGB24);
7109949213aSStephan Aßmus 
7119949213aSStephan Aßmus 	ResizeToPreferred();
7129949213aSStephan Aßmus }
7139949213aSStephan Aßmus 
7148687ff64SAxel Dörfler 
7159949213aSStephan Aßmus void
7169949213aSStephan Aßmus TranslatorWriteView::AttachedToWindow()
7179949213aSStephan Aßmus {
7188687ff64SAxel Dörfler 	fQualitySlider->SetTarget(this);
7198687ff64SAxel Dörfler 	fSmoothingSlider->SetTarget(this);
7208687ff64SAxel Dörfler 	fProgress->SetTarget(this);
7218687ff64SAxel Dörfler 	fOptimizeColors->SetTarget(this);
7228687ff64SAxel Dörfler 	fSmallerFile->SetTarget(this);
7238687ff64SAxel Dörfler 	fGrayAsRGB24->SetTarget(this);
7249949213aSStephan Aßmus }
7259949213aSStephan Aßmus 
7268687ff64SAxel Dörfler 
7279949213aSStephan Aßmus void
7289949213aSStephan Aßmus TranslatorWriteView::MessageReceived(BMessage *message)
7299949213aSStephan Aßmus {
7308687ff64SAxel Dörfler 	switch (message->what) {
7319949213aSStephan Aßmus 		case VIEW_MSG_SET_QUALITY:
7329949213aSStephan Aßmus 		{
7339949213aSStephan Aßmus 			int32 value;
7349949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
735d8e2fb50SAxel Dörfler 				fSettings->Quality = value;
736d8e2fb50SAxel Dörfler 				SaveSettings(fSettings);
7379949213aSStephan Aßmus 			}
7389949213aSStephan Aßmus 			break;
7399949213aSStephan Aßmus 		}
7409949213aSStephan Aßmus 		case VIEW_MSG_SET_SMOOTHING:
7419949213aSStephan Aßmus 		{
7429949213aSStephan Aßmus 			int32 value;
7439949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
744d8e2fb50SAxel Dörfler 				fSettings->Smoothing = value;
745d8e2fb50SAxel Dörfler 				SaveSettings(fSettings);
7469949213aSStephan Aßmus 			}
7479949213aSStephan Aßmus 			break;
7489949213aSStephan Aßmus 		}
7499949213aSStephan Aßmus 		case VIEW_MSG_SET_PROGRESSIVE:
7509949213aSStephan Aßmus 		{
7519949213aSStephan Aßmus 			int32 value;
7529949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
753d8e2fb50SAxel Dörfler 				fSettings->Progressive = value;
754d8e2fb50SAxel Dörfler 				SaveSettings(fSettings);
7559949213aSStephan Aßmus 			}
7569949213aSStephan Aßmus 			break;
7579949213aSStephan Aßmus 		}
7589949213aSStephan Aßmus 		case VIEW_MSG_SET_OPTIMIZECOLORS:
7599949213aSStephan Aßmus 		{
7609949213aSStephan Aßmus 			int32 value;
7619949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
762d8e2fb50SAxel Dörfler 				fSettings->OptimizeColors = value;
763d8e2fb50SAxel Dörfler 				SaveSettings(fSettings);
7649949213aSStephan Aßmus 			}
7658687ff64SAxel Dörfler 			fSmallerFile->SetEnabled(fSettings->OptimizeColors);
7669949213aSStephan Aßmus 			break;
7679949213aSStephan Aßmus 		}
7689949213aSStephan Aßmus 		case VIEW_MSG_SET_SMALLERFILE:
7699949213aSStephan Aßmus 		{
7709949213aSStephan Aßmus 			int32 value;
7719949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
772d8e2fb50SAxel Dörfler 				fSettings->SmallerFile = value;
773d8e2fb50SAxel Dörfler 				SaveSettings(fSettings);
7749949213aSStephan Aßmus 			}
7759949213aSStephan Aßmus 			break;
7769949213aSStephan Aßmus 		}
7779949213aSStephan Aßmus 		case VIEW_MSG_SET_GRAY1ASRGB24:
7789949213aSStephan Aßmus 		{
7799949213aSStephan Aßmus 			int32 value;
7809949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
781d8e2fb50SAxel Dörfler 				fSettings->B_GRAY1_as_B_RGB24 = value;
782d8e2fb50SAxel Dörfler 				SaveSettings(fSettings);
7839949213aSStephan Aßmus 			}
7849949213aSStephan Aßmus 			break;
7859949213aSStephan Aßmus 		}
7869949213aSStephan Aßmus 		default:
7879949213aSStephan Aßmus 			BView::MessageReceived(message);
7889949213aSStephan Aßmus 			break;
7899949213aSStephan Aßmus 	}
7909949213aSStephan Aßmus }
7919949213aSStephan Aßmus 
7929949213aSStephan Aßmus 
793d8e2fb50SAxel Dörfler //	#pragma mark -
7949949213aSStephan Aßmus 
795d8e2fb50SAxel Dörfler 
7969949213aSStephan Aßmus TranslatorAboutView::TranslatorAboutView(const char *name, float x, float y)
7979949213aSStephan Aßmus 	: SView(name, x, y)
7989949213aSStephan Aßmus {
7998687ff64SAxel Dörfler 	BStringView *title = new BStringView(BRect(10, 0, 10, 0), "Title",
8008687ff64SAxel Dörfler 		translatorName);
8019949213aSStephan Aßmus 	title->SetFont(be_bold_font);
8029949213aSStephan Aßmus 
8039949213aSStephan Aßmus 	AddChild(title);
8049949213aSStephan Aßmus 
8059949213aSStephan Aßmus 	BRect rect = title->Bounds();
8069949213aSStephan Aßmus 	float space = title->StringWidth("    ");
8079949213aSStephan Aßmus 
8089949213aSStephan Aßmus 	char versionString[16];
809d8e2fb50SAxel Dörfler 	sprintf(versionString, "v%d.%d.%d", (int)(translatorVersion >> 8),
810d8e2fb50SAxel Dörfler 		(int)((translatorVersion >> 4) & 0xf), (int)(translatorVersion & 0xf));
8119949213aSStephan Aßmus 
812d8e2fb50SAxel Dörfler 	BStringView *version = new BStringView(BRect(rect.right+space, rect.top,
813d8e2fb50SAxel Dörfler 		rect.right+space, rect.top), "Version", versionString);
8149949213aSStephan Aßmus 	version->SetFont(be_plain_font);
8159949213aSStephan Aßmus 	version->SetFontSize(9);
8169949213aSStephan Aßmus 	// Make version be in the same line as title
8179949213aSStephan Aßmus 	version->ResizeToPreferred();
8189949213aSStephan Aßmus 	version->MoveBy(0, rect.bottom-version->Frame().bottom);
8199949213aSStephan Aßmus 
8209949213aSStephan Aßmus 	AddChild(version);
8219949213aSStephan Aßmus 
8228687ff64SAxel Dörfler 	// Now for each line in translatorInfo add a BStringView
8238687ff64SAxel Dörfler 	char* current = translatorInfo;
8248687ff64SAxel Dörfler 	int32 index = 1;
8258687ff64SAxel Dörfler 	while (current != NULL && current[0]) {
8268687ff64SAxel Dörfler 		char text[128];
8278687ff64SAxel Dörfler 		char* newLine = strchr(current, '\n');
8288687ff64SAxel Dörfler 		if (newLine == NULL) {
8298687ff64SAxel Dörfler 			strlcpy(text, current, sizeof(text));
8308687ff64SAxel Dörfler 			current = NULL;
8318687ff64SAxel Dörfler 		} else {
8328687ff64SAxel Dörfler 			strlcpy(text, current, min_c((int32)sizeof(text), newLine + 1 - current));
8338687ff64SAxel Dörfler 			current = newLine + 1;
8348687ff64SAxel Dörfler 		}
8359949213aSStephan Aßmus 
8368687ff64SAxel Dörfler 		BStringView* string = new BStringView(BRect(10, GetPreferredHeight(),
8378687ff64SAxel Dörfler 			10, GetPreferredHeight()), "copyright", text);
8388687ff64SAxel Dörfler 		if (index > 3)
8398687ff64SAxel Dörfler 			string->SetFontSize(9);
8408687ff64SAxel Dörfler 		AddChild(string);
8418687ff64SAxel Dörfler 
8428687ff64SAxel Dörfler 		index++;
8439949213aSStephan Aßmus 	}
8449949213aSStephan Aßmus 
8459949213aSStephan Aßmus 	ResizeToPreferred();
8469949213aSStephan Aßmus }
8479949213aSStephan Aßmus 
8489949213aSStephan Aßmus 
849d8e2fb50SAxel Dörfler //	#pragma mark -
8509949213aSStephan Aßmus 
851d8e2fb50SAxel Dörfler 
8529949213aSStephan Aßmus TranslatorView::TranslatorView(const char *name)
853d8e2fb50SAxel Dörfler 	: SView(name),
854d8e2fb50SAxel Dörfler 	fTabWidth(30),
855d8e2fb50SAxel Dörfler 	fActiveChild(0)
8569949213aSStephan Aßmus {
8579949213aSStephan Aßmus 	// Set global var to true
858d8e2fb50SAxel Dörfler 	gAreSettingsRunning = true;
8599949213aSStephan Aßmus 
860d8e2fb50SAxel Dörfler 	// Load settings to global settings struct
861d8e2fb50SAxel Dörfler 	LoadSettings(&fSettings);
8629949213aSStephan Aßmus 
8638687ff64SAxel Dörfler 	font_height fontHeight;
8648687ff64SAxel Dörfler 	GetFontHeight(&fontHeight);
8658687ff64SAxel Dörfler 	fTabHeight = (int32)ceilf(fontHeight.ascent + fontHeight.descent + fontHeight.leading) + 7;
8669949213aSStephan Aßmus 	// Add left and top margins
8678687ff64SAxel Dörfler 	float top = fTabHeight + 20;
8689949213aSStephan Aßmus 	float left = 0;
8699949213aSStephan Aßmus 
8709949213aSStephan Aßmus 	// This will remember longest string width
8719949213aSStephan Aßmus 	int32 nameWidth = 0;
8729949213aSStephan Aßmus 
873d8e2fb50SAxel Dörfler 	SView *view = new TranslatorWriteView("Write", &fSettings, left, top);
8749949213aSStephan Aßmus 	AddChild(view);
875d8e2fb50SAxel Dörfler 	nameWidth = (int32)StringWidth(view->Name());
8768687ff64SAxel Dörfler 	fTabs.AddItem(new BTab(view));
8779949213aSStephan Aßmus 
878d8e2fb50SAxel Dörfler 	view = new TranslatorReadView("Read", &fSettings, left, top);
8799949213aSStephan Aßmus 	AddChild(view);
8809949213aSStephan Aßmus 	if (nameWidth < StringWidth(view->Name()))
881d8e2fb50SAxel Dörfler 		nameWidth = (int32)StringWidth(view->Name());
8828687ff64SAxel Dörfler 	fTabs.AddItem(new BTab(view));
8839949213aSStephan Aßmus 
8849949213aSStephan Aßmus 	view = new TranslatorAboutView("About", left, top);
8859949213aSStephan Aßmus 	AddChild(view);
8869949213aSStephan Aßmus 	if (nameWidth < StringWidth(view->Name()))
887d8e2fb50SAxel Dörfler 		nameWidth = (int32)StringWidth(view->Name());
8888687ff64SAxel Dörfler 	fTabs.AddItem(new BTab(view));
8899949213aSStephan Aßmus 
890d8e2fb50SAxel Dörfler 	fTabWidth += nameWidth;
891d8e2fb50SAxel Dörfler 	if (fTabWidth * CountChildren() > GetPreferredWidth())
892d8e2fb50SAxel Dörfler 		ResizePreferredBy((fTabWidth * CountChildren()) - GetPreferredWidth(), 0);
8939949213aSStephan Aßmus 
8949949213aSStephan Aßmus 	// Add right and bottom margins
8959949213aSStephan Aßmus 	ResizePreferredBy(10, 15);
8969949213aSStephan Aßmus 
8979949213aSStephan Aßmus 	ResizeToPreferred();
8989949213aSStephan Aßmus 
8999949213aSStephan Aßmus 	// Make TranslatorView resize itself with parent
9009949213aSStephan Aßmus 	SetFlags(Flags() | B_FOLLOW_ALL);
9019949213aSStephan Aßmus }
9029949213aSStephan Aßmus 
903d8e2fb50SAxel Dörfler 
904d8e2fb50SAxel Dörfler TranslatorView::~TranslatorView()
905d8e2fb50SAxel Dörfler {
906d8e2fb50SAxel Dörfler 	gAreSettingsRunning = false;
9078687ff64SAxel Dörfler 
9088687ff64SAxel Dörfler 	BTab* tab;
9098687ff64SAxel Dörfler 	while ((tab = (BTab*)fTabs.RemoveItem((int32)0)) != NULL) {
9108687ff64SAxel Dörfler 		delete tab;
9118687ff64SAxel Dörfler 	}
912d8e2fb50SAxel Dörfler }
913d8e2fb50SAxel Dörfler 
914d8e2fb50SAxel Dörfler 
915d8e2fb50SAxel Dörfler //!	Attached to window - resize parent to preferred
9169949213aSStephan Aßmus void
9179949213aSStephan Aßmus TranslatorView::AttachedToWindow()
9189949213aSStephan Aßmus {
9199949213aSStephan Aßmus 	// Hide all children except first one
920d8e2fb50SAxel Dörfler 	BView *child;
9219949213aSStephan Aßmus 	int32 index = 1;
922d8e2fb50SAxel Dörfler 	while ((child = ChildAt(index++)) != NULL)
9239949213aSStephan Aßmus 		child->Hide();
9249949213aSStephan Aßmus 
9258687ff64SAxel Dörfler }
9268687ff64SAxel Dörfler 
9278687ff64SAxel Dörfler 
9288687ff64SAxel Dörfler BRect
9298687ff64SAxel Dörfler TranslatorView::_TabFrame(int32 index) const
9308687ff64SAxel Dörfler {
9318687ff64SAxel Dörfler 	return BRect(index * fTabWidth, 10, (index + 1) * fTabWidth, 10 + fTabHeight);
9329949213aSStephan Aßmus }
9339949213aSStephan Aßmus 
934d8e2fb50SAxel Dörfler 
9359949213aSStephan Aßmus void
9369949213aSStephan Aßmus TranslatorView::Draw(BRect updateRect)
9379949213aSStephan Aßmus {
9389949213aSStephan Aßmus 	// This is needed because DataTranslations app hides children
9399949213aSStephan Aßmus 	// after user changes translator
940d8e2fb50SAxel Dörfler 	if (ChildAt(fActiveChild)->IsHidden())
941d8e2fb50SAxel Dörfler 		ChildAt(fActiveChild)->Show();
9429949213aSStephan Aßmus 
9439949213aSStephan Aßmus 	// Clear
9449949213aSStephan Aßmus 	SetHighColor(ViewColor());
9458687ff64SAxel Dörfler 	BRect frame = _TabFrame(0);
9468687ff64SAxel Dörfler 	FillRect(BRect(frame.left, frame.top, Bounds().right, frame.bottom - 1));
9479949213aSStephan Aßmus 
948d8e2fb50SAxel Dörfler 	int32 index = 0;
9498687ff64SAxel Dörfler 	BTab* tab;
9508687ff64SAxel Dörfler 	while ((tab = (BTab*)fTabs.ItemAt(index)) != NULL) {
9518687ff64SAxel Dörfler 		tab_position position;
9528687ff64SAxel Dörfler 		if (fActiveChild == index)
9538687ff64SAxel Dörfler 			position = B_TAB_FRONT;
9548687ff64SAxel Dörfler 		else if (index == 0)
9558687ff64SAxel Dörfler 			position = B_TAB_FIRST;
9569949213aSStephan Aßmus 		else
9578687ff64SAxel Dörfler 			position = B_TAB_ANY;
9589949213aSStephan Aßmus 
9598687ff64SAxel Dörfler 		tab->DrawTab(this, _TabFrame(index), position, index + 1 != fActiveChild);
9609949213aSStephan Aßmus 		index++;
9619949213aSStephan Aßmus 	}
962d8e2fb50SAxel Dörfler 
9638687ff64SAxel Dörfler 	// Draw bottom edge
9648687ff64SAxel Dörfler 	SetHighColor(tint_color(ViewColor(), B_LIGHTEN_MAX_TINT));
9658687ff64SAxel Dörfler 
9668687ff64SAxel Dörfler 	BRect selectedFrame = _TabFrame(fActiveChild);
9678687ff64SAxel Dörfler 	float offset = ceilf(frame.Height() / 2.0);
9688687ff64SAxel Dörfler 
9698687ff64SAxel Dörfler 	if (selectedFrame.left > frame.left) {
9708687ff64SAxel Dörfler 		StrokeLine(BPoint(frame.left, frame.bottom),
9718687ff64SAxel Dörfler 			BPoint(selectedFrame.left, frame.bottom));
9728687ff64SAxel Dörfler 	}
9738687ff64SAxel Dörfler 	if (selectedFrame.right + offset < Bounds().right) {
9748687ff64SAxel Dörfler 		StrokeLine(BPoint(selectedFrame.right + offset, frame.bottom),
9758687ff64SAxel Dörfler 			BPoint(Bounds().right, frame.bottom));
9768687ff64SAxel Dörfler 	}
9779949213aSStephan Aßmus }
9789949213aSStephan Aßmus 
979d8e2fb50SAxel Dörfler 
980d8e2fb50SAxel Dörfler //!	MouseDown, check if on tab, if so change tab if needed
9819949213aSStephan Aßmus void
9829949213aSStephan Aßmus TranslatorView::MouseDown(BPoint where)
9839949213aSStephan Aßmus {
9848687ff64SAxel Dörfler 	BRect frame = _TabFrame(fTabs.CountItems() - 1);
9858687ff64SAxel Dörfler 	frame.left = 0;
9868687ff64SAxel Dörfler 	if (!frame.Contains(where))
9878687ff64SAxel Dörfler 		return;
9888687ff64SAxel Dörfler 
9898687ff64SAxel Dörfler 	for (int32 index = fTabs.CountItems(); index-- > 0;) {
9908687ff64SAxel Dörfler 		if (!_TabFrame(index).Contains(where))
9918687ff64SAxel Dörfler 			continue;
9928687ff64SAxel Dörfler 
993d8e2fb50SAxel Dörfler 		if (fActiveChild != index) {
9949949213aSStephan Aßmus 			// Hide current visible child
995d8e2fb50SAxel Dörfler 			ChildAt(fActiveChild)->Hide();
9968687ff64SAxel Dörfler 
9979949213aSStephan Aßmus 			// This loop is needed because it looks like in DataTranslations
9989949213aSStephan Aßmus 			// view gets hidden more than one time when user changes translator
9998687ff64SAxel Dörfler 			while (ChildAt(index)->IsHidden()) {
10009949213aSStephan Aßmus 				ChildAt(index)->Show();
10018687ff64SAxel Dörfler 			}
10028687ff64SAxel Dörfler 
10039949213aSStephan Aßmus 			// Remember which one is currently visible
1004d8e2fb50SAxel Dörfler 			fActiveChild = index;
10058687ff64SAxel Dörfler 			Invalidate(frame);
10068687ff64SAxel Dörfler 			break;
10079949213aSStephan Aßmus 		}
10089949213aSStephan Aßmus 	}
1009d8e2fb50SAxel Dörfler }
10109949213aSStephan Aßmus 
10119949213aSStephan Aßmus 
1012d8e2fb50SAxel Dörfler //	#pragma mark -
10139949213aSStephan Aßmus 
1014d8e2fb50SAxel Dörfler 
1015d8e2fb50SAxel Dörfler TranslatorWindow::TranslatorWindow(bool quitOnClose)
1016117da2d7SAxel Dörfler 	: BWindow(BRect(100, 100, 100, 100), "JPEG Settings", B_TITLED_WINDOW,
1017117da2d7SAxel Dörfler 		B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS)
10189949213aSStephan Aßmus {
10199949213aSStephan Aßmus 	BRect extent(0, 0, 0, 0);
10209949213aSStephan Aßmus 	BView *config = NULL;
10219949213aSStephan Aßmus 	MakeConfig(NULL, &config, &extent);
10229949213aSStephan Aßmus 
10239949213aSStephan Aßmus 	AddChild(config);
10249949213aSStephan Aßmus 	ResizeTo(extent.Width(), extent.Height());
10259949213aSStephan Aßmus 
10269949213aSStephan Aßmus 	// Make application quit after this window close
1027d8e2fb50SAxel Dörfler 	if (quitOnClose)
10289949213aSStephan Aßmus 		SetFlags(Flags() | B_QUIT_ON_WINDOW_CLOSE);
10299949213aSStephan Aßmus }
10309949213aSStephan Aßmus 
10319949213aSStephan Aßmus 
1032d8e2fb50SAxel Dörfler //	#pragma mark - Translator Add-On
10339949213aSStephan Aßmus 
10349949213aSStephan Aßmus 
10359949213aSStephan Aßmus 
1036d8e2fb50SAxel Dörfler /*! Hook to create and return our configuration view */
10379949213aSStephan Aßmus status_t
10389949213aSStephan Aßmus MakeConfig(BMessage *ioExtension, BView **outView, BRect *outExtent)
10399949213aSStephan Aßmus {
10409949213aSStephan Aßmus 	*outView = new TranslatorView("TranslatorView");
10419949213aSStephan Aßmus 	*outExtent = (*outView)->Frame();
10429949213aSStephan Aßmus 	return B_OK;
10439949213aSStephan Aßmus }
10449949213aSStephan Aßmus 
1045d8e2fb50SAxel Dörfler /*! Determine whether or not we can handle this data */
10469949213aSStephan Aßmus status_t
1047d8e2fb50SAxel Dörfler Identify(BPositionIO *inSource, const translation_format *inFormat,
1048d8e2fb50SAxel Dörfler 	BMessage *ioExtension, translator_info *outInfo, uint32 outType)
10499949213aSStephan Aßmus {
1050d8e2fb50SAxel Dörfler 	if (outType != 0 && outType != B_TRANSLATOR_BITMAP && outType != JPEG_FORMAT)
10519949213aSStephan Aßmus 		return B_NO_TRANSLATOR;
10529949213aSStephan Aßmus 
10539949213aSStephan Aßmus 	// !!! You might need to make this buffer bigger to test for your native format
10549949213aSStephan Aßmus 	off_t position = inSource->Position();
10559949213aSStephan Aßmus 	char header[sizeof(TranslatorBitmap)];
10569949213aSStephan Aßmus 	status_t err = inSource->Read(header, sizeof(TranslatorBitmap));
10579949213aSStephan Aßmus 	inSource->Seek(position, SEEK_SET);
1058d8e2fb50SAxel Dörfler 	if (err < B_OK)
1059d8e2fb50SAxel Dörfler 		return err;
10609949213aSStephan Aßmus 
10619949213aSStephan Aßmus 	if (B_BENDIAN_TO_HOST_INT32(((TranslatorBitmap *)header)->magic) == B_TRANSLATOR_BITMAP) {
10629949213aSStephan Aßmus 		outInfo->type = inputFormats[1].type;
10639949213aSStephan Aßmus 		outInfo->translator = 0;
10649949213aSStephan Aßmus 		outInfo->group = inputFormats[1].group;
10659949213aSStephan Aßmus 		outInfo->quality = inputFormats[1].quality;
10669949213aSStephan Aßmus 		outInfo->capability = inputFormats[1].capability;
10679949213aSStephan Aßmus 		strcpy(outInfo->name, inputFormats[1].name);
10689949213aSStephan Aßmus 		strcpy(outInfo->MIME, inputFormats[1].MIME);
10699949213aSStephan Aßmus 	} else {
10709949213aSStephan Aßmus 		// First 3 bytes in jpg files are always the same from what i've seen so far
10719949213aSStephan Aßmus 		// check them
10729949213aSStephan Aßmus 		if (header[0] == (char)0xff && header[1] == (char)0xd8 && header[2] == (char)0xff) {
10739949213aSStephan Aßmus 		/* this below would be safer but it slows down whole thing
10749949213aSStephan Aßmus 
10759949213aSStephan Aßmus 			struct jpeg_decompress_struct cinfo;
10769949213aSStephan Aßmus 			struct jpeg_error_mgr jerr;
10779949213aSStephan Aßmus 			cinfo.err = jpeg_std_error(&jerr);
10789949213aSStephan Aßmus 			jpeg_create_decompress(&cinfo);
10799949213aSStephan Aßmus 			be_jpeg_stdio_src(&cinfo, inSource);
10809949213aSStephan Aßmus 			// now try to read header
10819949213aSStephan Aßmus 			// it can't be read before checking first 3 bytes
10829949213aSStephan Aßmus 			// because it will hang up if there is no header (not jpeg file)
10839949213aSStephan Aßmus 			int result = jpeg_read_header(&cinfo, FALSE);
10849949213aSStephan Aßmus 			jpeg_destroy_decompress(&cinfo);
10859949213aSStephan Aßmus 			if (result == JPEG_HEADER_OK) {
10869949213aSStephan Aßmus 		*/		outInfo->type = inputFormats[0].type;
10879949213aSStephan Aßmus 				outInfo->translator = 0;
10889949213aSStephan Aßmus 				outInfo->group = inputFormats[0].group;
10899949213aSStephan Aßmus 				outInfo->quality = inputFormats[0].quality;
10909949213aSStephan Aßmus 				outInfo->capability = inputFormats[0].capability;
10919949213aSStephan Aßmus 				strcpy(outInfo->name, inputFormats[0].name);
10929949213aSStephan Aßmus 				strcpy(outInfo->MIME, inputFormats[0].MIME);
10939949213aSStephan Aßmus 				return B_OK;
10949949213aSStephan Aßmus 		/*	} else
10959949213aSStephan Aßmus 				return B_NO_TRANSLATOR;
10969949213aSStephan Aßmus 		*/
10979949213aSStephan Aßmus 		} else
10989949213aSStephan Aßmus 			return B_NO_TRANSLATOR;
10999949213aSStephan Aßmus 	}
11009949213aSStephan Aßmus 
11019949213aSStephan Aßmus 	return B_OK;
11029949213aSStephan Aßmus }
11039949213aSStephan Aßmus 
1104*dbc936acSStephan Aßmus static jmp_buf sLongJumpBuffer;
1105*dbc936acSStephan Aßmus jmp_buf* gLongJumpBuffer = &sLongJumpBuffer;
1106*dbc936acSStephan Aßmus 
1107d8e2fb50SAxel Dörfler /*!	Arguably the most important method in the add-on */
11089949213aSStephan Aßmus status_t
1109d8e2fb50SAxel Dörfler Translate(BPositionIO *inSource, const translator_info *inInfo,
1110d8e2fb50SAxel Dörfler 	BMessage *ioExtension, uint32 outType, BPositionIO *outDestination)
11119949213aSStephan Aßmus {
11129949213aSStephan Aßmus 	// If no specific type was requested, convert to the interchange format
1113*dbc936acSStephan Aßmus 	if (outType == 0)
1114*dbc936acSStephan Aßmus 		outType = B_TRANSLATOR_BITMAP;
11159949213aSStephan Aßmus 
1116*dbc936acSStephan Aßmus 	// Setup a "breakpoint" since throwing exceptions does not seem to work
1117*dbc936acSStephan Aßmus 	// at all in an add-on. (?)
1118*dbc936acSStephan Aßmus 	// In the be_jerror.cpp we implement a handler for critical library errors
1119*dbc936acSStephan Aßmus 	// (be_error_exit()) and there we use the longjmp() function to return to
1120*dbc936acSStephan Aßmus 	// this place. If this happens, it is as if the setjmp() call is called
1121*dbc936acSStephan Aßmus 	// a second time, but this time the return value will be 1. The first
1122*dbc936acSStephan Aßmus 	// invokation will return 0.
1123*dbc936acSStephan Aßmus 	int jmpRet = setjmp(sLongJumpBuffer);
1124*dbc936acSStephan Aßmus 	if (jmpRet == 1)
1125*dbc936acSStephan Aßmus 		return B_ERROR;
1126*dbc936acSStephan Aßmus 
1127*dbc936acSStephan Aßmus 	try {
11289949213aSStephan Aßmus 		// What action to take, based on the findings of Identify()
11299949213aSStephan Aßmus 		if (outType == inInfo->type) {
11309949213aSStephan Aßmus 			return Copy(inSource, outDestination);
1131*dbc936acSStephan Aßmus 		} else if (inInfo->type == B_TRANSLATOR_BITMAP
1132*dbc936acSStephan Aßmus 				&& outType == JPEG_FORMAT) {
11339949213aSStephan Aßmus 			return Compress(inSource, outDestination);
1134*dbc936acSStephan Aßmus 		} else if (inInfo->type == JPEG_FORMAT
1135*dbc936acSStephan Aßmus 				&& outType == B_TRANSLATOR_BITMAP) {
113652e8f46aSAxel Dörfler 			return Decompress(inSource, outDestination, ioExtension);
11379949213aSStephan Aßmus 		}
1138*dbc936acSStephan Aßmus 	} catch (...) {
1139*dbc936acSStephan Aßmus 		fprintf(stderr, "libjpeg encoutered a critical error "
1140*dbc936acSStephan Aßmus 			"(caught C++ exception).\n");
1141*dbc936acSStephan Aßmus 		return B_ERROR;
1142*dbc936acSStephan Aßmus 	}
11439949213aSStephan Aßmus 
11449949213aSStephan Aßmus 	return B_NO_TRANSLATOR;
11459949213aSStephan Aßmus }
11469949213aSStephan Aßmus 
1147d8e2fb50SAxel Dörfler /*!	The user has requested the same format for input and output, so just copy */
114852e8f46aSAxel Dörfler static status_t
11499949213aSStephan Aßmus Copy(BPositionIO *in, BPositionIO *out)
11509949213aSStephan Aßmus {
11519949213aSStephan Aßmus 	int block_size = 65536;
11529949213aSStephan Aßmus 	void *buffer = malloc(block_size);
11539949213aSStephan Aßmus 	char temp[1024];
11549949213aSStephan Aßmus 	if (buffer == NULL) {
11559949213aSStephan Aßmus 		buffer = temp;
11569949213aSStephan Aßmus 		block_size = 1024;
11579949213aSStephan Aßmus 	}
11589949213aSStephan Aßmus 	status_t err = B_OK;
11599949213aSStephan Aßmus 
11609949213aSStephan Aßmus 	// Read until end of file or error
11619949213aSStephan Aßmus 	while (1) {
11629949213aSStephan Aßmus 		ssize_t to_read = block_size;
11639949213aSStephan Aßmus 		err = in->Read(buffer, to_read);
11649949213aSStephan Aßmus 		// Explicit check for EOF
11659949213aSStephan Aßmus 		if (err == -1) {
11669949213aSStephan Aßmus 			if (buffer != temp) free(buffer);
11679949213aSStephan Aßmus 			return B_OK;
11689949213aSStephan Aßmus 		}
11699949213aSStephan Aßmus 		if (err <= B_OK) break;
11709949213aSStephan Aßmus 		to_read = err;
11719949213aSStephan Aßmus 		err = out->Write(buffer, to_read);
11729949213aSStephan Aßmus 		if (err != to_read) if (err >= 0) err = B_DEVICE_FULL;
11739949213aSStephan Aßmus 		if (err < B_OK) break;
11749949213aSStephan Aßmus 	}
11759949213aSStephan Aßmus 
11769949213aSStephan Aßmus 	if (buffer != temp) free(buffer);
11779949213aSStephan Aßmus 	return (err >= 0) ? B_OK : err;
11789949213aSStephan Aßmus }
11799949213aSStephan Aßmus 
1180d8e2fb50SAxel Dörfler 
1181d8e2fb50SAxel Dörfler /*!	Encode into the native format */
118252e8f46aSAxel Dörfler static status_t
11839949213aSStephan Aßmus Compress(BPositionIO *in, BPositionIO *out)
11849949213aSStephan Aßmus {
11859949213aSStephan Aßmus 	// Load Settings
1186d8e2fb50SAxel Dörfler 	jpeg_settings settings;
1187d8e2fb50SAxel Dörfler 	LoadSettings(&settings);
11889949213aSStephan Aßmus 
11899949213aSStephan Aßmus 	// Read info about bitmap
11909949213aSStephan Aßmus 	TranslatorBitmap header;
11919949213aSStephan Aßmus 	status_t err = in->Read(&header, sizeof(TranslatorBitmap));
1192d8e2fb50SAxel Dörfler 	if (err < B_OK)
1193d8e2fb50SAxel Dörfler 		return err;
1194d8e2fb50SAxel Dörfler 	else if (err < (int)sizeof(TranslatorBitmap))
1195d8e2fb50SAxel Dörfler 		return B_ERROR;
11969949213aSStephan Aßmus 
11979949213aSStephan Aßmus 	// Grab dimension, color space, and size information from the stream
11989949213aSStephan Aßmus 	BRect bounds;
11999949213aSStephan Aßmus 	bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left);
12009949213aSStephan Aßmus 	bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top);
12019949213aSStephan Aßmus 	bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right);
12029949213aSStephan Aßmus 	bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom);
12039949213aSStephan Aßmus 
12049949213aSStephan Aßmus 	int32 in_row_bytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes);
12059949213aSStephan Aßmus 
12069949213aSStephan Aßmus 	int width = bounds.IntegerWidth() + 1;
12079949213aSStephan Aßmus 	int height = bounds.IntegerHeight() + 1;
12089949213aSStephan Aßmus 
12099949213aSStephan Aßmus 	// Function pointer to convert function
12109949213aSStephan Aßmus 	// It will point to proper function if needed
12119e34f742SAxel Dörfler 	void (*converter)(uchar *inscanline, uchar *outscanline,
12129e34f742SAxel Dörfler 		int32 inRowBytes) = NULL;
12139949213aSStephan Aßmus 
12149949213aSStephan Aßmus 	// Default color info
12159949213aSStephan Aßmus 	J_COLOR_SPACE jpg_color_space = JCS_RGB;
12169949213aSStephan Aßmus 	int jpg_input_components = 3;
12179949213aSStephan Aßmus 	int32 out_row_bytes;
12189949213aSStephan Aßmus 	int padding = 0;
12199949213aSStephan Aßmus 
1220d8e2fb50SAxel Dörfler 	switch ((color_space)B_BENDIAN_TO_HOST_INT32(header.colors)) {
12219949213aSStephan Aßmus 		case B_CMAP8:
12229949213aSStephan Aßmus 			converter = convert_from_cmap8_to_24;
12239949213aSStephan Aßmus 			padding = in_row_bytes - width;
12249949213aSStephan Aßmus 			break;
1225d8e2fb50SAxel Dörfler 
12269949213aSStephan Aßmus 		case B_GRAY1:
1227d8e2fb50SAxel Dörfler 			if (settings.B_GRAY1_as_B_RGB24) {
12289949213aSStephan Aßmus 				converter = convert_from_gray1_to_24;
12299949213aSStephan Aßmus 			} else {
12309949213aSStephan Aßmus 				jpg_input_components = 1;
12319949213aSStephan Aßmus 				jpg_color_space = JCS_GRAYSCALE;
12329949213aSStephan Aßmus 				converter = convert_from_gray1_to_gray8;
12339949213aSStephan Aßmus 			}
12349949213aSStephan Aßmus 			padding = in_row_bytes - (width/8);
12359949213aSStephan Aßmus 			break;
1236d8e2fb50SAxel Dörfler 
12379949213aSStephan Aßmus 		case B_GRAY8:
12389949213aSStephan Aßmus 			jpg_input_components = 1;
12399949213aSStephan Aßmus 			jpg_color_space = JCS_GRAYSCALE;
12409949213aSStephan Aßmus 			padding = in_row_bytes - width;
12419949213aSStephan Aßmus 			break;
1242d8e2fb50SAxel Dörfler 
12439949213aSStephan Aßmus 		case B_RGB15:
12449949213aSStephan Aßmus 		case B_RGBA15:
12459949213aSStephan Aßmus 			converter = convert_from_15_to_24;
12469949213aSStephan Aßmus 			padding = in_row_bytes - (width * 2);
12479949213aSStephan Aßmus 			break;
1248d8e2fb50SAxel Dörfler 
12499949213aSStephan Aßmus 		case B_RGB15_BIG:
12509949213aSStephan Aßmus 		case B_RGBA15_BIG:
12519949213aSStephan Aßmus 			converter = convert_from_15b_to_24;
12529949213aSStephan Aßmus 			padding = in_row_bytes - (width * 2);
12539949213aSStephan Aßmus 			break;
1254d8e2fb50SAxel Dörfler 
12559949213aSStephan Aßmus 		case B_RGB16:
12569949213aSStephan Aßmus 			converter = convert_from_16_to_24;
12579949213aSStephan Aßmus 			padding = in_row_bytes - (width * 2);
12589949213aSStephan Aßmus 			break;
1259d8e2fb50SAxel Dörfler 
12609949213aSStephan Aßmus 		case B_RGB16_BIG:
12619949213aSStephan Aßmus 			converter = convert_from_16b_to_24;
12629949213aSStephan Aßmus 			padding = in_row_bytes - (width * 2);
12639949213aSStephan Aßmus 			break;
1264d8e2fb50SAxel Dörfler 
12659949213aSStephan Aßmus 		case B_RGB24:
12669949213aSStephan Aßmus 			converter = convert_from_24_to_24;
12679949213aSStephan Aßmus 			padding = in_row_bytes - (width * 3);
12689949213aSStephan Aßmus 			break;
1269d8e2fb50SAxel Dörfler 
12709949213aSStephan Aßmus 		case B_RGB24_BIG:
12719949213aSStephan Aßmus 			padding = in_row_bytes - (width * 3);
12729949213aSStephan Aßmus 			break;
1273d8e2fb50SAxel Dörfler 
12749949213aSStephan Aßmus 		case B_RGB32:
12759949213aSStephan Aßmus 		case B_RGBA32:
12769949213aSStephan Aßmus 			converter = convert_from_32_to_24;
12779949213aSStephan Aßmus 			padding = in_row_bytes - (width * 4);
12789949213aSStephan Aßmus 			break;
1279d8e2fb50SAxel Dörfler 
12809949213aSStephan Aßmus 		case B_RGB32_BIG:
12819949213aSStephan Aßmus 		case B_RGBA32_BIG:
12829949213aSStephan Aßmus 			converter = convert_from_32b_to_24;
12839949213aSStephan Aßmus 			padding = in_row_bytes - (width * 4);
12849949213aSStephan Aßmus 			break;
1285d8e2fb50SAxel Dörfler 
12869949213aSStephan Aßmus 		case B_CMYK32:
12879949213aSStephan Aßmus 			jpg_color_space = JCS_CMYK;
12889949213aSStephan Aßmus 			jpg_input_components = 4;
12899949213aSStephan Aßmus 			padding = in_row_bytes - (width * 4);
12909949213aSStephan Aßmus 			break;
1291d8e2fb50SAxel Dörfler 
12929949213aSStephan Aßmus 		default:
12939949213aSStephan Aßmus 			fprintf(stderr, "Wrong type: Color space not implemented.\n");
12949949213aSStephan Aßmus 			return B_ERROR;
12959949213aSStephan Aßmus 	}
12969949213aSStephan Aßmus 	out_row_bytes = jpg_input_components * width;
12979949213aSStephan Aßmus 
12989949213aSStephan Aßmus 	// Set basic things needed for jpeg writing
12999949213aSStephan Aßmus 	struct jpeg_compress_struct cinfo;
13009949213aSStephan Aßmus 	struct jpeg_error_mgr jerr;
1301d8e2fb50SAxel Dörfler 	cinfo.err = be_jpeg_std_error(&jerr, &settings);
13029949213aSStephan Aßmus 	jpeg_create_compress(&cinfo);
13039949213aSStephan Aßmus 	be_jpeg_stdio_dest(&cinfo, out);
13049949213aSStephan Aßmus 
13059949213aSStephan Aßmus 	// Set basic values
13069949213aSStephan Aßmus 	cinfo.image_width = width;
13079949213aSStephan Aßmus 	cinfo.image_height = height;
13089949213aSStephan Aßmus 	cinfo.input_components = jpg_input_components;
13099949213aSStephan Aßmus 	cinfo.in_color_space = jpg_color_space;
13109949213aSStephan Aßmus 	jpeg_set_defaults(&cinfo);
13119949213aSStephan Aßmus 
13129949213aSStephan Aßmus 	// Set better accuracy
13139949213aSStephan Aßmus 	cinfo.dct_method = JDCT_ISLOW;
13149949213aSStephan Aßmus 
13159949213aSStephan Aßmus 	// This is needed to prevent some colors loss
13169949213aSStephan Aßmus 	// With it generated jpegs are as good as from Fireworks (at last! :D)
1317d8e2fb50SAxel Dörfler 	if (settings.OptimizeColors) {
13189949213aSStephan Aßmus 		int index = 0;
13199949213aSStephan Aßmus 		while (index < cinfo.num_components) {
13209949213aSStephan Aßmus 			cinfo.comp_info[index].h_samp_factor = 1;
13219949213aSStephan Aßmus 			cinfo.comp_info[index].v_samp_factor = 1;
13229949213aSStephan Aßmus 			// This will make file smaller, but with worse quality more or less
13239949213aSStephan Aßmus 			// like with 93%-94% (but it's subjective opinion) on tested images
13249949213aSStephan Aßmus 			// but with smaller size (between 92% and 93% on tested images)
1325d8e2fb50SAxel Dörfler 			if (settings.SmallerFile)
13269949213aSStephan Aßmus 				cinfo.comp_info[index].quant_tbl_no = 1;
13279949213aSStephan Aßmus 			// This will make bigger file, but also better quality ;]
13289949213aSStephan Aßmus 			// from my tests it seems like useless - better quality with smaller
13299949213aSStephan Aßmus 			// can be acheived without this
13309949213aSStephan Aßmus //			cinfo.comp_info[index].dc_tbl_no = 1;
13319949213aSStephan Aßmus //			cinfo.comp_info[index].ac_tbl_no = 1;
13329949213aSStephan Aßmus 			index++;
13339949213aSStephan Aßmus 		}
13349949213aSStephan Aßmus 	}
13359949213aSStephan Aßmus 
13369949213aSStephan Aßmus 	// Set quality
1337d8e2fb50SAxel Dörfler 	jpeg_set_quality(&cinfo, settings.Quality, true);
13389949213aSStephan Aßmus 
13399949213aSStephan Aßmus 	// Set progressive compression if needed
13409949213aSStephan Aßmus 	// if not, turn on optimizing in libjpeg
1341d8e2fb50SAxel Dörfler 	if (settings.Progressive)
13429949213aSStephan Aßmus 		jpeg_simple_progression(&cinfo);
13439949213aSStephan Aßmus 	else
13449949213aSStephan Aßmus 		cinfo.optimize_coding = TRUE;
13459949213aSStephan Aßmus 
13469949213aSStephan Aßmus 	// Set smoothing (effect like Blur)
1347d8e2fb50SAxel Dörfler 	cinfo.smoothing_factor = settings.Smoothing;
13489949213aSStephan Aßmus 
13499949213aSStephan Aßmus 	// Initialize compression
13509949213aSStephan Aßmus 	jpeg_start_compress(&cinfo, TRUE);
13519949213aSStephan Aßmus 
13529949213aSStephan Aßmus 	// Declare scanlines
13539949213aSStephan Aßmus 	JSAMPROW in_scanline = NULL;
13549949213aSStephan Aßmus 	JSAMPROW out_scanline = NULL;
13559949213aSStephan Aßmus 	JSAMPROW writeline;	// Pointer to in_scanline (default) or out_scanline (if there will be conversion)
13569949213aSStephan Aßmus 
13579949213aSStephan Aßmus 	// Allocate scanline
13589949213aSStephan Aßmus 	// Use libjpeg memory allocation functions, so in case of error it will free them itself
1359d8e2fb50SAxel Dörfler 	in_scanline = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo,
1360d8e2fb50SAxel Dörfler 		JPOOL_PERMANENT, in_row_bytes);
13619949213aSStephan Aßmus 
13629949213aSStephan Aßmus 	// We need 2nd scanline storage ony for conversion
13639949213aSStephan Aßmus 	if (converter != NULL) {
13649949213aSStephan Aßmus 		// There will be conversion, allocate second scanline...
13659949213aSStephan Aßmus 		// Use libjpeg memory allocation functions, so in case of error it will free them itself
1366d8e2fb50SAxel Dörfler 	    out_scanline = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo,
1367d8e2fb50SAxel Dörfler 	    	JPOOL_PERMANENT, out_row_bytes);
13689949213aSStephan Aßmus 		// ... and make it the one to write to file
13699949213aSStephan Aßmus 		writeline = out_scanline;
13709949213aSStephan Aßmus 	} else
13719949213aSStephan Aßmus 		writeline = in_scanline;
13729949213aSStephan Aßmus 
13739949213aSStephan Aßmus 	while (cinfo.next_scanline < cinfo.image_height) {
13749949213aSStephan Aßmus 		// Read scanline
13759949213aSStephan Aßmus 		err = in->Read(in_scanline, in_row_bytes);
13769949213aSStephan Aßmus 		if (err < in_row_bytes)
1377d8e2fb50SAxel Dörfler 			return err < B_OK ? Error((j_common_ptr)&cinfo, err)
1378d8e2fb50SAxel Dörfler 				: Error((j_common_ptr)&cinfo, B_ERROR);
13799949213aSStephan Aßmus 
13809949213aSStephan Aßmus 		// Convert if needed
13819949213aSStephan Aßmus 		if (converter != NULL)
13829949213aSStephan Aßmus 			converter(in_scanline, out_scanline, in_row_bytes - padding);
13839949213aSStephan Aßmus 
13849949213aSStephan Aßmus 		// Write scanline
13859949213aSStephan Aßmus 	   	jpeg_write_scanlines(&cinfo, &writeline, 1);
13869949213aSStephan Aßmus 	}
13879949213aSStephan Aßmus 
13889949213aSStephan Aßmus 	jpeg_finish_compress(&cinfo);
13899949213aSStephan Aßmus 	jpeg_destroy_compress(&cinfo);
13909949213aSStephan Aßmus 	return B_OK;
13919949213aSStephan Aßmus }
13929949213aSStephan Aßmus 
1393d8e2fb50SAxel Dörfler 
1394d8e2fb50SAxel Dörfler /*!	Decode the native format */
139552e8f46aSAxel Dörfler static status_t
139652e8f46aSAxel Dörfler Decompress(BPositionIO *in, BPositionIO *out, BMessage* ioExtension)
13979949213aSStephan Aßmus {
13989949213aSStephan Aßmus 	// Load Settings
1399d8e2fb50SAxel Dörfler 	jpeg_settings settings;
1400d8e2fb50SAxel Dörfler 	LoadSettings(&settings);
14019949213aSStephan Aßmus 
14029949213aSStephan Aßmus 	// Set basic things needed for jpeg reading
14039949213aSStephan Aßmus 	struct jpeg_decompress_struct cinfo;
14049949213aSStephan Aßmus 	struct jpeg_error_mgr jerr;
1405d8e2fb50SAxel Dörfler 	cinfo.err = be_jpeg_std_error(&jerr, &settings);
14069949213aSStephan Aßmus 	jpeg_create_decompress(&cinfo);
14079949213aSStephan Aßmus 	be_jpeg_stdio_src(&cinfo, in);
14089949213aSStephan Aßmus 
140952e8f46aSAxel Dörfler 	jpeg_save_markers(&cinfo, MARKER_EXIF, 131072);
141052e8f46aSAxel Dörfler 		// make sure the EXIF tag is stored
141152e8f46aSAxel Dörfler 
14129949213aSStephan Aßmus 	// Read info about image
14139949213aSStephan Aßmus 	jpeg_read_header(&cinfo, TRUE);
14149949213aSStephan Aßmus 
141552e8f46aSAxel Dörfler 	BMessage exif;
141652e8f46aSAxel Dörfler 
1417f13b5de6SAxel Dörfler 	// parse EXIF data and add it ioExtension, if any
141852e8f46aSAxel Dörfler 	jpeg_marker_struct* marker = cinfo.marker_list;
141952e8f46aSAxel Dörfler 	while (marker != NULL) {
142052e8f46aSAxel Dörfler 		if (marker->marker == MARKER_EXIF
142152e8f46aSAxel Dörfler 			&& !strncmp((char*)marker->data, "Exif", 4)) {
1422f13b5de6SAxel Dörfler 			if (ioExtension != NULL) {
142352e8f46aSAxel Dörfler 				// Strip EXIF header from TIFF data
142452e8f46aSAxel Dörfler 				ioExtension->AddData("exif", B_RAW_TYPE,
142552e8f46aSAxel Dörfler 					(uint8 *)marker->data + 6, marker->data_length - 6);
1426f13b5de6SAxel Dörfler 			}
142752e8f46aSAxel Dörfler 
142852e8f46aSAxel Dörfler 			BMemoryIO io(marker->data + 6, marker->data_length - 6);
142952e8f46aSAxel Dörfler 			convert_exif_to_message(io, exif);
143052e8f46aSAxel Dörfler 		}
143152e8f46aSAxel Dörfler 		marker = marker->next;
143252e8f46aSAxel Dörfler 	}
143352e8f46aSAxel Dörfler 
14349949213aSStephan Aßmus 	// Default color info
143552e8f46aSAxel Dörfler 	color_space outColorSpace = B_RGB32;
143652e8f46aSAxel Dörfler 	int outColorComponents = 4;
14379949213aSStephan Aßmus 
14389949213aSStephan Aßmus 	// Function pointer to convert function
14399949213aSStephan Aßmus 	// It will point to proper function if needed
144052e8f46aSAxel Dörfler 	void (*converter)(uchar *inScanLine, uchar *outScanLine,
14419e34f742SAxel Dörfler 		int32 inRowBytes, int32 xStep) = convert_from_24_to_32;
14429949213aSStephan Aßmus 
14439949213aSStephan Aßmus 	// If color space isn't rgb
14449949213aSStephan Aßmus 	if (cinfo.out_color_space != JCS_RGB) {
1445d8e2fb50SAxel Dörfler 		switch (cinfo.out_color_space) {
14469949213aSStephan Aßmus 			case JCS_UNKNOWN:		/* error/unspecified */
14479949213aSStephan Aßmus 				fprintf(stderr, "From Type: Jpeg uses unknown color type\n");
14489949213aSStephan Aßmus 				break;
14499949213aSStephan Aßmus 			case JCS_GRAYSCALE:		/* monochrome */
14509949213aSStephan Aßmus 				// Check if user wants to read only as RGB32 or not
1451d8e2fb50SAxel Dörfler 				if (!settings.Always_B_RGB32) {
14529949213aSStephan Aßmus 					// Grayscale
145352e8f46aSAxel Dörfler 					outColorSpace = B_GRAY8;
145452e8f46aSAxel Dörfler 					outColorComponents = 1;
14559e34f742SAxel Dörfler 					converter = translate_8;
14569949213aSStephan Aßmus 				} else {
14579949213aSStephan Aßmus 					// RGB
14589949213aSStephan Aßmus 					cinfo.out_color_space = JCS_RGB;
14599949213aSStephan Aßmus 					cinfo.output_components = 3;
14609949213aSStephan Aßmus 					converter = convert_from_24_to_32;
14619949213aSStephan Aßmus 				}
14629949213aSStephan Aßmus 				break;
14639949213aSStephan Aßmus 			case JCS_YCbCr:		/* Y/Cb/Cr (also known as YUV) */
14649949213aSStephan Aßmus 				cinfo.out_color_space = JCS_RGB;
14659949213aSStephan Aßmus 				converter = convert_from_24_to_32;
14669949213aSStephan Aßmus 				break;
14679949213aSStephan Aßmus 			case JCS_YCCK:		/* Y/Cb/Cr/K */
14689949213aSStephan Aßmus 				// Let libjpeg convert it to CMYK
14699949213aSStephan Aßmus 				cinfo.out_color_space = JCS_CMYK;
14709949213aSStephan Aßmus 				// Fall through to CMYK since we need the same settings
14719949213aSStephan Aßmus 			case JCS_CMYK:		/* C/M/Y/K */
14729949213aSStephan Aßmus 				// Use proper converter
1473d8e2fb50SAxel Dörfler 				if (settings.PhotoshopCMYK)
14749949213aSStephan Aßmus 					converter = convert_from_CMYK_to_32_photoshop;
14759949213aSStephan Aßmus 				else
14769949213aSStephan Aßmus 					converter = convert_from_CMYK_to_32;
14779949213aSStephan Aßmus 				break;
14789949213aSStephan Aßmus 			default:
14799949213aSStephan Aßmus 				fprintf(stderr, "From Type: Jpeg uses hmm... i don't know really :(\n");
14809949213aSStephan Aßmus 				break;
14819949213aSStephan Aßmus 		}
14829949213aSStephan Aßmus 	}
14839949213aSStephan Aßmus 
14849949213aSStephan Aßmus 	// Initialize decompression
14859949213aSStephan Aßmus 	jpeg_start_decompress(&cinfo);
14869949213aSStephan Aßmus 
14879e34f742SAxel Dörfler 	// retrieve orientation from settings/EXIF
148852e8f46aSAxel Dörfler 	int32 orientation;
14899e34f742SAxel Dörfler 	if (ioExtension == NULL
14909e34f742SAxel Dörfler 		|| ioExtension->FindInt32("exif:orientation", &orientation) != B_OK) {
149152e8f46aSAxel Dörfler 		if (exif.FindInt32("Orientation", &orientation) != B_OK)
149252e8f46aSAxel Dörfler 			orientation = 1;
149352e8f46aSAxel Dörfler 	}
14949949213aSStephan Aßmus 
14959e34f742SAxel Dörfler 	if (orientation != 1 && converter == NULL)
14969e34f742SAxel Dörfler 		converter = translate_8;
14979e34f742SAxel Dörfler 
14989e34f742SAxel Dörfler 	int32 outputWidth = orientation > 4 ? cinfo.output_height : cinfo.output_width;
14999e34f742SAxel Dörfler 	int32 outputHeight = orientation > 4 ? cinfo.output_width : cinfo.output_height;
15009e34f742SAxel Dörfler 
15019e34f742SAxel Dörfler 	int32 destOffset = dest_index(outputWidth, outputHeight,
15029e34f742SAxel Dörfler 		0, 0, orientation) * outColorComponents;
15039e34f742SAxel Dörfler 	int32 xStep = dest_index(outputWidth, outputHeight,
15049e34f742SAxel Dörfler 		1, 0, orientation) * outColorComponents - destOffset;
15059e34f742SAxel Dörfler 	int32 yStep = dest_index(outputWidth, outputHeight,
15069e34f742SAxel Dörfler 		0, 1, orientation) * outColorComponents - destOffset;
15079e34f742SAxel Dörfler 	bool needAll = orientation != 1;
15089e34f742SAxel Dörfler 
15099e34f742SAxel Dörfler 	// Initialize this bounds rect to the size of your image
15109e34f742SAxel Dörfler 	BRect bounds(0, 0, outputWidth - 1, outputHeight - 1);
15119e34f742SAxel Dörfler 
15129e34f742SAxel Dörfler #if 0
15139e34f742SAxel Dörfler printf("destOffset = %ld, xStep = %ld, yStep = %ld, input: %ld x %ld, output: %ld x %ld, orientation %ld\n",
15149e34f742SAxel Dörfler 	destOffset, xStep, yStep, (int32)cinfo.output_width, (int32)cinfo.output_height,
15159e34f742SAxel Dörfler 	bounds.IntegerWidth() + 1, bounds.IntegerHeight() + 1, orientation);
15169e34f742SAxel Dörfler #endif
15179e34f742SAxel Dörfler 
15189949213aSStephan Aßmus 	// Bytes count in one line of image (scanline)
15199e34f742SAxel Dörfler 	int32 inRowBytes = cinfo.output_width * cinfo.output_components;
15209e34f742SAxel Dörfler 	int32 rowBytes = (bounds.IntegerWidth() + 1) * outColorComponents;
15219e34f742SAxel Dörfler 	int32 dataSize = cinfo.output_width * cinfo.output_height
15229e34f742SAxel Dörfler 		* outColorComponents;
15239949213aSStephan Aßmus 
15249949213aSStephan Aßmus 	// Fill out the B_TRANSLATOR_BITMAP's header
15259949213aSStephan Aßmus 	TranslatorBitmap header;
15269949213aSStephan Aßmus 	header.magic = B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP);
15279949213aSStephan Aßmus 	header.bounds.left = B_HOST_TO_BENDIAN_FLOAT(bounds.left);
15289949213aSStephan Aßmus 	header.bounds.top = B_HOST_TO_BENDIAN_FLOAT(bounds.top);
15299949213aSStephan Aßmus 	header.bounds.right = B_HOST_TO_BENDIAN_FLOAT(bounds.right);
15309949213aSStephan Aßmus 	header.bounds.bottom = B_HOST_TO_BENDIAN_FLOAT(bounds.bottom);
153152e8f46aSAxel Dörfler 	header.colors = (color_space)B_HOST_TO_BENDIAN_INT32(outColorSpace);
153252e8f46aSAxel Dörfler 	header.rowBytes = B_HOST_TO_BENDIAN_INT32(rowBytes);
15339e34f742SAxel Dörfler 	header.dataSize = B_HOST_TO_BENDIAN_INT32(dataSize);
15349949213aSStephan Aßmus 
15359949213aSStephan Aßmus 	// Write out the header
15369949213aSStephan Aßmus 	status_t err = out->Write(&header, sizeof(TranslatorBitmap));
1537d8e2fb50SAxel Dörfler 	if (err < B_OK)
1538d8e2fb50SAxel Dörfler 		return Error((j_common_ptr)&cinfo, err);
1539d8e2fb50SAxel Dörfler 	else if (err < (int)sizeof(TranslatorBitmap))
1540d8e2fb50SAxel Dörfler 		return Error((j_common_ptr)&cinfo, B_ERROR);
15419949213aSStephan Aßmus 
15429949213aSStephan Aßmus 	// Declare scanlines
15439e34f742SAxel Dörfler 	JSAMPROW inScanLine = NULL;
15449e34f742SAxel Dörfler 	uint8* dest = NULL;
15459e34f742SAxel Dörfler 	uint8* destLine = NULL;
15469949213aSStephan Aßmus 
15479949213aSStephan Aßmus 	// Allocate scanline
15489949213aSStephan Aßmus 	// Use libjpeg memory allocation functions, so in case of error it will free them itself
15499e34f742SAxel Dörfler     inScanLine = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo,
15509e34f742SAxel Dörfler     	JPOOL_PERMANENT, inRowBytes);
15519949213aSStephan Aßmus 
15529949213aSStephan Aßmus 	// We need 2nd scanline storage only for conversion
15539949213aSStephan Aßmus 	if (converter != NULL) {
15549949213aSStephan Aßmus 		// There will be conversion, allocate second scanline...
15559e34f742SAxel Dörfler 		// Use libjpeg memory allocation functions, so in case of error it will free
15569e34f742SAxel Dörfler 		// them itself
15579e34f742SAxel Dörfler 	    dest = (uint8*)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo,
15589e34f742SAxel Dörfler 	    	JPOOL_PERMANENT, needAll ? dataSize : rowBytes);
15599e34f742SAxel Dörfler 	    destLine = dest + destOffset;
15609949213aSStephan Aßmus 	} else
15619e34f742SAxel Dörfler 		destLine = inScanLine;
15629949213aSStephan Aßmus 
15639949213aSStephan Aßmus 	while (cinfo.output_scanline < cinfo.output_height) {
15649949213aSStephan Aßmus 		// Read scanline
15659e34f742SAxel Dörfler 		jpeg_read_scanlines(&cinfo, &inScanLine, 1);
15669949213aSStephan Aßmus 
15679949213aSStephan Aßmus 		// Convert if needed
15689949213aSStephan Aßmus 		if (converter != NULL)
15699e34f742SAxel Dörfler 			converter(inScanLine, destLine, inRowBytes, xStep);
15709949213aSStephan Aßmus 
15719e34f742SAxel Dörfler 		if (!needAll) {
15729949213aSStephan Aßmus 	  		// Write the scanline buffer to the output stream
15739e34f742SAxel Dörfler 			ssize_t bytesWritten = out->Write(destLine, rowBytes);
15749e34f742SAxel Dörfler 			if (bytesWritten < rowBytes) {
15759e34f742SAxel Dörfler 				return bytesWritten < B_OK
15769e34f742SAxel Dörfler 					? Error((j_common_ptr)&cinfo, bytesWritten)
1577d8e2fb50SAxel Dörfler 					: Error((j_common_ptr)&cinfo, B_ERROR);
15789949213aSStephan Aßmus 			}
15799e34f742SAxel Dörfler 		} else
15809e34f742SAxel Dörfler 			destLine += yStep;
15819e34f742SAxel Dörfler 	}
15829e34f742SAxel Dörfler 
15839e34f742SAxel Dörfler 	if (needAll) {
15849e34f742SAxel Dörfler 		ssize_t bytesWritten = out->Write(dest, dataSize);
15859e34f742SAxel Dörfler 		if (bytesWritten < dataSize) {
15869e34f742SAxel Dörfler 			return bytesWritten < B_OK
15879e34f742SAxel Dörfler 				? Error((j_common_ptr)&cinfo, bytesWritten)
15889e34f742SAxel Dörfler 				: Error((j_common_ptr)&cinfo, B_ERROR);
15899e34f742SAxel Dörfler 		}
15909e34f742SAxel Dörfler 	}
15919949213aSStephan Aßmus 
15929949213aSStephan Aßmus 	jpeg_finish_decompress(&cinfo);
15939949213aSStephan Aßmus 	jpeg_destroy_decompress(&cinfo);
15949949213aSStephan Aßmus 	return B_OK;
15959949213aSStephan Aßmus }
15969949213aSStephan Aßmus 
1597d8e2fb50SAxel Dörfler /*!
1598d8e2fb50SAxel Dörfler 	Frees jpeg alocated memory
1599d8e2fb50SAxel Dörfler 	Returns given error (B_ERROR by default)
1600d8e2fb50SAxel Dörfler */
160152e8f46aSAxel Dörfler static status_t
16029949213aSStephan Aßmus Error(j_common_ptr cinfo, status_t error)
16039949213aSStephan Aßmus {
16049949213aSStephan Aßmus 	jpeg_destroy(cinfo);
16059949213aSStephan Aßmus 	return error;
16069949213aSStephan Aßmus }
1607d8e2fb50SAxel Dörfler 
1608d8e2fb50SAxel Dörfler 
1609d8e2fb50SAxel Dörfler //	#pragma mark -
1610d8e2fb50SAxel Dörfler 
1611d8e2fb50SAxel Dörfler 
1612d8e2fb50SAxel Dörfler int
1613117da2d7SAxel Dörfler main(int, char**)
1614117da2d7SAxel Dörfler {
1615117da2d7SAxel Dörfler 	BApplication app("application/x-vnd.Haiku-JPEGTranslator");
1616d8e2fb50SAxel Dörfler 
1617d8e2fb50SAxel Dörfler 	TranslatorWindow *window = new TranslatorWindow();
1618d8e2fb50SAxel Dörfler 	window->Show();
1619d8e2fb50SAxel Dörfler 
1620d8e2fb50SAxel Dörfler 	app.Run();
1621d8e2fb50SAxel Dörfler 	return 0;
1622d8e2fb50SAxel Dörfler }
1623d8e2fb50SAxel Dörfler 
1624