xref: /haiku/src/add-ons/translators/jpeg/JPEGTranslator.cpp (revision 7d48219b470e22b5147f0ae9adc8ee2049c981d3)
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"
34b98ef4f9SStephan Aßmus #include "TranslatorWindow.h"
3552e8f46aSAxel Dörfler #include "exif_parser.h"
3652e8f46aSAxel Dörfler 
3770d59669SSiarzhuk Zharski #include <syslog.h>
3870d59669SSiarzhuk Zharski 
39b98ef4f9SStephan Aßmus #include <Alignment.h>
4003901b6cSJérôme Duval #include <Catalog.h>
41*7d48219bSHannah Boneß #include <LayoutBuilder.h>
428687ff64SAxel Dörfler #include <TabView.h>
43b98ef4f9SStephan Aßmus #include <TextView.h>
448687ff64SAxel Dörfler 
45546208a5SOliver Tappe #undef B_TRANSLATION_CONTEXT
46546208a5SOliver Tappe #define B_TRANSLATION_CONTEXT "JPEGTranslator"
479949213aSStephan Aßmus 
4852e8f46aSAxel Dörfler #define MARKER_EXIF	0xe1
4952e8f46aSAxel Dörfler 
509949213aSStephan Aßmus // Set these accordingly
519949213aSStephan Aßmus #define JPEG_ACRONYM "JPEG"
529949213aSStephan Aßmus #define JPEG_FORMAT 'JPEG'
539949213aSStephan Aßmus #define JPEG_MIME_STRING "image/jpeg"
549949213aSStephan Aßmus #define JPEG_DESCRIPTION "JPEG image"
559949213aSStephan Aßmus 
569949213aSStephan Aßmus // The translation kit's native file type
579949213aSStephan Aßmus #define B_TRANSLATOR_BITMAP_MIME_STRING "image/x-be-bitmap"
58c095606eSRyan Leavengood #define B_TRANSLATOR_BITMAP_DESCRIPTION "Be Bitmap Format (JPEGTranslator)"
599949213aSStephan Aßmus 
60b98ef4f9SStephan Aßmus 
612e49ff35SSiarzhuk Zharski static const int32 sTranslatorVersion = B_TRANSLATION_MAKE_VERSION(1, 2, 0);
622e49ff35SSiarzhuk Zharski 
631da233a7SSiarzhuk Zharski static const char* sTranslatorName = B_TRANSLATE("JPEG images");
641da233a7SSiarzhuk Zharski static const char* sTranslatorInfo = B_TRANSLATE("©2002-2003, Marcin Konicki\n"
65f13b5de6SAxel Dörfler 	"©2005-2007, Haiku\n"
66758b1d0eSIngo Weinhold 	"\n"
677fd58091SJérôme Duval 	"Based on IJG library ©  1994-2009, Thomas G. Lane, Guido Vollbeding.\n"
682e49ff35SSiarzhuk Zharski 	"\thttp://www.ijg.org/files/\n"
69b98ef4f9SStephan Aßmus 	"\n"
70fcc3e627SStephan Aßmus 	"with \"lossless\" encoding support patch by Ken Murchison\n"
712e49ff35SSiarzhuk Zharski 	"\thttp://www.oceana.com/ftp/ljpeg/\n"
72758b1d0eSIngo Weinhold 	"\n"
73758b1d0eSIngo Weinhold 	"With some colorspace conversion routines by Magnus Hellman\n"
742e49ff35SSiarzhuk Zharski 	"\thttp://www.bebits.com/app/802\n");
759949213aSStephan Aßmus 
769949213aSStephan Aßmus // Define the formats we know how to read
77bf243977SPhilippe Houdoin static const translation_format sInputFormats[] = {
789949213aSStephan Aßmus 	{ JPEG_FORMAT, B_TRANSLATOR_BITMAP, 0.5, 0.5,
799949213aSStephan Aßmus 		JPEG_MIME_STRING, JPEG_DESCRIPTION },
809949213aSStephan Aßmus 	{ B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.5, 0.5,
817b5743baSPhilippe Houdoin 		B_TRANSLATOR_BITMAP_MIME_STRING, B_TRANSLATOR_BITMAP_DESCRIPTION }
829949213aSStephan Aßmus };
839949213aSStephan Aßmus 
849949213aSStephan Aßmus // Define the formats we know how to write
85bf243977SPhilippe Houdoin static const translation_format sOutputFormats[] = {
869949213aSStephan Aßmus 	{ JPEG_FORMAT, B_TRANSLATOR_BITMAP, 0.5, 0.5,
879949213aSStephan Aßmus 		JPEG_MIME_STRING, JPEG_DESCRIPTION },
889949213aSStephan Aßmus 	{ B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.5, 0.5,
897b5743baSPhilippe Houdoin 		B_TRANSLATOR_BITMAP_MIME_STRING, B_TRANSLATOR_BITMAP_DESCRIPTION }
909949213aSStephan Aßmus };
9152e8f46aSAxel Dörfler 
92d8e2fb50SAxel Dörfler 
93bf243977SPhilippe Houdoin static const TranSetting sDefaultSettings[] = {
94b98ef4f9SStephan Aßmus 	{JPEG_SET_SMOOTHING, TRAN_SETTING_INT32, 0},
95b98ef4f9SStephan Aßmus 	{JPEG_SET_QUALITY, TRAN_SETTING_INT32, 95},
96b98ef4f9SStephan Aßmus 	{JPEG_SET_PROGRESSIVE, TRAN_SETTING_BOOL, true},
97b98ef4f9SStephan Aßmus 	{JPEG_SET_OPT_COLORS, TRAN_SETTING_BOOL, true},
98b98ef4f9SStephan Aßmus 	{JPEG_SET_SMALL_FILES, TRAN_SETTING_BOOL, false},
99b98ef4f9SStephan Aßmus 	{JPEG_SET_GRAY1_AS_RGB24, TRAN_SETTING_BOOL, false},
100b98ef4f9SStephan Aßmus 	{JPEG_SET_ALWAYS_RGB32, TRAN_SETTING_BOOL, true},
101b98ef4f9SStephan Aßmus 	{JPEG_SET_PHOTOSHOP_CMYK, TRAN_SETTING_BOOL, true},
102b98ef4f9SStephan Aßmus 	{JPEG_SET_SHOWREADWARNING, TRAN_SETTING_BOOL, true}
103b98ef4f9SStephan Aßmus };
104bf243977SPhilippe Houdoin 
105bf243977SPhilippe Houdoin const uint32 kNumInputFormats = sizeof(sInputFormats) / sizeof(translation_format);
106bf243977SPhilippe Houdoin const uint32 kNumOutputFormats = sizeof(sOutputFormats) / sizeof(translation_format);
107bf243977SPhilippe Houdoin const uint32 kNumDefaultSettings = sizeof(sDefaultSettings) / sizeof(TranSetting);
1089949213aSStephan Aßmus 
109d8e2fb50SAxel Dörfler 
110b98ef4f9SStephan Aßmus namespace conversion {
111d8e2fb50SAxel Dörfler 
112d8e2fb50SAxel Dörfler 
1139e34f742SAxel Dörfler static bool
1149e34f742SAxel Dörfler x_flipped(int32 orientation)
1159e34f742SAxel Dörfler {
1169e34f742SAxel Dörfler 	return orientation == 2 || orientation == 3
1179e34f742SAxel Dörfler 		|| orientation == 6 || orientation == 7;
1189e34f742SAxel Dörfler }
1199e34f742SAxel Dörfler 
1209e34f742SAxel Dörfler 
1219e34f742SAxel Dörfler static bool
1229e34f742SAxel Dörfler y_flipped(int32 orientation)
1239e34f742SAxel Dörfler {
1249e34f742SAxel Dörfler 	return orientation == 3 || orientation == 4
1259e34f742SAxel Dörfler 		|| orientation == 7 || orientation == 8;
1269e34f742SAxel Dörfler }
1279e34f742SAxel Dörfler 
1289e34f742SAxel Dörfler 
1299e34f742SAxel Dörfler static int32
1309e34f742SAxel Dörfler dest_index(uint32 width, uint32 height, uint32 x, uint32 y, int32 orientation)
1319e34f742SAxel Dörfler {
1329e34f742SAxel Dörfler 	if (orientation > 4) {
1339e34f742SAxel Dörfler 		uint32 temp = x;
1349e34f742SAxel Dörfler 		x = y;
1359e34f742SAxel Dörfler 		y = temp;
1369e34f742SAxel Dörfler 	}
1379e34f742SAxel Dörfler 	if (y_flipped(orientation))
1389e34f742SAxel Dörfler 		y = height - 1 - y;
1399e34f742SAxel Dörfler 	if (x_flipped(orientation))
1409e34f742SAxel Dörfler 		x = width - 1 - x;
1419e34f742SAxel Dörfler 
1429e34f742SAxel Dörfler 	return y * width + x;
1439e34f742SAxel Dörfler }
1449e34f742SAxel Dörfler 
1459e34f742SAxel Dörfler 
1469e34f742SAxel Dörfler //	#pragma mark - conversion for compression
147d8e2fb50SAxel Dörfler 
148d8e2fb50SAxel Dörfler 
149d8e2fb50SAxel Dörfler inline void
1509e34f742SAxel Dörfler convert_from_gray1_to_gray8(uint8* in, uint8* out, int32 inRowBytes)
151d8e2fb50SAxel Dörfler {
152d8e2fb50SAxel Dörfler 	int32 index = 0;
153d8e2fb50SAxel Dörfler 	int32 index2 = 0;
1549e34f742SAxel Dörfler 	while (index < inRowBytes) {
155d8e2fb50SAxel Dörfler 		unsigned char c = in[index++];
156d8e2fb50SAxel Dörfler 		for (int b = 128; b; b = b>>1) {
157d8e2fb50SAxel Dörfler 			unsigned char color;
158d8e2fb50SAxel Dörfler 			if (c & b)
159d8e2fb50SAxel Dörfler 				color = 0;
160d8e2fb50SAxel Dörfler 			else
161d8e2fb50SAxel Dörfler 				color = 255;
162d8e2fb50SAxel Dörfler 			out[index2++] = color;
163d8e2fb50SAxel Dörfler 		}
164d8e2fb50SAxel Dörfler 	}
165d8e2fb50SAxel Dörfler }
166d8e2fb50SAxel Dörfler 
167d8e2fb50SAxel Dörfler 
168d8e2fb50SAxel Dörfler inline void
1699e34f742SAxel Dörfler convert_from_gray1_to_24(uint8* in, uint8* out, int32 inRowBytes)
170d8e2fb50SAxel Dörfler {
171d8e2fb50SAxel Dörfler 	int32 index = 0;
172d8e2fb50SAxel Dörfler 	int32 index2 = 0;
1739e34f742SAxel Dörfler 	while (index < inRowBytes) {
174d8e2fb50SAxel Dörfler 		unsigned char c = in[index++];
175d8e2fb50SAxel Dörfler 		for (int b = 128; b; b = b>>1) {
176d8e2fb50SAxel Dörfler 			unsigned char color;
177d8e2fb50SAxel Dörfler 			if (c & b)
178d8e2fb50SAxel Dörfler 				color = 0;
179d8e2fb50SAxel Dörfler 			else
180d8e2fb50SAxel Dörfler 				color = 255;
181d8e2fb50SAxel Dörfler 			out[index2++] = color;
182d8e2fb50SAxel Dörfler 			out[index2++] = color;
183d8e2fb50SAxel Dörfler 			out[index2++] = color;
184d8e2fb50SAxel Dörfler 		}
185d8e2fb50SAxel Dörfler 	}
186d8e2fb50SAxel Dörfler }
187d8e2fb50SAxel Dörfler 
188d8e2fb50SAxel Dörfler 
189d8e2fb50SAxel Dörfler inline void
1909e34f742SAxel Dörfler convert_from_cmap8_to_24(uint8* in, uint8* out, int32 inRowBytes)
191d8e2fb50SAxel Dörfler {
192d8e2fb50SAxel Dörfler 	const color_map * map = system_colors();
193d8e2fb50SAxel Dörfler 	int32 index = 0;
194d8e2fb50SAxel Dörfler 	int32 index2 = 0;
1959e34f742SAxel Dörfler 	while (index < inRowBytes) {
196d8e2fb50SAxel Dörfler 		rgb_color color = map->color_list[in[index++]];
197d8e2fb50SAxel Dörfler 
198d8e2fb50SAxel Dörfler 		out[index2++] = color.red;
199d8e2fb50SAxel Dörfler 		out[index2++] = color.green;
200d8e2fb50SAxel Dörfler 		out[index2++] = color.blue;
201d8e2fb50SAxel Dörfler 	}
202d8e2fb50SAxel Dörfler }
203d8e2fb50SAxel Dörfler 
204d8e2fb50SAxel Dörfler 
205d8e2fb50SAxel Dörfler inline void
2069e34f742SAxel Dörfler convert_from_15_to_24(uint8* in, uint8* out, int32 inRowBytes)
207d8e2fb50SAxel Dörfler {
208d8e2fb50SAxel Dörfler 	int32 index = 0;
209d8e2fb50SAxel Dörfler 	int32 index2 = 0;
210d8e2fb50SAxel Dörfler 	int16 in_pixel;
2119e34f742SAxel Dörfler 	while (index < inRowBytes) {
212d8e2fb50SAxel Dörfler 		in_pixel = in[index] | (in[index + 1] << 8);
213d8e2fb50SAxel Dörfler 		index += 2;
214d8e2fb50SAxel Dörfler 
215d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x7c00)) >> 7) | (((in_pixel & 0x7c00)) >> 12);
216d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x3e0)) >> 2) | (((in_pixel & 0x3e0)) >> 7);
217d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2);
218d8e2fb50SAxel Dörfler 	}
219d8e2fb50SAxel Dörfler }
220d8e2fb50SAxel Dörfler 
221d8e2fb50SAxel Dörfler 
222d8e2fb50SAxel Dörfler inline void
2239e34f742SAxel Dörfler convert_from_15b_to_24(uint8* in, uint8* out, int32 inRowBytes)
224d8e2fb50SAxel Dörfler {
225d8e2fb50SAxel Dörfler 	int32 index = 0;
226d8e2fb50SAxel Dörfler 	int32 index2 = 0;
227d8e2fb50SAxel Dörfler 	int16 in_pixel;
2289e34f742SAxel Dörfler 	while (index < inRowBytes) {
229d8e2fb50SAxel Dörfler 		in_pixel = in[index + 1] | (in[index] << 8);
230d8e2fb50SAxel Dörfler 		index += 2;
231d8e2fb50SAxel Dörfler 
232d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x7c00)) >> 7) | (((in_pixel & 0x7c00)) >> 12);
233d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x3e0)) >> 2) | (((in_pixel & 0x3e0)) >> 7);
234d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2);
235d8e2fb50SAxel Dörfler 	}
236d8e2fb50SAxel Dörfler }
237d8e2fb50SAxel Dörfler 
238d8e2fb50SAxel Dörfler 
239d8e2fb50SAxel Dörfler inline void
2409e34f742SAxel Dörfler convert_from_16_to_24(uint8* in, uint8* out, int32 inRowBytes)
241d8e2fb50SAxel Dörfler {
242d8e2fb50SAxel Dörfler 	int32 index = 0;
243d8e2fb50SAxel Dörfler 	int32 index2 = 0;
244d8e2fb50SAxel Dörfler 	int16 in_pixel;
2459e34f742SAxel Dörfler 	while (index < inRowBytes) {
246d8e2fb50SAxel Dörfler 		in_pixel = in[index] | (in[index + 1] << 8);
247d8e2fb50SAxel Dörfler 		index += 2;
248d8e2fb50SAxel Dörfler 
249d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0xf800)) >> 8) | (((in_pixel & 0xf800)) >> 13);
250d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x7e0)) >> 3) | (((in_pixel & 0x7e0)) >> 9);
251d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2);
252d8e2fb50SAxel Dörfler 	}
253d8e2fb50SAxel Dörfler }
254d8e2fb50SAxel Dörfler 
255d8e2fb50SAxel Dörfler 
256d8e2fb50SAxel Dörfler inline void
2579e34f742SAxel Dörfler convert_from_16b_to_24(uint8* in, uint8* out, int32 inRowBytes)
258d8e2fb50SAxel Dörfler {
259d8e2fb50SAxel Dörfler 	int32 index = 0;
260d8e2fb50SAxel Dörfler 	int32 index2 = 0;
261d8e2fb50SAxel Dörfler 	int16 in_pixel;
2629e34f742SAxel Dörfler 	while (index < inRowBytes) {
263d8e2fb50SAxel Dörfler 		in_pixel = in[index + 1] | (in[index] << 8);
264d8e2fb50SAxel Dörfler 		index += 2;
265d8e2fb50SAxel Dörfler 
266d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0xf800)) >> 8) | (((in_pixel & 0xf800)) >> 13);
267d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x7e0)) >> 3) | (((in_pixel & 0x7e0)) >> 9);
268d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2);
269d8e2fb50SAxel Dörfler 	}
270d8e2fb50SAxel Dörfler }
271d8e2fb50SAxel Dörfler 
272d8e2fb50SAxel Dörfler 
273d8e2fb50SAxel Dörfler inline void
2749e34f742SAxel Dörfler convert_from_24_to_24(uint8* in, uint8* out, int32 inRowBytes)
275d8e2fb50SAxel Dörfler {
276d8e2fb50SAxel Dörfler 	int32 index = 0;
277d8e2fb50SAxel Dörfler 	int32 index2 = 0;
2789e34f742SAxel Dörfler 	while (index < inRowBytes) {
279d8e2fb50SAxel Dörfler 		out[index2++] = in[index + 2];
280d8e2fb50SAxel Dörfler 		out[index2++] = in[index + 1];
281d8e2fb50SAxel Dörfler 		out[index2++] = in[index];
282d8e2fb50SAxel Dörfler 		index+=3;
283d8e2fb50SAxel Dörfler 	}
284d8e2fb50SAxel Dörfler }
285d8e2fb50SAxel Dörfler 
286d8e2fb50SAxel Dörfler 
287d8e2fb50SAxel Dörfler inline void
2889e34f742SAxel Dörfler convert_from_32_to_24(uint8* in, uint8* out, int32 inRowBytes)
289d8e2fb50SAxel Dörfler {
29051623681SAxel Dörfler 	inRowBytes /= 4;
29151623681SAxel Dörfler 
2929e34f742SAxel Dörfler 	for (int32 i = 0; i < inRowBytes; i++) {
2939e34f742SAxel Dörfler 		out[0] = in[2];
2949e34f742SAxel Dörfler 		out[1] = in[1];
2959e34f742SAxel Dörfler 		out[2] = in[0];
2969e34f742SAxel Dörfler 
2979e34f742SAxel Dörfler 		in += 4;
2989e34f742SAxel Dörfler 		out += 3;
299d8e2fb50SAxel Dörfler 	}
300d8e2fb50SAxel Dörfler }
301d8e2fb50SAxel Dörfler 
302d8e2fb50SAxel Dörfler 
303d8e2fb50SAxel Dörfler inline void
3049e34f742SAxel Dörfler convert_from_32b_to_24(uint8* in, uint8* out, int32 inRowBytes)
305d8e2fb50SAxel Dörfler {
30651623681SAxel Dörfler 	inRowBytes /= 4;
30751623681SAxel Dörfler 
3089e34f742SAxel Dörfler 	for (int32 i = 0; i < inRowBytes; i++) {
30951623681SAxel Dörfler 		out[0] = in[1];
31051623681SAxel Dörfler 		out[1] = in[2];
31151623681SAxel Dörfler 		out[2] = in[3];
3129e34f742SAxel Dörfler 
3139e34f742SAxel Dörfler 		in += 4;
3149e34f742SAxel Dörfler 		out += 3;
315d8e2fb50SAxel Dörfler 	}
316d8e2fb50SAxel Dörfler }
317d8e2fb50SAxel Dörfler 
318d8e2fb50SAxel Dörfler 
3199e34f742SAxel Dörfler //	#pragma mark - conversion for decompression
3209e34f742SAxel Dörfler 
3219e34f742SAxel Dörfler 
322d8e2fb50SAxel Dörfler inline void
3239e34f742SAxel Dörfler convert_from_CMYK_to_32_photoshop(uint8* in, uint8* out, int32 inRowBytes, int32 xStep)
324d8e2fb50SAxel Dörfler {
3259e34f742SAxel Dörfler 	for (int32 i = 0; i < inRowBytes; i += 4) {
3269e34f742SAxel Dörfler 		int32 black = in[3];
3279e34f742SAxel Dörfler 		out[0] = in[2] * black / 255;
3289e34f742SAxel Dörfler 		out[1] = in[1] * black / 255;
3299e34f742SAxel Dörfler 		out[2] = in[0] * black / 255;
3309e34f742SAxel Dörfler 		out[3] = 255;
3319e34f742SAxel Dörfler 
3329e34f742SAxel Dörfler 		in += 4;
3339e34f742SAxel Dörfler 		out += xStep;
334d8e2fb50SAxel Dörfler 	}
335d8e2fb50SAxel Dörfler }
336d8e2fb50SAxel Dörfler 
337d8e2fb50SAxel Dörfler 
338d8e2fb50SAxel Dörfler //!	!!! UNTESTED !!!
339d8e2fb50SAxel Dörfler inline void
3409e34f742SAxel Dörfler convert_from_CMYK_to_32(uint8* in, uint8* out, int32 inRowBytes, int32 xStep)
341d8e2fb50SAxel Dörfler {
3429e34f742SAxel Dörfler 	for (int32 i = 0; i < inRowBytes; i += 4) {
3439e34f742SAxel Dörfler 		int32 black = 255 - in[3];
3449e34f742SAxel Dörfler 		out[0] = ((255 - in[2]) * black) / 255;
3459e34f742SAxel Dörfler 		out[1] = ((255 - in[1]) * black) / 255;
3469e34f742SAxel Dörfler 		out[2] = ((255 - in[0]) * black) / 255;
3479e34f742SAxel Dörfler 		out[3] = 255;
3489e34f742SAxel Dörfler 
3499e34f742SAxel Dörfler 		in += 4;
3509e34f742SAxel Dörfler 		out += xStep;
351d8e2fb50SAxel Dörfler 	}
352d8e2fb50SAxel Dörfler }
353d8e2fb50SAxel Dörfler 
354d8e2fb50SAxel Dörfler 
355d8e2fb50SAxel Dörfler //!	RGB24 8:8:8 to xRGB 8:8:8:8
356d8e2fb50SAxel Dörfler inline void
3579e34f742SAxel Dörfler convert_from_24_to_32(uint8* in, uint8* out, int32 inRowBytes, int32 xStep)
358d8e2fb50SAxel Dörfler {
3599e34f742SAxel Dörfler 	for (int32 i = 0; i < inRowBytes; i += 3) {
3609e34f742SAxel Dörfler 		out[0] = in[2];
3619e34f742SAxel Dörfler 		out[1] = in[1];
3629e34f742SAxel Dörfler 		out[2] = in[0];
3639e34f742SAxel Dörfler 		out[3] = 255;
3649e34f742SAxel Dörfler 
3659e34f742SAxel Dörfler 		in += 3;
3669e34f742SAxel Dörfler 		out += xStep;
3679e34f742SAxel Dörfler 	}
3689e34f742SAxel Dörfler }
3699e34f742SAxel Dörfler 
3709e34f742SAxel Dörfler 
3719e34f742SAxel Dörfler //! 8-bit to 8-bit, only need when rotating the image
3729e34f742SAxel Dörfler void
3739e34f742SAxel Dörfler translate_8(uint8* in, uint8* out, int32 inRowBytes, int32 xStep)
3749e34f742SAxel Dörfler {
3759e34f742SAxel Dörfler 	for (int32 i = 0; i < inRowBytes; i++) {
3769e34f742SAxel Dörfler 		out[0] = in[0];
3779e34f742SAxel Dörfler 
3789e34f742SAxel Dörfler 		in++;
3799e34f742SAxel Dörfler 		out += xStep;
380d8e2fb50SAxel Dörfler 	}
381d8e2fb50SAxel Dörfler }
382d8e2fb50SAxel Dörfler 
383d8e2fb50SAxel Dörfler 
384b98ef4f9SStephan Aßmus } // namespace conversion
3858687ff64SAxel Dörfler 
3868687ff64SAxel Dörfler 
387d8e2fb50SAxel Dörfler //	#pragma mark -
388d8e2fb50SAxel Dörfler 
389d8e2fb50SAxel Dörfler 
390b98ef4f9SStephan Aßmus SSlider::SSlider(const char* name, const char* label,
391d8e2fb50SAxel Dörfler 		BMessage* message, int32 minValue, int32 maxValue, orientation posture,
392b98ef4f9SStephan Aßmus 		thumb_style thumbType, uint32 flags)
393b98ef4f9SStephan Aßmus 	: BSlider(name, label, message, minValue, maxValue,
394b98ef4f9SStephan Aßmus 		posture, thumbType, flags)
3959949213aSStephan Aßmus {
3968687ff64SAxel Dörfler 	rgb_color barColor = { 0, 0, 229, 255 };
3978687ff64SAxel Dörfler 	UseFillColor(true, &barColor);
3989949213aSStephan Aßmus }
3999949213aSStephan Aßmus 
4008687ff64SAxel Dörfler 
4018687ff64SAxel Dörfler //!	Update status string - show actual value
402b20d13f4SStefano Ceccherini const char*
4039949213aSStephan Aßmus SSlider::UpdateText() const
4049949213aSStephan Aßmus {
4058687ff64SAxel Dörfler 	snprintf(fStatusLabel, sizeof(fStatusLabel), "%ld", Value());
4068687ff64SAxel Dörfler 	return fStatusLabel;
4079949213aSStephan Aßmus }
4089949213aSStephan Aßmus 
4098687ff64SAxel Dörfler 
410d8e2fb50SAxel Dörfler //	#pragma mark -
4119949213aSStephan Aßmus 
412d8e2fb50SAxel Dörfler 
413b98ef4f9SStephan Aßmus TranslatorReadView::TranslatorReadView(const char* name,
414b98ef4f9SStephan Aßmus 	TranslatorSettings* settings)
415b98ef4f9SStephan Aßmus 	:
416b98ef4f9SStephan Aßmus 	BView(name, 0, new BGroupLayout(B_HORIZONTAL)),
417d8e2fb50SAxel Dörfler 	fSettings(settings)
418b98ef4f9SStephan Aßmus 		// settings should already be Acquired()
4199949213aSStephan Aßmus {
4202e49ff35SSiarzhuk Zharski 	fAlwaysRGB32 = new BCheckBox("alwaysrgb32",
4212e49ff35SSiarzhuk Zharski 		B_TRANSLATE("Read greyscale images as RGB32"),
422d8e2fb50SAxel Dörfler 		new BMessage(VIEW_MSG_SET_ALWAYSRGB32));
423b98ef4f9SStephan Aßmus 	if (fSettings->SetGetBool(JPEG_SET_ALWAYS_RGB32, NULL))
424b98ef4f9SStephan Aßmus 		fAlwaysRGB32->SetValue(B_CONTROL_ON);
4259949213aSStephan Aßmus 
4262e49ff35SSiarzhuk Zharski 	fPhotoshopCMYK = new BCheckBox("photoshopCMYK",
4272e49ff35SSiarzhuk Zharski 		B_TRANSLATE("Use CMYK code with 0 for 100% ink coverage"),
4288687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_PHOTOSHOPCMYK));
429b98ef4f9SStephan Aßmus 	if (fSettings->SetGetBool(JPEG_SET_PHOTOSHOP_CMYK, NULL))
430b98ef4f9SStephan Aßmus 		fPhotoshopCMYK->SetValue(B_CONTROL_ON);
4319949213aSStephan Aßmus 
4322e49ff35SSiarzhuk Zharski 	fShowErrorBox = new BCheckBox("error",
4332e49ff35SSiarzhuk Zharski 		B_TRANSLATE("Show warning messages"),
4348687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_SHOWREADERRORBOX));
435b98ef4f9SStephan Aßmus 	if (fSettings->SetGetBool(JPEG_SET_SHOWREADWARNING, NULL))
436b98ef4f9SStephan Aßmus 		fShowErrorBox->SetValue(B_CONTROL_ON);
4379949213aSStephan Aßmus 
438b98ef4f9SStephan Aßmus 	float padding = 5.0f;
439*7d48219bSHannah Boneß 
440*7d48219bSHannah Boneß 	BLayoutBuilder::Group<>(this, B_VERTICAL, padding)
441*7d48219bSHannah Boneß 		.SetInsets(padding)
442b98ef4f9SStephan Aßmus 		.Add(fAlwaysRGB32)
443b98ef4f9SStephan Aßmus 		.Add(fPhotoshopCMYK)
444b98ef4f9SStephan Aßmus 		.Add(fShowErrorBox)
445*7d48219bSHannah Boneß 		.AddGlue();
446b98ef4f9SStephan Aßmus }
447b98ef4f9SStephan Aßmus 
448b98ef4f9SStephan Aßmus 
449b98ef4f9SStephan Aßmus TranslatorReadView::~TranslatorReadView()
450b98ef4f9SStephan Aßmus {
451b98ef4f9SStephan Aßmus 	fSettings->Release();
4529949213aSStephan Aßmus }
4539949213aSStephan Aßmus 
4548687ff64SAxel Dörfler 
4559949213aSStephan Aßmus void
4569949213aSStephan Aßmus TranslatorReadView::AttachedToWindow()
4579949213aSStephan Aßmus {
458b98ef4f9SStephan Aßmus 	BView::AttachedToWindow();
459b20d13f4SStefano Ceccherini 
4608687ff64SAxel Dörfler 	fAlwaysRGB32->SetTarget(this);
4618687ff64SAxel Dörfler 	fPhotoshopCMYK->SetTarget(this);
4628687ff64SAxel Dörfler 	fShowErrorBox->SetTarget(this);
4639949213aSStephan Aßmus }
4649949213aSStephan Aßmus 
4658687ff64SAxel Dörfler 
4669949213aSStephan Aßmus void
4679949213aSStephan Aßmus TranslatorReadView::MessageReceived(BMessage* message)
4689949213aSStephan Aßmus {
4698687ff64SAxel Dörfler 	switch (message->what) {
4709949213aSStephan Aßmus 		case VIEW_MSG_SET_ALWAYSRGB32:
4719949213aSStephan Aßmus 		{
4729949213aSStephan Aßmus 			int32 value;
4739949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
474b98ef4f9SStephan Aßmus 				bool boolValue = value;
475b98ef4f9SStephan Aßmus 				fSettings->SetGetBool(JPEG_SET_ALWAYS_RGB32, &boolValue);
476b98ef4f9SStephan Aßmus 				fSettings->SaveSettings();
4779949213aSStephan Aßmus 			}
4789949213aSStephan Aßmus 			break;
4799949213aSStephan Aßmus 		}
4809949213aSStephan Aßmus 		case VIEW_MSG_SET_PHOTOSHOPCMYK:
4819949213aSStephan Aßmus 		{
4829949213aSStephan Aßmus 			int32 value;
4839949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
484b98ef4f9SStephan Aßmus 				bool boolValue = value;
485b98ef4f9SStephan Aßmus 				fSettings->SetGetBool(JPEG_SET_PHOTOSHOP_CMYK, &boolValue);
486b98ef4f9SStephan Aßmus 				fSettings->SaveSettings();
4879949213aSStephan Aßmus 			}
4889949213aSStephan Aßmus 			break;
4899949213aSStephan Aßmus 		}
4909949213aSStephan Aßmus 		case VIEW_MSG_SET_SHOWREADERRORBOX:
4919949213aSStephan Aßmus 		{
4929949213aSStephan Aßmus 			int32 value;
4939949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
494b98ef4f9SStephan Aßmus 				bool boolValue = value;
495b98ef4f9SStephan Aßmus 				fSettings->SetGetBool(JPEG_SET_SHOWREADWARNING, &boolValue);
496b98ef4f9SStephan Aßmus 				fSettings->SaveSettings();
4979949213aSStephan Aßmus 			}
4989949213aSStephan Aßmus 			break;
4999949213aSStephan Aßmus 		}
5009949213aSStephan Aßmus 		default:
5019949213aSStephan Aßmus 			BView::MessageReceived(message);
5029949213aSStephan Aßmus 			break;
5039949213aSStephan Aßmus 	}
5049949213aSStephan Aßmus }
5059949213aSStephan Aßmus 
5069949213aSStephan Aßmus 
5078687ff64SAxel Dörfler //	#pragma mark - TranslatorWriteView
5089949213aSStephan Aßmus 
5098687ff64SAxel Dörfler 
510b98ef4f9SStephan Aßmus TranslatorWriteView::TranslatorWriteView(const char* name,
511b98ef4f9SStephan Aßmus 	TranslatorSettings* settings)
512b98ef4f9SStephan Aßmus 	:
513b98ef4f9SStephan Aßmus 	BView(name, 0, new BGroupLayout(B_VERTICAL)),
514d8e2fb50SAxel Dörfler 	fSettings(settings)
515b98ef4f9SStephan Aßmus 		// settings should already be Acquired()
5169949213aSStephan Aßmus {
5172e49ff35SSiarzhuk Zharski 	fQualitySlider = new SSlider("quality", B_TRANSLATE("Output quality"),
5188687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_QUALITY), 0, 100);
5198687ff64SAxel Dörfler 	fQualitySlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
5208687ff64SAxel Dörfler 	fQualitySlider->SetHashMarkCount(10);
52103901b6cSJérôme Duval 	fQualitySlider->SetLimitLabels(B_TRANSLATE("Low"), B_TRANSLATE("High"));
522b98ef4f9SStephan Aßmus 	fQualitySlider->SetValue(fSettings->SetGetInt32(JPEG_SET_QUALITY, NULL));
5239949213aSStephan Aßmus 
5242e49ff35SSiarzhuk Zharski 	fSmoothingSlider = new SSlider("smoothing",
5252e49ff35SSiarzhuk Zharski 		B_TRANSLATE("Output smoothing strength"),
5268687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_SMOOTHING), 0, 100);
5278687ff64SAxel Dörfler 	fSmoothingSlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
5288687ff64SAxel Dörfler 	fSmoothingSlider->SetHashMarkCount(10);
52903901b6cSJérôme Duval 	fSmoothingSlider->SetLimitLabels(B_TRANSLATE("None"), B_TRANSLATE("High"));
530b98ef4f9SStephan Aßmus 	fSmoothingSlider->SetValue(
531b98ef4f9SStephan Aßmus 		fSettings->SetGetInt32(JPEG_SET_SMOOTHING, NULL));
5329949213aSStephan Aßmus 
5332e49ff35SSiarzhuk Zharski 	fProgress = new BCheckBox("progress",
5342e49ff35SSiarzhuk Zharski 		B_TRANSLATE("Use progressive compression"),
5358687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_PROGRESSIVE));
536b98ef4f9SStephan Aßmus 	if (fSettings->SetGetBool(JPEG_SET_PROGRESSIVE, NULL))
537b98ef4f9SStephan Aßmus 		fProgress->SetValue(B_CONTROL_ON);
5389949213aSStephan Aßmus 
5392e49ff35SSiarzhuk Zharski 	fSmallerFile = new BCheckBox("smallerfile",
5402e49ff35SSiarzhuk Zharski 		B_TRANSLATE("Make file smaller (sligthtly worse quality)"),
5418687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_SMALLERFILE));
542b98ef4f9SStephan Aßmus 	if (fSettings->SetGetBool(JPEG_SET_SMALL_FILES))
543b98ef4f9SStephan Aßmus 		fSmallerFile->SetValue(B_CONTROL_ON);
544b98ef4f9SStephan Aßmus 
5452e49ff35SSiarzhuk Zharski 	fOptimizeColors = new BCheckBox("optimizecolors",
5462e49ff35SSiarzhuk Zharski 		B_TRANSLATE("Prevent colors 'washing out'"),
547b98ef4f9SStephan Aßmus 		new BMessage(VIEW_MSG_SET_OPTIMIZECOLORS));
548b98ef4f9SStephan Aßmus 	if (fSettings->SetGetBool(JPEG_SET_OPT_COLORS, NULL))
549b98ef4f9SStephan Aßmus 		fOptimizeColors->SetValue(B_CONTROL_ON);
550b98ef4f9SStephan Aßmus 	else
5518687ff64SAxel Dörfler 		fSmallerFile->SetEnabled(false);
5529949213aSStephan Aßmus 
5532e49ff35SSiarzhuk Zharski 	fGrayAsRGB24 = new BCheckBox("gray1asrgb24",
5542e49ff35SSiarzhuk Zharski 		B_TRANSLATE("Write black-and-white images as RGB24"),
5558687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_GRAY1ASRGB24));
556b98ef4f9SStephan Aßmus 	if (fSettings->SetGetBool(JPEG_SET_GRAY1_AS_RGB24))
557b98ef4f9SStephan Aßmus 		fGrayAsRGB24->SetValue(B_CONTROL_ON);
5589949213aSStephan Aßmus 
559b98ef4f9SStephan Aßmus 	float padding = 5.0f;
560*7d48219bSHannah Boneß 	BLayoutBuilder::Group<>(this, B_VERTICAL, padding)
561*7d48219bSHannah Boneß 		.SetInsets(padding)
562b98ef4f9SStephan Aßmus 		.Add(fQualitySlider)
563b98ef4f9SStephan Aßmus 		.Add(fSmoothingSlider)
564b98ef4f9SStephan Aßmus 		.Add(fProgress)
565b98ef4f9SStephan Aßmus 		.Add(fOptimizeColors)
566b98ef4f9SStephan Aßmus 		.Add(fSmallerFile)
567b98ef4f9SStephan Aßmus 		.Add(fGrayAsRGB24)
568*7d48219bSHannah Boneß 		.AddGlue();
569b98ef4f9SStephan Aßmus }
5709949213aSStephan Aßmus 
571b98ef4f9SStephan Aßmus 
572b98ef4f9SStephan Aßmus TranslatorWriteView::~TranslatorWriteView()
573b98ef4f9SStephan Aßmus {
574b98ef4f9SStephan Aßmus 	fSettings->Release();
5759949213aSStephan Aßmus }
5769949213aSStephan Aßmus 
5778687ff64SAxel Dörfler 
5789949213aSStephan Aßmus void
5799949213aSStephan Aßmus TranslatorWriteView::AttachedToWindow()
5809949213aSStephan Aßmus {
581b98ef4f9SStephan Aßmus 	BView::AttachedToWindow();
582b20d13f4SStefano Ceccherini 
5838687ff64SAxel Dörfler 	fQualitySlider->SetTarget(this);
5848687ff64SAxel Dörfler 	fSmoothingSlider->SetTarget(this);
5858687ff64SAxel Dörfler 	fProgress->SetTarget(this);
5868687ff64SAxel Dörfler 	fOptimizeColors->SetTarget(this);
5878687ff64SAxel Dörfler 	fSmallerFile->SetTarget(this);
5888687ff64SAxel Dörfler 	fGrayAsRGB24->SetTarget(this);
5899949213aSStephan Aßmus }
5909949213aSStephan Aßmus 
5918687ff64SAxel Dörfler 
5929949213aSStephan Aßmus void
5939949213aSStephan Aßmus TranslatorWriteView::MessageReceived(BMessage* message)
5949949213aSStephan Aßmus {
5958687ff64SAxel Dörfler 	switch (message->what) {
5969949213aSStephan Aßmus 		case VIEW_MSG_SET_QUALITY:
5979949213aSStephan Aßmus 		{
5989949213aSStephan Aßmus 			int32 value;
5999949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
600b98ef4f9SStephan Aßmus 				fSettings->SetGetInt32(JPEG_SET_QUALITY, &value);
601b98ef4f9SStephan Aßmus 				fSettings->SaveSettings();
6029949213aSStephan Aßmus 			}
6039949213aSStephan Aßmus 			break;
6049949213aSStephan Aßmus 		}
6059949213aSStephan Aßmus 		case VIEW_MSG_SET_SMOOTHING:
6069949213aSStephan Aßmus 		{
6079949213aSStephan Aßmus 			int32 value;
6089949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
609b98ef4f9SStephan Aßmus 				fSettings->SetGetInt32(JPEG_SET_SMOOTHING, &value);
610b98ef4f9SStephan Aßmus 				fSettings->SaveSettings();
6119949213aSStephan Aßmus 			}
6129949213aSStephan Aßmus 			break;
6139949213aSStephan Aßmus 		}
6149949213aSStephan Aßmus 		case VIEW_MSG_SET_PROGRESSIVE:
6159949213aSStephan Aßmus 		{
6169949213aSStephan Aßmus 			int32 value;
6179949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
618b98ef4f9SStephan Aßmus 				bool boolValue = value;
619b98ef4f9SStephan Aßmus 				fSettings->SetGetBool(JPEG_SET_PROGRESSIVE, &boolValue);
620b98ef4f9SStephan Aßmus 				fSettings->SaveSettings();
6219949213aSStephan Aßmus 			}
6229949213aSStephan Aßmus 			break;
6239949213aSStephan Aßmus 		}
6249949213aSStephan Aßmus 		case VIEW_MSG_SET_OPTIMIZECOLORS:
6259949213aSStephan Aßmus 		{
6269949213aSStephan Aßmus 			int32 value;
6279949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
628b98ef4f9SStephan Aßmus 				bool boolValue = value;
629b98ef4f9SStephan Aßmus 				fSettings->SetGetBool(JPEG_SET_OPT_COLORS, &boolValue);
630b98ef4f9SStephan Aßmus 				fSmallerFile->SetEnabled(value);
631b98ef4f9SStephan Aßmus 				fSettings->SaveSettings();
6329949213aSStephan Aßmus 			}
6339949213aSStephan Aßmus 			break;
6349949213aSStephan Aßmus 		}
6359949213aSStephan Aßmus 		case VIEW_MSG_SET_SMALLERFILE:
6369949213aSStephan Aßmus 		{
6379949213aSStephan Aßmus 			int32 value;
6389949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
639b98ef4f9SStephan Aßmus 				bool boolValue = value;
640b98ef4f9SStephan Aßmus 				fSettings->SetGetBool(JPEG_SET_SMALL_FILES, &boolValue);
641b98ef4f9SStephan Aßmus 				fSettings->SaveSettings();
6429949213aSStephan Aßmus 			}
6439949213aSStephan Aßmus 			break;
6449949213aSStephan Aßmus 		}
6459949213aSStephan Aßmus 		case VIEW_MSG_SET_GRAY1ASRGB24:
6469949213aSStephan Aßmus 		{
6479949213aSStephan Aßmus 			int32 value;
6489949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
649b98ef4f9SStephan Aßmus 				bool boolValue = value;
650b98ef4f9SStephan Aßmus 				fSettings->SetGetBool(JPEG_SET_GRAY1_AS_RGB24, &boolValue);
651b98ef4f9SStephan Aßmus 				fSettings->SaveSettings();
6529949213aSStephan Aßmus 			}
6539949213aSStephan Aßmus 			break;
6549949213aSStephan Aßmus 		}
6559949213aSStephan Aßmus 		default:
6569949213aSStephan Aßmus 			BView::MessageReceived(message);
6579949213aSStephan Aßmus 			break;
6589949213aSStephan Aßmus 	}
6599949213aSStephan Aßmus }
6609949213aSStephan Aßmus 
6619949213aSStephan Aßmus 
662d8e2fb50SAxel Dörfler //	#pragma mark -
6639949213aSStephan Aßmus 
664d8e2fb50SAxel Dörfler 
665b98ef4f9SStephan Aßmus TranslatorAboutView::TranslatorAboutView(const char* name)
666b98ef4f9SStephan Aßmus 	:
667b98ef4f9SStephan Aßmus 	BView(name, 0, new BGroupLayout(B_VERTICAL))
6689949213aSStephan Aßmus {
669b98ef4f9SStephan Aßmus 	BAlignment labelAlignment = BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP);
6701da233a7SSiarzhuk Zharski 	BStringView* title = new BStringView("Title", sTranslatorName);
6719949213aSStephan Aßmus 	title->SetFont(be_bold_font);
672b98ef4f9SStephan Aßmus 	title->SetExplicitAlignment(labelAlignment);
6739949213aSStephan Aßmus 
6749949213aSStephan Aßmus 	char versionString[16];
675bf243977SPhilippe Houdoin 	sprintf(versionString, "v%d.%d.%d", (int)(sTranslatorVersion >> 8),
676bf243977SPhilippe Houdoin 		(int)((sTranslatorVersion >> 4) & 0xf), (int)(sTranslatorVersion & 0xf));
6779949213aSStephan Aßmus 
678b98ef4f9SStephan Aßmus 	BStringView* version = new BStringView("Version", versionString);
679b98ef4f9SStephan Aßmus 	version->SetExplicitAlignment(labelAlignment);
6809949213aSStephan Aßmus 
681b98ef4f9SStephan Aßmus 	BTextView* infoView = new BTextView("info");
6822e49ff35SSiarzhuk Zharski 	infoView->SetText(sTranslatorInfo);
683b98ef4f9SStephan Aßmus 	infoView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
684b98ef4f9SStephan Aßmus 	infoView->MakeEditable(false);
6859949213aSStephan Aßmus 
686b98ef4f9SStephan Aßmus 	float padding = 5.0f;
687*7d48219bSHannah Boneß 	BLayoutBuilder::Group<>(this, B_VERTICAL, padding)
688*7d48219bSHannah Boneß 		.SetInsets(padding)
689*7d48219bSHannah Boneß 		.AddGroup(B_HORIZONTAL, padding)
690b98ef4f9SStephan Aßmus 			.Add(title)
691b98ef4f9SStephan Aßmus 			.Add(version)
692b98ef4f9SStephan Aßmus 			.AddGlue()
693*7d48219bSHannah Boneß 		.End()
694*7d48219bSHannah Boneß 		.Add(infoView);
6959949213aSStephan Aßmus }
6969949213aSStephan Aßmus 
6979949213aSStephan Aßmus 
698b98ef4f9SStephan Aßmus TranslatorView::TranslatorView(const char* name, TranslatorSettings* settings)
699b98ef4f9SStephan Aßmus 	:
700b98ef4f9SStephan Aßmus 	BTabView(name)
7019949213aSStephan Aßmus {
70270d59669SSiarzhuk Zharski 	AddTab(new TranslatorWriteView(B_TRANSLATE("Write"), settings->Acquire()));
70370d59669SSiarzhuk Zharski 	AddTab(new TranslatorReadView(B_TRANSLATE("Read"), settings->Acquire()));
70470d59669SSiarzhuk Zharski 	AddTab(new TranslatorAboutView(B_TRANSLATE("About")));
7059949213aSStephan Aßmus 
706b98ef4f9SStephan Aßmus 	settings->Release();
7079949213aSStephan Aßmus 
708b98ef4f9SStephan Aßmus  	BFont font;
709b98ef4f9SStephan Aßmus  	GetFont(&font);
710b98ef4f9SStephan Aßmus  	SetExplicitPreferredSize(
711b98ef4f9SStephan Aßmus 		BSize((font.Size() * 380) / 12, (font.Size() * 250) / 12));
7129949213aSStephan Aßmus }
7139949213aSStephan Aßmus 
7149949213aSStephan Aßmus 
715d8e2fb50SAxel Dörfler //	#pragma mark - Translator Add-On
7169949213aSStephan Aßmus 
7179949213aSStephan Aßmus 
718b98ef4f9SStephan Aßmus BView*
719b98ef4f9SStephan Aßmus JPEGTranslator::NewConfigView(TranslatorSettings* settings)
7209949213aSStephan Aßmus {
721b98ef4f9SStephan Aßmus 	BView* configView = new TranslatorView("TranslatorView", settings);
722b98ef4f9SStephan Aßmus 	return configView;
7239949213aSStephan Aßmus }
7249949213aSStephan Aßmus 
725b98ef4f9SStephan Aßmus 
726d8e2fb50SAxel Dörfler /*! Determine whether or not we can handle this data */
7279949213aSStephan Aßmus status_t
728b98ef4f9SStephan Aßmus JPEGTranslator::DerivedIdentify(BPositionIO* inSource,
729b98ef4f9SStephan Aßmus 	const translation_format* inFormat, BMessage* ioExtension,
730b98ef4f9SStephan Aßmus 	translator_info* outInfo, uint32 outType)
7319949213aSStephan Aßmus {
732d8e2fb50SAxel Dörfler 	if (outType != 0 && outType != B_TRANSLATOR_BITMAP && outType != JPEG_FORMAT)
7339949213aSStephan Aßmus 		return B_NO_TRANSLATOR;
7349949213aSStephan Aßmus 
7359949213aSStephan Aßmus 	// !!! You might need to make this buffer bigger to test for your native format
7369949213aSStephan Aßmus 	off_t position = inSource->Position();
7379949213aSStephan Aßmus 	char header[sizeof(TranslatorBitmap)];
7389949213aSStephan Aßmus 	status_t err = inSource->Read(header, sizeof(TranslatorBitmap));
7399949213aSStephan Aßmus 	inSource->Seek(position, SEEK_SET);
740d8e2fb50SAxel Dörfler 	if (err < B_OK)
741d8e2fb50SAxel Dörfler 		return err;
7429949213aSStephan Aßmus 
7439949213aSStephan Aßmus 	if (B_BENDIAN_TO_HOST_INT32(((TranslatorBitmap *)header)->magic) == B_TRANSLATOR_BITMAP) {
744b98ef4f9SStephan Aßmus 		if (PopulateInfoFromFormat(outInfo, B_TRANSLATOR_BITMAP) != B_OK)
745b98ef4f9SStephan Aßmus 			return B_NO_TRANSLATOR;
7469949213aSStephan Aßmus 	} else {
7479949213aSStephan Aßmus 		// First 3 bytes in jpg files are always the same from what i've seen so far
7489949213aSStephan Aßmus 		// check them
7499949213aSStephan Aßmus 		if (header[0] == (char)0xff && header[1] == (char)0xd8 && header[2] == (char)0xff) {
750b98ef4f9SStephan Aßmus 			if (PopulateInfoFromFormat(outInfo, JPEG_FORMAT) != B_OK)
7519949213aSStephan Aßmus 				return B_NO_TRANSLATOR;
752b98ef4f9SStephan Aßmus 
7539949213aSStephan Aßmus 		} else
7549949213aSStephan Aßmus 			return B_NO_TRANSLATOR;
7559949213aSStephan Aßmus 	}
7569949213aSStephan Aßmus 
7579949213aSStephan Aßmus 	return B_OK;
7589949213aSStephan Aßmus }
7599949213aSStephan Aßmus 
760b98ef4f9SStephan Aßmus 
7619949213aSStephan Aßmus status_t
762b98ef4f9SStephan Aßmus JPEGTranslator::DerivedTranslate(BPositionIO* inSource,
763b98ef4f9SStephan Aßmus 	const translator_info* inInfo, BMessage* ioExtension, uint32 outType,
764b98ef4f9SStephan Aßmus 	BPositionIO* outDestination, int32 baseType)
7659949213aSStephan Aßmus {
7669949213aSStephan Aßmus 	// If no specific type was requested, convert to the interchange format
767dbc936acSStephan Aßmus 	if (outType == 0)
768dbc936acSStephan Aßmus 		outType = B_TRANSLATOR_BITMAP;
7699949213aSStephan Aßmus 
770dbc936acSStephan Aßmus 	// Setup a "breakpoint" since throwing exceptions does not seem to work
771dbc936acSStephan Aßmus 	// at all in an add-on. (?)
772dbc936acSStephan Aßmus 	// In the be_jerror.cpp we implement a handler for critical library errors
773dbc936acSStephan Aßmus 	// (be_error_exit()) and there we use the longjmp() function to return to
774dbc936acSStephan Aßmus 	// this place. If this happens, it is as if the setjmp() call is called
775dbc936acSStephan Aßmus 	// a second time, but this time the return value will be 1. The first
776dbc936acSStephan Aßmus 	// invokation will return 0.
777b91634cbSStephan Aßmus 	jmp_buf longJumpBuffer;
778b91634cbSStephan Aßmus 	int jmpRet = setjmp(longJumpBuffer);
779dbc936acSStephan Aßmus 	if (jmpRet == 1)
780dbc936acSStephan Aßmus 		return B_ERROR;
781dbc936acSStephan Aßmus 
782dbc936acSStephan Aßmus 	try {
7839949213aSStephan Aßmus 		// What action to take, based on the findings of Identify()
7849949213aSStephan Aßmus 		if (outType == inInfo->type) {
7859949213aSStephan Aßmus 			return Copy(inSource, outDestination);
786dbc936acSStephan Aßmus 		} else if (inInfo->type == B_TRANSLATOR_BITMAP
787dbc936acSStephan Aßmus 				&& outType == JPEG_FORMAT) {
788b91634cbSStephan Aßmus 			return Compress(inSource, outDestination, &longJumpBuffer);
789dbc936acSStephan Aßmus 		} else if (inInfo->type == JPEG_FORMAT
790dbc936acSStephan Aßmus 				&& outType == B_TRANSLATOR_BITMAP) {
791b91634cbSStephan Aßmus 			return Decompress(inSource, outDestination, ioExtension,
792b91634cbSStephan Aßmus 				&longJumpBuffer);
7939949213aSStephan Aßmus 		}
794dbc936acSStephan Aßmus 	} catch (...) {
79570d59669SSiarzhuk Zharski 		syslog(LOG_ERR, "libjpeg encountered a critical error (caught C++ "
79670d59669SSiarzhuk Zharski 			"exception).\n");
797dbc936acSStephan Aßmus 		return B_ERROR;
798dbc936acSStephan Aßmus 	}
7999949213aSStephan Aßmus 
8009949213aSStephan Aßmus 	return B_NO_TRANSLATOR;
8019949213aSStephan Aßmus }
8029949213aSStephan Aßmus 
803b98ef4f9SStephan Aßmus 
804d8e2fb50SAxel Dörfler /*!	The user has requested the same format for input and output, so just copy */
805b98ef4f9SStephan Aßmus status_t
806b98ef4f9SStephan Aßmus JPEGTranslator::Copy(BPositionIO* in, BPositionIO* out)
8079949213aSStephan Aßmus {
8089949213aSStephan Aßmus 	int block_size = 65536;
8099949213aSStephan Aßmus 	void* buffer = malloc(block_size);
8109949213aSStephan Aßmus 	char temp[1024];
8119949213aSStephan Aßmus 	if (buffer == NULL) {
8129949213aSStephan Aßmus 		buffer = temp;
8139949213aSStephan Aßmus 		block_size = 1024;
8149949213aSStephan Aßmus 	}
8159949213aSStephan Aßmus 	status_t err = B_OK;
8169949213aSStephan Aßmus 
8179949213aSStephan Aßmus 	// Read until end of file or error
8189949213aSStephan Aßmus 	while (1) {
8199949213aSStephan Aßmus 		ssize_t to_read = block_size;
8209949213aSStephan Aßmus 		err = in->Read(buffer, to_read);
8219949213aSStephan Aßmus 		// Explicit check for EOF
8229949213aSStephan Aßmus 		if (err == -1) {
8239949213aSStephan Aßmus 			if (buffer != temp) free(buffer);
8249949213aSStephan Aßmus 			return B_OK;
8259949213aSStephan Aßmus 		}
8269949213aSStephan Aßmus 		if (err <= B_OK) break;
8279949213aSStephan Aßmus 		to_read = err;
8289949213aSStephan Aßmus 		err = out->Write(buffer, to_read);
8299949213aSStephan Aßmus 		if (err != to_read) if (err >= 0) err = B_DEVICE_FULL;
8309949213aSStephan Aßmus 		if (err < B_OK) break;
8319949213aSStephan Aßmus 	}
8329949213aSStephan Aßmus 
8339949213aSStephan Aßmus 	if (buffer != temp) free(buffer);
8349949213aSStephan Aßmus 	return (err >= 0) ? B_OK : err;
8359949213aSStephan Aßmus }
8369949213aSStephan Aßmus 
837d8e2fb50SAxel Dörfler 
838d8e2fb50SAxel Dörfler /*!	Encode into the native format */
839b98ef4f9SStephan Aßmus status_t
840b98ef4f9SStephan Aßmus JPEGTranslator::Compress(BPositionIO* in, BPositionIO* out,
841b98ef4f9SStephan Aßmus 	const jmp_buf* longJumpBuffer)
8429949213aSStephan Aßmus {
843b98ef4f9SStephan Aßmus 	using namespace conversion;
8449949213aSStephan Aßmus 
8459949213aSStephan Aßmus 	// Read info about bitmap
8469949213aSStephan Aßmus 	TranslatorBitmap header;
8479949213aSStephan Aßmus 	status_t err = in->Read(&header, sizeof(TranslatorBitmap));
848d8e2fb50SAxel Dörfler 	if (err < B_OK)
849d8e2fb50SAxel Dörfler 		return err;
850d8e2fb50SAxel Dörfler 	else if (err < (int)sizeof(TranslatorBitmap))
851d8e2fb50SAxel Dörfler 		return B_ERROR;
8529949213aSStephan Aßmus 
8539949213aSStephan Aßmus 	// Grab dimension, color space, and size information from the stream
8549949213aSStephan Aßmus 	BRect bounds;
8559949213aSStephan Aßmus 	bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left);
8569949213aSStephan Aßmus 	bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top);
8579949213aSStephan Aßmus 	bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right);
8589949213aSStephan Aßmus 	bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom);
8599949213aSStephan Aßmus 
8609949213aSStephan Aßmus 	int32 in_row_bytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes);
8619949213aSStephan Aßmus 
8629949213aSStephan Aßmus 	int width = bounds.IntegerWidth() + 1;
8639949213aSStephan Aßmus 	int height = bounds.IntegerHeight() + 1;
8649949213aSStephan Aßmus 
8659949213aSStephan Aßmus 	// Function pointer to convert function
8669949213aSStephan Aßmus 	// It will point to proper function if needed
8679e34f742SAxel Dörfler 	void (*converter)(uchar* inscanline, uchar* outscanline,
8689e34f742SAxel Dörfler 		int32 inRowBytes) = NULL;
8699949213aSStephan Aßmus 
8709949213aSStephan Aßmus 	// Default color info
8719949213aSStephan Aßmus 	J_COLOR_SPACE jpg_color_space = JCS_RGB;
8729949213aSStephan Aßmus 	int jpg_input_components = 3;
8739949213aSStephan Aßmus 	int32 out_row_bytes;
8749949213aSStephan Aßmus 	int padding = 0;
8759949213aSStephan Aßmus 
876d8e2fb50SAxel Dörfler 	switch ((color_space)B_BENDIAN_TO_HOST_INT32(header.colors)) {
8779949213aSStephan Aßmus 		case B_CMAP8:
8789949213aSStephan Aßmus 			converter = convert_from_cmap8_to_24;
8799949213aSStephan Aßmus 			padding = in_row_bytes - width;
8809949213aSStephan Aßmus 			break;
881d8e2fb50SAxel Dörfler 
8829949213aSStephan Aßmus 		case B_GRAY1:
883b98ef4f9SStephan Aßmus 			if (fSettings->SetGetBool(JPEG_SET_GRAY1_AS_RGB24, NULL)) {
8849949213aSStephan Aßmus 				converter = convert_from_gray1_to_24;
8859949213aSStephan Aßmus 			} else {
8869949213aSStephan Aßmus 				jpg_input_components = 1;
8879949213aSStephan Aßmus 				jpg_color_space = JCS_GRAYSCALE;
8889949213aSStephan Aßmus 				converter = convert_from_gray1_to_gray8;
8899949213aSStephan Aßmus 			}
8909949213aSStephan Aßmus 			padding = in_row_bytes - (width / 8);
8919949213aSStephan Aßmus 			break;
892d8e2fb50SAxel Dörfler 
8939949213aSStephan Aßmus 		case B_GRAY8:
8949949213aSStephan Aßmus 			jpg_input_components = 1;
8959949213aSStephan Aßmus 			jpg_color_space = JCS_GRAYSCALE;
8969949213aSStephan Aßmus 			padding = in_row_bytes - width;
8979949213aSStephan Aßmus 			break;
898d8e2fb50SAxel Dörfler 
8999949213aSStephan Aßmus 		case B_RGB15:
9009949213aSStephan Aßmus 		case B_RGBA15:
9019949213aSStephan Aßmus 			converter = convert_from_15_to_24;
9029949213aSStephan Aßmus 			padding = in_row_bytes - (width * 2);
9039949213aSStephan Aßmus 			break;
904d8e2fb50SAxel Dörfler 
9059949213aSStephan Aßmus 		case B_RGB15_BIG:
9069949213aSStephan Aßmus 		case B_RGBA15_BIG:
9079949213aSStephan Aßmus 			converter = convert_from_15b_to_24;
9089949213aSStephan Aßmus 			padding = in_row_bytes - (width * 2);
9099949213aSStephan Aßmus 			break;
910d8e2fb50SAxel Dörfler 
9119949213aSStephan Aßmus 		case B_RGB16:
9129949213aSStephan Aßmus 			converter = convert_from_16_to_24;
9139949213aSStephan Aßmus 			padding = in_row_bytes - (width * 2);
9149949213aSStephan Aßmus 			break;
915d8e2fb50SAxel Dörfler 
9169949213aSStephan Aßmus 		case B_RGB16_BIG:
9179949213aSStephan Aßmus 			converter = convert_from_16b_to_24;
9189949213aSStephan Aßmus 			padding = in_row_bytes - (width * 2);
9199949213aSStephan Aßmus 			break;
920d8e2fb50SAxel Dörfler 
9219949213aSStephan Aßmus 		case B_RGB24:
9229949213aSStephan Aßmus 			converter = convert_from_24_to_24;
9239949213aSStephan Aßmus 			padding = in_row_bytes - (width * 3);
9249949213aSStephan Aßmus 			break;
925d8e2fb50SAxel Dörfler 
9269949213aSStephan Aßmus 		case B_RGB24_BIG:
9279949213aSStephan Aßmus 			padding = in_row_bytes - (width * 3);
9289949213aSStephan Aßmus 			break;
929d8e2fb50SAxel Dörfler 
9309949213aSStephan Aßmus 		case B_RGB32:
9319949213aSStephan Aßmus 		case B_RGBA32:
9329949213aSStephan Aßmus 			converter = convert_from_32_to_24;
9339949213aSStephan Aßmus 			padding = in_row_bytes - (width * 4);
9349949213aSStephan Aßmus 			break;
935d8e2fb50SAxel Dörfler 
9369949213aSStephan Aßmus 		case B_RGB32_BIG:
9379949213aSStephan Aßmus 		case B_RGBA32_BIG:
9389949213aSStephan Aßmus 			converter = convert_from_32b_to_24;
9399949213aSStephan Aßmus 			padding = in_row_bytes - (width * 4);
9409949213aSStephan Aßmus 			break;
941d8e2fb50SAxel Dörfler 
9429949213aSStephan Aßmus 		case B_CMYK32:
9439949213aSStephan Aßmus 			jpg_color_space = JCS_CMYK;
9449949213aSStephan Aßmus 			jpg_input_components = 4;
9459949213aSStephan Aßmus 			padding = in_row_bytes - (width * 4);
9469949213aSStephan Aßmus 			break;
947d8e2fb50SAxel Dörfler 
9489949213aSStephan Aßmus 		default:
94970d59669SSiarzhuk Zharski 			syslog(LOG_ERR, "Wrong type: Color space not implemented.\n");
9509949213aSStephan Aßmus 			return B_ERROR;
9519949213aSStephan Aßmus 	}
9529949213aSStephan Aßmus 	out_row_bytes = jpg_input_components * width;
9539949213aSStephan Aßmus 
9549949213aSStephan Aßmus 	// Set basic things needed for jpeg writing
9559949213aSStephan Aßmus 	struct jpeg_compress_struct cinfo;
9569949213aSStephan Aßmus 	struct jpeg_error_mgr jerr;
957b98ef4f9SStephan Aßmus 	cinfo.err = be_jpeg_std_error(&jerr, fSettings, longJumpBuffer);
9589949213aSStephan Aßmus 	jpeg_create_compress(&cinfo);
9599949213aSStephan Aßmus 	be_jpeg_stdio_dest(&cinfo, out);
9609949213aSStephan Aßmus 
9619949213aSStephan Aßmus 	// Set basic values
9629949213aSStephan Aßmus 	cinfo.image_width = width;
9639949213aSStephan Aßmus 	cinfo.image_height = height;
9649949213aSStephan Aßmus 	cinfo.input_components = jpg_input_components;
9659949213aSStephan Aßmus 	cinfo.in_color_space = jpg_color_space;
9669949213aSStephan Aßmus 	jpeg_set_defaults(&cinfo);
9679949213aSStephan Aßmus 
9689949213aSStephan Aßmus 	// Set better accuracy
9699949213aSStephan Aßmus 	cinfo.dct_method = JDCT_ISLOW;
9709949213aSStephan Aßmus 
9719949213aSStephan Aßmus 	// This is needed to prevent some colors loss
9729949213aSStephan Aßmus 	// With it generated jpegs are as good as from Fireworks (at last! :D)
973b98ef4f9SStephan Aßmus 	if (fSettings->SetGetBool(JPEG_SET_OPT_COLORS, NULL)) {
9749949213aSStephan Aßmus 		int index = 0;
9759949213aSStephan Aßmus 		while (index < cinfo.num_components) {
9769949213aSStephan Aßmus 			cinfo.comp_info[index].h_samp_factor = 1;
9779949213aSStephan Aßmus 			cinfo.comp_info[index].v_samp_factor = 1;
9789949213aSStephan Aßmus 			// This will make file smaller, but with worse quality more or less
9799949213aSStephan Aßmus 			// like with 93%-94% (but it's subjective opinion) on tested images
9809949213aSStephan Aßmus 			// but with smaller size (between 92% and 93% on tested images)
981b98ef4f9SStephan Aßmus 			if (fSettings->SetGetBool(JPEG_SET_SMALL_FILES))
9829949213aSStephan Aßmus 				cinfo.comp_info[index].quant_tbl_no = 1;
9839949213aSStephan Aßmus 			// This will make bigger file, but also better quality ;]
9849949213aSStephan Aßmus 			// from my tests it seems like useless - better quality with smaller
9859949213aSStephan Aßmus 			// can be acheived without this
9869949213aSStephan Aßmus //			cinfo.comp_info[index].dc_tbl_no = 1;
9879949213aSStephan Aßmus //			cinfo.comp_info[index].ac_tbl_no = 1;
9889949213aSStephan Aßmus 			index++;
9899949213aSStephan Aßmus 		}
9909949213aSStephan Aßmus 	}
9919949213aSStephan Aßmus 
9929949213aSStephan Aßmus 	// Set quality
993b98ef4f9SStephan Aßmus 	jpeg_set_quality(&cinfo, fSettings->SetGetInt32(JPEG_SET_QUALITY, NULL), true);
9949949213aSStephan Aßmus 
9959949213aSStephan Aßmus 	// Set progressive compression if needed
9969949213aSStephan Aßmus 	// if not, turn on optimizing in libjpeg
997b98ef4f9SStephan Aßmus 	if (fSettings->SetGetBool(JPEG_SET_PROGRESSIVE, NULL))
9989949213aSStephan Aßmus 		jpeg_simple_progression(&cinfo);
9999949213aSStephan Aßmus 	else
10009949213aSStephan Aßmus 		cinfo.optimize_coding = TRUE;
10019949213aSStephan Aßmus 
10029949213aSStephan Aßmus 	// Set smoothing (effect like Blur)
1003b98ef4f9SStephan Aßmus 	cinfo.smoothing_factor = fSettings->SetGetInt32(JPEG_SET_SMOOTHING, NULL);
10049949213aSStephan Aßmus 
10059949213aSStephan Aßmus 	// Initialize compression
10069949213aSStephan Aßmus 	jpeg_start_compress(&cinfo, TRUE);
10079949213aSStephan Aßmus 
10089949213aSStephan Aßmus 	// Declare scanlines
10099949213aSStephan Aßmus 	JSAMPROW in_scanline = NULL;
10109949213aSStephan Aßmus 	JSAMPROW out_scanline = NULL;
1011b98ef4f9SStephan Aßmus 	JSAMPROW writeline;
1012b98ef4f9SStephan Aßmus 		// Pointer to in_scanline (default) or out_scanline (if there will be conversion)
10139949213aSStephan Aßmus 
10149949213aSStephan Aßmus 	// Allocate scanline
10159949213aSStephan Aßmus 	// Use libjpeg memory allocation functions, so in case of error it will free them itself
1016d8e2fb50SAxel Dörfler 	in_scanline = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo,
1017d8e2fb50SAxel Dörfler 		JPOOL_PERMANENT, in_row_bytes);
10189949213aSStephan Aßmus 
10199949213aSStephan Aßmus 	// We need 2nd scanline storage ony for conversion
10209949213aSStephan Aßmus 	if (converter != NULL) {
10219949213aSStephan Aßmus 		// There will be conversion, allocate second scanline...
10229949213aSStephan Aßmus 		// Use libjpeg memory allocation functions, so in case of error it will free them itself
1023d8e2fb50SAxel Dörfler 	    out_scanline = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo,
1024d8e2fb50SAxel Dörfler 	    	JPOOL_PERMANENT, out_row_bytes);
10259949213aSStephan Aßmus 		// ... and make it the one to write to file
10269949213aSStephan Aßmus 		writeline = out_scanline;
10279949213aSStephan Aßmus 	} else
10289949213aSStephan Aßmus 		writeline = in_scanline;
10299949213aSStephan Aßmus 
10309949213aSStephan Aßmus 	while (cinfo.next_scanline < cinfo.image_height) {
10319949213aSStephan Aßmus 		// Read scanline
10329949213aSStephan Aßmus 		err = in->Read(in_scanline, in_row_bytes);
10339949213aSStephan Aßmus 		if (err < in_row_bytes)
1034d8e2fb50SAxel Dörfler 			return err < B_OK ? Error((j_common_ptr)&cinfo, err)
1035d8e2fb50SAxel Dörfler 				: Error((j_common_ptr)&cinfo, B_ERROR);
10369949213aSStephan Aßmus 
10379949213aSStephan Aßmus 		// Convert if needed
10389949213aSStephan Aßmus 		if (converter != NULL)
10399949213aSStephan Aßmus 			converter(in_scanline, out_scanline, in_row_bytes - padding);
10409949213aSStephan Aßmus 
10419949213aSStephan Aßmus 		// Write scanline
10429949213aSStephan Aßmus 	   	jpeg_write_scanlines(&cinfo, &writeline, 1);
10439949213aSStephan Aßmus 	}
10449949213aSStephan Aßmus 
10459949213aSStephan Aßmus 	jpeg_finish_compress(&cinfo);
10469949213aSStephan Aßmus 	jpeg_destroy_compress(&cinfo);
10479949213aSStephan Aßmus 	return B_OK;
10489949213aSStephan Aßmus }
10499949213aSStephan Aßmus 
1050d8e2fb50SAxel Dörfler 
1051d8e2fb50SAxel Dörfler /*!	Decode the native format */
1052b98ef4f9SStephan Aßmus status_t
1053b98ef4f9SStephan Aßmus JPEGTranslator::Decompress(BPositionIO* in, BPositionIO* out,
1054b98ef4f9SStephan Aßmus 	BMessage* ioExtension, const jmp_buf* longJumpBuffer)
10559949213aSStephan Aßmus {
1056b98ef4f9SStephan Aßmus 	using namespace conversion;
10579949213aSStephan Aßmus 
10589949213aSStephan Aßmus 	// Set basic things needed for jpeg reading
10599949213aSStephan Aßmus 	struct jpeg_decompress_struct cinfo;
10609949213aSStephan Aßmus 	struct jpeg_error_mgr jerr;
1061b98ef4f9SStephan Aßmus 	cinfo.err = be_jpeg_std_error(&jerr, fSettings, longJumpBuffer);
10629949213aSStephan Aßmus 	jpeg_create_decompress(&cinfo);
10639949213aSStephan Aßmus 	be_jpeg_stdio_src(&cinfo, in);
10649949213aSStephan Aßmus 
106552e8f46aSAxel Dörfler 	jpeg_save_markers(&cinfo, MARKER_EXIF, 131072);
106652e8f46aSAxel Dörfler 		// make sure the EXIF tag is stored
106752e8f46aSAxel Dörfler 
10689949213aSStephan Aßmus 	// Read info about image
10699949213aSStephan Aßmus 	jpeg_read_header(&cinfo, TRUE);
10709949213aSStephan Aßmus 
107152e8f46aSAxel Dörfler 	BMessage exif;
107252e8f46aSAxel Dörfler 
1073f13b5de6SAxel Dörfler 	// parse EXIF data and add it ioExtension, if any
107452e8f46aSAxel Dörfler 	jpeg_marker_struct* marker = cinfo.marker_list;
107552e8f46aSAxel Dörfler 	while (marker != NULL) {
107652e8f46aSAxel Dörfler 		if (marker->marker == MARKER_EXIF
107752e8f46aSAxel Dörfler 			&& !strncmp((char*)marker->data, "Exif", 4)) {
1078f13b5de6SAxel Dörfler 			if (ioExtension != NULL) {
107952e8f46aSAxel Dörfler 				// Strip EXIF header from TIFF data
108052e8f46aSAxel Dörfler 				ioExtension->AddData("exif", B_RAW_TYPE,
108152e8f46aSAxel Dörfler 					(uint8*)marker->data + 6, marker->data_length - 6);
1082f13b5de6SAxel Dörfler 			}
108352e8f46aSAxel Dörfler 
108452e8f46aSAxel Dörfler 			BMemoryIO io(marker->data + 6, marker->data_length - 6);
108552e8f46aSAxel Dörfler 			convert_exif_to_message(io, exif);
108652e8f46aSAxel Dörfler 		}
108752e8f46aSAxel Dörfler 		marker = marker->next;
108852e8f46aSAxel Dörfler 	}
108952e8f46aSAxel Dörfler 
10909949213aSStephan Aßmus 	// Default color info
109152e8f46aSAxel Dörfler 	color_space outColorSpace = B_RGB32;
109252e8f46aSAxel Dörfler 	int outColorComponents = 4;
10939949213aSStephan Aßmus 
10949949213aSStephan Aßmus 	// Function pointer to convert function
10959949213aSStephan Aßmus 	// It will point to proper function if needed
109652e8f46aSAxel Dörfler 	void (*converter)(uchar* inScanLine, uchar* outScanLine,
10979e34f742SAxel Dörfler 		int32 inRowBytes, int32 xStep) = convert_from_24_to_32;
10989949213aSStephan Aßmus 
10999949213aSStephan Aßmus 	// If color space isn't rgb
11009949213aSStephan Aßmus 	if (cinfo.out_color_space != JCS_RGB) {
1101d8e2fb50SAxel Dörfler 		switch (cinfo.out_color_space) {
11029949213aSStephan Aßmus 			case JCS_UNKNOWN:		/* error/unspecified */
110370d59669SSiarzhuk Zharski 				syslog(LOG_ERR, "From Type: Jpeg uses unknown color type\n");
11049949213aSStephan Aßmus 				break;
11059949213aSStephan Aßmus 			case JCS_GRAYSCALE:		/* monochrome */
11069949213aSStephan Aßmus 				// Check if user wants to read only as RGB32 or not
1107b98ef4f9SStephan Aßmus 				if (!fSettings->SetGetBool(JPEG_SET_ALWAYS_RGB32, NULL)) {
11089949213aSStephan Aßmus 					// Grayscale
110952e8f46aSAxel Dörfler 					outColorSpace = B_GRAY8;
111052e8f46aSAxel Dörfler 					outColorComponents = 1;
11119e34f742SAxel Dörfler 					converter = translate_8;
11129949213aSStephan Aßmus 				} else {
11139949213aSStephan Aßmus 					// RGB
11149949213aSStephan Aßmus 					cinfo.out_color_space = JCS_RGB;
11159949213aSStephan Aßmus 					cinfo.output_components = 3;
11169949213aSStephan Aßmus 					converter = convert_from_24_to_32;
11179949213aSStephan Aßmus 				}
11189949213aSStephan Aßmus 				break;
11199949213aSStephan Aßmus 			case JCS_YCbCr:		/* Y/Cb/Cr (also known as YUV) */
11209949213aSStephan Aßmus 				cinfo.out_color_space = JCS_RGB;
11219949213aSStephan Aßmus 				converter = convert_from_24_to_32;
11229949213aSStephan Aßmus 				break;
11239949213aSStephan Aßmus 			case JCS_YCCK:		/* Y/Cb/Cr/K */
11249949213aSStephan Aßmus 				// Let libjpeg convert it to CMYK
11259949213aSStephan Aßmus 				cinfo.out_color_space = JCS_CMYK;
11269949213aSStephan Aßmus 				// Fall through to CMYK since we need the same settings
11279949213aSStephan Aßmus 			case JCS_CMYK:		/* C/M/Y/K */
11289949213aSStephan Aßmus 				// Use proper converter
1129b98ef4f9SStephan Aßmus 				if (fSettings->SetGetBool(JPEG_SET_PHOTOSHOP_CMYK))
11309949213aSStephan Aßmus 					converter = convert_from_CMYK_to_32_photoshop;
11319949213aSStephan Aßmus 				else
11329949213aSStephan Aßmus 					converter = convert_from_CMYK_to_32;
11339949213aSStephan Aßmus 				break;
11349949213aSStephan Aßmus 			default:
113570d59669SSiarzhuk Zharski 				syslog(LOG_ERR,
113670d59669SSiarzhuk Zharski 						"From Type: Jpeg uses hmm... i don't know really :(\n");
11379949213aSStephan Aßmus 				break;
11389949213aSStephan Aßmus 		}
11399949213aSStephan Aßmus 	}
11409949213aSStephan Aßmus 
11419949213aSStephan Aßmus 	// Initialize decompression
11429949213aSStephan Aßmus 	jpeg_start_decompress(&cinfo);
11439949213aSStephan Aßmus 
11449e34f742SAxel Dörfler 	// retrieve orientation from settings/EXIF
114552e8f46aSAxel Dörfler 	int32 orientation;
11469e34f742SAxel Dörfler 	if (ioExtension == NULL
11479e34f742SAxel Dörfler 		|| ioExtension->FindInt32("exif:orientation", &orientation) != B_OK) {
114852e8f46aSAxel Dörfler 		if (exif.FindInt32("Orientation", &orientation) != B_OK)
114952e8f46aSAxel Dörfler 			orientation = 1;
115052e8f46aSAxel Dörfler 	}
11519949213aSStephan Aßmus 
11529e34f742SAxel Dörfler 	if (orientation != 1 && converter == NULL)
11539e34f742SAxel Dörfler 		converter = translate_8;
11549e34f742SAxel Dörfler 
11559e34f742SAxel Dörfler 	int32 outputWidth = orientation > 4 ? cinfo.output_height : cinfo.output_width;
11569e34f742SAxel Dörfler 	int32 outputHeight = orientation > 4 ? cinfo.output_width : cinfo.output_height;
11579e34f742SAxel Dörfler 
11589e34f742SAxel Dörfler 	int32 destOffset = dest_index(outputWidth, outputHeight,
11599e34f742SAxel Dörfler 		0, 0, orientation) * outColorComponents;
11609e34f742SAxel Dörfler 	int32 xStep = dest_index(outputWidth, outputHeight,
11619e34f742SAxel Dörfler 		1, 0, orientation) * outColorComponents - destOffset;
11629e34f742SAxel Dörfler 	int32 yStep = dest_index(outputWidth, outputHeight,
11639e34f742SAxel Dörfler 		0, 1, orientation) * outColorComponents - destOffset;
11649e34f742SAxel Dörfler 	bool needAll = orientation != 1;
11659e34f742SAxel Dörfler 
11669e34f742SAxel Dörfler 	// Initialize this bounds rect to the size of your image
11679e34f742SAxel Dörfler 	BRect bounds(0, 0, outputWidth - 1, outputHeight - 1);
11689e34f742SAxel Dörfler 
11699e34f742SAxel Dörfler #if 0
11709e34f742SAxel Dörfler printf("destOffset = %ld, xStep = %ld, yStep = %ld, input: %ld x %ld, output: %ld x %ld, orientation %ld\n",
11719e34f742SAxel Dörfler 	destOffset, xStep, yStep, (int32)cinfo.output_width, (int32)cinfo.output_height,
11729e34f742SAxel Dörfler 	bounds.IntegerWidth() + 1, bounds.IntegerHeight() + 1, orientation);
11739e34f742SAxel Dörfler #endif
11749e34f742SAxel Dörfler 
11759949213aSStephan Aßmus 	// Bytes count in one line of image (scanline)
11769e34f742SAxel Dörfler 	int32 inRowBytes = cinfo.output_width * cinfo.output_components;
11779e34f742SAxel Dörfler 	int32 rowBytes = (bounds.IntegerWidth() + 1) * outColorComponents;
11789e34f742SAxel Dörfler 	int32 dataSize = cinfo.output_width * cinfo.output_height
11799e34f742SAxel Dörfler 		* outColorComponents;
11809949213aSStephan Aßmus 
11819949213aSStephan Aßmus 	// Fill out the B_TRANSLATOR_BITMAP's header
11829949213aSStephan Aßmus 	TranslatorBitmap header;
11839949213aSStephan Aßmus 	header.magic = B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP);
11849949213aSStephan Aßmus 	header.bounds.left = B_HOST_TO_BENDIAN_FLOAT(bounds.left);
11859949213aSStephan Aßmus 	header.bounds.top = B_HOST_TO_BENDIAN_FLOAT(bounds.top);
11869949213aSStephan Aßmus 	header.bounds.right = B_HOST_TO_BENDIAN_FLOAT(bounds.right);
11879949213aSStephan Aßmus 	header.bounds.bottom = B_HOST_TO_BENDIAN_FLOAT(bounds.bottom);
118852e8f46aSAxel Dörfler 	header.colors = (color_space)B_HOST_TO_BENDIAN_INT32(outColorSpace);
118952e8f46aSAxel Dörfler 	header.rowBytes = B_HOST_TO_BENDIAN_INT32(rowBytes);
11909e34f742SAxel Dörfler 	header.dataSize = B_HOST_TO_BENDIAN_INT32(dataSize);
11919949213aSStephan Aßmus 
11929949213aSStephan Aßmus 	// Write out the header
11939949213aSStephan Aßmus 	status_t err = out->Write(&header, sizeof(TranslatorBitmap));
1194d8e2fb50SAxel Dörfler 	if (err < B_OK)
1195d8e2fb50SAxel Dörfler 		return Error((j_common_ptr)&cinfo, err);
1196d8e2fb50SAxel Dörfler 	else if (err < (int)sizeof(TranslatorBitmap))
1197d8e2fb50SAxel Dörfler 		return Error((j_common_ptr)&cinfo, B_ERROR);
11989949213aSStephan Aßmus 
11999949213aSStephan Aßmus 	// Declare scanlines
12009e34f742SAxel Dörfler 	JSAMPROW inScanLine = NULL;
12019e34f742SAxel Dörfler 	uint8* dest = NULL;
12029e34f742SAxel Dörfler 	uint8* destLine = NULL;
12039949213aSStephan Aßmus 
12049949213aSStephan Aßmus 	// Allocate scanline
12059949213aSStephan Aßmus 	// Use libjpeg memory allocation functions, so in case of error it will free them itself
12069e34f742SAxel Dörfler     inScanLine = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo,
12079e34f742SAxel Dörfler     	JPOOL_PERMANENT, inRowBytes);
12089949213aSStephan Aßmus 
12099949213aSStephan Aßmus 	// We need 2nd scanline storage only for conversion
12109949213aSStephan Aßmus 	if (converter != NULL) {
12119949213aSStephan Aßmus 		// There will be conversion, allocate second scanline...
1212b98ef4f9SStephan Aßmus 		// Use libjpeg memory allocation functions, so in case of error it will
1213b98ef4f9SStephan Aßmus 		// free them itself
12149e34f742SAxel Dörfler 	    dest = (uint8*)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo,
12159e34f742SAxel Dörfler 	    	JPOOL_PERMANENT, needAll ? dataSize : rowBytes);
12169e34f742SAxel Dörfler 	    destLine = dest + destOffset;
12179949213aSStephan Aßmus 	} else
12189e34f742SAxel Dörfler 		destLine = inScanLine;
12199949213aSStephan Aßmus 
12209949213aSStephan Aßmus 	while (cinfo.output_scanline < cinfo.output_height) {
12219949213aSStephan Aßmus 		// Read scanline
12229e34f742SAxel Dörfler 		jpeg_read_scanlines(&cinfo, &inScanLine, 1);
12239949213aSStephan Aßmus 
12249949213aSStephan Aßmus 		// Convert if needed
12259949213aSStephan Aßmus 		if (converter != NULL)
12269e34f742SAxel Dörfler 			converter(inScanLine, destLine, inRowBytes, xStep);
12279949213aSStephan Aßmus 
12289e34f742SAxel Dörfler 		if (!needAll) {
12299949213aSStephan Aßmus 	  		// Write the scanline buffer to the output stream
12309e34f742SAxel Dörfler 			ssize_t bytesWritten = out->Write(destLine, rowBytes);
12319e34f742SAxel Dörfler 			if (bytesWritten < rowBytes) {
12329e34f742SAxel Dörfler 				return bytesWritten < B_OK
12339e34f742SAxel Dörfler 					? Error((j_common_ptr)&cinfo, bytesWritten)
1234d8e2fb50SAxel Dörfler 					: Error((j_common_ptr)&cinfo, B_ERROR);
12359949213aSStephan Aßmus 			}
12369e34f742SAxel Dörfler 		} else
12379e34f742SAxel Dörfler 			destLine += yStep;
12389e34f742SAxel Dörfler 	}
12399e34f742SAxel Dörfler 
12409e34f742SAxel Dörfler 	if (needAll) {
12419e34f742SAxel Dörfler 		ssize_t bytesWritten = out->Write(dest, dataSize);
12429e34f742SAxel Dörfler 		if (bytesWritten < dataSize) {
12439e34f742SAxel Dörfler 			return bytesWritten < B_OK
12449e34f742SAxel Dörfler 				? Error((j_common_ptr)&cinfo, bytesWritten)
12459e34f742SAxel Dörfler 				: Error((j_common_ptr)&cinfo, B_ERROR);
12469e34f742SAxel Dörfler 		}
12479e34f742SAxel Dörfler 	}
12489949213aSStephan Aßmus 
12499949213aSStephan Aßmus 	jpeg_finish_decompress(&cinfo);
12509949213aSStephan Aßmus 	jpeg_destroy_decompress(&cinfo);
12519949213aSStephan Aßmus 	return B_OK;
12529949213aSStephan Aßmus }
12539949213aSStephan Aßmus 
1254b98ef4f9SStephan Aßmus /*! have the other PopulateInfoFromFormat() check both inputFormats & outputFormats */
1255b98ef4f9SStephan Aßmus status_t
1256b98ef4f9SStephan Aßmus JPEGTranslator::PopulateInfoFromFormat(translator_info* info,
1257b98ef4f9SStephan Aßmus 	uint32 formatType, translator_id id)
1258b98ef4f9SStephan Aßmus {
1259b98ef4f9SStephan Aßmus 	int32 formatCount;
1260b98ef4f9SStephan Aßmus 	const translation_format* formats = OutputFormats(&formatCount);
1261b98ef4f9SStephan Aßmus 	for (int i = 0; i <= 1 ;formats = InputFormats(&formatCount), i++) {
1262b98ef4f9SStephan Aßmus 		if (PopulateInfoFromFormat(info, formatType,
1263b98ef4f9SStephan Aßmus 			formats, formatCount) == B_OK) {
1264b98ef4f9SStephan Aßmus 			info->translator = id;
1265b98ef4f9SStephan Aßmus 			return B_OK;
1266b98ef4f9SStephan Aßmus 		}
1267b98ef4f9SStephan Aßmus 	}
1268b98ef4f9SStephan Aßmus 
1269b98ef4f9SStephan Aßmus 	return B_ERROR;
1270b98ef4f9SStephan Aßmus }
1271b98ef4f9SStephan Aßmus 
1272b98ef4f9SStephan Aßmus 
1273b98ef4f9SStephan Aßmus status_t
1274b98ef4f9SStephan Aßmus JPEGTranslator::PopulateInfoFromFormat(translator_info* info,
1275b98ef4f9SStephan Aßmus 	uint32 formatType, const translation_format* formats, int32 formatCount)
1276b98ef4f9SStephan Aßmus {
1277b98ef4f9SStephan Aßmus 	for (int i = 0; i < formatCount; i++) {
1278b98ef4f9SStephan Aßmus 		if (formats[i].type == formatType) {
1279b98ef4f9SStephan Aßmus 			info->type = formatType;
1280b98ef4f9SStephan Aßmus 			info->group = formats[i].group;
1281b98ef4f9SStephan Aßmus 			info->quality = formats[i].quality;
1282b98ef4f9SStephan Aßmus 			info->capability = formats[i].capability;
128370d59669SSiarzhuk Zharski 			BString str1(formats[i].name);
128470d59669SSiarzhuk Zharski 			str1.ReplaceFirst("Be Bitmap Format (JPEGTranslator)",
128570d59669SSiarzhuk Zharski 				B_TRANSLATE("Be Bitmap Format (JPEGTranslator)"));
128670d59669SSiarzhuk Zharski 			strncpy(info->name, str1.String(), sizeof(info->name));
1287b98ef4f9SStephan Aßmus 			strcpy(info->MIME,  formats[i].MIME);
1288b98ef4f9SStephan Aßmus 			return B_OK;
1289b98ef4f9SStephan Aßmus 		}
1290b98ef4f9SStephan Aßmus 	}
1291b98ef4f9SStephan Aßmus 
1292b98ef4f9SStephan Aßmus 	return B_ERROR;
1293b98ef4f9SStephan Aßmus }
1294b98ef4f9SStephan Aßmus 
1295d8e2fb50SAxel Dörfler /*!
1296d8e2fb50SAxel Dörfler 	Frees jpeg alocated memory
1297d8e2fb50SAxel Dörfler 	Returns given error (B_ERROR by default)
1298d8e2fb50SAxel Dörfler */
1299b98ef4f9SStephan Aßmus status_t
1300b98ef4f9SStephan Aßmus JPEGTranslator::Error(j_common_ptr cinfo, status_t error)
13019949213aSStephan Aßmus {
13029949213aSStephan Aßmus 	jpeg_destroy(cinfo);
13039949213aSStephan Aßmus 	return error;
13049949213aSStephan Aßmus }
1305d8e2fb50SAxel Dörfler 
1306d8e2fb50SAxel Dörfler 
1307b98ef4f9SStephan Aßmus JPEGTranslator::JPEGTranslator()
1308bf243977SPhilippe Houdoin 	: BaseTranslator(sTranslatorName, sTranslatorInfo, sTranslatorVersion,
1309bf243977SPhilippe Houdoin 		sInputFormats,  kNumInputFormats,
1310bf243977SPhilippe Houdoin 		sOutputFormats, kNumOutputFormats,
1311bf243977SPhilippe Houdoin 		SETTINGS_FILE,
1312bf243977SPhilippe Houdoin 		sDefaultSettings, kNumDefaultSettings,
1313b98ef4f9SStephan Aßmus 		B_TRANSLATOR_BITMAP, JPEG_FORMAT)
1314b98ef4f9SStephan Aßmus {}
1315b98ef4f9SStephan Aßmus 
1316b98ef4f9SStephan Aßmus 
1317b98ef4f9SStephan Aßmus BTranslator*
1318b98ef4f9SStephan Aßmus make_nth_translator(int32 n, image_id you, uint32 flags, ...)
1319b98ef4f9SStephan Aßmus {
1320b98ef4f9SStephan Aßmus 	if (n == 0)
1321b98ef4f9SStephan Aßmus 		return new JPEGTranslator();
1322b98ef4f9SStephan Aßmus 
1323b98ef4f9SStephan Aßmus 	return NULL;
1324b98ef4f9SStephan Aßmus }
1325d8e2fb50SAxel Dörfler 
1326d8e2fb50SAxel Dörfler 
1327d8e2fb50SAxel Dörfler int
1328117da2d7SAxel Dörfler main(int, char**)
1329117da2d7SAxel Dörfler {
1330117da2d7SAxel Dörfler 	BApplication app("application/x-vnd.Haiku-JPEGTranslator");
1331b98ef4f9SStephan Aßmus 	JPEGTranslator* translator = new JPEGTranslator();
1332bf243977SPhilippe Houdoin 	if (LaunchTranslatorWindow(translator, sTranslatorName) == B_OK)
1333d8e2fb50SAxel Dörfler 		app.Run();
1334b98ef4f9SStephan Aßmus 
1335d8e2fb50SAxel Dörfler 	return 0;
1336d8e2fb50SAxel Dörfler }
1337d8e2fb50SAxel Dörfler 
1338