xref: /haiku/src/add-ons/translators/jpeg/JPEGTranslator.cpp (revision f13b5de61ef55cf942542088982492a4d1255d73)
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"
56*f13b5de6SAxel 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 
66*f13b5de6SAxel 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 {
3739e34f742SAxel Dörfler 	for (int32 i = 0; i < inRowBytes; i++) {
3749e34f742SAxel Dörfler 		out[0] = in[2];
3759e34f742SAxel Dörfler 		out[1] = in[1];
3769e34f742SAxel Dörfler 		out[2] = in[0];
3779e34f742SAxel Dörfler 
3789e34f742SAxel Dörfler 		in += 4;
3799e34f742SAxel Dörfler 		out += 3;
380d8e2fb50SAxel Dörfler 	}
381d8e2fb50SAxel Dörfler }
382d8e2fb50SAxel Dörfler 
383d8e2fb50SAxel Dörfler 
384d8e2fb50SAxel Dörfler inline void
3859e34f742SAxel Dörfler convert_from_32b_to_24(uint8* in, uint8* out, int32 inRowBytes)
386d8e2fb50SAxel Dörfler {
3879e34f742SAxel Dörfler 	for (int32 i = 0; i < inRowBytes; i++) {
3889e34f742SAxel Dörfler 		out[1] = in[0];
3899e34f742SAxel Dörfler 		out[2] = in[1];
3909e34f742SAxel Dörfler 		out[3] = in[2];
3919e34f742SAxel Dörfler 
3929e34f742SAxel Dörfler 		in += 4;
3939e34f742SAxel Dörfler 		out += 3;
394d8e2fb50SAxel Dörfler 	}
395d8e2fb50SAxel Dörfler }
396d8e2fb50SAxel Dörfler 
397d8e2fb50SAxel Dörfler 
3989e34f742SAxel Dörfler //	#pragma mark - conversion for decompression
3999e34f742SAxel Dörfler 
4009e34f742SAxel Dörfler 
401d8e2fb50SAxel Dörfler inline void
4029e34f742SAxel Dörfler convert_from_CMYK_to_32_photoshop(uint8* in, uint8* out, int32 inRowBytes, int32 xStep)
403d8e2fb50SAxel Dörfler {
4049e34f742SAxel Dörfler 	for (int32 i = 0; i < inRowBytes; i += 4) {
4059e34f742SAxel Dörfler 		int32 black = in[3];
4069e34f742SAxel Dörfler 		out[0] = in[2] * black / 255;
4079e34f742SAxel Dörfler 		out[1] = in[1] * black / 255;
4089e34f742SAxel Dörfler 		out[2] = in[0] * black / 255;
4099e34f742SAxel Dörfler 		out[3] = 255;
4109e34f742SAxel Dörfler 
4119e34f742SAxel Dörfler 		in += 4;
4129e34f742SAxel Dörfler 		out += xStep;
413d8e2fb50SAxel Dörfler 	}
414d8e2fb50SAxel Dörfler }
415d8e2fb50SAxel Dörfler 
416d8e2fb50SAxel Dörfler 
417d8e2fb50SAxel Dörfler //!	!!! UNTESTED !!!
418d8e2fb50SAxel Dörfler inline void
4199e34f742SAxel Dörfler convert_from_CMYK_to_32(uint8* in, uint8* out, int32 inRowBytes, int32 xStep)
420d8e2fb50SAxel Dörfler {
4219e34f742SAxel Dörfler 	for (int32 i = 0; i < inRowBytes; i += 4) {
4229e34f742SAxel Dörfler 		int32 black = 255 - in[3];
4239e34f742SAxel Dörfler 		out[0] = ((255 - in[2]) * black) / 255;
4249e34f742SAxel Dörfler 		out[1] = ((255 - in[1]) * black) / 255;
4259e34f742SAxel Dörfler 		out[2] = ((255 - in[0]) * black) / 255;
4269e34f742SAxel Dörfler 		out[3] = 255;
4279e34f742SAxel Dörfler 
4289e34f742SAxel Dörfler 		in += 4;
4299e34f742SAxel Dörfler 		out += xStep;
430d8e2fb50SAxel Dörfler 	}
431d8e2fb50SAxel Dörfler }
432d8e2fb50SAxel Dörfler 
433d8e2fb50SAxel Dörfler 
434d8e2fb50SAxel Dörfler //!	RGB24 8:8:8 to xRGB 8:8:8:8
435d8e2fb50SAxel Dörfler inline void
4369e34f742SAxel Dörfler convert_from_24_to_32(uint8* in, uint8* out, int32 inRowBytes, int32 xStep)
437d8e2fb50SAxel Dörfler {
4389e34f742SAxel Dörfler 	for (int32 i = 0; i < inRowBytes; i += 3) {
4399e34f742SAxel Dörfler 		out[0] = in[2];
4409e34f742SAxel Dörfler 		out[1] = in[1];
4419e34f742SAxel Dörfler 		out[2] = in[0];
4429e34f742SAxel Dörfler 		out[3] = 255;
4439e34f742SAxel Dörfler 
4449e34f742SAxel Dörfler 		in += 3;
4459e34f742SAxel Dörfler 		out += xStep;
4469e34f742SAxel Dörfler 	}
4479e34f742SAxel Dörfler }
4489e34f742SAxel Dörfler 
4499e34f742SAxel Dörfler 
4509e34f742SAxel Dörfler //! 8-bit to 8-bit, only need when rotating the image
4519e34f742SAxel Dörfler void
4529e34f742SAxel Dörfler translate_8(uint8* in, uint8* out, int32 inRowBytes, int32 xStep)
4539e34f742SAxel Dörfler {
4549e34f742SAxel Dörfler 	for (int32 i = 0; i < inRowBytes; i++) {
4559e34f742SAxel Dörfler 		out[0] = in[0];
4569e34f742SAxel Dörfler 
4579e34f742SAxel Dörfler 		in++;
4589e34f742SAxel Dörfler 		out += xStep;
459d8e2fb50SAxel Dörfler 	}
460d8e2fb50SAxel Dörfler }
461d8e2fb50SAxel Dörfler 
462d8e2fb50SAxel Dörfler 
4638687ff64SAxel Dörfler //	#pragma mark - SView
4648687ff64SAxel Dörfler 
4658687ff64SAxel Dörfler 
4668687ff64SAxel Dörfler SView::SView(const char *name, float x, float y)
4678687ff64SAxel Dörfler 	: BView(BRect(x, y, x, y), name, B_FOLLOW_NONE, B_WILL_DRAW)
4688687ff64SAxel Dörfler {
4698687ff64SAxel Dörfler 	fPreferredWidth = 0;
4708687ff64SAxel Dörfler 	fPreferredHeight = 0;
4718687ff64SAxel Dörfler 
4728687ff64SAxel Dörfler 	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
4738687ff64SAxel Dörfler 	SetLowColor(ViewColor());
4748687ff64SAxel Dörfler 
4758687ff64SAxel Dörfler 	SetFont(be_plain_font);
4768687ff64SAxel Dörfler }
4778687ff64SAxel Dörfler 
4788687ff64SAxel Dörfler 
4798687ff64SAxel Dörfler void
4808687ff64SAxel Dörfler SView::GetPreferredSize(float* _width, float* _height)
4818687ff64SAxel Dörfler {
4828687ff64SAxel Dörfler 	if (_width)
4838687ff64SAxel Dörfler 		*_width = fPreferredWidth;
4848687ff64SAxel Dörfler 	if (_height)
4858687ff64SAxel Dörfler 		*_height = fPreferredHeight;
4868687ff64SAxel Dörfler }
4878687ff64SAxel Dörfler 
4888687ff64SAxel Dörfler 
4898687ff64SAxel Dörfler void
4908687ff64SAxel Dörfler SView::ResizeToPreferred()
4918687ff64SAxel Dörfler {
4928687ff64SAxel Dörfler 	ResizeTo(fPreferredWidth, fPreferredHeight);
4938687ff64SAxel Dörfler }
4948687ff64SAxel Dörfler 
4958687ff64SAxel Dörfler 
4968687ff64SAxel Dörfler void
4978687ff64SAxel Dörfler SView::ResizePreferredBy(float width, float height)
4988687ff64SAxel Dörfler {
4998687ff64SAxel Dörfler 	fPreferredWidth += width;
5008687ff64SAxel Dörfler 	fPreferredHeight += height;
5018687ff64SAxel Dörfler }
5028687ff64SAxel Dörfler 
5038687ff64SAxel Dörfler 
5048687ff64SAxel Dörfler void
505f9810471SAxel Dörfler SView::AddChild(BView *child, BView *before)
5068687ff64SAxel Dörfler {
5078687ff64SAxel Dörfler 	BView::AddChild(child, before);
5088687ff64SAxel Dörfler 	child->ResizeToPreferred();
5098687ff64SAxel Dörfler 	BRect frame = child->Frame();
5108687ff64SAxel Dörfler 
5118687ff64SAxel Dörfler 	if (frame.right > fPreferredWidth)
5128687ff64SAxel Dörfler 		fPreferredWidth = frame.right;
5138687ff64SAxel Dörfler 	if (frame.bottom > fPreferredHeight)
5148687ff64SAxel Dörfler 		fPreferredHeight = frame.bottom;
5158687ff64SAxel Dörfler }
5168687ff64SAxel Dörfler 
5178687ff64SAxel Dörfler 
518d8e2fb50SAxel Dörfler //	#pragma mark -
519d8e2fb50SAxel Dörfler 
520d8e2fb50SAxel Dörfler 
521d8e2fb50SAxel Dörfler SSlider::SSlider(BRect frame, const char *name, const char *label,
522d8e2fb50SAxel Dörfler 		BMessage *message, int32 minValue, int32 maxValue, orientation posture,
523d8e2fb50SAxel Dörfler 		thumb_style thumbType, uint32 resizingMode, uint32 flags)
524d8e2fb50SAxel Dörfler 	: BSlider(frame, name, label, message, minValue, maxValue,
525d8e2fb50SAxel Dörfler 		posture, thumbType, resizingMode, flags)
5269949213aSStephan Aßmus {
5278687ff64SAxel Dörfler 	rgb_color barColor = { 0, 0, 229, 255 };
5288687ff64SAxel Dörfler 	UseFillColor(true, &barColor);
5299949213aSStephan Aßmus }
5309949213aSStephan Aßmus 
5318687ff64SAxel Dörfler 
5328687ff64SAxel Dörfler //!	Update status string - show actual value
5339949213aSStephan Aßmus char*
5349949213aSStephan Aßmus SSlider::UpdateText() const
5359949213aSStephan Aßmus {
5368687ff64SAxel Dörfler 	snprintf(fStatusLabel, sizeof(fStatusLabel), "%ld", Value());
5378687ff64SAxel Dörfler 	return fStatusLabel;
5389949213aSStephan Aßmus }
5399949213aSStephan Aßmus 
5408687ff64SAxel Dörfler 
5418687ff64SAxel Dörfler //!	BSlider::ResizeToPreferred + Resize width if it's too small to show label and status
5429949213aSStephan Aßmus void
5439949213aSStephan Aßmus SSlider::ResizeToPreferred()
5449949213aSStephan Aßmus {
5459949213aSStephan Aßmus 	int32 width = (int32)ceil(StringWidth(Label()) + StringWidth("9999"));
5468687ff64SAxel Dörfler 	if (width < 230)
5478687ff64SAxel Dörfler 		width = 230;
5488687ff64SAxel Dörfler 
5499949213aSStephan Aßmus 	float w, h;
5509949213aSStephan Aßmus 	GetPreferredSize(&w, &h);
5519949213aSStephan Aßmus 	ResizeTo(width, h);
5529949213aSStephan Aßmus }
5539949213aSStephan Aßmus 
5549949213aSStephan Aßmus 
555d8e2fb50SAxel Dörfler //	#pragma mark -
5569949213aSStephan Aßmus 
557d8e2fb50SAxel Dörfler 
558d8e2fb50SAxel Dörfler TranslatorReadView::TranslatorReadView(const char *name, jpeg_settings *settings,
559d8e2fb50SAxel Dörfler 		float x, float y)
5609949213aSStephan Aßmus 	: SView(name, x, y),
561d8e2fb50SAxel Dörfler 	fSettings(settings)
5629949213aSStephan Aßmus {
5638687ff64SAxel Dörfler 	fAlwaysRGB32 = new BCheckBox(BRect(10, GetPreferredHeight(), 10,
564d8e2fb50SAxel Dörfler 		GetPreferredHeight()), "alwaysrgb32", VIEW_LABEL_ALWAYSRGB32,
565d8e2fb50SAxel Dörfler 		new BMessage(VIEW_MSG_SET_ALWAYSRGB32));
5668687ff64SAxel Dörfler 	fAlwaysRGB32->SetFont(be_plain_font);
567d8e2fb50SAxel Dörfler 	if (fSettings->Always_B_RGB32)
5688687ff64SAxel Dörfler 		fAlwaysRGB32->SetValue(1);
5699949213aSStephan Aßmus 
5708687ff64SAxel Dörfler 	AddChild(fAlwaysRGB32);
5719949213aSStephan Aßmus 
5728687ff64SAxel Dörfler 	fPhotoshopCMYK = new BCheckBox(BRect(10, GetPreferredHeight(), 10,
5738687ff64SAxel Dörfler 		GetPreferredHeight()), "photoshopCMYK", VIEW_LABEL_PHOTOSHOPCMYK,
5748687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_PHOTOSHOPCMYK));
5758687ff64SAxel Dörfler 	fPhotoshopCMYK->SetFont(be_plain_font);
576d8e2fb50SAxel Dörfler 	if (fSettings->PhotoshopCMYK)
5778687ff64SAxel Dörfler 		fPhotoshopCMYK->SetValue(1);
5789949213aSStephan Aßmus 
5798687ff64SAxel Dörfler 	AddChild(fPhotoshopCMYK);
5809949213aSStephan Aßmus 
5818687ff64SAxel Dörfler 	fShowErrorBox = new BCheckBox(BRect(10, GetPreferredHeight(), 10,
5828687ff64SAxel Dörfler 		GetPreferredHeight()), "error", VIEW_LABEL_SHOWREADERRORBOX,
5838687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_SHOWREADERRORBOX));
5848687ff64SAxel Dörfler 	fShowErrorBox->SetFont(be_plain_font);
585d8e2fb50SAxel Dörfler 	if (fSettings->ShowReadWarningBox)
5868687ff64SAxel Dörfler 		fShowErrorBox->SetValue(1);
5879949213aSStephan Aßmus 
5888687ff64SAxel Dörfler 	AddChild(fShowErrorBox);
5899949213aSStephan Aßmus 
5909949213aSStephan Aßmus 	ResizeToPreferred();
5919949213aSStephan Aßmus }
5929949213aSStephan Aßmus 
5938687ff64SAxel Dörfler 
5949949213aSStephan Aßmus void
5959949213aSStephan Aßmus TranslatorReadView::AttachedToWindow()
5969949213aSStephan Aßmus {
5978687ff64SAxel Dörfler 	fAlwaysRGB32->SetTarget(this);
5988687ff64SAxel Dörfler 	fPhotoshopCMYK->SetTarget(this);
5998687ff64SAxel Dörfler 	fShowErrorBox->SetTarget(this);
6009949213aSStephan Aßmus }
6019949213aSStephan Aßmus 
6028687ff64SAxel Dörfler 
6039949213aSStephan Aßmus void
6049949213aSStephan Aßmus TranslatorReadView::MessageReceived(BMessage* message)
6059949213aSStephan Aßmus {
6068687ff64SAxel Dörfler 	switch (message->what) {
6079949213aSStephan Aßmus 		case VIEW_MSG_SET_ALWAYSRGB32:
6089949213aSStephan Aßmus 		{
6099949213aSStephan Aßmus 			int32 value;
6109949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
611d8e2fb50SAxel Dörfler 				fSettings->Always_B_RGB32 = value;
612d8e2fb50SAxel Dörfler 				SaveSettings(fSettings);
6139949213aSStephan Aßmus 			}
6149949213aSStephan Aßmus 			break;
6159949213aSStephan Aßmus 		}
6169949213aSStephan Aßmus 		case VIEW_MSG_SET_PHOTOSHOPCMYK:
6179949213aSStephan Aßmus 		{
6189949213aSStephan Aßmus 			int32 value;
6199949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
620d8e2fb50SAxel Dörfler 				fSettings->PhotoshopCMYK = value;
621d8e2fb50SAxel Dörfler 				SaveSettings(fSettings);
6229949213aSStephan Aßmus 			}
6239949213aSStephan Aßmus 			break;
6249949213aSStephan Aßmus 		}
6259949213aSStephan Aßmus 		case VIEW_MSG_SET_SHOWREADERRORBOX:
6269949213aSStephan Aßmus 		{
6279949213aSStephan Aßmus 			int32 value;
6289949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
629d8e2fb50SAxel Dörfler 				fSettings->ShowReadWarningBox = value;
630d8e2fb50SAxel Dörfler 				SaveSettings(fSettings);
6319949213aSStephan Aßmus 			}
6329949213aSStephan Aßmus 			break;
6339949213aSStephan Aßmus 		}
6349949213aSStephan Aßmus 		default:
6359949213aSStephan Aßmus 			BView::MessageReceived(message);
6369949213aSStephan Aßmus 			break;
6379949213aSStephan Aßmus 	}
6389949213aSStephan Aßmus }
6399949213aSStephan Aßmus 
6409949213aSStephan Aßmus 
6418687ff64SAxel Dörfler //	#pragma mark - TranslatorWriteView
6429949213aSStephan Aßmus 
6438687ff64SAxel Dörfler 
6448687ff64SAxel Dörfler TranslatorWriteView::TranslatorWriteView(const char *name, jpeg_settings *settings,
6458687ff64SAxel Dörfler 		float x, float y)
6469949213aSStephan Aßmus 	: SView(name, x, y),
647d8e2fb50SAxel Dörfler 	fSettings(settings)
6489949213aSStephan Aßmus {
6498687ff64SAxel Dörfler 	fQualitySlider = new SSlider(BRect(10, GetPreferredHeight(), 10,
6508687ff64SAxel Dörfler 		GetPreferredHeight()), "quality", VIEW_LABEL_QUALITY,
6518687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_QUALITY), 0, 100);
6528687ff64SAxel Dörfler 	fQualitySlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
6538687ff64SAxel Dörfler 	fQualitySlider->SetHashMarkCount(10);
6548687ff64SAxel Dörfler 	fQualitySlider->SetLimitLabels("Low", "High");
6558687ff64SAxel Dörfler 	fQualitySlider->SetFont(be_plain_font);
6568687ff64SAxel Dörfler 	fQualitySlider->SetValue(fSettings->Quality);
6578687ff64SAxel Dörfler 	AddChild(fQualitySlider);
6589949213aSStephan Aßmus 
6598687ff64SAxel Dörfler 	fSmoothingSlider = new SSlider(BRect(10, GetPreferredHeight()+10, 10,
6608687ff64SAxel Dörfler 		GetPreferredHeight()), "smoothing", VIEW_LABEL_SMOOTHING,
6618687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_SMOOTHING), 0, 100);
6628687ff64SAxel Dörfler 	fSmoothingSlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
6638687ff64SAxel Dörfler 	fSmoothingSlider->SetHashMarkCount(10);
6648687ff64SAxel Dörfler 	fSmoothingSlider->SetLimitLabels("None", "High");
6658687ff64SAxel Dörfler 	fSmoothingSlider->SetFont(be_plain_font);
6668687ff64SAxel Dörfler 	fSmoothingSlider->SetValue(fSettings->Smoothing);
6678687ff64SAxel Dörfler 	AddChild(fSmoothingSlider);
6689949213aSStephan Aßmus 
6698687ff64SAxel Dörfler 	fProgress = new BCheckBox(BRect(10, GetPreferredHeight()+10, 10,
6708687ff64SAxel Dörfler 		GetPreferredHeight()), "progress", VIEW_LABEL_PROGRESSIVE,
6718687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_PROGRESSIVE));
6728687ff64SAxel Dörfler 	fProgress->SetFont(be_plain_font);
673d8e2fb50SAxel Dörfler 	if (fSettings->Progressive)
6748687ff64SAxel Dörfler 		fProgress->SetValue(1);
6759949213aSStephan Aßmus 
6768687ff64SAxel Dörfler 	AddChild(fProgress);
6779949213aSStephan Aßmus 
6788687ff64SAxel Dörfler 	fOptimizeColors = new BCheckBox(BRect(10, GetPreferredHeight()+5, 10,
6798687ff64SAxel Dörfler 		GetPreferredHeight() + 5), "optimizecolors", VIEW_LABEL_OPTIMIZECOLORS,
6808687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_OPTIMIZECOLORS));
6818687ff64SAxel Dörfler 	fOptimizeColors->SetFont(be_plain_font);
682d8e2fb50SAxel Dörfler 	if (fSettings->OptimizeColors)
6838687ff64SAxel Dörfler 		fOptimizeColors->SetValue(1);
6849949213aSStephan Aßmus 
6858687ff64SAxel Dörfler 	AddChild(fOptimizeColors);
6869949213aSStephan Aßmus 
6878687ff64SAxel Dörfler 	fSmallerFile = new BCheckBox(BRect(25, GetPreferredHeight()+5, 25,
6888687ff64SAxel Dörfler 		GetPreferredHeight() + 5), "smallerfile", VIEW_LABEL_SMALLERFILE,
6898687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_SMALLERFILE));
6908687ff64SAxel Dörfler 	fSmallerFile->SetFont(be_plain_font);
691d8e2fb50SAxel Dörfler 	if (fSettings->SmallerFile)
6928687ff64SAxel Dörfler 		fSmallerFile->SetValue(1);
693d8e2fb50SAxel Dörfler 	if (!fSettings->OptimizeColors)
6948687ff64SAxel Dörfler 		fSmallerFile->SetEnabled(false);
6959949213aSStephan Aßmus 
6968687ff64SAxel Dörfler 	AddChild(fSmallerFile);
6979949213aSStephan Aßmus 
6988687ff64SAxel Dörfler 	fGrayAsRGB24 = new BCheckBox(BRect(10, GetPreferredHeight()+5, 25,
6998687ff64SAxel Dörfler 		GetPreferredHeight()+5), "gray1asrgb24", VIEW_LABEL_GRAY1ASRGB24,
7008687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_GRAY1ASRGB24));
7018687ff64SAxel Dörfler 	fGrayAsRGB24->SetFont(be_plain_font);
702d8e2fb50SAxel Dörfler 	if (fSettings->B_GRAY1_as_B_RGB24)
7038687ff64SAxel Dörfler 		fGrayAsRGB24->SetValue(1);
7049949213aSStephan Aßmus 
7058687ff64SAxel Dörfler 	AddChild(fGrayAsRGB24);
7069949213aSStephan Aßmus 
7079949213aSStephan Aßmus 	ResizeToPreferred();
7089949213aSStephan Aßmus }
7099949213aSStephan Aßmus 
7108687ff64SAxel Dörfler 
7119949213aSStephan Aßmus void
7129949213aSStephan Aßmus TranslatorWriteView::AttachedToWindow()
7139949213aSStephan Aßmus {
7148687ff64SAxel Dörfler 	fQualitySlider->SetTarget(this);
7158687ff64SAxel Dörfler 	fSmoothingSlider->SetTarget(this);
7168687ff64SAxel Dörfler 	fProgress->SetTarget(this);
7178687ff64SAxel Dörfler 	fOptimizeColors->SetTarget(this);
7188687ff64SAxel Dörfler 	fSmallerFile->SetTarget(this);
7198687ff64SAxel Dörfler 	fGrayAsRGB24->SetTarget(this);
7209949213aSStephan Aßmus }
7219949213aSStephan Aßmus 
7228687ff64SAxel Dörfler 
7239949213aSStephan Aßmus void
7249949213aSStephan Aßmus TranslatorWriteView::MessageReceived(BMessage *message)
7259949213aSStephan Aßmus {
7268687ff64SAxel Dörfler 	switch (message->what) {
7279949213aSStephan Aßmus 		case VIEW_MSG_SET_QUALITY:
7289949213aSStephan Aßmus 		{
7299949213aSStephan Aßmus 			int32 value;
7309949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
731d8e2fb50SAxel Dörfler 				fSettings->Quality = value;
732d8e2fb50SAxel Dörfler 				SaveSettings(fSettings);
7339949213aSStephan Aßmus 			}
7349949213aSStephan Aßmus 			break;
7359949213aSStephan Aßmus 		}
7369949213aSStephan Aßmus 		case VIEW_MSG_SET_SMOOTHING:
7379949213aSStephan Aßmus 		{
7389949213aSStephan Aßmus 			int32 value;
7399949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
740d8e2fb50SAxel Dörfler 				fSettings->Smoothing = value;
741d8e2fb50SAxel Dörfler 				SaveSettings(fSettings);
7429949213aSStephan Aßmus 			}
7439949213aSStephan Aßmus 			break;
7449949213aSStephan Aßmus 		}
7459949213aSStephan Aßmus 		case VIEW_MSG_SET_PROGRESSIVE:
7469949213aSStephan Aßmus 		{
7479949213aSStephan Aßmus 			int32 value;
7489949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
749d8e2fb50SAxel Dörfler 				fSettings->Progressive = value;
750d8e2fb50SAxel Dörfler 				SaveSettings(fSettings);
7519949213aSStephan Aßmus 			}
7529949213aSStephan Aßmus 			break;
7539949213aSStephan Aßmus 		}
7549949213aSStephan Aßmus 		case VIEW_MSG_SET_OPTIMIZECOLORS:
7559949213aSStephan Aßmus 		{
7569949213aSStephan Aßmus 			int32 value;
7579949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
758d8e2fb50SAxel Dörfler 				fSettings->OptimizeColors = value;
759d8e2fb50SAxel Dörfler 				SaveSettings(fSettings);
7609949213aSStephan Aßmus 			}
7618687ff64SAxel Dörfler 			fSmallerFile->SetEnabled(fSettings->OptimizeColors);
7629949213aSStephan Aßmus 			break;
7639949213aSStephan Aßmus 		}
7649949213aSStephan Aßmus 		case VIEW_MSG_SET_SMALLERFILE:
7659949213aSStephan Aßmus 		{
7669949213aSStephan Aßmus 			int32 value;
7679949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
768d8e2fb50SAxel Dörfler 				fSettings->SmallerFile = value;
769d8e2fb50SAxel Dörfler 				SaveSettings(fSettings);
7709949213aSStephan Aßmus 			}
7719949213aSStephan Aßmus 			break;
7729949213aSStephan Aßmus 		}
7739949213aSStephan Aßmus 		case VIEW_MSG_SET_GRAY1ASRGB24:
7749949213aSStephan Aßmus 		{
7759949213aSStephan Aßmus 			int32 value;
7769949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
777d8e2fb50SAxel Dörfler 				fSettings->B_GRAY1_as_B_RGB24 = value;
778d8e2fb50SAxel Dörfler 				SaveSettings(fSettings);
7799949213aSStephan Aßmus 			}
7809949213aSStephan Aßmus 			break;
7819949213aSStephan Aßmus 		}
7829949213aSStephan Aßmus 		default:
7839949213aSStephan Aßmus 			BView::MessageReceived(message);
7849949213aSStephan Aßmus 			break;
7859949213aSStephan Aßmus 	}
7869949213aSStephan Aßmus }
7879949213aSStephan Aßmus 
7889949213aSStephan Aßmus 
789d8e2fb50SAxel Dörfler //	#pragma mark -
7909949213aSStephan Aßmus 
791d8e2fb50SAxel Dörfler 
7929949213aSStephan Aßmus TranslatorAboutView::TranslatorAboutView(const char *name, float x, float y)
7939949213aSStephan Aßmus 	: SView(name, x, y)
7949949213aSStephan Aßmus {
7958687ff64SAxel Dörfler 	BStringView *title = new BStringView(BRect(10, 0, 10, 0), "Title",
7968687ff64SAxel Dörfler 		translatorName);
7979949213aSStephan Aßmus 	title->SetFont(be_bold_font);
7989949213aSStephan Aßmus 
7999949213aSStephan Aßmus 	AddChild(title);
8009949213aSStephan Aßmus 
8019949213aSStephan Aßmus 	BRect rect = title->Bounds();
8029949213aSStephan Aßmus 	float space = title->StringWidth("    ");
8039949213aSStephan Aßmus 
8049949213aSStephan Aßmus 	char versionString[16];
805d8e2fb50SAxel Dörfler 	sprintf(versionString, "v%d.%d.%d", (int)(translatorVersion >> 8),
806d8e2fb50SAxel Dörfler 		(int)((translatorVersion >> 4) & 0xf), (int)(translatorVersion & 0xf));
8079949213aSStephan Aßmus 
808d8e2fb50SAxel Dörfler 	BStringView *version = new BStringView(BRect(rect.right+space, rect.top,
809d8e2fb50SAxel Dörfler 		rect.right+space, rect.top), "Version", versionString);
8109949213aSStephan Aßmus 	version->SetFont(be_plain_font);
8119949213aSStephan Aßmus 	version->SetFontSize(9);
8129949213aSStephan Aßmus 	// Make version be in the same line as title
8139949213aSStephan Aßmus 	version->ResizeToPreferred();
8149949213aSStephan Aßmus 	version->MoveBy(0, rect.bottom-version->Frame().bottom);
8159949213aSStephan Aßmus 
8169949213aSStephan Aßmus 	AddChild(version);
8179949213aSStephan Aßmus 
8188687ff64SAxel Dörfler 	// Now for each line in translatorInfo add a BStringView
8198687ff64SAxel Dörfler 	char* current = translatorInfo;
8208687ff64SAxel Dörfler 	int32 index = 1;
8218687ff64SAxel Dörfler 	while (current != NULL && current[0]) {
8228687ff64SAxel Dörfler 		char text[128];
8238687ff64SAxel Dörfler 		char* newLine = strchr(current, '\n');
8248687ff64SAxel Dörfler 		if (newLine == NULL) {
8258687ff64SAxel Dörfler 			strlcpy(text, current, sizeof(text));
8268687ff64SAxel Dörfler 			current = NULL;
8278687ff64SAxel Dörfler 		} else {
8288687ff64SAxel Dörfler 			strlcpy(text, current, min_c((int32)sizeof(text), newLine + 1 - current));
8298687ff64SAxel Dörfler 			current = newLine + 1;
8308687ff64SAxel Dörfler 		}
8319949213aSStephan Aßmus 
8328687ff64SAxel Dörfler 		BStringView* string = new BStringView(BRect(10, GetPreferredHeight(),
8338687ff64SAxel Dörfler 			10, GetPreferredHeight()), "copyright", text);
8348687ff64SAxel Dörfler 		if (index > 3)
8358687ff64SAxel Dörfler 			string->SetFontSize(9);
8368687ff64SAxel Dörfler 		AddChild(string);
8378687ff64SAxel Dörfler 
8388687ff64SAxel Dörfler 		index++;
8399949213aSStephan Aßmus 	}
8409949213aSStephan Aßmus 
8419949213aSStephan Aßmus 	ResizeToPreferred();
8429949213aSStephan Aßmus }
8439949213aSStephan Aßmus 
8449949213aSStephan Aßmus 
845d8e2fb50SAxel Dörfler //	#pragma mark -
8469949213aSStephan Aßmus 
847d8e2fb50SAxel Dörfler 
8489949213aSStephan Aßmus TranslatorView::TranslatorView(const char *name)
849d8e2fb50SAxel Dörfler 	: SView(name),
850d8e2fb50SAxel Dörfler 	fTabWidth(30),
851d8e2fb50SAxel Dörfler 	fActiveChild(0)
8529949213aSStephan Aßmus {
8539949213aSStephan Aßmus 	// Set global var to true
854d8e2fb50SAxel Dörfler 	gAreSettingsRunning = true;
8559949213aSStephan Aßmus 
856d8e2fb50SAxel Dörfler 	// Load settings to global settings struct
857d8e2fb50SAxel Dörfler 	LoadSettings(&fSettings);
8589949213aSStephan Aßmus 
8598687ff64SAxel Dörfler 	font_height fontHeight;
8608687ff64SAxel Dörfler 	GetFontHeight(&fontHeight);
8618687ff64SAxel Dörfler 	fTabHeight = (int32)ceilf(fontHeight.ascent + fontHeight.descent + fontHeight.leading) + 7;
8629949213aSStephan Aßmus 	// Add left and top margins
8638687ff64SAxel Dörfler 	float top = fTabHeight + 20;
8649949213aSStephan Aßmus 	float left = 0;
8659949213aSStephan Aßmus 
8669949213aSStephan Aßmus 	// This will remember longest string width
8679949213aSStephan Aßmus 	int32 nameWidth = 0;
8689949213aSStephan Aßmus 
869d8e2fb50SAxel Dörfler 	SView *view = new TranslatorWriteView("Write", &fSettings, left, top);
8709949213aSStephan Aßmus 	AddChild(view);
871d8e2fb50SAxel Dörfler 	nameWidth = (int32)StringWidth(view->Name());
8728687ff64SAxel Dörfler 	fTabs.AddItem(new BTab(view));
8739949213aSStephan Aßmus 
874d8e2fb50SAxel Dörfler 	view = new TranslatorReadView("Read", &fSettings, left, top);
8759949213aSStephan Aßmus 	AddChild(view);
8769949213aSStephan Aßmus 	if (nameWidth < StringWidth(view->Name()))
877d8e2fb50SAxel Dörfler 		nameWidth = (int32)StringWidth(view->Name());
8788687ff64SAxel Dörfler 	fTabs.AddItem(new BTab(view));
8799949213aSStephan Aßmus 
8809949213aSStephan Aßmus 	view = new TranslatorAboutView("About", left, top);
8819949213aSStephan Aßmus 	AddChild(view);
8829949213aSStephan Aßmus 	if (nameWidth < StringWidth(view->Name()))
883d8e2fb50SAxel Dörfler 		nameWidth = (int32)StringWidth(view->Name());
8848687ff64SAxel Dörfler 	fTabs.AddItem(new BTab(view));
8859949213aSStephan Aßmus 
886d8e2fb50SAxel Dörfler 	fTabWidth += nameWidth;
887d8e2fb50SAxel Dörfler 	if (fTabWidth * CountChildren() > GetPreferredWidth())
888d8e2fb50SAxel Dörfler 		ResizePreferredBy((fTabWidth * CountChildren()) - GetPreferredWidth(), 0);
8899949213aSStephan Aßmus 
8909949213aSStephan Aßmus 	// Add right and bottom margins
8919949213aSStephan Aßmus 	ResizePreferredBy(10, 15);
8929949213aSStephan Aßmus 
8939949213aSStephan Aßmus 	ResizeToPreferred();
8949949213aSStephan Aßmus 
8959949213aSStephan Aßmus 	// Make TranslatorView resize itself with parent
8969949213aSStephan Aßmus 	SetFlags(Flags() | B_FOLLOW_ALL);
8979949213aSStephan Aßmus }
8989949213aSStephan Aßmus 
899d8e2fb50SAxel Dörfler 
900d8e2fb50SAxel Dörfler TranslatorView::~TranslatorView()
901d8e2fb50SAxel Dörfler {
902d8e2fb50SAxel Dörfler 	gAreSettingsRunning = false;
9038687ff64SAxel Dörfler 
9048687ff64SAxel Dörfler 	BTab* tab;
9058687ff64SAxel Dörfler 	while ((tab = (BTab*)fTabs.RemoveItem((int32)0)) != NULL) {
9068687ff64SAxel Dörfler 		delete tab;
9078687ff64SAxel Dörfler 	}
908d8e2fb50SAxel Dörfler }
909d8e2fb50SAxel Dörfler 
910d8e2fb50SAxel Dörfler 
911d8e2fb50SAxel Dörfler //!	Attached to window - resize parent to preferred
9129949213aSStephan Aßmus void
9139949213aSStephan Aßmus TranslatorView::AttachedToWindow()
9149949213aSStephan Aßmus {
9159949213aSStephan Aßmus 	// Hide all children except first one
916d8e2fb50SAxel Dörfler 	BView *child;
9179949213aSStephan Aßmus 	int32 index = 1;
918d8e2fb50SAxel Dörfler 	while ((child = ChildAt(index++)) != NULL)
9199949213aSStephan Aßmus 		child->Hide();
9209949213aSStephan Aßmus 
9218687ff64SAxel Dörfler }
9228687ff64SAxel Dörfler 
9238687ff64SAxel Dörfler 
9248687ff64SAxel Dörfler BRect
9258687ff64SAxel Dörfler TranslatorView::_TabFrame(int32 index) const
9268687ff64SAxel Dörfler {
9278687ff64SAxel Dörfler 	return BRect(index * fTabWidth, 10, (index + 1) * fTabWidth, 10 + fTabHeight);
9289949213aSStephan Aßmus }
9299949213aSStephan Aßmus 
930d8e2fb50SAxel Dörfler 
9319949213aSStephan Aßmus void
9329949213aSStephan Aßmus TranslatorView::Draw(BRect updateRect)
9339949213aSStephan Aßmus {
9349949213aSStephan Aßmus 	// This is needed because DataTranslations app hides children
9359949213aSStephan Aßmus 	// after user changes translator
936d8e2fb50SAxel Dörfler 	if (ChildAt(fActiveChild)->IsHidden())
937d8e2fb50SAxel Dörfler 		ChildAt(fActiveChild)->Show();
9389949213aSStephan Aßmus 
9399949213aSStephan Aßmus 	// Clear
9409949213aSStephan Aßmus 	SetHighColor(ViewColor());
9418687ff64SAxel Dörfler 	BRect frame = _TabFrame(0);
9428687ff64SAxel Dörfler 	FillRect(BRect(frame.left, frame.top, Bounds().right, frame.bottom - 1));
9439949213aSStephan Aßmus 
944d8e2fb50SAxel Dörfler 	int32 index = 0;
9458687ff64SAxel Dörfler 	BTab* tab;
9468687ff64SAxel Dörfler 	while ((tab = (BTab*)fTabs.ItemAt(index)) != NULL) {
9478687ff64SAxel Dörfler 		tab_position position;
9488687ff64SAxel Dörfler 		if (fActiveChild == index)
9498687ff64SAxel Dörfler 			position = B_TAB_FRONT;
9508687ff64SAxel Dörfler 		else if (index == 0)
9518687ff64SAxel Dörfler 			position = B_TAB_FIRST;
9529949213aSStephan Aßmus 		else
9538687ff64SAxel Dörfler 			position = B_TAB_ANY;
9549949213aSStephan Aßmus 
9558687ff64SAxel Dörfler 		tab->DrawTab(this, _TabFrame(index), position, index + 1 != fActiveChild);
9569949213aSStephan Aßmus 		index++;
9579949213aSStephan Aßmus 	}
958d8e2fb50SAxel Dörfler 
9598687ff64SAxel Dörfler 	// Draw bottom edge
9608687ff64SAxel Dörfler 	SetHighColor(tint_color(ViewColor(), B_LIGHTEN_MAX_TINT));
9618687ff64SAxel Dörfler 
9628687ff64SAxel Dörfler 	BRect selectedFrame = _TabFrame(fActiveChild);
9638687ff64SAxel Dörfler 	float offset = ceilf(frame.Height() / 2.0);
9648687ff64SAxel Dörfler 
9658687ff64SAxel Dörfler 	if (selectedFrame.left > frame.left) {
9668687ff64SAxel Dörfler 		StrokeLine(BPoint(frame.left, frame.bottom),
9678687ff64SAxel Dörfler 			BPoint(selectedFrame.left, frame.bottom));
9688687ff64SAxel Dörfler 	}
9698687ff64SAxel Dörfler 	if (selectedFrame.right + offset < Bounds().right) {
9708687ff64SAxel Dörfler 		StrokeLine(BPoint(selectedFrame.right + offset, frame.bottom),
9718687ff64SAxel Dörfler 			BPoint(Bounds().right, frame.bottom));
9728687ff64SAxel Dörfler 	}
9739949213aSStephan Aßmus }
9749949213aSStephan Aßmus 
975d8e2fb50SAxel Dörfler 
976d8e2fb50SAxel Dörfler //!	MouseDown, check if on tab, if so change tab if needed
9779949213aSStephan Aßmus void
9789949213aSStephan Aßmus TranslatorView::MouseDown(BPoint where)
9799949213aSStephan Aßmus {
9808687ff64SAxel Dörfler 	BRect frame = _TabFrame(fTabs.CountItems() - 1);
9818687ff64SAxel Dörfler 	frame.left = 0;
9828687ff64SAxel Dörfler 	if (!frame.Contains(where))
9838687ff64SAxel Dörfler 		return;
9848687ff64SAxel Dörfler 
9858687ff64SAxel Dörfler 	for (int32 index = fTabs.CountItems(); index-- > 0;) {
9868687ff64SAxel Dörfler 		if (!_TabFrame(index).Contains(where))
9878687ff64SAxel Dörfler 			continue;
9888687ff64SAxel Dörfler 
989d8e2fb50SAxel Dörfler 		if (fActiveChild != index) {
9909949213aSStephan Aßmus 			// Hide current visible child
991d8e2fb50SAxel Dörfler 			ChildAt(fActiveChild)->Hide();
9928687ff64SAxel Dörfler 
9939949213aSStephan Aßmus 			// This loop is needed because it looks like in DataTranslations
9949949213aSStephan Aßmus 			// view gets hidden more than one time when user changes translator
9958687ff64SAxel Dörfler 			while (ChildAt(index)->IsHidden()) {
9969949213aSStephan Aßmus 				ChildAt(index)->Show();
9978687ff64SAxel Dörfler 			}
9988687ff64SAxel Dörfler 
9999949213aSStephan Aßmus 			// Remember which one is currently visible
1000d8e2fb50SAxel Dörfler 			fActiveChild = index;
10018687ff64SAxel Dörfler 			Invalidate(frame);
10028687ff64SAxel Dörfler 			break;
10039949213aSStephan Aßmus 		}
10049949213aSStephan Aßmus 	}
1005d8e2fb50SAxel Dörfler }
10069949213aSStephan Aßmus 
10079949213aSStephan Aßmus 
1008d8e2fb50SAxel Dörfler //	#pragma mark -
10099949213aSStephan Aßmus 
1010d8e2fb50SAxel Dörfler 
1011d8e2fb50SAxel Dörfler TranslatorWindow::TranslatorWindow(bool quitOnClose)
1012117da2d7SAxel Dörfler 	: BWindow(BRect(100, 100, 100, 100), "JPEG Settings", B_TITLED_WINDOW,
1013117da2d7SAxel Dörfler 		B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS)
10149949213aSStephan Aßmus {
10159949213aSStephan Aßmus 	BRect extent(0, 0, 0, 0);
10169949213aSStephan Aßmus 	BView *config = NULL;
10179949213aSStephan Aßmus 	MakeConfig(NULL, &config, &extent);
10189949213aSStephan Aßmus 
10199949213aSStephan Aßmus 	AddChild(config);
10209949213aSStephan Aßmus 	ResizeTo(extent.Width(), extent.Height());
10219949213aSStephan Aßmus 
10229949213aSStephan Aßmus 	// Make application quit after this window close
1023d8e2fb50SAxel Dörfler 	if (quitOnClose)
10249949213aSStephan Aßmus 		SetFlags(Flags() | B_QUIT_ON_WINDOW_CLOSE);
10259949213aSStephan Aßmus }
10269949213aSStephan Aßmus 
10279949213aSStephan Aßmus 
1028d8e2fb50SAxel Dörfler //	#pragma mark - Translator Add-On
10299949213aSStephan Aßmus 
10309949213aSStephan Aßmus 
10319949213aSStephan Aßmus 
1032d8e2fb50SAxel Dörfler /*! Hook to create and return our configuration view */
10339949213aSStephan Aßmus status_t
10349949213aSStephan Aßmus MakeConfig(BMessage *ioExtension, BView **outView, BRect *outExtent)
10359949213aSStephan Aßmus {
10369949213aSStephan Aßmus 	*outView = new TranslatorView("TranslatorView");
10379949213aSStephan Aßmus 	*outExtent = (*outView)->Frame();
10389949213aSStephan Aßmus 	return B_OK;
10399949213aSStephan Aßmus }
10409949213aSStephan Aßmus 
1041d8e2fb50SAxel Dörfler /*! Determine whether or not we can handle this data */
10429949213aSStephan Aßmus status_t
1043d8e2fb50SAxel Dörfler Identify(BPositionIO *inSource, const translation_format *inFormat,
1044d8e2fb50SAxel Dörfler 	BMessage *ioExtension, translator_info *outInfo, uint32 outType)
10459949213aSStephan Aßmus {
1046d8e2fb50SAxel Dörfler 	if (outType != 0 && outType != B_TRANSLATOR_BITMAP && outType != JPEG_FORMAT)
10479949213aSStephan Aßmus 		return B_NO_TRANSLATOR;
10489949213aSStephan Aßmus 
10499949213aSStephan Aßmus 	// !!! You might need to make this buffer bigger to test for your native format
10509949213aSStephan Aßmus 	off_t position = inSource->Position();
10519949213aSStephan Aßmus 	char header[sizeof(TranslatorBitmap)];
10529949213aSStephan Aßmus 	status_t err = inSource->Read(header, sizeof(TranslatorBitmap));
10539949213aSStephan Aßmus 	inSource->Seek(position, SEEK_SET);
1054d8e2fb50SAxel Dörfler 	if (err < B_OK)
1055d8e2fb50SAxel Dörfler 		return err;
10569949213aSStephan Aßmus 
10579949213aSStephan Aßmus 	if (B_BENDIAN_TO_HOST_INT32(((TranslatorBitmap *)header)->magic) == B_TRANSLATOR_BITMAP) {
10589949213aSStephan Aßmus 		outInfo->type = inputFormats[1].type;
10599949213aSStephan Aßmus 		outInfo->translator = 0;
10609949213aSStephan Aßmus 		outInfo->group = inputFormats[1].group;
10619949213aSStephan Aßmus 		outInfo->quality = inputFormats[1].quality;
10629949213aSStephan Aßmus 		outInfo->capability = inputFormats[1].capability;
10639949213aSStephan Aßmus 		strcpy(outInfo->name, inputFormats[1].name);
10649949213aSStephan Aßmus 		strcpy(outInfo->MIME, inputFormats[1].MIME);
10659949213aSStephan Aßmus 	} else {
10669949213aSStephan Aßmus 		// First 3 bytes in jpg files are always the same from what i've seen so far
10679949213aSStephan Aßmus 		// check them
10689949213aSStephan Aßmus 		if (header[0] == (char)0xff && header[1] == (char)0xd8 && header[2] == (char)0xff) {
10699949213aSStephan Aßmus 		/* this below would be safer but it slows down whole thing
10709949213aSStephan Aßmus 
10719949213aSStephan Aßmus 			struct jpeg_decompress_struct cinfo;
10729949213aSStephan Aßmus 			struct jpeg_error_mgr jerr;
10739949213aSStephan Aßmus 			cinfo.err = jpeg_std_error(&jerr);
10749949213aSStephan Aßmus 			jpeg_create_decompress(&cinfo);
10759949213aSStephan Aßmus 			be_jpeg_stdio_src(&cinfo, inSource);
10769949213aSStephan Aßmus 			// now try to read header
10779949213aSStephan Aßmus 			// it can't be read before checking first 3 bytes
10789949213aSStephan Aßmus 			// because it will hang up if there is no header (not jpeg file)
10799949213aSStephan Aßmus 			int result = jpeg_read_header(&cinfo, FALSE);
10809949213aSStephan Aßmus 			jpeg_destroy_decompress(&cinfo);
10819949213aSStephan Aßmus 			if (result == JPEG_HEADER_OK) {
10829949213aSStephan Aßmus 		*/		outInfo->type = inputFormats[0].type;
10839949213aSStephan Aßmus 				outInfo->translator = 0;
10849949213aSStephan Aßmus 				outInfo->group = inputFormats[0].group;
10859949213aSStephan Aßmus 				outInfo->quality = inputFormats[0].quality;
10869949213aSStephan Aßmus 				outInfo->capability = inputFormats[0].capability;
10879949213aSStephan Aßmus 				strcpy(outInfo->name, inputFormats[0].name);
10889949213aSStephan Aßmus 				strcpy(outInfo->MIME, inputFormats[0].MIME);
10899949213aSStephan Aßmus 				return B_OK;
10909949213aSStephan Aßmus 		/*	} else
10919949213aSStephan Aßmus 				return B_NO_TRANSLATOR;
10929949213aSStephan Aßmus 		*/
10939949213aSStephan Aßmus 		} else
10949949213aSStephan Aßmus 			return B_NO_TRANSLATOR;
10959949213aSStephan Aßmus 	}
10969949213aSStephan Aßmus 
10979949213aSStephan Aßmus 	return B_OK;
10989949213aSStephan Aßmus }
10999949213aSStephan Aßmus 
1100d8e2fb50SAxel Dörfler /*!	Arguably the most important method in the add-on */
11019949213aSStephan Aßmus status_t
1102d8e2fb50SAxel Dörfler Translate(BPositionIO *inSource, const translator_info *inInfo,
1103d8e2fb50SAxel Dörfler 	BMessage *ioExtension, uint32 outType, BPositionIO *outDestination)
11049949213aSStephan Aßmus {
11059949213aSStephan Aßmus 	// If no specific type was requested, convert to the interchange format
11069949213aSStephan Aßmus 	if (outType == 0) outType = B_TRANSLATOR_BITMAP;
11079949213aSStephan Aßmus 
11089949213aSStephan Aßmus 	// What action to take, based on the findings of Identify()
11099949213aSStephan Aßmus 	if (outType == inInfo->type) {
11109949213aSStephan Aßmus 		return Copy(inSource, outDestination);
11119949213aSStephan Aßmus 	} else if (inInfo->type == B_TRANSLATOR_BITMAP && outType == JPEG_FORMAT) {
11129949213aSStephan Aßmus 		return Compress(inSource, outDestination);
11139949213aSStephan Aßmus 	} else if (inInfo->type == JPEG_FORMAT && outType == B_TRANSLATOR_BITMAP) {
111452e8f46aSAxel Dörfler 		return Decompress(inSource, outDestination, ioExtension);
11159949213aSStephan Aßmus 	}
11169949213aSStephan Aßmus 
11179949213aSStephan Aßmus 	return B_NO_TRANSLATOR;
11189949213aSStephan Aßmus }
11199949213aSStephan Aßmus 
1120d8e2fb50SAxel Dörfler /*!	The user has requested the same format for input and output, so just copy */
112152e8f46aSAxel Dörfler static status_t
11229949213aSStephan Aßmus Copy(BPositionIO *in, BPositionIO *out)
11239949213aSStephan Aßmus {
11249949213aSStephan Aßmus 	int block_size = 65536;
11259949213aSStephan Aßmus 	void *buffer = malloc(block_size);
11269949213aSStephan Aßmus 	char temp[1024];
11279949213aSStephan Aßmus 	if (buffer == NULL) {
11289949213aSStephan Aßmus 		buffer = temp;
11299949213aSStephan Aßmus 		block_size = 1024;
11309949213aSStephan Aßmus 	}
11319949213aSStephan Aßmus 	status_t err = B_OK;
11329949213aSStephan Aßmus 
11339949213aSStephan Aßmus 	// Read until end of file or error
11349949213aSStephan Aßmus 	while (1) {
11359949213aSStephan Aßmus 		ssize_t to_read = block_size;
11369949213aSStephan Aßmus 		err = in->Read(buffer, to_read);
11379949213aSStephan Aßmus 		// Explicit check for EOF
11389949213aSStephan Aßmus 		if (err == -1) {
11399949213aSStephan Aßmus 			if (buffer != temp) free(buffer);
11409949213aSStephan Aßmus 			return B_OK;
11419949213aSStephan Aßmus 		}
11429949213aSStephan Aßmus 		if (err <= B_OK) break;
11439949213aSStephan Aßmus 		to_read = err;
11449949213aSStephan Aßmus 		err = out->Write(buffer, to_read);
11459949213aSStephan Aßmus 		if (err != to_read) if (err >= 0) err = B_DEVICE_FULL;
11469949213aSStephan Aßmus 		if (err < B_OK) break;
11479949213aSStephan Aßmus 	}
11489949213aSStephan Aßmus 
11499949213aSStephan Aßmus 	if (buffer != temp) free(buffer);
11509949213aSStephan Aßmus 	return (err >= 0) ? B_OK : err;
11519949213aSStephan Aßmus }
11529949213aSStephan Aßmus 
1153d8e2fb50SAxel Dörfler 
1154d8e2fb50SAxel Dörfler /*!	Encode into the native format */
115552e8f46aSAxel Dörfler static status_t
11569949213aSStephan Aßmus Compress(BPositionIO *in, BPositionIO *out)
11579949213aSStephan Aßmus {
11589949213aSStephan Aßmus 	// Load Settings
1159d8e2fb50SAxel Dörfler 	jpeg_settings settings;
1160d8e2fb50SAxel Dörfler 	LoadSettings(&settings);
11619949213aSStephan Aßmus 
11629949213aSStephan Aßmus 	// Read info about bitmap
11639949213aSStephan Aßmus 	TranslatorBitmap header;
11649949213aSStephan Aßmus 	status_t err = in->Read(&header, sizeof(TranslatorBitmap));
1165d8e2fb50SAxel Dörfler 	if (err < B_OK)
1166d8e2fb50SAxel Dörfler 		return err;
1167d8e2fb50SAxel Dörfler 	else if (err < (int)sizeof(TranslatorBitmap))
1168d8e2fb50SAxel Dörfler 		return B_ERROR;
11699949213aSStephan Aßmus 
11709949213aSStephan Aßmus 	// Grab dimension, color space, and size information from the stream
11719949213aSStephan Aßmus 	BRect bounds;
11729949213aSStephan Aßmus 	bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left);
11739949213aSStephan Aßmus 	bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top);
11749949213aSStephan Aßmus 	bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right);
11759949213aSStephan Aßmus 	bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom);
11769949213aSStephan Aßmus 
11779949213aSStephan Aßmus 	int32 in_row_bytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes);
11789949213aSStephan Aßmus 
11799949213aSStephan Aßmus 	int width = bounds.IntegerWidth() + 1;
11809949213aSStephan Aßmus 	int height = bounds.IntegerHeight() + 1;
11819949213aSStephan Aßmus 
11829949213aSStephan Aßmus 	// Function pointer to convert function
11839949213aSStephan Aßmus 	// It will point to proper function if needed
11849e34f742SAxel Dörfler 	void (*converter)(uchar *inscanline, uchar *outscanline,
11859e34f742SAxel Dörfler 		int32 inRowBytes) = NULL;
11869949213aSStephan Aßmus 
11879949213aSStephan Aßmus 	// Default color info
11889949213aSStephan Aßmus 	J_COLOR_SPACE jpg_color_space = JCS_RGB;
11899949213aSStephan Aßmus 	int jpg_input_components = 3;
11909949213aSStephan Aßmus 	int32 out_row_bytes;
11919949213aSStephan Aßmus 	int padding = 0;
11929949213aSStephan Aßmus 
1193d8e2fb50SAxel Dörfler 	switch ((color_space)B_BENDIAN_TO_HOST_INT32(header.colors)) {
11949949213aSStephan Aßmus 		case B_CMAP8:
11959949213aSStephan Aßmus 			converter = convert_from_cmap8_to_24;
11969949213aSStephan Aßmus 			padding = in_row_bytes - width;
11979949213aSStephan Aßmus 			break;
1198d8e2fb50SAxel Dörfler 
11999949213aSStephan Aßmus 		case B_GRAY1:
1200d8e2fb50SAxel Dörfler 			if (settings.B_GRAY1_as_B_RGB24) {
12019949213aSStephan Aßmus 				converter = convert_from_gray1_to_24;
12029949213aSStephan Aßmus 			} else {
12039949213aSStephan Aßmus 				jpg_input_components = 1;
12049949213aSStephan Aßmus 				jpg_color_space = JCS_GRAYSCALE;
12059949213aSStephan Aßmus 				converter = convert_from_gray1_to_gray8;
12069949213aSStephan Aßmus 			}
12079949213aSStephan Aßmus 			padding = in_row_bytes - (width/8);
12089949213aSStephan Aßmus 			break;
1209d8e2fb50SAxel Dörfler 
12109949213aSStephan Aßmus 		case B_GRAY8:
12119949213aSStephan Aßmus 			jpg_input_components = 1;
12129949213aSStephan Aßmus 			jpg_color_space = JCS_GRAYSCALE;
12139949213aSStephan Aßmus 			padding = in_row_bytes - width;
12149949213aSStephan Aßmus 			break;
1215d8e2fb50SAxel Dörfler 
12169949213aSStephan Aßmus 		case B_RGB15:
12179949213aSStephan Aßmus 		case B_RGBA15:
12189949213aSStephan Aßmus 			converter = convert_from_15_to_24;
12199949213aSStephan Aßmus 			padding = in_row_bytes - (width * 2);
12209949213aSStephan Aßmus 			break;
1221d8e2fb50SAxel Dörfler 
12229949213aSStephan Aßmus 		case B_RGB15_BIG:
12239949213aSStephan Aßmus 		case B_RGBA15_BIG:
12249949213aSStephan Aßmus 			converter = convert_from_15b_to_24;
12259949213aSStephan Aßmus 			padding = in_row_bytes - (width * 2);
12269949213aSStephan Aßmus 			break;
1227d8e2fb50SAxel Dörfler 
12289949213aSStephan Aßmus 		case B_RGB16:
12299949213aSStephan Aßmus 			converter = convert_from_16_to_24;
12309949213aSStephan Aßmus 			padding = in_row_bytes - (width * 2);
12319949213aSStephan Aßmus 			break;
1232d8e2fb50SAxel Dörfler 
12339949213aSStephan Aßmus 		case B_RGB16_BIG:
12349949213aSStephan Aßmus 			converter = convert_from_16b_to_24;
12359949213aSStephan Aßmus 			padding = in_row_bytes - (width * 2);
12369949213aSStephan Aßmus 			break;
1237d8e2fb50SAxel Dörfler 
12389949213aSStephan Aßmus 		case B_RGB24:
12399949213aSStephan Aßmus 			converter = convert_from_24_to_24;
12409949213aSStephan Aßmus 			padding = in_row_bytes - (width * 3);
12419949213aSStephan Aßmus 			break;
1242d8e2fb50SAxel Dörfler 
12439949213aSStephan Aßmus 		case B_RGB24_BIG:
12449949213aSStephan Aßmus 			padding = in_row_bytes - (width * 3);
12459949213aSStephan Aßmus 			break;
1246d8e2fb50SAxel Dörfler 
12479949213aSStephan Aßmus 		case B_RGB32:
12489949213aSStephan Aßmus 		case B_RGBA32:
12499949213aSStephan Aßmus 			converter = convert_from_32_to_24;
12509949213aSStephan Aßmus 			padding = in_row_bytes - (width * 4);
12519949213aSStephan Aßmus 			break;
1252d8e2fb50SAxel Dörfler 
12539949213aSStephan Aßmus 		case B_RGB32_BIG:
12549949213aSStephan Aßmus 		case B_RGBA32_BIG:
12559949213aSStephan Aßmus 			converter = convert_from_32b_to_24;
12569949213aSStephan Aßmus 			padding = in_row_bytes - (width * 4);
12579949213aSStephan Aßmus 			break;
1258d8e2fb50SAxel Dörfler 
12599949213aSStephan Aßmus 		case B_CMYK32:
12609949213aSStephan Aßmus 			jpg_color_space = JCS_CMYK;
12619949213aSStephan Aßmus 			jpg_input_components = 4;
12629949213aSStephan Aßmus 			padding = in_row_bytes - (width * 4);
12639949213aSStephan Aßmus 			break;
1264d8e2fb50SAxel Dörfler 
12659949213aSStephan Aßmus 		default:
12669949213aSStephan Aßmus 			fprintf(stderr, "Wrong type: Color space not implemented.\n");
12679949213aSStephan Aßmus 			return B_ERROR;
12689949213aSStephan Aßmus 	}
12699949213aSStephan Aßmus 	out_row_bytes = jpg_input_components * width;
12709949213aSStephan Aßmus 
12719949213aSStephan Aßmus 	// Set basic things needed for jpeg writing
12729949213aSStephan Aßmus 	struct jpeg_compress_struct cinfo;
12739949213aSStephan Aßmus 	struct jpeg_error_mgr jerr;
1274d8e2fb50SAxel Dörfler 	cinfo.err = be_jpeg_std_error(&jerr, &settings);
12759949213aSStephan Aßmus 	jpeg_create_compress(&cinfo);
12769949213aSStephan Aßmus 	be_jpeg_stdio_dest(&cinfo, out);
12779949213aSStephan Aßmus 
12789949213aSStephan Aßmus 	// Set basic values
12799949213aSStephan Aßmus 	cinfo.image_width = width;
12809949213aSStephan Aßmus 	cinfo.image_height = height;
12819949213aSStephan Aßmus 	cinfo.input_components = jpg_input_components;
12829949213aSStephan Aßmus 	cinfo.in_color_space = jpg_color_space;
12839949213aSStephan Aßmus 	jpeg_set_defaults(&cinfo);
12849949213aSStephan Aßmus 
12859949213aSStephan Aßmus 	// Set better accuracy
12869949213aSStephan Aßmus 	cinfo.dct_method = JDCT_ISLOW;
12879949213aSStephan Aßmus 
12889949213aSStephan Aßmus 	// This is needed to prevent some colors loss
12899949213aSStephan Aßmus 	// With it generated jpegs are as good as from Fireworks (at last! :D)
1290d8e2fb50SAxel Dörfler 	if (settings.OptimizeColors) {
12919949213aSStephan Aßmus 		int index = 0;
12929949213aSStephan Aßmus 		while (index < cinfo.num_components) {
12939949213aSStephan Aßmus 			cinfo.comp_info[index].h_samp_factor = 1;
12949949213aSStephan Aßmus 			cinfo.comp_info[index].v_samp_factor = 1;
12959949213aSStephan Aßmus 			// This will make file smaller, but with worse quality more or less
12969949213aSStephan Aßmus 			// like with 93%-94% (but it's subjective opinion) on tested images
12979949213aSStephan Aßmus 			// but with smaller size (between 92% and 93% on tested images)
1298d8e2fb50SAxel Dörfler 			if (settings.SmallerFile)
12999949213aSStephan Aßmus 				cinfo.comp_info[index].quant_tbl_no = 1;
13009949213aSStephan Aßmus 			// This will make bigger file, but also better quality ;]
13019949213aSStephan Aßmus 			// from my tests it seems like useless - better quality with smaller
13029949213aSStephan Aßmus 			// can be acheived without this
13039949213aSStephan Aßmus //			cinfo.comp_info[index].dc_tbl_no = 1;
13049949213aSStephan Aßmus //			cinfo.comp_info[index].ac_tbl_no = 1;
13059949213aSStephan Aßmus 			index++;
13069949213aSStephan Aßmus 		}
13079949213aSStephan Aßmus 	}
13089949213aSStephan Aßmus 
13099949213aSStephan Aßmus 	// Set quality
1310d8e2fb50SAxel Dörfler 	jpeg_set_quality(&cinfo, settings.Quality, true);
13119949213aSStephan Aßmus 
13129949213aSStephan Aßmus 	// Set progressive compression if needed
13139949213aSStephan Aßmus 	// if not, turn on optimizing in libjpeg
1314d8e2fb50SAxel Dörfler 	if (settings.Progressive)
13159949213aSStephan Aßmus 		jpeg_simple_progression(&cinfo);
13169949213aSStephan Aßmus 	else
13179949213aSStephan Aßmus 		cinfo.optimize_coding = TRUE;
13189949213aSStephan Aßmus 
13199949213aSStephan Aßmus 	// Set smoothing (effect like Blur)
1320d8e2fb50SAxel Dörfler 	cinfo.smoothing_factor = settings.Smoothing;
13219949213aSStephan Aßmus 
13229949213aSStephan Aßmus 	// Initialize compression
13239949213aSStephan Aßmus 	jpeg_start_compress(&cinfo, TRUE);
13249949213aSStephan Aßmus 
13259949213aSStephan Aßmus 	// Declare scanlines
13269949213aSStephan Aßmus 	JSAMPROW in_scanline = NULL;
13279949213aSStephan Aßmus 	JSAMPROW out_scanline = NULL;
13289949213aSStephan Aßmus 	JSAMPROW writeline;	// Pointer to in_scanline (default) or out_scanline (if there will be conversion)
13299949213aSStephan Aßmus 
13309949213aSStephan Aßmus 	// Allocate scanline
13319949213aSStephan Aßmus 	// Use libjpeg memory allocation functions, so in case of error it will free them itself
1332d8e2fb50SAxel Dörfler 	in_scanline = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo,
1333d8e2fb50SAxel Dörfler 		JPOOL_PERMANENT, in_row_bytes);
13349949213aSStephan Aßmus 
13359949213aSStephan Aßmus 	// We need 2nd scanline storage ony for conversion
13369949213aSStephan Aßmus 	if (converter != NULL) {
13379949213aSStephan Aßmus 		// There will be conversion, allocate second scanline...
13389949213aSStephan Aßmus 		// Use libjpeg memory allocation functions, so in case of error it will free them itself
1339d8e2fb50SAxel Dörfler 	    out_scanline = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo,
1340d8e2fb50SAxel Dörfler 	    	JPOOL_PERMANENT, out_row_bytes);
13419949213aSStephan Aßmus 		// ... and make it the one to write to file
13429949213aSStephan Aßmus 		writeline = out_scanline;
13439949213aSStephan Aßmus 	} else
13449949213aSStephan Aßmus 		writeline = in_scanline;
13459949213aSStephan Aßmus 
13469949213aSStephan Aßmus 	while (cinfo.next_scanline < cinfo.image_height) {
13479949213aSStephan Aßmus 		// Read scanline
13489949213aSStephan Aßmus 		err = in->Read(in_scanline, in_row_bytes);
13499949213aSStephan Aßmus 		if (err < in_row_bytes)
1350d8e2fb50SAxel Dörfler 			return err < B_OK ? Error((j_common_ptr)&cinfo, err)
1351d8e2fb50SAxel Dörfler 				: Error((j_common_ptr)&cinfo, B_ERROR);
13529949213aSStephan Aßmus 
13539949213aSStephan Aßmus 		// Convert if needed
13549949213aSStephan Aßmus 		if (converter != NULL)
13559949213aSStephan Aßmus 			converter(in_scanline, out_scanline, in_row_bytes - padding);
13569949213aSStephan Aßmus 
13579949213aSStephan Aßmus 		// Write scanline
13589949213aSStephan Aßmus 	   	jpeg_write_scanlines(&cinfo, &writeline, 1);
13599949213aSStephan Aßmus 	}
13609949213aSStephan Aßmus 
13619949213aSStephan Aßmus 	jpeg_finish_compress(&cinfo);
13629949213aSStephan Aßmus 	jpeg_destroy_compress(&cinfo);
13639949213aSStephan Aßmus 	return B_OK;
13649949213aSStephan Aßmus }
13659949213aSStephan Aßmus 
1366d8e2fb50SAxel Dörfler 
1367d8e2fb50SAxel Dörfler /*!	Decode the native format */
136852e8f46aSAxel Dörfler static status_t
136952e8f46aSAxel Dörfler Decompress(BPositionIO *in, BPositionIO *out, BMessage* ioExtension)
13709949213aSStephan Aßmus {
13719949213aSStephan Aßmus 	// Load Settings
1372d8e2fb50SAxel Dörfler 	jpeg_settings settings;
1373d8e2fb50SAxel Dörfler 	LoadSettings(&settings);
13749949213aSStephan Aßmus 
13759949213aSStephan Aßmus 	// Set basic things needed for jpeg reading
13769949213aSStephan Aßmus 	struct jpeg_decompress_struct cinfo;
13779949213aSStephan Aßmus 	struct jpeg_error_mgr jerr;
1378d8e2fb50SAxel Dörfler 	cinfo.err = be_jpeg_std_error(&jerr, &settings);
13799949213aSStephan Aßmus 	jpeg_create_decompress(&cinfo);
13809949213aSStephan Aßmus 	be_jpeg_stdio_src(&cinfo, in);
13819949213aSStephan Aßmus 
138252e8f46aSAxel Dörfler 	jpeg_save_markers(&cinfo, MARKER_EXIF, 131072);
138352e8f46aSAxel Dörfler 		// make sure the EXIF tag is stored
138452e8f46aSAxel Dörfler 
13859949213aSStephan Aßmus 	// Read info about image
13869949213aSStephan Aßmus 	jpeg_read_header(&cinfo, TRUE);
13879949213aSStephan Aßmus 
138852e8f46aSAxel Dörfler 	BMessage exif;
138952e8f46aSAxel Dörfler 
1390*f13b5de6SAxel Dörfler 	// parse EXIF data and add it ioExtension, if any
139152e8f46aSAxel Dörfler 	jpeg_marker_struct* marker = cinfo.marker_list;
139252e8f46aSAxel Dörfler 	while (marker != NULL) {
139352e8f46aSAxel Dörfler 		if (marker->marker == MARKER_EXIF
139452e8f46aSAxel Dörfler 			&& !strncmp((char*)marker->data, "Exif", 4)) {
1395*f13b5de6SAxel Dörfler 			if (ioExtension != NULL) {
139652e8f46aSAxel Dörfler 				// Strip EXIF header from TIFF data
139752e8f46aSAxel Dörfler 				ioExtension->AddData("exif", B_RAW_TYPE,
139852e8f46aSAxel Dörfler 					(uint8 *)marker->data + 6, marker->data_length - 6);
1399*f13b5de6SAxel Dörfler 			}
140052e8f46aSAxel Dörfler 
140152e8f46aSAxel Dörfler 			BMemoryIO io(marker->data + 6, marker->data_length - 6);
140252e8f46aSAxel Dörfler 			convert_exif_to_message(io, exif);
140352e8f46aSAxel Dörfler 		}
140452e8f46aSAxel Dörfler 		marker = marker->next;
140552e8f46aSAxel Dörfler 	}
140652e8f46aSAxel Dörfler 
14079949213aSStephan Aßmus 	// Default color info
140852e8f46aSAxel Dörfler 	color_space outColorSpace = B_RGB32;
140952e8f46aSAxel Dörfler 	int outColorComponents = 4;
14109949213aSStephan Aßmus 
14119949213aSStephan Aßmus 	// Function pointer to convert function
14129949213aSStephan Aßmus 	// It will point to proper function if needed
141352e8f46aSAxel Dörfler 	void (*converter)(uchar *inScanLine, uchar *outScanLine,
14149e34f742SAxel Dörfler 		int32 inRowBytes, int32 xStep) = convert_from_24_to_32;
14159949213aSStephan Aßmus 
14169949213aSStephan Aßmus 	// If color space isn't rgb
14179949213aSStephan Aßmus 	if (cinfo.out_color_space != JCS_RGB) {
1418d8e2fb50SAxel Dörfler 		switch (cinfo.out_color_space) {
14199949213aSStephan Aßmus 			case JCS_UNKNOWN:		/* error/unspecified */
14209949213aSStephan Aßmus 				fprintf(stderr, "From Type: Jpeg uses unknown color type\n");
14219949213aSStephan Aßmus 				break;
14229949213aSStephan Aßmus 			case JCS_GRAYSCALE:		/* monochrome */
14239949213aSStephan Aßmus 				// Check if user wants to read only as RGB32 or not
1424d8e2fb50SAxel Dörfler 				if (!settings.Always_B_RGB32) {
14259949213aSStephan Aßmus 					// Grayscale
142652e8f46aSAxel Dörfler 					outColorSpace = B_GRAY8;
142752e8f46aSAxel Dörfler 					outColorComponents = 1;
14289e34f742SAxel Dörfler 					converter = translate_8;
14299949213aSStephan Aßmus 				} else {
14309949213aSStephan Aßmus 					// RGB
14319949213aSStephan Aßmus 					cinfo.out_color_space = JCS_RGB;
14329949213aSStephan Aßmus 					cinfo.output_components = 3;
14339949213aSStephan Aßmus 					converter = convert_from_24_to_32;
14349949213aSStephan Aßmus 				}
14359949213aSStephan Aßmus 				break;
14369949213aSStephan Aßmus 			case JCS_YCbCr:		/* Y/Cb/Cr (also known as YUV) */
14379949213aSStephan Aßmus 				cinfo.out_color_space = JCS_RGB;
14389949213aSStephan Aßmus 				converter = convert_from_24_to_32;
14399949213aSStephan Aßmus 				break;
14409949213aSStephan Aßmus 			case JCS_YCCK:		/* Y/Cb/Cr/K */
14419949213aSStephan Aßmus 				// Let libjpeg convert it to CMYK
14429949213aSStephan Aßmus 				cinfo.out_color_space = JCS_CMYK;
14439949213aSStephan Aßmus 				// Fall through to CMYK since we need the same settings
14449949213aSStephan Aßmus 			case JCS_CMYK:		/* C/M/Y/K */
14459949213aSStephan Aßmus 				// Use proper converter
1446d8e2fb50SAxel Dörfler 				if (settings.PhotoshopCMYK)
14479949213aSStephan Aßmus 					converter = convert_from_CMYK_to_32_photoshop;
14489949213aSStephan Aßmus 				else
14499949213aSStephan Aßmus 					converter = convert_from_CMYK_to_32;
14509949213aSStephan Aßmus 				break;
14519949213aSStephan Aßmus 			default:
14529949213aSStephan Aßmus 				fprintf(stderr, "From Type: Jpeg uses hmm... i don't know really :(\n");
14539949213aSStephan Aßmus 				break;
14549949213aSStephan Aßmus 		}
14559949213aSStephan Aßmus 	}
14569949213aSStephan Aßmus 
14579949213aSStephan Aßmus 	// Initialize decompression
14589949213aSStephan Aßmus 	jpeg_start_decompress(&cinfo);
14599949213aSStephan Aßmus 
14609e34f742SAxel Dörfler 	// retrieve orientation from settings/EXIF
146152e8f46aSAxel Dörfler 	int32 orientation;
14629e34f742SAxel Dörfler 	if (ioExtension == NULL
14639e34f742SAxel Dörfler 		|| ioExtension->FindInt32("exif:orientation", &orientation) != B_OK) {
146452e8f46aSAxel Dörfler 		if (exif.FindInt32("Orientation", &orientation) != B_OK)
146552e8f46aSAxel Dörfler 			orientation = 1;
146652e8f46aSAxel Dörfler 	}
14679949213aSStephan Aßmus 
14689e34f742SAxel Dörfler 	if (orientation != 1 && converter == NULL)
14699e34f742SAxel Dörfler 		converter = translate_8;
14709e34f742SAxel Dörfler 
14719e34f742SAxel Dörfler 	int32 outputWidth = orientation > 4 ? cinfo.output_height : cinfo.output_width;
14729e34f742SAxel Dörfler 	int32 outputHeight = orientation > 4 ? cinfo.output_width : cinfo.output_height;
14739e34f742SAxel Dörfler 
14749e34f742SAxel Dörfler 	int32 destOffset = dest_index(outputWidth, outputHeight,
14759e34f742SAxel Dörfler 		0, 0, orientation) * outColorComponents;
14769e34f742SAxel Dörfler 	int32 xStep = dest_index(outputWidth, outputHeight,
14779e34f742SAxel Dörfler 		1, 0, orientation) * outColorComponents - destOffset;
14789e34f742SAxel Dörfler 	int32 yStep = dest_index(outputWidth, outputHeight,
14799e34f742SAxel Dörfler 		0, 1, orientation) * outColorComponents - destOffset;
14809e34f742SAxel Dörfler 	bool needAll = orientation != 1;
14819e34f742SAxel Dörfler 
14829e34f742SAxel Dörfler 	// Initialize this bounds rect to the size of your image
14839e34f742SAxel Dörfler 	BRect bounds(0, 0, outputWidth - 1, outputHeight - 1);
14849e34f742SAxel Dörfler 
14859e34f742SAxel Dörfler #if 0
14869e34f742SAxel Dörfler printf("destOffset = %ld, xStep = %ld, yStep = %ld, input: %ld x %ld, output: %ld x %ld, orientation %ld\n",
14879e34f742SAxel Dörfler 	destOffset, xStep, yStep, (int32)cinfo.output_width, (int32)cinfo.output_height,
14889e34f742SAxel Dörfler 	bounds.IntegerWidth() + 1, bounds.IntegerHeight() + 1, orientation);
14899e34f742SAxel Dörfler #endif
14909e34f742SAxel Dörfler 
14919949213aSStephan Aßmus 	// Bytes count in one line of image (scanline)
14929e34f742SAxel Dörfler 	int32 inRowBytes = cinfo.output_width * cinfo.output_components;
14939e34f742SAxel Dörfler 	int32 rowBytes = (bounds.IntegerWidth() + 1) * outColorComponents;
14949e34f742SAxel Dörfler 	int32 dataSize = cinfo.output_width * cinfo.output_height
14959e34f742SAxel Dörfler 		* outColorComponents;
14969949213aSStephan Aßmus 
14979949213aSStephan Aßmus 	// Fill out the B_TRANSLATOR_BITMAP's header
14989949213aSStephan Aßmus 	TranslatorBitmap header;
14999949213aSStephan Aßmus 	header.magic = B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP);
15009949213aSStephan Aßmus 	header.bounds.left = B_HOST_TO_BENDIAN_FLOAT(bounds.left);
15019949213aSStephan Aßmus 	header.bounds.top = B_HOST_TO_BENDIAN_FLOAT(bounds.top);
15029949213aSStephan Aßmus 	header.bounds.right = B_HOST_TO_BENDIAN_FLOAT(bounds.right);
15039949213aSStephan Aßmus 	header.bounds.bottom = B_HOST_TO_BENDIAN_FLOAT(bounds.bottom);
150452e8f46aSAxel Dörfler 	header.colors = (color_space)B_HOST_TO_BENDIAN_INT32(outColorSpace);
150552e8f46aSAxel Dörfler 	header.rowBytes = B_HOST_TO_BENDIAN_INT32(rowBytes);
15069e34f742SAxel Dörfler 	header.dataSize = B_HOST_TO_BENDIAN_INT32(dataSize);
15079949213aSStephan Aßmus 
15089949213aSStephan Aßmus 	// Write out the header
15099949213aSStephan Aßmus 	status_t err = out->Write(&header, sizeof(TranslatorBitmap));
1510d8e2fb50SAxel Dörfler 	if (err < B_OK)
1511d8e2fb50SAxel Dörfler 		return Error((j_common_ptr)&cinfo, err);
1512d8e2fb50SAxel Dörfler 	else if (err < (int)sizeof(TranslatorBitmap))
1513d8e2fb50SAxel Dörfler 		return Error((j_common_ptr)&cinfo, B_ERROR);
15149949213aSStephan Aßmus 
15159949213aSStephan Aßmus 	// Declare scanlines
15169e34f742SAxel Dörfler 	JSAMPROW inScanLine = NULL;
15179e34f742SAxel Dörfler 	uint8* dest = NULL;
15189e34f742SAxel Dörfler 	uint8* destLine = NULL;
15199949213aSStephan Aßmus 
15209949213aSStephan Aßmus 	// Allocate scanline
15219949213aSStephan Aßmus 	// Use libjpeg memory allocation functions, so in case of error it will free them itself
15229e34f742SAxel Dörfler     inScanLine = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo,
15239e34f742SAxel Dörfler     	JPOOL_PERMANENT, inRowBytes);
15249949213aSStephan Aßmus 
15259949213aSStephan Aßmus 	// We need 2nd scanline storage only for conversion
15269949213aSStephan Aßmus 	if (converter != NULL) {
15279949213aSStephan Aßmus 		// There will be conversion, allocate second scanline...
15289e34f742SAxel Dörfler 		// Use libjpeg memory allocation functions, so in case of error it will free
15299e34f742SAxel Dörfler 		// them itself
15309e34f742SAxel Dörfler 	    dest = (uint8*)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo,
15319e34f742SAxel Dörfler 	    	JPOOL_PERMANENT, needAll ? dataSize : rowBytes);
15329e34f742SAxel Dörfler 	    destLine = dest + destOffset;
15339949213aSStephan Aßmus 	} else
15349e34f742SAxel Dörfler 		destLine = inScanLine;
15359949213aSStephan Aßmus 
15369949213aSStephan Aßmus 	while (cinfo.output_scanline < cinfo.output_height) {
15379949213aSStephan Aßmus 		// Read scanline
15389e34f742SAxel Dörfler 		jpeg_read_scanlines(&cinfo, &inScanLine, 1);
15399949213aSStephan Aßmus 
15409949213aSStephan Aßmus 		// Convert if needed
15419949213aSStephan Aßmus 		if (converter != NULL)
15429e34f742SAxel Dörfler 			converter(inScanLine, destLine, inRowBytes, xStep);
15439949213aSStephan Aßmus 
15449e34f742SAxel Dörfler 		if (!needAll) {
15459949213aSStephan Aßmus 	  		// Write the scanline buffer to the output stream
15469e34f742SAxel Dörfler 			ssize_t bytesWritten = out->Write(destLine, rowBytes);
15479e34f742SAxel Dörfler 			if (bytesWritten < rowBytes) {
15489e34f742SAxel Dörfler 				return bytesWritten < B_OK
15499e34f742SAxel Dörfler 					? Error((j_common_ptr)&cinfo, bytesWritten)
1550d8e2fb50SAxel Dörfler 					: Error((j_common_ptr)&cinfo, B_ERROR);
15519949213aSStephan Aßmus 			}
15529e34f742SAxel Dörfler 		} else
15539e34f742SAxel Dörfler 			destLine += yStep;
15549e34f742SAxel Dörfler 	}
15559e34f742SAxel Dörfler 
15569e34f742SAxel Dörfler 	if (needAll) {
15579e34f742SAxel Dörfler 		ssize_t bytesWritten = out->Write(dest, dataSize);
15589e34f742SAxel Dörfler 		if (bytesWritten < dataSize) {
15599e34f742SAxel Dörfler 			return bytesWritten < B_OK
15609e34f742SAxel Dörfler 				? Error((j_common_ptr)&cinfo, bytesWritten)
15619e34f742SAxel Dörfler 				: Error((j_common_ptr)&cinfo, B_ERROR);
15629e34f742SAxel Dörfler 		}
15639e34f742SAxel Dörfler 	}
15649949213aSStephan Aßmus 
15659949213aSStephan Aßmus 	jpeg_finish_decompress(&cinfo);
15669949213aSStephan Aßmus 	jpeg_destroy_decompress(&cinfo);
15679949213aSStephan Aßmus 	return B_OK;
15689949213aSStephan Aßmus }
15699949213aSStephan Aßmus 
1570d8e2fb50SAxel Dörfler /*!
1571d8e2fb50SAxel Dörfler 	Frees jpeg alocated memory
1572d8e2fb50SAxel Dörfler 	Returns given error (B_ERROR by default)
1573d8e2fb50SAxel Dörfler */
157452e8f46aSAxel Dörfler static status_t
15759949213aSStephan Aßmus Error(j_common_ptr cinfo, status_t error)
15769949213aSStephan Aßmus {
15779949213aSStephan Aßmus 	jpeg_destroy(cinfo);
15789949213aSStephan Aßmus 	return error;
15799949213aSStephan Aßmus }
1580d8e2fb50SAxel Dörfler 
1581d8e2fb50SAxel Dörfler 
1582d8e2fb50SAxel Dörfler //	#pragma mark -
1583d8e2fb50SAxel Dörfler 
1584d8e2fb50SAxel Dörfler 
1585d8e2fb50SAxel Dörfler int
1586117da2d7SAxel Dörfler main(int, char**)
1587117da2d7SAxel Dörfler {
1588117da2d7SAxel Dörfler 	BApplication app("application/x-vnd.Haiku-JPEGTranslator");
1589d8e2fb50SAxel Dörfler 
1590d8e2fb50SAxel Dörfler 	TranslatorWindow *window = new TranslatorWindow();
1591d8e2fb50SAxel Dörfler 	window->Show();
1592d8e2fb50SAxel Dörfler 
1593d8e2fb50SAxel Dörfler 	app.Run();
1594d8e2fb50SAxel Dörfler 	return 0;
1595d8e2fb50SAxel Dörfler }
1596d8e2fb50SAxel Dörfler 
1597