xref: /haiku/src/add-ons/translators/jpeg/JPEGTranslator.cpp (revision d8e2fb507a66c3f3c9353303adf6059f0ea4be50)
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 
359949213aSStephan Aßmus 
369949213aSStephan Aßmus // Set these accordingly
379949213aSStephan Aßmus #define JPEG_ACRONYM "JPEG"
389949213aSStephan Aßmus #define JPEG_FORMAT 'JPEG'
399949213aSStephan Aßmus #define JPEG_MIME_STRING "image/jpeg"
409949213aSStephan Aßmus #define JPEG_DESCRIPTION "JPEG image"
419949213aSStephan Aßmus 
429949213aSStephan Aßmus // The translation kit's native file type
439949213aSStephan Aßmus #define B_TRANSLATOR_BITMAP_MIME_STRING "image/x-be-bitmap"
449949213aSStephan Aßmus #define B_TRANSLATOR_BITMAP_DESCRIPTION "Be Bitmap image"
459949213aSStephan Aßmus 
469949213aSStephan Aßmus // Translation Kit required globals
479949213aSStephan Aßmus char translatorName[] = "JPEG translator";
48758b1d0eSIngo Weinhold char translatorInfo[] = "© 2002-2003, Shard\n"
49758b1d0eSIngo Weinhold "\n"
50758b1d0eSIngo Weinhold "Based on IJG library © 1991-1998, Thomas G. Lane\"\n"
51758b1d0eSIngo Weinhold "          http://www.ijg.org/files/\n"
52758b1d0eSIngo Weinhold "with \"Lossless\" encoding support patch by Ken Murchison\n"
53758b1d0eSIngo Weinhold "          http://www.oceana.com/ftp/ljpeg/\n"
54758b1d0eSIngo Weinhold "\n"
55758b1d0eSIngo Weinhold "With some colorspace conversion routines by Magnus Hellman\n"
56758b1d0eSIngo Weinhold "          http://www.bebits.com/app/802\n"
57758b1d0eSIngo Weinhold "";
58*d8e2fb50SAxel Dörfler 
599949213aSStephan Aßmus int32 translatorVersion = 273;	// 256 = v1.0.0
609949213aSStephan Aßmus 
619949213aSStephan Aßmus // Define the formats we know how to read
629949213aSStephan Aßmus translation_format inputFormats[] = {
639949213aSStephan Aßmus 	{ JPEG_FORMAT, B_TRANSLATOR_BITMAP, 0.5, 0.5,
649949213aSStephan Aßmus 		JPEG_MIME_STRING, JPEG_DESCRIPTION },
659949213aSStephan Aßmus 	{ B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.5, 0.5,
669949213aSStephan Aßmus 		B_TRANSLATOR_BITMAP_MIME_STRING, B_TRANSLATOR_BITMAP_DESCRIPTION },
67*d8e2fb50SAxel Dörfler 	{}
689949213aSStephan Aßmus };
699949213aSStephan Aßmus 
709949213aSStephan Aßmus // Define the formats we know how to write
719949213aSStephan Aßmus translation_format outputFormats[] = {
729949213aSStephan Aßmus 	{ JPEG_FORMAT, B_TRANSLATOR_BITMAP, 0.5, 0.5,
739949213aSStephan Aßmus 		JPEG_MIME_STRING, JPEG_DESCRIPTION },
749949213aSStephan Aßmus 	{ B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.5, 0.5,
759949213aSStephan Aßmus 		B_TRANSLATOR_BITMAP_MIME_STRING, B_TRANSLATOR_BITMAP_DESCRIPTION },
76*d8e2fb50SAxel Dörfler 	{}
779949213aSStephan Aßmus };
789949213aSStephan Aßmus 
79*d8e2fb50SAxel Dörfler 
80*d8e2fb50SAxel Dörfler bool gAreSettingsRunning = false;
819949213aSStephan Aßmus 
829949213aSStephan Aßmus 
83*d8e2fb50SAxel Dörfler //!	Make settings to defaults
84*d8e2fb50SAxel Dörfler void
85*d8e2fb50SAxel Dörfler LoadDefaultSettings(jpeg_settings *settings)
86*d8e2fb50SAxel Dörfler {
87*d8e2fb50SAxel Dörfler 	settings->Smoothing = 0;
88*d8e2fb50SAxel Dörfler 	settings->Quality = 95;
89*d8e2fb50SAxel Dörfler 	settings->Progressive = true;
90*d8e2fb50SAxel Dörfler 	settings->OptimizeColors = true;
91*d8e2fb50SAxel Dörfler 	settings->SmallerFile = false;
92*d8e2fb50SAxel Dörfler 	settings->B_GRAY1_as_B_RGB24 = false;
93*d8e2fb50SAxel Dörfler 	settings->Always_B_RGB32 = true;
94*d8e2fb50SAxel Dörfler 	settings->PhotoshopCMYK = true;
95*d8e2fb50SAxel Dörfler 	settings->ShowReadWarningBox = true;
96*d8e2fb50SAxel Dörfler }
979949213aSStephan Aßmus 
98*d8e2fb50SAxel Dörfler 
99*d8e2fb50SAxel Dörfler //!	Save settings to config file
100*d8e2fb50SAxel Dörfler void
101*d8e2fb50SAxel Dörfler SaveSettings(jpeg_settings *settings)
102*d8e2fb50SAxel Dörfler {
103*d8e2fb50SAxel Dörfler 	// Make path to settings file
104*d8e2fb50SAxel Dörfler 	BPath path;
105*d8e2fb50SAxel Dörfler 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) {
106*d8e2fb50SAxel Dörfler 		path.SetTo(SETTINGS_PATH);
107*d8e2fb50SAxel Dörfler 		path.Append(SETTINGS_FILE);
108*d8e2fb50SAxel Dörfler 	} else
109*d8e2fb50SAxel Dörfler 		path.Append(SETTINGS_FILE);
110*d8e2fb50SAxel Dörfler 
111*d8e2fb50SAxel Dörfler 	// Open settings file (create it if there's no file) and write settings
112*d8e2fb50SAxel Dörfler 	FILE *file = NULL;
113*d8e2fb50SAxel Dörfler 	if ((file = fopen( path.Path(), "wb+"))) {
114*d8e2fb50SAxel Dörfler 		fwrite(settings, sizeof(jpeg_settings), 1, file);
115*d8e2fb50SAxel Dörfler 		fclose(file);
116*d8e2fb50SAxel Dörfler 	}
117*d8e2fb50SAxel Dörfler }
118*d8e2fb50SAxel Dörfler 
119*d8e2fb50SAxel Dörfler 
120*d8e2fb50SAxel Dörfler //!	Return true if settings were run, false if not
121*d8e2fb50SAxel Dörfler bool
122*d8e2fb50SAxel Dörfler SettingsChangedAlert()
123*d8e2fb50SAxel Dörfler {
124*d8e2fb50SAxel Dörfler 	// If settings view wasn't already initialized (settings not running)
125*d8e2fb50SAxel Dörfler 	// and user wants to run settings
126*d8e2fb50SAxel Dörfler 	if (!gAreSettingsRunning
127*d8e2fb50SAxel Dörfler 		&& (new BAlert("Different settings file",
128*d8e2fb50SAxel Dörfler 					"JPEG settings were set to default because of incompatible settings file.",
129*d8e2fb50SAxel Dörfler 					"Configure settings", "OK", NULL, B_WIDTH_AS_USUAL,
130*d8e2fb50SAxel Dörfler 					B_WARNING_ALERT))->Go() == 0) {
131*d8e2fb50SAxel Dörfler 		// Create settings window (with no quit on close!), launch
132*d8e2fb50SAxel Dörfler 		// it and wait until it's closed
133*d8e2fb50SAxel Dörfler 		status_t err;
134*d8e2fb50SAxel Dörfler 		TranslatorWindow *window = new TranslatorWindow(false);
135*d8e2fb50SAxel Dörfler 		window->Show();
136*d8e2fb50SAxel Dörfler 		wait_for_thread(window->Thread(), &err);
137*d8e2fb50SAxel Dörfler 		return true;
138*d8e2fb50SAxel Dörfler 	}
139*d8e2fb50SAxel Dörfler 
140*d8e2fb50SAxel Dörfler 	return false;
141*d8e2fb50SAxel Dörfler }
142*d8e2fb50SAxel Dörfler 
143*d8e2fb50SAxel Dörfler 
144*d8e2fb50SAxel Dörfler /*!
145*d8e2fb50SAxel Dörfler 	Load settings from config file
146*d8e2fb50SAxel Dörfler 	If can't find it make them default and try to save
147*d8e2fb50SAxel Dörfler */
148*d8e2fb50SAxel Dörfler void
149*d8e2fb50SAxel Dörfler LoadSettings(jpeg_settings *settings)
150*d8e2fb50SAxel Dörfler {
151*d8e2fb50SAxel Dörfler 	// Make path to settings file
152*d8e2fb50SAxel Dörfler 	BPath path;
153*d8e2fb50SAxel Dörfler 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) {
154*d8e2fb50SAxel Dörfler 		path.SetTo(SETTINGS_PATH);
155*d8e2fb50SAxel Dörfler 		path.Append(SETTINGS_FILE);
156*d8e2fb50SAxel Dörfler 	} else
157*d8e2fb50SAxel Dörfler 		path.Append(SETTINGS_FILE);
158*d8e2fb50SAxel Dörfler 
159*d8e2fb50SAxel Dörfler 	// Open settings file (create it if there's no file) and write settings
160*d8e2fb50SAxel Dörfler 	FILE *file = NULL;
161*d8e2fb50SAxel Dörfler 	if ((file = fopen( path.Path(), "rb"))) {
162*d8e2fb50SAxel Dörfler 		if ( !fread(settings, sizeof(jpeg_settings), 1, file)) {
163*d8e2fb50SAxel Dörfler 			// settings struct has changed size
164*d8e2fb50SAxel Dörfler 			// Load default settings, and Save them
165*d8e2fb50SAxel Dörfler 			fclose(file);
166*d8e2fb50SAxel Dörfler 			LoadDefaultSettings(settings);
167*d8e2fb50SAxel Dörfler 			SaveSettings(settings);
168*d8e2fb50SAxel Dörfler 			// Tell user settings were changed to default, and ask to run settings panel or not
169*d8e2fb50SAxel Dörfler 			if (SettingsChangedAlert())
170*d8e2fb50SAxel Dörfler 				// User configured settings, load them again
171*d8e2fb50SAxel Dörfler 				LoadSettings(settings);
172*d8e2fb50SAxel Dörfler 		} else
173*d8e2fb50SAxel Dörfler 			fclose(file);
174*d8e2fb50SAxel Dörfler 	} else if ((file = fopen( path.Path(), "wb+"))) {
175*d8e2fb50SAxel Dörfler 		LoadDefaultSettings(settings);
176*d8e2fb50SAxel Dörfler 		fwrite(settings, sizeof(jpeg_settings), 1, file);
177*d8e2fb50SAxel Dörfler 		fclose(file);
178*d8e2fb50SAxel Dörfler 		// Tell user settings were changed to default, and ask to run settings panel or not
179*d8e2fb50SAxel Dörfler 		if (SettingsChangedAlert())
180*d8e2fb50SAxel Dörfler 			// User configured settings, load them again
181*d8e2fb50SAxel Dörfler 			LoadSettings(settings);
182*d8e2fb50SAxel Dörfler 	}
183*d8e2fb50SAxel Dörfler }
184*d8e2fb50SAxel Dörfler 
185*d8e2fb50SAxel Dörfler 
186*d8e2fb50SAxel Dörfler //	#pragma mark - conversion routines
187*d8e2fb50SAxel Dörfler 
188*d8e2fb50SAxel Dörfler 
189*d8e2fb50SAxel Dörfler inline void
190*d8e2fb50SAxel Dörfler convert_from_gray1_to_gray8(uchar *in, uchar *out, int in_bytes)
191*d8e2fb50SAxel Dörfler {
192*d8e2fb50SAxel Dörfler 	int32 index = 0;
193*d8e2fb50SAxel Dörfler 	int32 index2 = 0;
194*d8e2fb50SAxel Dörfler 	while (index < in_bytes) {
195*d8e2fb50SAxel Dörfler 		unsigned char c = in[index++];
196*d8e2fb50SAxel Dörfler 		for (int b = 128; b; b = b>>1) {
197*d8e2fb50SAxel Dörfler 			unsigned char color;
198*d8e2fb50SAxel Dörfler 			if (c & b)
199*d8e2fb50SAxel Dörfler 				color = 0;
200*d8e2fb50SAxel Dörfler 			else
201*d8e2fb50SAxel Dörfler 				color = 255;
202*d8e2fb50SAxel Dörfler 			out[index2++] = color;
203*d8e2fb50SAxel Dörfler 		}
204*d8e2fb50SAxel Dörfler 	}
205*d8e2fb50SAxel Dörfler }
206*d8e2fb50SAxel Dörfler 
207*d8e2fb50SAxel Dörfler 
208*d8e2fb50SAxel Dörfler inline void
209*d8e2fb50SAxel Dörfler convert_from_gray1_to_24(uchar *in, uchar *out, int in_bytes)
210*d8e2fb50SAxel Dörfler {
211*d8e2fb50SAxel Dörfler 	int32 index = 0;
212*d8e2fb50SAxel Dörfler 	int32 index2 = 0;
213*d8e2fb50SAxel Dörfler 	while (index < in_bytes) {
214*d8e2fb50SAxel Dörfler 		unsigned char c = in[index++];
215*d8e2fb50SAxel Dörfler 		for (int b = 128; b; b = b>>1) {
216*d8e2fb50SAxel Dörfler 			unsigned char color;
217*d8e2fb50SAxel Dörfler 			if (c & b)
218*d8e2fb50SAxel Dörfler 				color = 0;
219*d8e2fb50SAxel Dörfler 			else
220*d8e2fb50SAxel Dörfler 				color = 255;
221*d8e2fb50SAxel Dörfler 			out[index2++] = color;
222*d8e2fb50SAxel Dörfler 			out[index2++] = color;
223*d8e2fb50SAxel Dörfler 			out[index2++] = color;
224*d8e2fb50SAxel Dörfler 		}
225*d8e2fb50SAxel Dörfler 	}
226*d8e2fb50SAxel Dörfler }
227*d8e2fb50SAxel Dörfler 
228*d8e2fb50SAxel Dörfler 
229*d8e2fb50SAxel Dörfler inline void
230*d8e2fb50SAxel Dörfler convert_from_cmap8_to_24(uchar *in, uchar *out, int in_bytes)
231*d8e2fb50SAxel Dörfler {
232*d8e2fb50SAxel Dörfler 	const color_map * map = system_colors();
233*d8e2fb50SAxel Dörfler 	int32 index = 0;
234*d8e2fb50SAxel Dörfler 	int32 index2 = 0;
235*d8e2fb50SAxel Dörfler 	while (index < in_bytes) {
236*d8e2fb50SAxel Dörfler 		rgb_color color = map->color_list[in[index++]];
237*d8e2fb50SAxel Dörfler 
238*d8e2fb50SAxel Dörfler 		out[index2++] = color.red;
239*d8e2fb50SAxel Dörfler 		out[index2++] = color.green;
240*d8e2fb50SAxel Dörfler 		out[index2++] = color.blue;
241*d8e2fb50SAxel Dörfler 	}
242*d8e2fb50SAxel Dörfler }
243*d8e2fb50SAxel Dörfler 
244*d8e2fb50SAxel Dörfler 
245*d8e2fb50SAxel Dörfler inline void
246*d8e2fb50SAxel Dörfler convert_from_15_to_24(uchar *in, uchar *out, int in_bytes)
247*d8e2fb50SAxel Dörfler {
248*d8e2fb50SAxel Dörfler 	int32 index = 0;
249*d8e2fb50SAxel Dörfler 	int32 index2 = 0;
250*d8e2fb50SAxel Dörfler 	int16 in_pixel;
251*d8e2fb50SAxel Dörfler 	while (index < in_bytes) {
252*d8e2fb50SAxel Dörfler 		in_pixel = in[index] | (in[index+1] << 8);
253*d8e2fb50SAxel Dörfler 		index += 2;
254*d8e2fb50SAxel Dörfler 
255*d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x7c00)) >> 7) | (((in_pixel & 0x7c00)) >> 12);
256*d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x3e0)) >> 2) | (((in_pixel & 0x3e0)) >> 7);
257*d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2);
258*d8e2fb50SAxel Dörfler 	}
259*d8e2fb50SAxel Dörfler }
260*d8e2fb50SAxel Dörfler 
261*d8e2fb50SAxel Dörfler 
262*d8e2fb50SAxel Dörfler inline void
263*d8e2fb50SAxel Dörfler convert_from_15b_to_24(uchar *in, uchar *out, int in_bytes)
264*d8e2fb50SAxel Dörfler {
265*d8e2fb50SAxel Dörfler 	int32 index = 0;
266*d8e2fb50SAxel Dörfler 	int32 index2 = 0;
267*d8e2fb50SAxel Dörfler 	int16 in_pixel;
268*d8e2fb50SAxel Dörfler 	while (index < in_bytes) {
269*d8e2fb50SAxel Dörfler 		in_pixel = in[index+1] | (in[index] << 8);
270*d8e2fb50SAxel Dörfler 		index += 2;
271*d8e2fb50SAxel Dörfler 
272*d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x7c00)) >> 7) | (((in_pixel & 0x7c00)) >> 12);
273*d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x3e0)) >> 2) | (((in_pixel & 0x3e0)) >> 7);
274*d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2);
275*d8e2fb50SAxel Dörfler 	}
276*d8e2fb50SAxel Dörfler }
277*d8e2fb50SAxel Dörfler 
278*d8e2fb50SAxel Dörfler 
279*d8e2fb50SAxel Dörfler inline void
280*d8e2fb50SAxel Dörfler convert_from_16_to_24(uchar *in, uchar *out, int in_bytes)
281*d8e2fb50SAxel Dörfler {
282*d8e2fb50SAxel Dörfler 	int32 index = 0;
283*d8e2fb50SAxel Dörfler 	int32 index2 = 0;
284*d8e2fb50SAxel Dörfler 	int16 in_pixel;
285*d8e2fb50SAxel Dörfler 	while (index < in_bytes) {
286*d8e2fb50SAxel Dörfler 		in_pixel = in[index] | (in[index+1] << 8);
287*d8e2fb50SAxel Dörfler 		index += 2;
288*d8e2fb50SAxel Dörfler 
289*d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0xf800)) >> 8) | (((in_pixel & 0xf800)) >> 13);
290*d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x7e0)) >> 3) | (((in_pixel & 0x7e0)) >> 9);
291*d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2);
292*d8e2fb50SAxel Dörfler 	}
293*d8e2fb50SAxel Dörfler }
294*d8e2fb50SAxel Dörfler 
295*d8e2fb50SAxel Dörfler 
296*d8e2fb50SAxel Dörfler inline void
297*d8e2fb50SAxel Dörfler convert_from_16b_to_24(uchar *in, uchar *out, int in_bytes)
298*d8e2fb50SAxel Dörfler {
299*d8e2fb50SAxel Dörfler 	int32 index = 0;
300*d8e2fb50SAxel Dörfler 	int32 index2 = 0;
301*d8e2fb50SAxel Dörfler 	int16 in_pixel;
302*d8e2fb50SAxel Dörfler 	while (index < in_bytes) {
303*d8e2fb50SAxel Dörfler 		in_pixel = in[index+1] | (in[index] << 8);
304*d8e2fb50SAxel Dörfler 		index += 2;
305*d8e2fb50SAxel Dörfler 
306*d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0xf800)) >> 8) | (((in_pixel & 0xf800)) >> 13);
307*d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x7e0)) >> 3) | (((in_pixel & 0x7e0)) >> 9);
308*d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2);
309*d8e2fb50SAxel Dörfler 	}
310*d8e2fb50SAxel Dörfler }
311*d8e2fb50SAxel Dörfler 
312*d8e2fb50SAxel Dörfler 
313*d8e2fb50SAxel Dörfler inline void
314*d8e2fb50SAxel Dörfler convert_from_24_to_24(uchar *in, uchar *out, int in_bytes)
315*d8e2fb50SAxel Dörfler {
316*d8e2fb50SAxel Dörfler 	int32 index = 0;
317*d8e2fb50SAxel Dörfler 	int32 index2 = 0;
318*d8e2fb50SAxel Dörfler 	while (index < in_bytes) {
319*d8e2fb50SAxel Dörfler 		out[index2++] = in[index+2];
320*d8e2fb50SAxel Dörfler 		out[index2++] = in[index+1];
321*d8e2fb50SAxel Dörfler 		out[index2++] = in[index];
322*d8e2fb50SAxel Dörfler 		index+=3;
323*d8e2fb50SAxel Dörfler 	}
324*d8e2fb50SAxel Dörfler }
325*d8e2fb50SAxel Dörfler 
326*d8e2fb50SAxel Dörfler 
327*d8e2fb50SAxel Dörfler inline void
328*d8e2fb50SAxel Dörfler convert_from_32_to_24(uchar *in, uchar *out, int in_bytes)
329*d8e2fb50SAxel Dörfler {
330*d8e2fb50SAxel Dörfler 	int32 index = 0;
331*d8e2fb50SAxel Dörfler 	int32 index2 = 0;
332*d8e2fb50SAxel Dörfler 	while (index < in_bytes) {
333*d8e2fb50SAxel Dörfler 		out[index2++] = in[index+2];
334*d8e2fb50SAxel Dörfler 		out[index2++] = in[index+1];
335*d8e2fb50SAxel Dörfler 		out[index2++] = in[index];
336*d8e2fb50SAxel Dörfler 		index+=4;
337*d8e2fb50SAxel Dörfler 	}
338*d8e2fb50SAxel Dörfler }
339*d8e2fb50SAxel Dörfler 
340*d8e2fb50SAxel Dörfler 
341*d8e2fb50SAxel Dörfler inline void
342*d8e2fb50SAxel Dörfler convert_from_32b_to_24(uchar *in, uchar *out, int in_bytes)
343*d8e2fb50SAxel Dörfler {
344*d8e2fb50SAxel Dörfler 	int32 index = 0;
345*d8e2fb50SAxel Dörfler 	int32 index2 = 0;
346*d8e2fb50SAxel Dörfler 	while (index < in_bytes) {
347*d8e2fb50SAxel Dörfler 		index++;
348*d8e2fb50SAxel Dörfler 		out[index2++] = in[index++];
349*d8e2fb50SAxel Dörfler 		out[index2++] = in[index++];
350*d8e2fb50SAxel Dörfler 		out[index2++] = in[index++];
351*d8e2fb50SAxel Dörfler 	}
352*d8e2fb50SAxel Dörfler }
353*d8e2fb50SAxel Dörfler 
354*d8e2fb50SAxel Dörfler 
355*d8e2fb50SAxel Dörfler inline void
356*d8e2fb50SAxel Dörfler convert_from_CMYK_to_32_photoshop(uchar *in, uchar *out, int out_bytes)
357*d8e2fb50SAxel Dörfler {
358*d8e2fb50SAxel Dörfler 	int32 index = 0;
359*d8e2fb50SAxel Dörfler 	int32 index2 = 0;
360*d8e2fb50SAxel Dörfler 	int32 black = 0;
361*d8e2fb50SAxel Dörfler 	while (index < out_bytes) {
362*d8e2fb50SAxel Dörfler 		black = in[index2+3];
363*d8e2fb50SAxel Dörfler 		out[index++] = in[index2+2]*black/255;
364*d8e2fb50SAxel Dörfler 		out[index++] = in[index2+1]*black/255;
365*d8e2fb50SAxel Dörfler 		out[index++] = in[index2]*black/255;
366*d8e2fb50SAxel Dörfler 		out[index++] = 255;
367*d8e2fb50SAxel Dörfler 		index2 += 4;
368*d8e2fb50SAxel Dörfler 	}
369*d8e2fb50SAxel Dörfler }
370*d8e2fb50SAxel Dörfler 
371*d8e2fb50SAxel Dörfler 
372*d8e2fb50SAxel Dörfler //!	!!! UNTESTED !!!
373*d8e2fb50SAxel Dörfler inline void
374*d8e2fb50SAxel Dörfler convert_from_CMYK_to_32(uchar *in, uchar *out, int out_bytes)
375*d8e2fb50SAxel Dörfler {
376*d8e2fb50SAxel Dörfler 	int32 index = 0;
377*d8e2fb50SAxel Dörfler 	int32 index2 = 0;
378*d8e2fb50SAxel Dörfler 	int32 black = 0;
379*d8e2fb50SAxel Dörfler 	while (index < out_bytes) {
380*d8e2fb50SAxel Dörfler 		black = 255 - in[index2+3];
381*d8e2fb50SAxel Dörfler 		out[index++] = ((255-in[index2+2])*black)/255;
382*d8e2fb50SAxel Dörfler 		out[index++] = ((255-in[index2+1])*black)/255;
383*d8e2fb50SAxel Dörfler 		out[index++] = ((255-in[index2])*black)/255;
384*d8e2fb50SAxel Dörfler 		out[index++] = 255;
385*d8e2fb50SAxel Dörfler 		index2 += 4;
386*d8e2fb50SAxel Dörfler 	}
387*d8e2fb50SAxel Dörfler }
388*d8e2fb50SAxel Dörfler 
389*d8e2fb50SAxel Dörfler 
390*d8e2fb50SAxel Dörfler //!	RGB24 8:8:8 to xRGB 8:8:8:8
391*d8e2fb50SAxel Dörfler inline void
392*d8e2fb50SAxel Dörfler convert_from_24_to_32(uchar *in, uchar *out, int out_bytes)
393*d8e2fb50SAxel Dörfler {
394*d8e2fb50SAxel Dörfler 	int32 index = 0;
395*d8e2fb50SAxel Dörfler 	int32 index2 = 0;
396*d8e2fb50SAxel Dörfler 	while (index < out_bytes) {
397*d8e2fb50SAxel Dörfler 		out[index++] = in[index2+2];
398*d8e2fb50SAxel Dörfler 		out[index++] = in[index2+1];
399*d8e2fb50SAxel Dörfler 		out[index++] = in[index2];
400*d8e2fb50SAxel Dörfler 		out[index++] = 255;
401*d8e2fb50SAxel Dörfler 		index2 += 3;
402*d8e2fb50SAxel Dörfler 	}
403*d8e2fb50SAxel Dörfler }
404*d8e2fb50SAxel Dörfler 
405*d8e2fb50SAxel Dörfler 
406*d8e2fb50SAxel Dörfler //	#pragma mark -
407*d8e2fb50SAxel Dörfler 
408*d8e2fb50SAxel Dörfler 
409*d8e2fb50SAxel Dörfler SSlider::SSlider(BRect frame, const char *name, const char *label,
410*d8e2fb50SAxel Dörfler 		BMessage *message, int32 minValue, int32 maxValue, orientation posture,
411*d8e2fb50SAxel Dörfler 		thumb_style thumbType, uint32 resizingMode, uint32 flags)
412*d8e2fb50SAxel Dörfler 	: BSlider(frame, name, label, message, minValue, maxValue,
413*d8e2fb50SAxel Dörfler 		posture, thumbType, resizingMode, flags)
4149949213aSStephan Aßmus {
4159949213aSStephan Aßmus 	rgb_color bar_color = { 0, 0, 229, 255 };
4169949213aSStephan Aßmus 	UseFillColor(true, &bar_color);
4179949213aSStephan Aßmus }
4189949213aSStephan Aßmus 
4199949213aSStephan Aßmus //---------------------------------------------------
4209949213aSStephan Aßmus //	Update status string - show actual value
4219949213aSStephan Aßmus //---------------------------------------------------
4229949213aSStephan Aßmus char*
4239949213aSStephan Aßmus SSlider::UpdateText() const
4249949213aSStephan Aßmus {
4259949213aSStephan Aßmus 	sprintf( (char*)statusLabel, "%ld", Value());
4269949213aSStephan Aßmus 	return (char*)statusLabel;
4279949213aSStephan Aßmus }
4289949213aSStephan Aßmus 
4299949213aSStephan Aßmus //---------------------------------------------------
4309949213aSStephan Aßmus //	BSlider::ResizeToPreferred + Resize width if it's too small to show label and status
4319949213aSStephan Aßmus //---------------------------------------------------
4329949213aSStephan Aßmus void
4339949213aSStephan Aßmus SSlider::ResizeToPreferred()
4349949213aSStephan Aßmus {
4359949213aSStephan Aßmus 	int32 width = (int32)ceil(StringWidth( Label()) + StringWidth("9999"));
4369949213aSStephan Aßmus 	if (width < 230) width = 230;
4379949213aSStephan Aßmus 	float w, h;
4389949213aSStephan Aßmus 	GetPreferredSize(&w, &h);
4399949213aSStephan Aßmus 	ResizeTo(width, h);
4409949213aSStephan Aßmus }
4419949213aSStephan Aßmus 
4429949213aSStephan Aßmus 
443*d8e2fb50SAxel Dörfler //	#pragma mark -
4449949213aSStephan Aßmus 
445*d8e2fb50SAxel Dörfler 
446*d8e2fb50SAxel Dörfler TranslatorReadView::TranslatorReadView(const char *name, jpeg_settings *settings,
447*d8e2fb50SAxel Dörfler 		float x, float y)
4489949213aSStephan Aßmus 	: SView(name, x, y),
449*d8e2fb50SAxel Dörfler 	fSettings(settings)
4509949213aSStephan Aßmus {
451*d8e2fb50SAxel Dörfler 	alwaysrgb32 = new BCheckBox( BRect(10, GetPreferredHeight(), 10,
452*d8e2fb50SAxel Dörfler 		GetPreferredHeight()), "alwaysrgb32", VIEW_LABEL_ALWAYSRGB32,
453*d8e2fb50SAxel Dörfler 		new BMessage(VIEW_MSG_SET_ALWAYSRGB32));
4549949213aSStephan Aßmus 	alwaysrgb32->SetFont(be_plain_font);
455*d8e2fb50SAxel Dörfler 	if (fSettings->Always_B_RGB32)
4569949213aSStephan Aßmus 		alwaysrgb32->SetValue(1);
4579949213aSStephan Aßmus 
4589949213aSStephan Aßmus 	AddChild(alwaysrgb32);
4599949213aSStephan Aßmus 
4609949213aSStephan Aßmus 	photoshopCMYK = new BCheckBox( BRect(10, GetPreferredHeight(), 10, GetPreferredHeight()), "photoshopCMYK", VIEW_LABEL_PHOTOSHOPCMYK, new BMessage(VIEW_MSG_SET_PHOTOSHOPCMYK));
4619949213aSStephan Aßmus 	photoshopCMYK->SetFont(be_plain_font);
462*d8e2fb50SAxel Dörfler 	if (fSettings->PhotoshopCMYK)
4639949213aSStephan Aßmus 		photoshopCMYK->SetValue(1);
4649949213aSStephan Aßmus 
4659949213aSStephan Aßmus 	AddChild(photoshopCMYK);
4669949213aSStephan Aßmus 
4679949213aSStephan Aßmus 	showerrorbox = new BCheckBox( BRect(10, GetPreferredHeight(), 10, GetPreferredHeight()), "progress", VIEW_LABEL_SHOWREADERRORBOX, new BMessage(VIEW_MSG_SET_SHOWREADERRORBOX));
4689949213aSStephan Aßmus 	showerrorbox->SetFont(be_plain_font);
469*d8e2fb50SAxel Dörfler 	if (fSettings->ShowReadWarningBox)
4709949213aSStephan Aßmus 		showerrorbox->SetValue(1);
4719949213aSStephan Aßmus 
4729949213aSStephan Aßmus 	AddChild(showerrorbox);
4739949213aSStephan Aßmus 
4749949213aSStephan Aßmus 	ResizeToPreferred();
4759949213aSStephan Aßmus }
4769949213aSStephan Aßmus 
4779949213aSStephan Aßmus //---------------------------------------------------
4789949213aSStephan Aßmus //	Attached to window - set children target
4799949213aSStephan Aßmus //---------------------------------------------------
4809949213aSStephan Aßmus void
4819949213aSStephan Aßmus TranslatorReadView::AttachedToWindow()
4829949213aSStephan Aßmus {
4839949213aSStephan Aßmus 	alwaysrgb32->SetTarget(this);
4849949213aSStephan Aßmus 	photoshopCMYK->SetTarget(this);
4859949213aSStephan Aßmus 	showerrorbox->SetTarget(this);
4869949213aSStephan Aßmus }
4879949213aSStephan Aßmus 
4889949213aSStephan Aßmus //---------------------------------------------------
4899949213aSStephan Aßmus //	MessageReceived - receive GUI changes, save settings
4909949213aSStephan Aßmus //---------------------------------------------------
4919949213aSStephan Aßmus void
4929949213aSStephan Aßmus TranslatorReadView::MessageReceived(BMessage *message)
4939949213aSStephan Aßmus {
4949949213aSStephan Aßmus 	switch (message->what)
4959949213aSStephan Aßmus 	{
4969949213aSStephan Aßmus 		case VIEW_MSG_SET_ALWAYSRGB32:
4979949213aSStephan Aßmus 		{
4989949213aSStephan Aßmus 			int32 value;
4999949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
500*d8e2fb50SAxel Dörfler 				fSettings->Always_B_RGB32 = value;
501*d8e2fb50SAxel Dörfler 				SaveSettings(fSettings);
5029949213aSStephan Aßmus 			}
5039949213aSStephan Aßmus 			break;
5049949213aSStephan Aßmus 		}
5059949213aSStephan Aßmus 		case VIEW_MSG_SET_PHOTOSHOPCMYK:
5069949213aSStephan Aßmus 		{
5079949213aSStephan Aßmus 			int32 value;
5089949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
509*d8e2fb50SAxel Dörfler 				fSettings->PhotoshopCMYK = value;
510*d8e2fb50SAxel Dörfler 				SaveSettings(fSettings);
5119949213aSStephan Aßmus 			}
5129949213aSStephan Aßmus 			break;
5139949213aSStephan Aßmus 		}
5149949213aSStephan Aßmus 		case VIEW_MSG_SET_SHOWREADERRORBOX:
5159949213aSStephan Aßmus 		{
5169949213aSStephan Aßmus 			int32 value;
5179949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
518*d8e2fb50SAxel Dörfler 				fSettings->ShowReadWarningBox = value;
519*d8e2fb50SAxel Dörfler 				SaveSettings(fSettings);
5209949213aSStephan Aßmus 			}
5219949213aSStephan Aßmus 			break;
5229949213aSStephan Aßmus 		}
5239949213aSStephan Aßmus 		default:
5249949213aSStephan Aßmus 			BView::MessageReceived(message);
5259949213aSStephan Aßmus 			break;
5269949213aSStephan Aßmus 	}
5279949213aSStephan Aßmus }
5289949213aSStephan Aßmus 
5299949213aSStephan Aßmus 
5309949213aSStephan Aßmus //----------------------------------------------------------------------------
5319949213aSStephan Aßmus //
5329949213aSStephan Aßmus //	Functions :: TranslatorWriteView
5339949213aSStephan Aßmus //
5349949213aSStephan Aßmus //----------------------------------------------------------------------------
5359949213aSStephan Aßmus 
5369949213aSStephan Aßmus //---------------------------------------------------
5379949213aSStephan Aßmus //	Constructor
5389949213aSStephan Aßmus //---------------------------------------------------
539*d8e2fb50SAxel Dörfler TranslatorWriteView::TranslatorWriteView(const char *name, jpeg_settings *settings, float x, float y)
5409949213aSStephan Aßmus :	SView(name, x, y),
541*d8e2fb50SAxel Dörfler 	fSettings(settings)
5429949213aSStephan Aßmus {
5439949213aSStephan Aßmus 	quality = new SSlider( BRect(10, GetPreferredHeight(), 10, GetPreferredHeight()), "quality", VIEW_LABEL_QUALITY, new BMessage(VIEW_MSG_SET_QUALITY), 0, 100);
5449949213aSStephan Aßmus 	quality->SetHashMarks(B_HASH_MARKS_BOTTOM);
5459949213aSStephan Aßmus 	quality->SetHashMarkCount(10);
5469949213aSStephan Aßmus 	quality->SetLimitLabels("Low", "High");
5479949213aSStephan Aßmus 	quality->SetFont(be_plain_font);
548*d8e2fb50SAxel Dörfler 	quality->SetValue(fSettings->Quality);
5499949213aSStephan Aßmus 
5509949213aSStephan Aßmus 	AddChild(quality);
5519949213aSStephan Aßmus 
5529949213aSStephan Aßmus 	smoothing = new SSlider( BRect(10, GetPreferredHeight()+10, 10, GetPreferredHeight()), "smoothing", VIEW_LABEL_SMOOTHING, new BMessage(VIEW_MSG_SET_SMOOTHING), 0, 100);
5539949213aSStephan Aßmus 	smoothing->SetHashMarks(B_HASH_MARKS_BOTTOM);
5549949213aSStephan Aßmus 	smoothing->SetHashMarkCount(10);
5559949213aSStephan Aßmus 	smoothing->SetLimitLabels("None", "High");
5569949213aSStephan Aßmus 	smoothing->SetFont(be_plain_font);
557*d8e2fb50SAxel Dörfler 	smoothing->SetValue(fSettings->Smoothing);
5589949213aSStephan Aßmus 
5599949213aSStephan Aßmus 	AddChild(smoothing);
5609949213aSStephan Aßmus 
5619949213aSStephan Aßmus 	progress = new BCheckBox( BRect(10, GetPreferredHeight()+10, 10, GetPreferredHeight()), "progress", VIEW_LABEL_PROGRESSIVE, new BMessage(VIEW_MSG_SET_PROGRESSIVE));
5629949213aSStephan Aßmus 	progress->SetFont(be_plain_font);
563*d8e2fb50SAxel Dörfler 	if (fSettings->Progressive)
5649949213aSStephan Aßmus 		progress->SetValue(1);
5659949213aSStephan Aßmus 
5669949213aSStephan Aßmus 	AddChild(progress);
5679949213aSStephan Aßmus 
5689949213aSStephan Aßmus 	optimizecolors = new BCheckBox( BRect(10, GetPreferredHeight()+5, 10, GetPreferredHeight()+5), "optimizecolors", VIEW_LABEL_OPTIMIZECOLORS, new BMessage(VIEW_MSG_SET_OPTIMIZECOLORS));
5699949213aSStephan Aßmus 	optimizecolors->SetFont(be_plain_font);
570*d8e2fb50SAxel Dörfler 	if (fSettings->OptimizeColors)
5719949213aSStephan Aßmus 		optimizecolors->SetValue(1);
5729949213aSStephan Aßmus 
5739949213aSStephan Aßmus 	AddChild(optimizecolors);
5749949213aSStephan Aßmus 
5759949213aSStephan Aßmus 	smallerfile = new BCheckBox( BRect(25, GetPreferredHeight()+5, 25, GetPreferredHeight()+5), "smallerfile", VIEW_LABEL_SMALLERFILE, new BMessage(VIEW_MSG_SET_SMALLERFILE));
5769949213aSStephan Aßmus 	smallerfile->SetFont(be_plain_font);
577*d8e2fb50SAxel Dörfler 	if (fSettings->SmallerFile)
5789949213aSStephan Aßmus 		smallerfile->SetValue(1);
579*d8e2fb50SAxel Dörfler 	if (!fSettings->OptimizeColors)
5809949213aSStephan Aßmus 		smallerfile->SetEnabled(false);
5819949213aSStephan Aßmus 
5829949213aSStephan Aßmus 	AddChild(smallerfile);
5839949213aSStephan Aßmus 
5849949213aSStephan Aßmus 	gray1asrgb24 = new BCheckBox( BRect(10, GetPreferredHeight()+5, 25, GetPreferredHeight()+5), "gray1asrgb24", VIEW_LABEL_GRAY1ASRGB24, new BMessage(VIEW_MSG_SET_GRAY1ASRGB24));
5859949213aSStephan Aßmus 	gray1asrgb24->SetFont(be_plain_font);
586*d8e2fb50SAxel Dörfler 	if (fSettings->B_GRAY1_as_B_RGB24)
5879949213aSStephan Aßmus 		gray1asrgb24->SetValue(1);
5889949213aSStephan Aßmus 
5899949213aSStephan Aßmus 	AddChild(gray1asrgb24);
5909949213aSStephan Aßmus 
5919949213aSStephan Aßmus 	ResizeToPreferred();
5929949213aSStephan Aßmus }
5939949213aSStephan Aßmus 
5949949213aSStephan Aßmus //---------------------------------------------------
5959949213aSStephan Aßmus //	Attached to window - set children target
5969949213aSStephan Aßmus //---------------------------------------------------
5979949213aSStephan Aßmus void
5989949213aSStephan Aßmus TranslatorWriteView::AttachedToWindow()
5999949213aSStephan Aßmus {
6009949213aSStephan Aßmus 	quality->SetTarget(this);
6019949213aSStephan Aßmus 	smoothing->SetTarget(this);
6029949213aSStephan Aßmus 	progress->SetTarget(this);
6039949213aSStephan Aßmus 	optimizecolors->SetTarget(this);
6049949213aSStephan Aßmus 	smallerfile->SetTarget(this);
6059949213aSStephan Aßmus 	gray1asrgb24->SetTarget(this);
6069949213aSStephan Aßmus }
6079949213aSStephan Aßmus 
6089949213aSStephan Aßmus //---------------------------------------------------
6099949213aSStephan Aßmus //	MessageReceived - receive GUI changes, save settings
6109949213aSStephan Aßmus //---------------------------------------------------
6119949213aSStephan Aßmus void
6129949213aSStephan Aßmus TranslatorWriteView::MessageReceived(BMessage *message)
6139949213aSStephan Aßmus {
6149949213aSStephan Aßmus 	switch (message->what)
6159949213aSStephan Aßmus 	{
6169949213aSStephan Aßmus 		case VIEW_MSG_SET_QUALITY:
6179949213aSStephan Aßmus 		{
6189949213aSStephan Aßmus 			int32 value;
6199949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
620*d8e2fb50SAxel Dörfler 				fSettings->Quality = value;
621*d8e2fb50SAxel Dörfler 				SaveSettings(fSettings);
6229949213aSStephan Aßmus 			}
6239949213aSStephan Aßmus 			break;
6249949213aSStephan Aßmus 		}
6259949213aSStephan Aßmus 		case VIEW_MSG_SET_SMOOTHING:
6269949213aSStephan Aßmus 		{
6279949213aSStephan Aßmus 			int32 value;
6289949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
629*d8e2fb50SAxel Dörfler 				fSettings->Smoothing = value;
630*d8e2fb50SAxel Dörfler 				SaveSettings(fSettings);
6319949213aSStephan Aßmus 			}
6329949213aSStephan Aßmus 			break;
6339949213aSStephan Aßmus 		}
6349949213aSStephan Aßmus 		case VIEW_MSG_SET_PROGRESSIVE:
6359949213aSStephan Aßmus 		{
6369949213aSStephan Aßmus 			int32 value;
6379949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
638*d8e2fb50SAxel Dörfler 				fSettings->Progressive = value;
639*d8e2fb50SAxel Dörfler 				SaveSettings(fSettings);
6409949213aSStephan Aßmus 			}
6419949213aSStephan Aßmus 			break;
6429949213aSStephan Aßmus 		}
6439949213aSStephan Aßmus 		case VIEW_MSG_SET_OPTIMIZECOLORS:
6449949213aSStephan Aßmus 		{
6459949213aSStephan Aßmus 			int32 value;
6469949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
647*d8e2fb50SAxel Dörfler 				fSettings->OptimizeColors = value;
648*d8e2fb50SAxel Dörfler 				SaveSettings(fSettings);
6499949213aSStephan Aßmus 			}
650*d8e2fb50SAxel Dörfler 			smallerfile->SetEnabled(fSettings->OptimizeColors);
6519949213aSStephan Aßmus 			break;
6529949213aSStephan Aßmus 		}
6539949213aSStephan Aßmus 		case VIEW_MSG_SET_SMALLERFILE:
6549949213aSStephan Aßmus 		{
6559949213aSStephan Aßmus 			int32 value;
6569949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
657*d8e2fb50SAxel Dörfler 				fSettings->SmallerFile = value;
658*d8e2fb50SAxel Dörfler 				SaveSettings(fSettings);
6599949213aSStephan Aßmus 			}
6609949213aSStephan Aßmus 			break;
6619949213aSStephan Aßmus 		}
6629949213aSStephan Aßmus 		case VIEW_MSG_SET_GRAY1ASRGB24:
6639949213aSStephan Aßmus 		{
6649949213aSStephan Aßmus 			int32 value;
6659949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
666*d8e2fb50SAxel Dörfler 				fSettings->B_GRAY1_as_B_RGB24 = value;
667*d8e2fb50SAxel Dörfler 				SaveSettings(fSettings);
6689949213aSStephan Aßmus 			}
6699949213aSStephan Aßmus 			break;
6709949213aSStephan Aßmus 		}
6719949213aSStephan Aßmus 		default:
6729949213aSStephan Aßmus 			BView::MessageReceived(message);
6739949213aSStephan Aßmus 			break;
6749949213aSStephan Aßmus 	}
6759949213aSStephan Aßmus }
6769949213aSStephan Aßmus 
6779949213aSStephan Aßmus 
678*d8e2fb50SAxel Dörfler //	#pragma mark -
6799949213aSStephan Aßmus 
680*d8e2fb50SAxel Dörfler 
6819949213aSStephan Aßmus TranslatorAboutView::TranslatorAboutView(const char *name, float x, float y)
6829949213aSStephan Aßmus 	: SView(name, x, y)
6839949213aSStephan Aßmus {
6849949213aSStephan Aßmus 	BStringView *title = new BStringView( BRect(10, 0, 10, 0), "Title", translatorName);
6859949213aSStephan Aßmus 	title->SetFont(be_bold_font);
6869949213aSStephan Aßmus 
6879949213aSStephan Aßmus 	AddChild(title);
6889949213aSStephan Aßmus 
6899949213aSStephan Aßmus 	BRect rect = title->Bounds();
6909949213aSStephan Aßmus 	float space = title->StringWidth("    ");
6919949213aSStephan Aßmus 
6929949213aSStephan Aßmus 	char versionString[16];
693*d8e2fb50SAxel Dörfler 	sprintf(versionString, "v%d.%d.%d", (int)(translatorVersion >> 8),
694*d8e2fb50SAxel Dörfler 		(int)((translatorVersion >> 4) & 0xf), (int)(translatorVersion & 0xf));
6959949213aSStephan Aßmus 
696*d8e2fb50SAxel Dörfler 	BStringView *version = new BStringView(BRect(rect.right+space, rect.top,
697*d8e2fb50SAxel Dörfler 		rect.right+space, rect.top), "Version", versionString);
6989949213aSStephan Aßmus 	version->SetFont(be_plain_font);
6999949213aSStephan Aßmus 	version->SetFontSize( 9);
7009949213aSStephan Aßmus 	// Make version be in the same line as title
7019949213aSStephan Aßmus 	version->ResizeToPreferred();
7029949213aSStephan Aßmus 	version->MoveBy(0, rect.bottom-version->Frame().bottom);
7039949213aSStephan Aßmus 
7049949213aSStephan Aßmus 	AddChild(version);
7059949213aSStephan Aßmus 
7069949213aSStephan Aßmus 	// Now for each line in translatorInfo add BStringView
7079949213aSStephan Aßmus 	BStringView *copyright;
7089949213aSStephan Aßmus 	const char *current = translatorInfo;
7099949213aSStephan Aßmus 	char *temp = translatorInfo;
7109949213aSStephan Aßmus 	while (*current != 0) {
7119949213aSStephan Aßmus 		// Find next line char
7129949213aSStephan Aßmus 		temp = strchr(current, 0x0a);
7139949213aSStephan Aßmus 		// If found replace it with 0 so current will look like ending here
7149949213aSStephan Aßmus 		if (temp)
7159949213aSStephan Aßmus 			*temp = 0;
7169949213aSStephan Aßmus 		// Add BStringView showing what's under current
717*d8e2fb50SAxel Dörfler 		copyright = new BStringView(BRect(10, GetPreferredHeight(),
718*d8e2fb50SAxel Dörfler 			10, GetPreferredHeight()), "Copyright", current);
7199949213aSStephan Aßmus 		copyright->SetFont(be_plain_font);
7209949213aSStephan Aßmus 		copyright->SetFontSize( 9);
7219949213aSStephan Aßmus 		AddChild(copyright);
7229949213aSStephan Aßmus 
7239949213aSStephan Aßmus 		// If there was next line, move current there and put next line char back
7249949213aSStephan Aßmus 		if (temp) {
7259949213aSStephan Aßmus 			current = temp+1;
7269949213aSStephan Aßmus 			*temp = 0x0a;
7279949213aSStephan Aßmus 		} else
7289949213aSStephan Aßmus 		// If there was no next line char break loop
7299949213aSStephan Aßmus 			break;
7309949213aSStephan Aßmus 	}
7319949213aSStephan Aßmus 
7329949213aSStephan Aßmus 	ResizeToPreferred();
7339949213aSStephan Aßmus }
7349949213aSStephan Aßmus 
7359949213aSStephan Aßmus 
736*d8e2fb50SAxel Dörfler //	#pragma mark -
7379949213aSStephan Aßmus 
738*d8e2fb50SAxel Dörfler 
7399949213aSStephan Aßmus TranslatorView::TranslatorView(const char *name)
740*d8e2fb50SAxel Dörfler 	: SView(name),
741*d8e2fb50SAxel Dörfler 	fTabWidth(30),
742*d8e2fb50SAxel Dörfler 	fTabHeight(7 + (int32)be_plain_font->Size()),
743*d8e2fb50SAxel Dörfler 		// TODO: this apparently uses BFont::Size() as height in pixels!!!
744*d8e2fb50SAxel Dörfler 	fActiveChild(0)
7459949213aSStephan Aßmus {
7469949213aSStephan Aßmus 	// Set global var to true
747*d8e2fb50SAxel Dörfler 	gAreSettingsRunning = true;
7489949213aSStephan Aßmus 
7499949213aSStephan Aßmus 	// Without this strings are not correctly aliased
7509949213aSStephan Aßmus 	// THX to Jack Burton for info :)
7519949213aSStephan Aßmus 	SetLowColor( ViewColor());
7529949213aSStephan Aßmus 
753*d8e2fb50SAxel Dörfler 	// Load settings to global settings struct
754*d8e2fb50SAxel Dörfler 	LoadSettings(&fSettings);
7559949213aSStephan Aßmus 
7569949213aSStephan Aßmus 	// Add left and top margins
757*d8e2fb50SAxel Dörfler 	float top = fTabHeight+15;
7589949213aSStephan Aßmus 	float left = 0;
7599949213aSStephan Aßmus 
7609949213aSStephan Aßmus 	// This will remember longest string width
7619949213aSStephan Aßmus 	int32 nameWidth = 0;
7629949213aSStephan Aßmus 
763*d8e2fb50SAxel Dörfler 	SView *view = new TranslatorWriteView("Write", &fSettings, left, top);
7649949213aSStephan Aßmus 	AddChild(view);
765*d8e2fb50SAxel Dörfler 	nameWidth = (int32)StringWidth(view->Name());
7669949213aSStephan Aßmus 
767*d8e2fb50SAxel Dörfler 	view = new TranslatorReadView("Read", &fSettings, left, top);
7689949213aSStephan Aßmus 	AddChild(view);
7699949213aSStephan Aßmus 	if (nameWidth < StringWidth(view->Name()))
770*d8e2fb50SAxel Dörfler 		nameWidth = (int32)StringWidth(view->Name());
7719949213aSStephan Aßmus 
7729949213aSStephan Aßmus 	view = new TranslatorAboutView("About", left, top);
7739949213aSStephan Aßmus 	AddChild(view);
7749949213aSStephan Aßmus 	if (nameWidth < StringWidth(view->Name()))
775*d8e2fb50SAxel Dörfler 		nameWidth = (int32)StringWidth(view->Name());
7769949213aSStephan Aßmus 
777*d8e2fb50SAxel Dörfler 	fTabWidth += nameWidth;
778*d8e2fb50SAxel Dörfler 	if (fTabWidth * CountChildren() > GetPreferredWidth())
779*d8e2fb50SAxel Dörfler 		ResizePreferredBy((fTabWidth * CountChildren()) - GetPreferredWidth(), 0);
7809949213aSStephan Aßmus 
7819949213aSStephan Aßmus 	// Add right and bottom margins
7829949213aSStephan Aßmus 	ResizePreferredBy(10, 15);
7839949213aSStephan Aßmus 
7849949213aSStephan Aßmus 	ResizeToPreferred();
7859949213aSStephan Aßmus 
7869949213aSStephan Aßmus 	// Make TranslatorView resize itself with parent
7879949213aSStephan Aßmus 	SetFlags( Flags() | B_FOLLOW_ALL);
7889949213aSStephan Aßmus }
7899949213aSStephan Aßmus 
790*d8e2fb50SAxel Dörfler 
791*d8e2fb50SAxel Dörfler TranslatorView::~TranslatorView()
792*d8e2fb50SAxel Dörfler {
793*d8e2fb50SAxel Dörfler 	gAreSettingsRunning = false;
794*d8e2fb50SAxel Dörfler }
795*d8e2fb50SAxel Dörfler 
796*d8e2fb50SAxel Dörfler 
797*d8e2fb50SAxel Dörfler //!	Attached to window - resize parent to preferred
7989949213aSStephan Aßmus void
7999949213aSStephan Aßmus TranslatorView::AttachedToWindow()
8009949213aSStephan Aßmus {
8019949213aSStephan Aßmus 	// Hide all children except first one
802*d8e2fb50SAxel Dörfler 	BView *child;
8039949213aSStephan Aßmus 	int32 index = 1;
804*d8e2fb50SAxel Dörfler 	while ((child = ChildAt(index++)) != NULL)
8059949213aSStephan Aßmus 		child->Hide();
8069949213aSStephan Aßmus 
8079949213aSStephan Aßmus 	// Hack for DataTranslations which doesn't resize visible area to requested by view
8089949213aSStephan Aßmus 	// which makes some parts of bigger than usual translationviews out of visible area
8099949213aSStephan Aßmus 	// so if it was loaded to DataTranslations resize window if needed
8109949213aSStephan Aßmus 	BWindow *window = Window();
8119949213aSStephan Aßmus 	if (!strcmp(window->Name(), "DataTranslations")) {
8129949213aSStephan Aßmus 		BView *view = Parent();
8139949213aSStephan Aßmus 		if (view) {
8149949213aSStephan Aßmus 			BRect frame = view->Frame();
815*d8e2fb50SAxel Dörfler 			if (frame.Width() < GetPreferredWidth()
816*d8e2fb50SAxel Dörfler 				|| (frame.Height()-48) < GetPreferredHeight()) {
8179949213aSStephan Aßmus 				float x = ceil(GetPreferredWidth() - frame.Width());
8189949213aSStephan Aßmus 				float y = ceil(GetPreferredHeight() - (frame.Height()-48));
819*d8e2fb50SAxel Dörfler 				if (x < 0)
820*d8e2fb50SAxel Dörfler 					x = 0;
821*d8e2fb50SAxel Dörfler 				if (y < 0)
822*d8e2fb50SAxel Dörfler 					y = 0;
8239949213aSStephan Aßmus 
8249949213aSStephan Aßmus 				// DataTranslations has main view called "Background"
8259949213aSStephan Aßmus 				// change it's resizing mode so it will always resize with window
8269949213aSStephan Aßmus 				// also make sure view will be redrawed after resize
8279949213aSStephan Aßmus 				view = window->FindView("Background");
8289949213aSStephan Aßmus 				if (view) {
8299949213aSStephan Aßmus 					view->SetResizingMode(B_FOLLOW_ALL);
8309949213aSStephan Aßmus 					view->SetFlags(B_FULL_UPDATE_ON_RESIZE);
8319949213aSStephan Aßmus 				}
8329949213aSStephan Aßmus 
8339949213aSStephan Aßmus 				// The same with "Info..." button, except redrawing, which isn't needed
8349949213aSStephan Aßmus 				view = window->FindView("Info…");
8359949213aSStephan Aßmus 				if (view)
8369949213aSStephan Aßmus 					view->SetResizingMode(B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
8379949213aSStephan Aßmus 
8389949213aSStephan Aßmus 				window->ResizeBy(x, y);
8399949213aSStephan Aßmus 
8409949213aSStephan Aßmus 				// Let user resize window if resizing option is not already there...
8419949213aSStephan Aßmus 				uint32 flags = window->Flags();
8429949213aSStephan Aßmus 				if (flags & B_NOT_RESIZABLE) {
8439949213aSStephan Aßmus 					// ...but first prevent too small window (so "Info..." button will not look strange ;)
8449949213aSStephan Aßmus 					// max will be 800x600 which should be enough for now
8459949213aSStephan Aßmus 					window->SetSizeLimits(400, 800, 66, 600);
8469949213aSStephan Aßmus 
8479949213aSStephan Aßmus 					flags ^= B_NOT_RESIZABLE;
8489949213aSStephan Aßmus 					window->SetFlags(flags);
8499949213aSStephan Aßmus 				}
8509949213aSStephan Aßmus 			}
8519949213aSStephan Aßmus 		}
8529949213aSStephan Aßmus 	}
8539949213aSStephan Aßmus }
8549949213aSStephan Aßmus 
855*d8e2fb50SAxel Dörfler 
8569949213aSStephan Aßmus void
8579949213aSStephan Aßmus TranslatorView::Draw(BRect updateRect)
8589949213aSStephan Aßmus {
8599949213aSStephan Aßmus 	// This is needed because DataTranslations app hides children
8609949213aSStephan Aßmus 	// after user changes translator
861*d8e2fb50SAxel Dörfler 	if (ChildAt(fActiveChild)->IsHidden())
862*d8e2fb50SAxel Dörfler 		ChildAt(fActiveChild)->Show();
8639949213aSStephan Aßmus 
8649949213aSStephan Aßmus 	// Prepare colors used for drawing "tabs"
8659949213aSStephan Aßmus 	rgb_color dark_line_color = tint_color( ViewColor(), B_DARKEN_2_TINT);
8669949213aSStephan Aßmus 	rgb_color darkest_line_color = tint_color( ViewColor(), B_DARKEN_3_TINT);
8679949213aSStephan Aßmus 	rgb_color light_line_color = tint_color( ViewColor(), B_LIGHTEN_MAX_TINT);
8689949213aSStephan Aßmus 	rgb_color text_color = ui_color(B_MENU_ITEM_TEXT_COLOR);
8699949213aSStephan Aßmus 
8709949213aSStephan Aßmus 	// Clear
8719949213aSStephan Aßmus 	SetHighColor( ViewColor());
872*d8e2fb50SAxel Dörfler 	FillRect(BRect(0, 0, Frame().right, fTabHeight));
8739949213aSStephan Aßmus 
874*d8e2fb50SAxel Dörfler 	int32 index = 0;
875*d8e2fb50SAxel Dörfler 	float left = 0;
876*d8e2fb50SAxel Dörfler 	BView *child;
877*d8e2fb50SAxel Dörfler 	while ((child = ChildAt(index)) != NULL) {
878*d8e2fb50SAxel Dörfler 		// TODO: this apparently uses BFont::Size() as height in pixels!!!
8799949213aSStephan Aßmus 		// Draw outline
8809949213aSStephan Aßmus 		SetHighColor(dark_line_color);
881*d8e2fb50SAxel Dörfler 		StrokeLine(BPoint(left, 10), BPoint(left, fTabHeight));
8829949213aSStephan Aßmus 		StrokeArc(BPoint(left + 10, 10), 10, 10, 90, 90);
883*d8e2fb50SAxel Dörfler 		StrokeLine(BPoint(left + 10, 0), BPoint(left + fTabWidth - 10, 0));
884*d8e2fb50SAxel Dörfler 		StrokeArc(BPoint(left + fTabWidth - 10, 10), 9, 10, 0, 90);
885*d8e2fb50SAxel Dörfler 		StrokeLine(BPoint(left + fTabWidth - 1, 10),
886*d8e2fb50SAxel Dörfler 			BPoint(left + fTabWidth - 1, fTabHeight));
8879949213aSStephan Aßmus 		// Draw "shadow" on the right side
8889949213aSStephan Aßmus 		SetHighColor(darkest_line_color);
889*d8e2fb50SAxel Dörfler 		StrokeArc( BPoint(left+fTabWidth-10, 10), 10, 10, 0, 50);
890*d8e2fb50SAxel Dörfler 		StrokeLine( BPoint(left+fTabWidth, 10), BPoint(left + fTabWidth, fTabHeight - 1));
8919949213aSStephan Aßmus 		// Draw label
8929949213aSStephan Aßmus 		SetHighColor(text_color);
893*d8e2fb50SAxel Dörfler 		DrawString(child->Name(), BPoint(left + (fTabWidth / 2)
894*d8e2fb50SAxel Dörfler 			- (StringWidth(child->Name()) / 2), 3 + be_plain_font->Size()));
895*d8e2fb50SAxel Dörfler 
8969949213aSStephan Aßmus 		// Draw "light" on left and top side
8979949213aSStephan Aßmus 		SetHighColor(light_line_color);
8989949213aSStephan Aßmus 		StrokeArc(BPoint(left + 10, 10), 9, 9, 90, 90);
899*d8e2fb50SAxel Dörfler 		StrokeLine(BPoint(left + 1, 10), BPoint(left + 1, fTabHeight));
900*d8e2fb50SAxel Dörfler 		StrokeLine(BPoint(left + 10, 1), BPoint(left + fTabWidth - 8, 1));
9019949213aSStephan Aßmus 		// Draw bottom edge
902*d8e2fb50SAxel Dörfler 		if (fActiveChild != index)
903*d8e2fb50SAxel Dörfler 			StrokeLine(BPoint(left - 2, fTabHeight), BPoint(left + fTabWidth, fTabHeight));
9049949213aSStephan Aßmus 		else
905*d8e2fb50SAxel Dörfler 			StrokeLine(BPoint(left - 2, fTabHeight), BPoint(left + 1, fTabHeight));
9069949213aSStephan Aßmus 
907*d8e2fb50SAxel Dörfler 		left += fTabWidth + 2;
9089949213aSStephan Aßmus 		index++;
9099949213aSStephan Aßmus 	}
910*d8e2fb50SAxel Dörfler 
9119949213aSStephan Aßmus 	// Draw bottom edge to the rigth side
912*d8e2fb50SAxel Dörfler 	StrokeLine(BPoint(left - 2, fTabHeight), BPoint(Bounds().Width(), fTabHeight));
9139949213aSStephan Aßmus }
9149949213aSStephan Aßmus 
915*d8e2fb50SAxel Dörfler 
916*d8e2fb50SAxel Dörfler //!	MouseDown, check if on tab, if so change tab if needed
9179949213aSStephan Aßmus void
9189949213aSStephan Aßmus TranslatorView::MouseDown(BPoint where)
9199949213aSStephan Aßmus {
9209949213aSStephan Aßmus 	// If user clicked on tabs part of view
921*d8e2fb50SAxel Dörfler 	if (where.y <= fTabHeight) {
9229949213aSStephan Aßmus 		// If there is a tab (not whole width is occupied by tabs)
923*d8e2fb50SAxel Dörfler 		if (where.x < fTabWidth*CountChildren()) {
9249949213aSStephan Aßmus 			// Which tab was selected?
925*d8e2fb50SAxel Dörfler 			int32 index = int32(where.x / fTabWidth);
926*d8e2fb50SAxel Dörfler 			if (fActiveChild != index) {
9279949213aSStephan Aßmus 				// Hide current visible child
928*d8e2fb50SAxel Dörfler 				ChildAt(fActiveChild)->Hide();
9299949213aSStephan Aßmus 				// This loop is needed because it looks like in DataTranslations
9309949213aSStephan Aßmus 				// view gets hidden more than one time when user changes translator
9319949213aSStephan Aßmus 				while (ChildAt(index)->IsHidden())
9329949213aSStephan Aßmus 					ChildAt(index)->Show();
9339949213aSStephan Aßmus 				// Remember which one is currently visible
934*d8e2fb50SAxel Dörfler 				fActiveChild = index;
9359949213aSStephan Aßmus 				// Redraw
9369949213aSStephan Aßmus 				Draw( Frame());
9379949213aSStephan Aßmus 			}
9389949213aSStephan Aßmus 		}
9399949213aSStephan Aßmus 	}
940*d8e2fb50SAxel Dörfler }
9419949213aSStephan Aßmus 
9429949213aSStephan Aßmus 
943*d8e2fb50SAxel Dörfler //	#pragma mark -
9449949213aSStephan Aßmus 
945*d8e2fb50SAxel Dörfler 
946*d8e2fb50SAxel Dörfler TranslatorWindow::TranslatorWindow(bool quitOnClose)
9479949213aSStephan Aßmus :	BWindow(BRect(100, 100, 100, 100), "JPEG Settings", B_TITLED_WINDOW, B_NOT_ZOOMABLE)
9489949213aSStephan Aßmus {
9499949213aSStephan Aßmus 	BRect extent(0, 0, 0, 0);
9509949213aSStephan Aßmus 	BView *config = NULL;
9519949213aSStephan Aßmus 	MakeConfig(NULL, &config, &extent);
9529949213aSStephan Aßmus 
9539949213aSStephan Aßmus 	AddChild(config);
9549949213aSStephan Aßmus 	ResizeTo(extent.Width(), extent.Height());
9559949213aSStephan Aßmus 
9569949213aSStephan Aßmus 	// Make application quit after this window close
957*d8e2fb50SAxel Dörfler 	if (quitOnClose)
9589949213aSStephan Aßmus 		SetFlags(Flags() | B_QUIT_ON_WINDOW_CLOSE);
9599949213aSStephan Aßmus }
9609949213aSStephan Aßmus 
9619949213aSStephan Aßmus 
962*d8e2fb50SAxel Dörfler //	#pragma mark - Translator Add-On
9639949213aSStephan Aßmus 
9649949213aSStephan Aßmus 
9659949213aSStephan Aßmus 
966*d8e2fb50SAxel Dörfler /*! Hook to create and return our configuration view */
9679949213aSStephan Aßmus status_t
9689949213aSStephan Aßmus MakeConfig(BMessage *ioExtension, BView **outView, BRect *outExtent)
9699949213aSStephan Aßmus {
9709949213aSStephan Aßmus 	*outView = new TranslatorView("TranslatorView");
9719949213aSStephan Aßmus 	*outExtent = (*outView)->Frame();
9729949213aSStephan Aßmus 	return B_OK;
9739949213aSStephan Aßmus }
9749949213aSStephan Aßmus 
975*d8e2fb50SAxel Dörfler /*! Determine whether or not we can handle this data */
9769949213aSStephan Aßmus status_t
977*d8e2fb50SAxel Dörfler Identify(BPositionIO *inSource, const translation_format *inFormat,
978*d8e2fb50SAxel Dörfler 	BMessage *ioExtension, translator_info *outInfo, uint32 outType)
9799949213aSStephan Aßmus {
9809949213aSStephan Aßmus 
981*d8e2fb50SAxel Dörfler 	if (outType != 0 && outType != B_TRANSLATOR_BITMAP && outType != JPEG_FORMAT)
9829949213aSStephan Aßmus 		return B_NO_TRANSLATOR;
9839949213aSStephan Aßmus 
9849949213aSStephan Aßmus 	// !!! You might need to make this buffer bigger to test for your native format
9859949213aSStephan Aßmus 	off_t position = inSource->Position();
9869949213aSStephan Aßmus 	char header[sizeof(TranslatorBitmap)];
9879949213aSStephan Aßmus 	status_t err = inSource->Read(header, sizeof(TranslatorBitmap));
9889949213aSStephan Aßmus 	inSource->Seek(position, SEEK_SET);
989*d8e2fb50SAxel Dörfler 	if (err < B_OK)
990*d8e2fb50SAxel Dörfler 		return err;
9919949213aSStephan Aßmus 
9929949213aSStephan Aßmus 	if (B_BENDIAN_TO_HOST_INT32(((TranslatorBitmap *)header)->magic) == B_TRANSLATOR_BITMAP) {
9939949213aSStephan Aßmus 		outInfo->type = inputFormats[1].type;
9949949213aSStephan Aßmus 		outInfo->translator = 0;
9959949213aSStephan Aßmus 		outInfo->group = inputFormats[1].group;
9969949213aSStephan Aßmus 		outInfo->quality = inputFormats[1].quality;
9979949213aSStephan Aßmus 		outInfo->capability = inputFormats[1].capability;
9989949213aSStephan Aßmus 		strcpy(outInfo->name, inputFormats[1].name);
9999949213aSStephan Aßmus 		strcpy(outInfo->MIME, inputFormats[1].MIME);
10009949213aSStephan Aßmus 	} else {
10019949213aSStephan Aßmus 		// First 3 bytes in jpg files are always the same from what i've seen so far
10029949213aSStephan Aßmus 		// check them
10039949213aSStephan Aßmus 		if (header[0] == (char)0xff && header[1] == (char)0xd8 && header[2] == (char)0xff) {
10049949213aSStephan Aßmus 		/* this below would be safer but it slows down whole thing
10059949213aSStephan Aßmus 
10069949213aSStephan Aßmus 			struct jpeg_decompress_struct cinfo;
10079949213aSStephan Aßmus 			struct jpeg_error_mgr jerr;
10089949213aSStephan Aßmus 			cinfo.err = jpeg_std_error(&jerr);
10099949213aSStephan Aßmus 			jpeg_create_decompress(&cinfo);
10109949213aSStephan Aßmus 			be_jpeg_stdio_src(&cinfo, inSource);
10119949213aSStephan Aßmus 			// now try to read header
10129949213aSStephan Aßmus 			// it can't be read before checking first 3 bytes
10139949213aSStephan Aßmus 			// because it will hang up if there is no header (not jpeg file)
10149949213aSStephan Aßmus 			int result = jpeg_read_header(&cinfo, FALSE);
10159949213aSStephan Aßmus 			jpeg_destroy_decompress(&cinfo);
10169949213aSStephan Aßmus 			if (result == JPEG_HEADER_OK) {
10179949213aSStephan Aßmus 		*/		outInfo->type = inputFormats[0].type;
10189949213aSStephan Aßmus 				outInfo->translator = 0;
10199949213aSStephan Aßmus 				outInfo->group = inputFormats[0].group;
10209949213aSStephan Aßmus 				outInfo->quality = inputFormats[0].quality;
10219949213aSStephan Aßmus 				outInfo->capability = inputFormats[0].capability;
10229949213aSStephan Aßmus 				strcpy(outInfo->name, inputFormats[0].name);
10239949213aSStephan Aßmus 				strcpy(outInfo->MIME, inputFormats[0].MIME);
10249949213aSStephan Aßmus 				return B_OK;
10259949213aSStephan Aßmus 		/*	} else
10269949213aSStephan Aßmus 				return B_NO_TRANSLATOR;
10279949213aSStephan Aßmus 		*/
10289949213aSStephan Aßmus 		} else
10299949213aSStephan Aßmus 			return B_NO_TRANSLATOR;
10309949213aSStephan Aßmus 	}
10319949213aSStephan Aßmus 
10329949213aSStephan Aßmus 	return B_OK;
10339949213aSStephan Aßmus }
10349949213aSStephan Aßmus 
1035*d8e2fb50SAxel Dörfler /*!	Arguably the most important method in the add-on */
10369949213aSStephan Aßmus status_t
1037*d8e2fb50SAxel Dörfler Translate(BPositionIO *inSource, const translator_info *inInfo,
1038*d8e2fb50SAxel Dörfler 	BMessage *ioExtension, uint32 outType, BPositionIO *outDestination)
10399949213aSStephan Aßmus {
10409949213aSStephan Aßmus 	// If no specific type was requested, convert to the interchange format
10419949213aSStephan Aßmus 	if (outType == 0) outType = B_TRANSLATOR_BITMAP;
10429949213aSStephan Aßmus 
10439949213aSStephan Aßmus 	// What action to take, based on the findings of Identify()
10449949213aSStephan Aßmus 	if (outType == inInfo->type) {
10459949213aSStephan Aßmus 		return Copy(inSource, outDestination);
10469949213aSStephan Aßmus 	} else if (inInfo->type == B_TRANSLATOR_BITMAP && outType == JPEG_FORMAT) {
10479949213aSStephan Aßmus 		return Compress(inSource, outDestination);
10489949213aSStephan Aßmus 	} else if (inInfo->type == JPEG_FORMAT && outType == B_TRANSLATOR_BITMAP) {
10499949213aSStephan Aßmus 		return Decompress(inSource, outDestination);
10509949213aSStephan Aßmus 	}
10519949213aSStephan Aßmus 
10529949213aSStephan Aßmus 	return B_NO_TRANSLATOR;
10539949213aSStephan Aßmus }
10549949213aSStephan Aßmus 
1055*d8e2fb50SAxel Dörfler /*!	The user has requested the same format for input and output, so just copy */
10569949213aSStephan Aßmus status_t
10579949213aSStephan Aßmus Copy(BPositionIO *in, BPositionIO *out)
10589949213aSStephan Aßmus {
10599949213aSStephan Aßmus 	int block_size = 65536;
10609949213aSStephan Aßmus 	void *buffer = malloc(block_size);
10619949213aSStephan Aßmus 	char temp[1024];
10629949213aSStephan Aßmus 	if (buffer == NULL) {
10639949213aSStephan Aßmus 		buffer = temp;
10649949213aSStephan Aßmus 		block_size = 1024;
10659949213aSStephan Aßmus 	}
10669949213aSStephan Aßmus 	status_t err = B_OK;
10679949213aSStephan Aßmus 
10689949213aSStephan Aßmus 	// Read until end of file or error
10699949213aSStephan Aßmus 	while (1) {
10709949213aSStephan Aßmus 		ssize_t to_read = block_size;
10719949213aSStephan Aßmus 		err = in->Read(buffer, to_read);
10729949213aSStephan Aßmus 		// Explicit check for EOF
10739949213aSStephan Aßmus 		if (err == -1) {
10749949213aSStephan Aßmus 			if (buffer != temp) free(buffer);
10759949213aSStephan Aßmus 			return B_OK;
10769949213aSStephan Aßmus 		}
10779949213aSStephan Aßmus 		if (err <= B_OK) break;
10789949213aSStephan Aßmus 		to_read = err;
10799949213aSStephan Aßmus 		err = out->Write(buffer, to_read);
10809949213aSStephan Aßmus 		if (err != to_read) if (err >= 0) err = B_DEVICE_FULL;
10819949213aSStephan Aßmus 		if (err < B_OK) break;
10829949213aSStephan Aßmus 	}
10839949213aSStephan Aßmus 
10849949213aSStephan Aßmus 	if (buffer != temp) free(buffer);
10859949213aSStephan Aßmus 	return (err >= 0) ? B_OK : err;
10869949213aSStephan Aßmus }
10879949213aSStephan Aßmus 
1088*d8e2fb50SAxel Dörfler 
1089*d8e2fb50SAxel Dörfler /*!	Encode into the native format */
10909949213aSStephan Aßmus status_t
10919949213aSStephan Aßmus Compress(BPositionIO *in, BPositionIO *out)
10929949213aSStephan Aßmus {
10939949213aSStephan Aßmus 	// Load Settings
1094*d8e2fb50SAxel Dörfler 	jpeg_settings settings;
1095*d8e2fb50SAxel Dörfler 	LoadSettings(&settings);
10969949213aSStephan Aßmus 
10979949213aSStephan Aßmus 	// Read info about bitmap
10989949213aSStephan Aßmus 	TranslatorBitmap header;
10999949213aSStephan Aßmus 	status_t err = in->Read(&header, sizeof(TranslatorBitmap));
1100*d8e2fb50SAxel Dörfler 	if (err < B_OK)
1101*d8e2fb50SAxel Dörfler 		return err;
1102*d8e2fb50SAxel Dörfler 	else if (err < (int)sizeof(TranslatorBitmap))
1103*d8e2fb50SAxel Dörfler 		return B_ERROR;
11049949213aSStephan Aßmus 
11059949213aSStephan Aßmus 	// Grab dimension, color space, and size information from the stream
11069949213aSStephan Aßmus 	BRect bounds;
11079949213aSStephan Aßmus 	bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left);
11089949213aSStephan Aßmus 	bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top);
11099949213aSStephan Aßmus 	bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right);
11109949213aSStephan Aßmus 	bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom);
11119949213aSStephan Aßmus 
11129949213aSStephan Aßmus 	int32 in_row_bytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes);
11139949213aSStephan Aßmus 
11149949213aSStephan Aßmus 	int width = bounds.IntegerWidth() + 1;
11159949213aSStephan Aßmus 	int height = bounds.IntegerHeight() + 1;
11169949213aSStephan Aßmus 
11179949213aSStephan Aßmus 	// Function pointer to convert function
11189949213aSStephan Aßmus 	// It will point to proper function if needed
11199949213aSStephan Aßmus 	void (*converter)(uchar *inscanline, uchar *outscanline, int inrow_bytes) = NULL;
11209949213aSStephan Aßmus 
11219949213aSStephan Aßmus 	// Default color info
11229949213aSStephan Aßmus 	J_COLOR_SPACE jpg_color_space = JCS_RGB;
11239949213aSStephan Aßmus 	int jpg_input_components = 3;
11249949213aSStephan Aßmus 	int32 out_row_bytes;
11259949213aSStephan Aßmus 	int padding = 0;
11269949213aSStephan Aßmus 
1127*d8e2fb50SAxel Dörfler 	switch ((color_space)B_BENDIAN_TO_HOST_INT32(header.colors)) {
11289949213aSStephan Aßmus 		case B_CMAP8:
11299949213aSStephan Aßmus 			converter = convert_from_cmap8_to_24;
11309949213aSStephan Aßmus 			padding = in_row_bytes - width;
11319949213aSStephan Aßmus 			break;
1132*d8e2fb50SAxel Dörfler 
11339949213aSStephan Aßmus 		case B_GRAY1:
1134*d8e2fb50SAxel Dörfler 			if (settings.B_GRAY1_as_B_RGB24) {
11359949213aSStephan Aßmus 				converter = convert_from_gray1_to_24;
11369949213aSStephan Aßmus 			} else {
11379949213aSStephan Aßmus 				jpg_input_components = 1;
11389949213aSStephan Aßmus 				jpg_color_space = JCS_GRAYSCALE;
11399949213aSStephan Aßmus 				converter = convert_from_gray1_to_gray8;
11409949213aSStephan Aßmus 			}
11419949213aSStephan Aßmus 			padding = in_row_bytes - (width/8);
11429949213aSStephan Aßmus 			break;
1143*d8e2fb50SAxel Dörfler 
11449949213aSStephan Aßmus 		case B_GRAY8:
11459949213aSStephan Aßmus 			jpg_input_components = 1;
11469949213aSStephan Aßmus 			jpg_color_space = JCS_GRAYSCALE;
11479949213aSStephan Aßmus 			padding = in_row_bytes - width;
11489949213aSStephan Aßmus 			break;
1149*d8e2fb50SAxel Dörfler 
11509949213aSStephan Aßmus 		case B_RGB15:
11519949213aSStephan Aßmus 		case B_RGBA15:
11529949213aSStephan Aßmus 			converter = convert_from_15_to_24;
11539949213aSStephan Aßmus 			padding = in_row_bytes - (width * 2);
11549949213aSStephan Aßmus 			break;
1155*d8e2fb50SAxel Dörfler 
11569949213aSStephan Aßmus 		case B_RGB15_BIG:
11579949213aSStephan Aßmus 		case B_RGBA15_BIG:
11589949213aSStephan Aßmus 			converter = convert_from_15b_to_24;
11599949213aSStephan Aßmus 			padding = in_row_bytes - (width * 2);
11609949213aSStephan Aßmus 			break;
1161*d8e2fb50SAxel Dörfler 
11629949213aSStephan Aßmus 		case B_RGB16:
11639949213aSStephan Aßmus 			converter = convert_from_16_to_24;
11649949213aSStephan Aßmus 			padding = in_row_bytes - (width * 2);
11659949213aSStephan Aßmus 			break;
1166*d8e2fb50SAxel Dörfler 
11679949213aSStephan Aßmus 		case B_RGB16_BIG:
11689949213aSStephan Aßmus 			converter = convert_from_16b_to_24;
11699949213aSStephan Aßmus 			padding = in_row_bytes - (width * 2);
11709949213aSStephan Aßmus 			break;
1171*d8e2fb50SAxel Dörfler 
11729949213aSStephan Aßmus 		case B_RGB24:
11739949213aSStephan Aßmus 			converter = convert_from_24_to_24;
11749949213aSStephan Aßmus 			padding = in_row_bytes - (width * 3);
11759949213aSStephan Aßmus 			break;
1176*d8e2fb50SAxel Dörfler 
11779949213aSStephan Aßmus 		case B_RGB24_BIG:
11789949213aSStephan Aßmus 			padding = in_row_bytes - (width * 3);
11799949213aSStephan Aßmus 			break;
1180*d8e2fb50SAxel Dörfler 
11819949213aSStephan Aßmus 		case B_RGB32:
11829949213aSStephan Aßmus 		case B_RGBA32:
11839949213aSStephan Aßmus 			converter = convert_from_32_to_24;
11849949213aSStephan Aßmus 			padding = in_row_bytes - (width * 4);
11859949213aSStephan Aßmus 			break;
1186*d8e2fb50SAxel Dörfler 
11879949213aSStephan Aßmus 		case B_RGB32_BIG:
11889949213aSStephan Aßmus 		case B_RGBA32_BIG:
11899949213aSStephan Aßmus 			converter = convert_from_32b_to_24;
11909949213aSStephan Aßmus 			padding = in_row_bytes - (width * 4);
11919949213aSStephan Aßmus 			break;
1192*d8e2fb50SAxel Dörfler 
11939949213aSStephan Aßmus 		case B_CMYK32:
11949949213aSStephan Aßmus 			jpg_color_space = JCS_CMYK;
11959949213aSStephan Aßmus 			jpg_input_components = 4;
11969949213aSStephan Aßmus 			padding = in_row_bytes - (width * 4);
11979949213aSStephan Aßmus 			break;
1198*d8e2fb50SAxel Dörfler 
11999949213aSStephan Aßmus 		default:
12009949213aSStephan Aßmus 			fprintf(stderr, "Wrong type: Color space not implemented.\n");
12019949213aSStephan Aßmus 			return B_ERROR;
12029949213aSStephan Aßmus 	}
12039949213aSStephan Aßmus 	out_row_bytes = jpg_input_components * width;
12049949213aSStephan Aßmus 
12059949213aSStephan Aßmus 	// Set basic things needed for jpeg writing
12069949213aSStephan Aßmus 	struct jpeg_compress_struct cinfo;
12079949213aSStephan Aßmus 	struct jpeg_error_mgr jerr;
1208*d8e2fb50SAxel Dörfler 	cinfo.err = be_jpeg_std_error(&jerr, &settings);
12099949213aSStephan Aßmus 	jpeg_create_compress(&cinfo);
12109949213aSStephan Aßmus 	be_jpeg_stdio_dest(&cinfo, out);
12119949213aSStephan Aßmus 
12129949213aSStephan Aßmus 	// Set basic values
12139949213aSStephan Aßmus 	cinfo.image_width = width;
12149949213aSStephan Aßmus 	cinfo.image_height = height;
12159949213aSStephan Aßmus 	cinfo.input_components = jpg_input_components;
12169949213aSStephan Aßmus 	cinfo.in_color_space = jpg_color_space;
12179949213aSStephan Aßmus 	jpeg_set_defaults(&cinfo);
12189949213aSStephan Aßmus 
12199949213aSStephan Aßmus 	// Set better accuracy
12209949213aSStephan Aßmus 	cinfo.dct_method = JDCT_ISLOW;
12219949213aSStephan Aßmus 
12229949213aSStephan Aßmus 	// This is needed to prevent some colors loss
12239949213aSStephan Aßmus 	// With it generated jpegs are as good as from Fireworks (at last! :D)
1224*d8e2fb50SAxel Dörfler 	if (settings.OptimizeColors) {
12259949213aSStephan Aßmus 		int index = 0;
12269949213aSStephan Aßmus 		while (index < cinfo.num_components) {
12279949213aSStephan Aßmus 			cinfo.comp_info[index].h_samp_factor = 1;
12289949213aSStephan Aßmus 			cinfo.comp_info[index].v_samp_factor = 1;
12299949213aSStephan Aßmus 			// This will make file smaller, but with worse quality more or less
12309949213aSStephan Aßmus 			// like with 93%-94% (but it's subjective opinion) on tested images
12319949213aSStephan Aßmus 			// but with smaller size (between 92% and 93% on tested images)
1232*d8e2fb50SAxel Dörfler 			if (settings.SmallerFile)
12339949213aSStephan Aßmus 				cinfo.comp_info[index].quant_tbl_no = 1;
12349949213aSStephan Aßmus 			// This will make bigger file, but also better quality ;]
12359949213aSStephan Aßmus 			// from my tests it seems like useless - better quality with smaller
12369949213aSStephan Aßmus 			// can be acheived without this
12379949213aSStephan Aßmus //			cinfo.comp_info[index].dc_tbl_no = 1;
12389949213aSStephan Aßmus //			cinfo.comp_info[index].ac_tbl_no = 1;
12399949213aSStephan Aßmus 			index++;
12409949213aSStephan Aßmus 		}
12419949213aSStephan Aßmus 	}
12429949213aSStephan Aßmus 
12439949213aSStephan Aßmus 	// Set quality
1244*d8e2fb50SAxel Dörfler 	jpeg_set_quality(&cinfo, settings.Quality, true);
12459949213aSStephan Aßmus 
12469949213aSStephan Aßmus 	// Set progressive compression if needed
12479949213aSStephan Aßmus 	// if not, turn on optimizing in libjpeg
1248*d8e2fb50SAxel Dörfler 	if (settings.Progressive)
12499949213aSStephan Aßmus 		jpeg_simple_progression(&cinfo);
12509949213aSStephan Aßmus 	else
12519949213aSStephan Aßmus 		cinfo.optimize_coding = TRUE;
12529949213aSStephan Aßmus 
12539949213aSStephan Aßmus 	// Set smoothing (effect like Blur)
1254*d8e2fb50SAxel Dörfler 	cinfo.smoothing_factor = settings.Smoothing;
12559949213aSStephan Aßmus 
12569949213aSStephan Aßmus 	// Initialize compression
12579949213aSStephan Aßmus 	jpeg_start_compress(&cinfo, TRUE);
12589949213aSStephan Aßmus 
12599949213aSStephan Aßmus 	// Declare scanlines
12609949213aSStephan Aßmus 	JSAMPROW in_scanline = NULL;
12619949213aSStephan Aßmus 	JSAMPROW out_scanline = NULL;
12629949213aSStephan Aßmus 	JSAMPROW writeline;	// Pointer to in_scanline (default) or out_scanline (if there will be conversion)
12639949213aSStephan Aßmus 
12649949213aSStephan Aßmus 	// Allocate scanline
12659949213aSStephan Aßmus 	// Use libjpeg memory allocation functions, so in case of error it will free them itself
1266*d8e2fb50SAxel Dörfler 	in_scanline = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo,
1267*d8e2fb50SAxel Dörfler 		JPOOL_PERMANENT, in_row_bytes);
12689949213aSStephan Aßmus 
12699949213aSStephan Aßmus 	// We need 2nd scanline storage ony for conversion
12709949213aSStephan Aßmus 	if (converter != NULL) {
12719949213aSStephan Aßmus 		// There will be conversion, allocate second scanline...
12729949213aSStephan Aßmus 		// Use libjpeg memory allocation functions, so in case of error it will free them itself
1273*d8e2fb50SAxel Dörfler 	    out_scanline = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo,
1274*d8e2fb50SAxel Dörfler 	    	JPOOL_PERMANENT, out_row_bytes);
12759949213aSStephan Aßmus 		// ... and make it the one to write to file
12769949213aSStephan Aßmus 		writeline = out_scanline;
12779949213aSStephan Aßmus 	} else
12789949213aSStephan Aßmus 		writeline = in_scanline;
12799949213aSStephan Aßmus 
12809949213aSStephan Aßmus 	while (cinfo.next_scanline < cinfo.image_height) {
12819949213aSStephan Aßmus 		// Read scanline
12829949213aSStephan Aßmus 		err = in->Read(in_scanline, in_row_bytes);
12839949213aSStephan Aßmus 		if (err < in_row_bytes)
1284*d8e2fb50SAxel Dörfler 			return err < B_OK ? Error((j_common_ptr)&cinfo, err)
1285*d8e2fb50SAxel Dörfler 				: Error((j_common_ptr)&cinfo, B_ERROR);
12869949213aSStephan Aßmus 
12879949213aSStephan Aßmus 		// Convert if needed
12889949213aSStephan Aßmus 		if (converter != NULL)
12899949213aSStephan Aßmus 			converter(in_scanline, out_scanline, in_row_bytes-padding);
12909949213aSStephan Aßmus 
12919949213aSStephan Aßmus 		// Write scanline
12929949213aSStephan Aßmus 	   	jpeg_write_scanlines(&cinfo, &writeline, 1);
12939949213aSStephan Aßmus 	}
12949949213aSStephan Aßmus 
12959949213aSStephan Aßmus 	jpeg_finish_compress(&cinfo);
12969949213aSStephan Aßmus 	jpeg_destroy_compress(&cinfo);
12979949213aSStephan Aßmus 	return B_OK;
12989949213aSStephan Aßmus }
12999949213aSStephan Aßmus 
1300*d8e2fb50SAxel Dörfler 
1301*d8e2fb50SAxel Dörfler /*!	Decode the native format */
13029949213aSStephan Aßmus status_t
13039949213aSStephan Aßmus Decompress(BPositionIO *in, BPositionIO *out)
13049949213aSStephan Aßmus {
13059949213aSStephan Aßmus 	// Load Settings
1306*d8e2fb50SAxel Dörfler 	jpeg_settings settings;
1307*d8e2fb50SAxel Dörfler 	LoadSettings(&settings);
13089949213aSStephan Aßmus 
13099949213aSStephan Aßmus 	// Set basic things needed for jpeg reading
13109949213aSStephan Aßmus 	struct jpeg_decompress_struct cinfo;
13119949213aSStephan Aßmus 	struct jpeg_error_mgr jerr;
1312*d8e2fb50SAxel Dörfler 	cinfo.err = be_jpeg_std_error(&jerr, &settings);
13139949213aSStephan Aßmus 	jpeg_create_decompress(&cinfo);
13149949213aSStephan Aßmus 	be_jpeg_stdio_src(&cinfo, in);
13159949213aSStephan Aßmus 
13169949213aSStephan Aßmus 	// Read info about image
13179949213aSStephan Aßmus 	jpeg_read_header(&cinfo, TRUE);
13189949213aSStephan Aßmus 
13199949213aSStephan Aßmus 	// Default color info
13209949213aSStephan Aßmus 	color_space out_color_space = B_RGB32;
13219949213aSStephan Aßmus 	int out_color_components = 4;
13229949213aSStephan Aßmus 
13239949213aSStephan Aßmus 	// Function pointer to convert function
13249949213aSStephan Aßmus 	// It will point to proper function if needed
13259949213aSStephan Aßmus 	void (*converter)(uchar *inscanline, uchar *outscanline, int inrow_bytes) = convert_from_24_to_32;
13269949213aSStephan Aßmus 
13279949213aSStephan Aßmus 	// If color space isn't rgb
13289949213aSStephan Aßmus 	if (cinfo.out_color_space != JCS_RGB) {
1329*d8e2fb50SAxel Dörfler 		switch (cinfo.out_color_space) {
13309949213aSStephan Aßmus 			case JCS_UNKNOWN:		/* error/unspecified */
13319949213aSStephan Aßmus 				fprintf(stderr, "From Type: Jpeg uses unknown color type\n");
13329949213aSStephan Aßmus 				break;
13339949213aSStephan Aßmus 			case JCS_GRAYSCALE:		/* monochrome */
13349949213aSStephan Aßmus 				// Check if user wants to read only as RGB32 or not
1335*d8e2fb50SAxel Dörfler 				if (!settings.Always_B_RGB32) {
13369949213aSStephan Aßmus 					// Grayscale
13379949213aSStephan Aßmus 					out_color_space = B_GRAY8;
13389949213aSStephan Aßmus 					out_color_components = 1;
13399949213aSStephan Aßmus 					converter = NULL;
13409949213aSStephan Aßmus 				} else {
13419949213aSStephan Aßmus 					// RGB
13429949213aSStephan Aßmus 					cinfo.out_color_space = JCS_RGB;
13439949213aSStephan Aßmus 					cinfo.output_components = 3;
13449949213aSStephan Aßmus 					converter = convert_from_24_to_32;
13459949213aSStephan Aßmus 				}
13469949213aSStephan Aßmus 				break;
13479949213aSStephan Aßmus 			case JCS_YCbCr:		/* Y/Cb/Cr (also known as YUV) */
13489949213aSStephan Aßmus 				cinfo.out_color_space = JCS_RGB;
13499949213aSStephan Aßmus 				converter = convert_from_24_to_32;
13509949213aSStephan Aßmus 				break;
13519949213aSStephan Aßmus 			case JCS_YCCK:		/* Y/Cb/Cr/K */
13529949213aSStephan Aßmus 				// Let libjpeg convert it to CMYK
13539949213aSStephan Aßmus 				cinfo.out_color_space = JCS_CMYK;
13549949213aSStephan Aßmus 				// Fall through to CMYK since we need the same settings
13559949213aSStephan Aßmus 			case JCS_CMYK:		/* C/M/Y/K */
13569949213aSStephan Aßmus 				// Use proper converter
1357*d8e2fb50SAxel Dörfler 				if (settings.PhotoshopCMYK)
13589949213aSStephan Aßmus 					converter = convert_from_CMYK_to_32_photoshop;
13599949213aSStephan Aßmus 				else
13609949213aSStephan Aßmus 					converter = convert_from_CMYK_to_32;
13619949213aSStephan Aßmus 				break;
13629949213aSStephan Aßmus 			default:
13639949213aSStephan Aßmus 				fprintf(stderr, "From Type: Jpeg uses hmm... i don't know really :(\n");
13649949213aSStephan Aßmus 				break;
13659949213aSStephan Aßmus 		}
13669949213aSStephan Aßmus 	}
13679949213aSStephan Aßmus 
13689949213aSStephan Aßmus 	// Initialize decompression
13699949213aSStephan Aßmus 	jpeg_start_decompress(&cinfo);
13709949213aSStephan Aßmus 
13719949213aSStephan Aßmus 	// !!! Initialize this bounds rect to the size of your image
13729949213aSStephan Aßmus 	BRect bounds( 0, 0, cinfo.output_width-1, cinfo.output_height-1);
13739949213aSStephan Aßmus 
13749949213aSStephan Aßmus 	// Bytes count in one line of image (scanline)
13759949213aSStephan Aßmus 	int64 row_bytes = cinfo.output_width * out_color_components;
13769949213aSStephan Aßmus 
13779949213aSStephan Aßmus 	// Fill out the B_TRANSLATOR_BITMAP's header
13789949213aSStephan Aßmus 	TranslatorBitmap header;
13799949213aSStephan Aßmus 	header.magic = B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP);
13809949213aSStephan Aßmus 	header.bounds.left = B_HOST_TO_BENDIAN_FLOAT(bounds.left);
13819949213aSStephan Aßmus 	header.bounds.top = B_HOST_TO_BENDIAN_FLOAT(bounds.top);
13829949213aSStephan Aßmus 	header.bounds.right = B_HOST_TO_BENDIAN_FLOAT(bounds.right);
13839949213aSStephan Aßmus 	header.bounds.bottom = B_HOST_TO_BENDIAN_FLOAT(bounds.bottom);
13849949213aSStephan Aßmus 	header.colors = (color_space)B_HOST_TO_BENDIAN_INT32(out_color_space);
13859949213aSStephan Aßmus 	header.rowBytes = B_HOST_TO_BENDIAN_INT32(row_bytes);
13869949213aSStephan Aßmus 	header.dataSize = B_HOST_TO_BENDIAN_INT32(row_bytes * cinfo.output_height);
13879949213aSStephan Aßmus 
13889949213aSStephan Aßmus 	// Write out the header
13899949213aSStephan Aßmus 	status_t err = out->Write(&header, sizeof(TranslatorBitmap));
1390*d8e2fb50SAxel Dörfler 	if (err < B_OK)
1391*d8e2fb50SAxel Dörfler 		return Error((j_common_ptr)&cinfo, err);
1392*d8e2fb50SAxel Dörfler 	else if (err < (int)sizeof(TranslatorBitmap))
1393*d8e2fb50SAxel Dörfler 		return Error((j_common_ptr)&cinfo, B_ERROR);
13949949213aSStephan Aßmus 
13959949213aSStephan Aßmus 	// Declare scanlines
13969949213aSStephan Aßmus 	JSAMPROW in_scanline = NULL;
13979949213aSStephan Aßmus 	JSAMPROW out_scanline = NULL;
13989949213aSStephan Aßmus 	JSAMPROW writeline;	// Pointer to in_scanline or out_scanline (if there will be conversion)
13999949213aSStephan Aßmus 
14009949213aSStephan Aßmus 	// Allocate scanline
14019949213aSStephan Aßmus 	// Use libjpeg memory allocation functions, so in case of error it will free them itself
1402*d8e2fb50SAxel Dörfler     in_scanline = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo,
1403*d8e2fb50SAxel Dörfler     	JPOOL_PERMANENT, row_bytes);
14049949213aSStephan Aßmus 
14059949213aSStephan Aßmus 	// We need 2nd scanline storage only for conversion
14069949213aSStephan Aßmus 	if (converter != NULL) {
14079949213aSStephan Aßmus 		// There will be conversion, allocate second scanline...
14089949213aSStephan Aßmus 		// Use libjpeg memory allocation functions, so in case of error it will free them itself
1409*d8e2fb50SAxel Dörfler 	    out_scanline = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo,
1410*d8e2fb50SAxel Dörfler 	    	JPOOL_PERMANENT, row_bytes);
14119949213aSStephan Aßmus 		// ... and make it the one to write to file
14129949213aSStephan Aßmus 		writeline = out_scanline;
14139949213aSStephan Aßmus 	} else
14149949213aSStephan Aßmus 		writeline = in_scanline;
14159949213aSStephan Aßmus 
14169949213aSStephan Aßmus 	while (cinfo.output_scanline < cinfo.output_height) {
14179949213aSStephan Aßmus 		// Read scanline
14189949213aSStephan Aßmus 		jpeg_read_scanlines(&cinfo, &in_scanline, 1);
14199949213aSStephan Aßmus 
14209949213aSStephan Aßmus 		// Convert if needed
14219949213aSStephan Aßmus 		if (converter != NULL)
14229949213aSStephan Aßmus 			converter(in_scanline, out_scanline, row_bytes);
14239949213aSStephan Aßmus 
14249949213aSStephan Aßmus   		// Write the scanline buffer to the output stream
14259949213aSStephan Aßmus 		err = out->Write(writeline, row_bytes);
14269949213aSStephan Aßmus 		if (err < row_bytes)
1427*d8e2fb50SAxel Dörfler 			return err < B_OK ? Error((j_common_ptr)&cinfo, err)
1428*d8e2fb50SAxel Dörfler 				: Error((j_common_ptr)&cinfo, B_ERROR);
14299949213aSStephan Aßmus 	}
14309949213aSStephan Aßmus 
14319949213aSStephan Aßmus 	jpeg_finish_decompress(&cinfo);
14329949213aSStephan Aßmus 	jpeg_destroy_decompress(&cinfo);
14339949213aSStephan Aßmus 	return B_OK;
14349949213aSStephan Aßmus }
14359949213aSStephan Aßmus 
1436*d8e2fb50SAxel Dörfler /*!
1437*d8e2fb50SAxel Dörfler 	Frees jpeg alocated memory
1438*d8e2fb50SAxel Dörfler 	Returns given error (B_ERROR by default)
1439*d8e2fb50SAxel Dörfler */
14409949213aSStephan Aßmus status_t
14419949213aSStephan Aßmus Error(j_common_ptr cinfo, status_t error)
14429949213aSStephan Aßmus {
14439949213aSStephan Aßmus 	jpeg_destroy(cinfo);
14449949213aSStephan Aßmus 	return error;
14459949213aSStephan Aßmus }
1446*d8e2fb50SAxel Dörfler 
1447*d8e2fb50SAxel Dörfler 
1448*d8e2fb50SAxel Dörfler //	#pragma mark -
1449*d8e2fb50SAxel Dörfler 
1450*d8e2fb50SAxel Dörfler 
1451*d8e2fb50SAxel Dörfler int
1452*d8e2fb50SAxel Dörfler main() {
1453*d8e2fb50SAxel Dörfler 	BApplication app("application/x-vnd.Shard.JPEGTranslator");
1454*d8e2fb50SAxel Dörfler 
1455*d8e2fb50SAxel Dörfler 	TranslatorWindow *window = new TranslatorWindow();
1456*d8e2fb50SAxel Dörfler 	window->Show();
1457*d8e2fb50SAxel Dörfler 
1458*d8e2fb50SAxel Dörfler 	app.Run();
1459*d8e2fb50SAxel Dörfler 	return 0;
1460*d8e2fb50SAxel Dörfler }
1461*d8e2fb50SAxel Dörfler 
1462