xref: /haiku/src/add-ons/translators/jpeg/JPEGTranslator.cpp (revision b98ef4f94b232d4ea6c4c7906a3d023d177af56a)
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"
34*b98ef4f9SStephan Aßmus #include "TranslatorWindow.h"
3552e8f46aSAxel Dörfler #include "exif_parser.h"
3652e8f46aSAxel Dörfler 
37*b98ef4f9SStephan Aßmus #include <Alignment.h>
38*b98ef4f9SStephan Aßmus #include <GridLayoutBuilder.h>
39*b98ef4f9SStephan Aßmus #include <GroupLayoutBuilder.h>
408687ff64SAxel Dörfler #include <TabView.h>
41*b98ef4f9SStephan Aßmus #include <TextView.h>
428687ff64SAxel Dörfler 
439949213aSStephan Aßmus 
4452e8f46aSAxel Dörfler #define MARKER_EXIF	0xe1
4552e8f46aSAxel Dörfler 
469949213aSStephan Aßmus // Set these accordingly
479949213aSStephan Aßmus #define JPEG_ACRONYM "JPEG"
489949213aSStephan Aßmus #define JPEG_FORMAT 'JPEG'
499949213aSStephan Aßmus #define JPEG_MIME_STRING "image/jpeg"
509949213aSStephan Aßmus #define JPEG_DESCRIPTION "JPEG image"
519949213aSStephan Aßmus 
529949213aSStephan Aßmus // The translation kit's native file type
539949213aSStephan Aßmus #define B_TRANSLATOR_BITMAP_MIME_STRING "image/x-be-bitmap"
54c095606eSRyan Leavengood #define B_TRANSLATOR_BITMAP_DESCRIPTION "Be Bitmap Format (JPEGTranslator)"
559949213aSStephan Aßmus 
56*b98ef4f9SStephan Aßmus 
579949213aSStephan Aßmus // Translation Kit required globals
58*b98ef4f9SStephan Aßmus char gTranslatorName[] = "JPEG images";
59*b98ef4f9SStephan Aßmus char gTranslatorInfo[] =
608687ff64SAxel Dörfler 	"©2002-2003, Marcin Konicki\n"
61f13b5de6SAxel Dörfler 	"©2005-2007, Haiku\n"
62758b1d0eSIngo Weinhold 	"\n"
637fd58091SJérôme Duval 	"Based on IJG library ©  1994-2009, Thomas G. Lane, Guido Vollbeding.\n"
64758b1d0eSIngo Weinhold 	"          http://www.ijg.org/files/\n"
65*b98ef4f9SStephan Aßmus 	"\n"
66fcc3e627SStephan Aßmus 	"with \"lossless\" encoding support patch by Ken Murchison\n"
67758b1d0eSIngo Weinhold 	"          http://www.oceana.com/ftp/ljpeg/\n"
68758b1d0eSIngo Weinhold 	"\n"
69758b1d0eSIngo Weinhold 	"With some colorspace conversion routines by Magnus Hellman\n"
708687ff64SAxel Dörfler 	"          http://www.bebits.com/app/802\n";
71d8e2fb50SAxel Dörfler 
72*b98ef4f9SStephan Aßmus int32 gTranslatorVersion = B_TRANSLATION_MAKE_VERSION(1, 2, 0);
739949213aSStephan Aßmus 
749949213aSStephan Aßmus // Define the formats we know how to read
75*b98ef4f9SStephan Aßmus const translation_format gInputFormats[] = {
769949213aSStephan Aßmus 	{ JPEG_FORMAT, B_TRANSLATOR_BITMAP, 0.5, 0.5,
779949213aSStephan Aßmus 		JPEG_MIME_STRING, JPEG_DESCRIPTION },
789949213aSStephan Aßmus 	{ B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.5, 0.5,
799949213aSStephan Aßmus 		B_TRANSLATOR_BITMAP_MIME_STRING, B_TRANSLATOR_BITMAP_DESCRIPTION },
80d8e2fb50SAxel Dörfler 	{}
819949213aSStephan Aßmus };
82*b98ef4f9SStephan Aßmus const int gInputFormatCount = sizeof(gInputFormats) / sizeof(translation_format);
839949213aSStephan Aßmus 
849949213aSStephan Aßmus // Define the formats we know how to write
85*b98ef4f9SStephan Aßmus const translation_format gOutputFormats[] = {
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,
899949213aSStephan Aßmus 		B_TRANSLATOR_BITMAP_MIME_STRING, B_TRANSLATOR_BITMAP_DESCRIPTION },
90d8e2fb50SAxel Dörfler 	{}
919949213aSStephan Aßmus };
92*b98ef4f9SStephan Aßmus const int gOutputFormatCount = sizeof(gOutputFormats) / sizeof(translation_format);
9352e8f46aSAxel Dörfler 
94d8e2fb50SAxel Dörfler 
95*b98ef4f9SStephan Aßmus TranSetting gSettings[] = {
96*b98ef4f9SStephan Aßmus 	{JPEG_SET_SMOOTHING, TRAN_SETTING_INT32, 0},
97*b98ef4f9SStephan Aßmus 	{JPEG_SET_QUALITY, TRAN_SETTING_INT32, 95},
98*b98ef4f9SStephan Aßmus 	{JPEG_SET_PROGRESSIVE, TRAN_SETTING_BOOL, true},
99*b98ef4f9SStephan Aßmus 	{JPEG_SET_OPT_COLORS, TRAN_SETTING_BOOL, true},
100*b98ef4f9SStephan Aßmus 	{JPEG_SET_SMALL_FILES, TRAN_SETTING_BOOL, false},
101*b98ef4f9SStephan Aßmus 	{JPEG_SET_GRAY1_AS_RGB24, TRAN_SETTING_BOOL, false},
102*b98ef4f9SStephan Aßmus 	{JPEG_SET_ALWAYS_RGB32, TRAN_SETTING_BOOL, true},
103*b98ef4f9SStephan Aßmus 	{JPEG_SET_PHOTOSHOP_CMYK, TRAN_SETTING_BOOL, true},
104*b98ef4f9SStephan Aßmus 	{JPEG_SET_SHOWREADWARNING, TRAN_SETTING_BOOL, true}
105*b98ef4f9SStephan Aßmus };
106*b98ef4f9SStephan Aßmus const int gSettingsCount = sizeof(gSettings) / sizeof(TranSetting);
1079949213aSStephan Aßmus 
108d8e2fb50SAxel Dörfler 
109*b98ef4f9SStephan Aßmus namespace conversion {
110d8e2fb50SAxel Dörfler 
111d8e2fb50SAxel Dörfler 
1129e34f742SAxel Dörfler static bool
1139e34f742SAxel Dörfler x_flipped(int32 orientation)
1149e34f742SAxel Dörfler {
1159e34f742SAxel Dörfler 	return orientation == 2 || orientation == 3
1169e34f742SAxel Dörfler 		|| orientation == 6 || orientation == 7;
1179e34f742SAxel Dörfler }
1189e34f742SAxel Dörfler 
1199e34f742SAxel Dörfler 
1209e34f742SAxel Dörfler static bool
1219e34f742SAxel Dörfler y_flipped(int32 orientation)
1229e34f742SAxel Dörfler {
1239e34f742SAxel Dörfler 	return orientation == 3 || orientation == 4
1249e34f742SAxel Dörfler 		|| orientation == 7 || orientation == 8;
1259e34f742SAxel Dörfler }
1269e34f742SAxel Dörfler 
1279e34f742SAxel Dörfler 
1289e34f742SAxel Dörfler static int32
1299e34f742SAxel Dörfler dest_index(uint32 width, uint32 height, uint32 x, uint32 y, int32 orientation)
1309e34f742SAxel Dörfler {
1319e34f742SAxel Dörfler 	if (orientation > 4) {
1329e34f742SAxel Dörfler 		uint32 temp = x;
1339e34f742SAxel Dörfler 		x = y;
1349e34f742SAxel Dörfler 		y = temp;
1359e34f742SAxel Dörfler 	}
1369e34f742SAxel Dörfler 	if (y_flipped(orientation))
1379e34f742SAxel Dörfler 		y = height - 1 - y;
1389e34f742SAxel Dörfler 	if (x_flipped(orientation))
1399e34f742SAxel Dörfler 		x = width - 1 - x;
1409e34f742SAxel Dörfler 
1419e34f742SAxel Dörfler 	return y * width + x;
1429e34f742SAxel Dörfler }
1439e34f742SAxel Dörfler 
1449e34f742SAxel Dörfler 
1459e34f742SAxel Dörfler //	#pragma mark - conversion for compression
146d8e2fb50SAxel Dörfler 
147d8e2fb50SAxel Dörfler 
148d8e2fb50SAxel Dörfler inline void
1499e34f742SAxel Dörfler convert_from_gray1_to_gray8(uint8* in, uint8* out, int32 inRowBytes)
150d8e2fb50SAxel Dörfler {
151d8e2fb50SAxel Dörfler 	int32 index = 0;
152d8e2fb50SAxel Dörfler 	int32 index2 = 0;
1539e34f742SAxel Dörfler 	while (index < inRowBytes) {
154d8e2fb50SAxel Dörfler 		unsigned char c = in[index++];
155d8e2fb50SAxel Dörfler 		for (int b = 128; b; b = b>>1) {
156d8e2fb50SAxel Dörfler 			unsigned char color;
157d8e2fb50SAxel Dörfler 			if (c & b)
158d8e2fb50SAxel Dörfler 				color = 0;
159d8e2fb50SAxel Dörfler 			else
160d8e2fb50SAxel Dörfler 				color = 255;
161d8e2fb50SAxel Dörfler 			out[index2++] = color;
162d8e2fb50SAxel Dörfler 		}
163d8e2fb50SAxel Dörfler 	}
164d8e2fb50SAxel Dörfler }
165d8e2fb50SAxel Dörfler 
166d8e2fb50SAxel Dörfler 
167d8e2fb50SAxel Dörfler inline void
1689e34f742SAxel Dörfler convert_from_gray1_to_24(uint8* in, uint8* out, int32 inRowBytes)
169d8e2fb50SAxel Dörfler {
170d8e2fb50SAxel Dörfler 	int32 index = 0;
171d8e2fb50SAxel Dörfler 	int32 index2 = 0;
1729e34f742SAxel Dörfler 	while (index < inRowBytes) {
173d8e2fb50SAxel Dörfler 		unsigned char c = in[index++];
174d8e2fb50SAxel Dörfler 		for (int b = 128; b; b = b>>1) {
175d8e2fb50SAxel Dörfler 			unsigned char color;
176d8e2fb50SAxel Dörfler 			if (c & b)
177d8e2fb50SAxel Dörfler 				color = 0;
178d8e2fb50SAxel Dörfler 			else
179d8e2fb50SAxel Dörfler 				color = 255;
180d8e2fb50SAxel Dörfler 			out[index2++] = color;
181d8e2fb50SAxel Dörfler 			out[index2++] = color;
182d8e2fb50SAxel Dörfler 			out[index2++] = color;
183d8e2fb50SAxel Dörfler 		}
184d8e2fb50SAxel Dörfler 	}
185d8e2fb50SAxel Dörfler }
186d8e2fb50SAxel Dörfler 
187d8e2fb50SAxel Dörfler 
188d8e2fb50SAxel Dörfler inline void
1899e34f742SAxel Dörfler convert_from_cmap8_to_24(uint8* in, uint8* out, int32 inRowBytes)
190d8e2fb50SAxel Dörfler {
191d8e2fb50SAxel Dörfler 	const color_map * map = system_colors();
192d8e2fb50SAxel Dörfler 	int32 index = 0;
193d8e2fb50SAxel Dörfler 	int32 index2 = 0;
1949e34f742SAxel Dörfler 	while (index < inRowBytes) {
195d8e2fb50SAxel Dörfler 		rgb_color color = map->color_list[in[index++]];
196d8e2fb50SAxel Dörfler 
197d8e2fb50SAxel Dörfler 		out[index2++] = color.red;
198d8e2fb50SAxel Dörfler 		out[index2++] = color.green;
199d8e2fb50SAxel Dörfler 		out[index2++] = color.blue;
200d8e2fb50SAxel Dörfler 	}
201d8e2fb50SAxel Dörfler }
202d8e2fb50SAxel Dörfler 
203d8e2fb50SAxel Dörfler 
204d8e2fb50SAxel Dörfler inline void
2059e34f742SAxel Dörfler convert_from_15_to_24(uint8* in, uint8* out, int32 inRowBytes)
206d8e2fb50SAxel Dörfler {
207d8e2fb50SAxel Dörfler 	int32 index = 0;
208d8e2fb50SAxel Dörfler 	int32 index2 = 0;
209d8e2fb50SAxel Dörfler 	int16 in_pixel;
2109e34f742SAxel Dörfler 	while (index < inRowBytes) {
211d8e2fb50SAxel Dörfler 		in_pixel = in[index] | (in[index + 1] << 8);
212d8e2fb50SAxel Dörfler 		index += 2;
213d8e2fb50SAxel Dörfler 
214d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x7c00)) >> 7) | (((in_pixel & 0x7c00)) >> 12);
215d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x3e0)) >> 2) | (((in_pixel & 0x3e0)) >> 7);
216d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2);
217d8e2fb50SAxel Dörfler 	}
218d8e2fb50SAxel Dörfler }
219d8e2fb50SAxel Dörfler 
220d8e2fb50SAxel Dörfler 
221d8e2fb50SAxel Dörfler inline void
2229e34f742SAxel Dörfler convert_from_15b_to_24(uint8* in, uint8* out, int32 inRowBytes)
223d8e2fb50SAxel Dörfler {
224d8e2fb50SAxel Dörfler 	int32 index = 0;
225d8e2fb50SAxel Dörfler 	int32 index2 = 0;
226d8e2fb50SAxel Dörfler 	int16 in_pixel;
2279e34f742SAxel Dörfler 	while (index < inRowBytes) {
228d8e2fb50SAxel Dörfler 		in_pixel = in[index + 1] | (in[index] << 8);
229d8e2fb50SAxel Dörfler 		index += 2;
230d8e2fb50SAxel Dörfler 
231d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x7c00)) >> 7) | (((in_pixel & 0x7c00)) >> 12);
232d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x3e0)) >> 2) | (((in_pixel & 0x3e0)) >> 7);
233d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2);
234d8e2fb50SAxel Dörfler 	}
235d8e2fb50SAxel Dörfler }
236d8e2fb50SAxel Dörfler 
237d8e2fb50SAxel Dörfler 
238d8e2fb50SAxel Dörfler inline void
2399e34f742SAxel Dörfler convert_from_16_to_24(uint8* in, uint8* out, int32 inRowBytes)
240d8e2fb50SAxel Dörfler {
241d8e2fb50SAxel Dörfler 	int32 index = 0;
242d8e2fb50SAxel Dörfler 	int32 index2 = 0;
243d8e2fb50SAxel Dörfler 	int16 in_pixel;
2449e34f742SAxel Dörfler 	while (index < inRowBytes) {
245d8e2fb50SAxel Dörfler 		in_pixel = in[index] | (in[index + 1] << 8);
246d8e2fb50SAxel Dörfler 		index += 2;
247d8e2fb50SAxel Dörfler 
248d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0xf800)) >> 8) | (((in_pixel & 0xf800)) >> 13);
249d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x7e0)) >> 3) | (((in_pixel & 0x7e0)) >> 9);
250d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2);
251d8e2fb50SAxel Dörfler 	}
252d8e2fb50SAxel Dörfler }
253d8e2fb50SAxel Dörfler 
254d8e2fb50SAxel Dörfler 
255d8e2fb50SAxel Dörfler inline void
2569e34f742SAxel Dörfler convert_from_16b_to_24(uint8* in, uint8* out, int32 inRowBytes)
257d8e2fb50SAxel Dörfler {
258d8e2fb50SAxel Dörfler 	int32 index = 0;
259d8e2fb50SAxel Dörfler 	int32 index2 = 0;
260d8e2fb50SAxel Dörfler 	int16 in_pixel;
2619e34f742SAxel Dörfler 	while (index < inRowBytes) {
262d8e2fb50SAxel Dörfler 		in_pixel = in[index + 1] | (in[index] << 8);
263d8e2fb50SAxel Dörfler 		index += 2;
264d8e2fb50SAxel Dörfler 
265d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0xf800)) >> 8) | (((in_pixel & 0xf800)) >> 13);
266d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x7e0)) >> 3) | (((in_pixel & 0x7e0)) >> 9);
267d8e2fb50SAxel Dörfler 		out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2);
268d8e2fb50SAxel Dörfler 	}
269d8e2fb50SAxel Dörfler }
270d8e2fb50SAxel Dörfler 
271d8e2fb50SAxel Dörfler 
272d8e2fb50SAxel Dörfler inline void
2739e34f742SAxel Dörfler convert_from_24_to_24(uint8* in, uint8* out, int32 inRowBytes)
274d8e2fb50SAxel Dörfler {
275d8e2fb50SAxel Dörfler 	int32 index = 0;
276d8e2fb50SAxel Dörfler 	int32 index2 = 0;
2779e34f742SAxel Dörfler 	while (index < inRowBytes) {
278d8e2fb50SAxel Dörfler 		out[index2++] = in[index + 2];
279d8e2fb50SAxel Dörfler 		out[index2++] = in[index + 1];
280d8e2fb50SAxel Dörfler 		out[index2++] = in[index];
281d8e2fb50SAxel Dörfler 		index+=3;
282d8e2fb50SAxel Dörfler 	}
283d8e2fb50SAxel Dörfler }
284d8e2fb50SAxel Dörfler 
285d8e2fb50SAxel Dörfler 
286d8e2fb50SAxel Dörfler inline void
2879e34f742SAxel Dörfler convert_from_32_to_24(uint8* in, uint8* out, int32 inRowBytes)
288d8e2fb50SAxel Dörfler {
28951623681SAxel Dörfler 	inRowBytes /= 4;
29051623681SAxel Dörfler 
2919e34f742SAxel Dörfler 	for (int32 i = 0; i < inRowBytes; i++) {
2929e34f742SAxel Dörfler 		out[0] = in[2];
2939e34f742SAxel Dörfler 		out[1] = in[1];
2949e34f742SAxel Dörfler 		out[2] = in[0];
2959e34f742SAxel Dörfler 
2969e34f742SAxel Dörfler 		in += 4;
2979e34f742SAxel Dörfler 		out += 3;
298d8e2fb50SAxel Dörfler 	}
299d8e2fb50SAxel Dörfler }
300d8e2fb50SAxel Dörfler 
301d8e2fb50SAxel Dörfler 
302d8e2fb50SAxel Dörfler inline void
3039e34f742SAxel Dörfler convert_from_32b_to_24(uint8* in, uint8* out, int32 inRowBytes)
304d8e2fb50SAxel Dörfler {
30551623681SAxel Dörfler 	inRowBytes /= 4;
30651623681SAxel Dörfler 
3079e34f742SAxel Dörfler 	for (int32 i = 0; i < inRowBytes; i++) {
30851623681SAxel Dörfler 		out[0] = in[1];
30951623681SAxel Dörfler 		out[1] = in[2];
31051623681SAxel Dörfler 		out[2] = in[3];
3119e34f742SAxel Dörfler 
3129e34f742SAxel Dörfler 		in += 4;
3139e34f742SAxel Dörfler 		out += 3;
314d8e2fb50SAxel Dörfler 	}
315d8e2fb50SAxel Dörfler }
316d8e2fb50SAxel Dörfler 
317d8e2fb50SAxel Dörfler 
3189e34f742SAxel Dörfler //	#pragma mark - conversion for decompression
3199e34f742SAxel Dörfler 
3209e34f742SAxel Dörfler 
321d8e2fb50SAxel Dörfler inline void
3229e34f742SAxel Dörfler convert_from_CMYK_to_32_photoshop(uint8* in, uint8* out, int32 inRowBytes, int32 xStep)
323d8e2fb50SAxel Dörfler {
3249e34f742SAxel Dörfler 	for (int32 i = 0; i < inRowBytes; i += 4) {
3259e34f742SAxel Dörfler 		int32 black = in[3];
3269e34f742SAxel Dörfler 		out[0] = in[2] * black / 255;
3279e34f742SAxel Dörfler 		out[1] = in[1] * black / 255;
3289e34f742SAxel Dörfler 		out[2] = in[0] * black / 255;
3299e34f742SAxel Dörfler 		out[3] = 255;
3309e34f742SAxel Dörfler 
3319e34f742SAxel Dörfler 		in += 4;
3329e34f742SAxel Dörfler 		out += xStep;
333d8e2fb50SAxel Dörfler 	}
334d8e2fb50SAxel Dörfler }
335d8e2fb50SAxel Dörfler 
336d8e2fb50SAxel Dörfler 
337d8e2fb50SAxel Dörfler //!	!!! UNTESTED !!!
338d8e2fb50SAxel Dörfler inline void
3399e34f742SAxel Dörfler convert_from_CMYK_to_32(uint8* in, uint8* out, int32 inRowBytes, int32 xStep)
340d8e2fb50SAxel Dörfler {
3419e34f742SAxel Dörfler 	for (int32 i = 0; i < inRowBytes; i += 4) {
3429e34f742SAxel Dörfler 		int32 black = 255 - in[3];
3439e34f742SAxel Dörfler 		out[0] = ((255 - in[2]) * black) / 255;
3449e34f742SAxel Dörfler 		out[1] = ((255 - in[1]) * black) / 255;
3459e34f742SAxel Dörfler 		out[2] = ((255 - in[0]) * black) / 255;
3469e34f742SAxel Dörfler 		out[3] = 255;
3479e34f742SAxel Dörfler 
3489e34f742SAxel Dörfler 		in += 4;
3499e34f742SAxel Dörfler 		out += xStep;
350d8e2fb50SAxel Dörfler 	}
351d8e2fb50SAxel Dörfler }
352d8e2fb50SAxel Dörfler 
353d8e2fb50SAxel Dörfler 
354d8e2fb50SAxel Dörfler //!	RGB24 8:8:8 to xRGB 8:8:8:8
355d8e2fb50SAxel Dörfler inline void
3569e34f742SAxel Dörfler convert_from_24_to_32(uint8* in, uint8* out, int32 inRowBytes, int32 xStep)
357d8e2fb50SAxel Dörfler {
3589e34f742SAxel Dörfler 	for (int32 i = 0; i < inRowBytes; i += 3) {
3599e34f742SAxel Dörfler 		out[0] = in[2];
3609e34f742SAxel Dörfler 		out[1] = in[1];
3619e34f742SAxel Dörfler 		out[2] = in[0];
3629e34f742SAxel Dörfler 		out[3] = 255;
3639e34f742SAxel Dörfler 
3649e34f742SAxel Dörfler 		in += 3;
3659e34f742SAxel Dörfler 		out += xStep;
3669e34f742SAxel Dörfler 	}
3679e34f742SAxel Dörfler }
3689e34f742SAxel Dörfler 
3699e34f742SAxel Dörfler 
3709e34f742SAxel Dörfler //! 8-bit to 8-bit, only need when rotating the image
3719e34f742SAxel Dörfler void
3729e34f742SAxel Dörfler translate_8(uint8* in, uint8* out, int32 inRowBytes, int32 xStep)
3739e34f742SAxel Dörfler {
3749e34f742SAxel Dörfler 	for (int32 i = 0; i < inRowBytes; i++) {
3759e34f742SAxel Dörfler 		out[0] = in[0];
3769e34f742SAxel Dörfler 
3779e34f742SAxel Dörfler 		in++;
3789e34f742SAxel Dörfler 		out += xStep;
379d8e2fb50SAxel Dörfler 	}
380d8e2fb50SAxel Dörfler }
381d8e2fb50SAxel Dörfler 
382d8e2fb50SAxel Dörfler 
383*b98ef4f9SStephan Aßmus } // namespace conversion
3848687ff64SAxel Dörfler 
3858687ff64SAxel Dörfler 
386d8e2fb50SAxel Dörfler //	#pragma mark -
387d8e2fb50SAxel Dörfler 
388d8e2fb50SAxel Dörfler 
389*b98ef4f9SStephan Aßmus SSlider::SSlider(const char* name, const char* label,
390d8e2fb50SAxel Dörfler 		BMessage* message, int32 minValue, int32 maxValue, orientation posture,
391*b98ef4f9SStephan Aßmus 		thumb_style thumbType, uint32 flags)
392*b98ef4f9SStephan Aßmus 	: BSlider(name, label, message, minValue, maxValue,
393*b98ef4f9SStephan Aßmus 		posture, thumbType, flags)
3949949213aSStephan Aßmus {
3958687ff64SAxel Dörfler 	rgb_color barColor = { 0, 0, 229, 255 };
3968687ff64SAxel Dörfler 	UseFillColor(true, &barColor);
3979949213aSStephan Aßmus }
3989949213aSStephan Aßmus 
3998687ff64SAxel Dörfler 
4008687ff64SAxel Dörfler //!	Update status string - show actual value
401b20d13f4SStefano Ceccherini const char*
4029949213aSStephan Aßmus SSlider::UpdateText() const
4039949213aSStephan Aßmus {
4048687ff64SAxel Dörfler 	snprintf(fStatusLabel, sizeof(fStatusLabel), "%ld", Value());
4058687ff64SAxel Dörfler 	return fStatusLabel;
4069949213aSStephan Aßmus }
4079949213aSStephan Aßmus 
4088687ff64SAxel Dörfler 
409d8e2fb50SAxel Dörfler //	#pragma mark -
4109949213aSStephan Aßmus 
411d8e2fb50SAxel Dörfler 
412*b98ef4f9SStephan Aßmus TranslatorReadView::TranslatorReadView(const char* name,
413*b98ef4f9SStephan Aßmus 	TranslatorSettings* settings)
414*b98ef4f9SStephan Aßmus 	:
415*b98ef4f9SStephan Aßmus 	BView(name, 0, new BGroupLayout(B_HORIZONTAL)),
416d8e2fb50SAxel Dörfler 	fSettings(settings)
417*b98ef4f9SStephan Aßmus 		// settings should already be Acquired()
4189949213aSStephan Aßmus {
419*b98ef4f9SStephan Aßmus 	fAlwaysRGB32 = new BCheckBox("alwaysrgb32", VIEW_LABEL_ALWAYSRGB32,
420d8e2fb50SAxel Dörfler 		new BMessage(VIEW_MSG_SET_ALWAYSRGB32));
421*b98ef4f9SStephan Aßmus 	if (fSettings->SetGetBool(JPEG_SET_ALWAYS_RGB32, NULL))
422*b98ef4f9SStephan Aßmus 		fAlwaysRGB32->SetValue(B_CONTROL_ON);
4239949213aSStephan Aßmus 
424*b98ef4f9SStephan Aßmus 	fPhotoshopCMYK = new BCheckBox("photoshopCMYK", VIEW_LABEL_PHOTOSHOPCMYK,
4258687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_PHOTOSHOPCMYK));
426*b98ef4f9SStephan Aßmus 	if (fSettings->SetGetBool(JPEG_SET_PHOTOSHOP_CMYK, NULL))
427*b98ef4f9SStephan Aßmus 		fPhotoshopCMYK->SetValue(B_CONTROL_ON);
4289949213aSStephan Aßmus 
429*b98ef4f9SStephan Aßmus 	fShowErrorBox = new BCheckBox("error", VIEW_LABEL_SHOWREADERRORBOX,
4308687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_SHOWREADERRORBOX));
431*b98ef4f9SStephan Aßmus 	if (fSettings->SetGetBool(JPEG_SET_SHOWREADWARNING, NULL))
432*b98ef4f9SStephan Aßmus 		fShowErrorBox->SetValue(B_CONTROL_ON);
4339949213aSStephan Aßmus 
434*b98ef4f9SStephan Aßmus 	float padding = 5.0f;
435*b98ef4f9SStephan Aßmus 	AddChild(BGroupLayoutBuilder(B_VERTICAL, padding)
436*b98ef4f9SStephan Aßmus 		.Add(fAlwaysRGB32)
437*b98ef4f9SStephan Aßmus 		.Add(fPhotoshopCMYK)
438*b98ef4f9SStephan Aßmus 		.Add(fShowErrorBox)
439*b98ef4f9SStephan Aßmus 		.AddGlue()
440*b98ef4f9SStephan Aßmus 		.SetInsets(padding, padding, padding, padding)
441*b98ef4f9SStephan Aßmus 	);
4429949213aSStephan Aßmus 
443*b98ef4f9SStephan Aßmus }
444*b98ef4f9SStephan Aßmus 
445*b98ef4f9SStephan Aßmus 
446*b98ef4f9SStephan Aßmus TranslatorReadView::~TranslatorReadView()
447*b98ef4f9SStephan Aßmus {
448*b98ef4f9SStephan Aßmus 	fSettings->Release();
4499949213aSStephan Aßmus }
4509949213aSStephan Aßmus 
4518687ff64SAxel Dörfler 
4529949213aSStephan Aßmus void
4539949213aSStephan Aßmus TranslatorReadView::AttachedToWindow()
4549949213aSStephan Aßmus {
455*b98ef4f9SStephan Aßmus 	BView::AttachedToWindow();
456b20d13f4SStefano Ceccherini 
4578687ff64SAxel Dörfler 	fAlwaysRGB32->SetTarget(this);
4588687ff64SAxel Dörfler 	fPhotoshopCMYK->SetTarget(this);
4598687ff64SAxel Dörfler 	fShowErrorBox->SetTarget(this);
4609949213aSStephan Aßmus }
4619949213aSStephan Aßmus 
4628687ff64SAxel Dörfler 
4639949213aSStephan Aßmus void
4649949213aSStephan Aßmus TranslatorReadView::MessageReceived(BMessage* message)
4659949213aSStephan Aßmus {
4668687ff64SAxel Dörfler 	switch (message->what) {
4679949213aSStephan Aßmus 		case VIEW_MSG_SET_ALWAYSRGB32:
4689949213aSStephan Aßmus 		{
4699949213aSStephan Aßmus 			int32 value;
4709949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
471*b98ef4f9SStephan Aßmus 				bool boolValue = value;
472*b98ef4f9SStephan Aßmus 				fSettings->SetGetBool(JPEG_SET_ALWAYS_RGB32, &boolValue);
473*b98ef4f9SStephan Aßmus 				fSettings->SaveSettings();
4749949213aSStephan Aßmus 			}
4759949213aSStephan Aßmus 			break;
4769949213aSStephan Aßmus 		}
4779949213aSStephan Aßmus 		case VIEW_MSG_SET_PHOTOSHOPCMYK:
4789949213aSStephan Aßmus 		{
4799949213aSStephan Aßmus 			int32 value;
4809949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
481*b98ef4f9SStephan Aßmus 				bool boolValue = value;
482*b98ef4f9SStephan Aßmus 				fSettings->SetGetBool(JPEG_SET_PHOTOSHOP_CMYK, &boolValue);
483*b98ef4f9SStephan Aßmus 				fSettings->SaveSettings();
4849949213aSStephan Aßmus 			}
4859949213aSStephan Aßmus 			break;
4869949213aSStephan Aßmus 		}
4879949213aSStephan Aßmus 		case VIEW_MSG_SET_SHOWREADERRORBOX:
4889949213aSStephan Aßmus 		{
4899949213aSStephan Aßmus 			int32 value;
4909949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
491*b98ef4f9SStephan Aßmus 				bool boolValue = value;
492*b98ef4f9SStephan Aßmus 				fSettings->SetGetBool(JPEG_SET_SHOWREADWARNING, &boolValue);
493*b98ef4f9SStephan Aßmus 				fSettings->SaveSettings();
4949949213aSStephan Aßmus 			}
4959949213aSStephan Aßmus 			break;
4969949213aSStephan Aßmus 		}
4979949213aSStephan Aßmus 		default:
4989949213aSStephan Aßmus 			BView::MessageReceived(message);
4999949213aSStephan Aßmus 			break;
5009949213aSStephan Aßmus 	}
5019949213aSStephan Aßmus }
5029949213aSStephan Aßmus 
5039949213aSStephan Aßmus 
5048687ff64SAxel Dörfler //	#pragma mark - TranslatorWriteView
5059949213aSStephan Aßmus 
5068687ff64SAxel Dörfler 
507*b98ef4f9SStephan Aßmus TranslatorWriteView::TranslatorWriteView(const char* name,
508*b98ef4f9SStephan Aßmus 	TranslatorSettings* settings)
509*b98ef4f9SStephan Aßmus 	:
510*b98ef4f9SStephan Aßmus 	BView(name, 0, new BGroupLayout(B_VERTICAL)),
511d8e2fb50SAxel Dörfler 	fSettings(settings)
512*b98ef4f9SStephan Aßmus 		// settings should already be Acquired()
5139949213aSStephan Aßmus {
514*b98ef4f9SStephan Aßmus 	fQualitySlider = new SSlider("quality", VIEW_LABEL_QUALITY,
5158687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_QUALITY), 0, 100);
5168687ff64SAxel Dörfler 	fQualitySlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
5178687ff64SAxel Dörfler 	fQualitySlider->SetHashMarkCount(10);
5188687ff64SAxel Dörfler 	fQualitySlider->SetLimitLabels("Low", "High");
519*b98ef4f9SStephan Aßmus 	fQualitySlider->SetValue(fSettings->SetGetInt32(JPEG_SET_QUALITY, NULL));
5209949213aSStephan Aßmus 
521*b98ef4f9SStephan Aßmus 	fSmoothingSlider = new SSlider("smoothing", VIEW_LABEL_SMOOTHING,
5228687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_SMOOTHING), 0, 100);
5238687ff64SAxel Dörfler 	fSmoothingSlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
5248687ff64SAxel Dörfler 	fSmoothingSlider->SetHashMarkCount(10);
5258687ff64SAxel Dörfler 	fSmoothingSlider->SetLimitLabels("None", "High");
526*b98ef4f9SStephan Aßmus 	fSmoothingSlider->SetValue(
527*b98ef4f9SStephan Aßmus 		fSettings->SetGetInt32(JPEG_SET_SMOOTHING, NULL));
5289949213aSStephan Aßmus 
529*b98ef4f9SStephan Aßmus 	fProgress = new BCheckBox("progress", VIEW_LABEL_PROGRESSIVE,
5308687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_PROGRESSIVE));
531*b98ef4f9SStephan Aßmus 	if (fSettings->SetGetBool(JPEG_SET_PROGRESSIVE, NULL))
532*b98ef4f9SStephan Aßmus 		fProgress->SetValue(B_CONTROL_ON);
5339949213aSStephan Aßmus 
534*b98ef4f9SStephan Aßmus 	fSmallerFile = new BCheckBox("smallerfile", VIEW_LABEL_SMALLERFILE,
5358687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_SMALLERFILE));
536*b98ef4f9SStephan Aßmus 	if (fSettings->SetGetBool(JPEG_SET_SMALL_FILES))
537*b98ef4f9SStephan Aßmus 		fSmallerFile->SetValue(B_CONTROL_ON);
538*b98ef4f9SStephan Aßmus 
539*b98ef4f9SStephan Aßmus 	fOptimizeColors = new BCheckBox("optimizecolors", VIEW_LABEL_OPTIMIZECOLORS,
540*b98ef4f9SStephan Aßmus 		new BMessage(VIEW_MSG_SET_OPTIMIZECOLORS));
541*b98ef4f9SStephan Aßmus 	if (fSettings->SetGetBool(JPEG_SET_OPT_COLORS, NULL))
542*b98ef4f9SStephan Aßmus 		fOptimizeColors->SetValue(B_CONTROL_ON);
543*b98ef4f9SStephan Aßmus 	else
5448687ff64SAxel Dörfler 		fSmallerFile->SetEnabled(false);
5459949213aSStephan Aßmus 
546*b98ef4f9SStephan Aßmus 	fGrayAsRGB24 = new BCheckBox("gray1asrgb24", VIEW_LABEL_GRAY1ASRGB24,
5478687ff64SAxel Dörfler 		new BMessage(VIEW_MSG_SET_GRAY1ASRGB24));
548*b98ef4f9SStephan Aßmus 	if (fSettings->SetGetBool(JPEG_SET_GRAY1_AS_RGB24))
549*b98ef4f9SStephan Aßmus 		fGrayAsRGB24->SetValue(B_CONTROL_ON);
5509949213aSStephan Aßmus 
551*b98ef4f9SStephan Aßmus 	float padding = 5.0f;
552*b98ef4f9SStephan Aßmus 	AddChild(BGroupLayoutBuilder(B_VERTICAL, padding)
553*b98ef4f9SStephan Aßmus 		.Add(fQualitySlider)
554*b98ef4f9SStephan Aßmus 		.Add(fSmoothingSlider)
555*b98ef4f9SStephan Aßmus 		.Add(fProgress)
556*b98ef4f9SStephan Aßmus 		.Add(fOptimizeColors)
557*b98ef4f9SStephan Aßmus 		.Add(fSmallerFile)
558*b98ef4f9SStephan Aßmus 		.Add(fGrayAsRGB24)
559*b98ef4f9SStephan Aßmus 		.AddGlue()
560*b98ef4f9SStephan Aßmus 		.SetInsets(padding, padding, padding, padding)
561*b98ef4f9SStephan Aßmus 	);
562*b98ef4f9SStephan Aßmus }
5639949213aSStephan Aßmus 
564*b98ef4f9SStephan Aßmus 
565*b98ef4f9SStephan Aßmus TranslatorWriteView::~TranslatorWriteView()
566*b98ef4f9SStephan Aßmus {
567*b98ef4f9SStephan Aßmus 	fSettings->Release();
5689949213aSStephan Aßmus }
5699949213aSStephan Aßmus 
5708687ff64SAxel Dörfler 
5719949213aSStephan Aßmus void
5729949213aSStephan Aßmus TranslatorWriteView::AttachedToWindow()
5739949213aSStephan Aßmus {
574*b98ef4f9SStephan Aßmus 	BView::AttachedToWindow();
575b20d13f4SStefano Ceccherini 
5768687ff64SAxel Dörfler 	fQualitySlider->SetTarget(this);
5778687ff64SAxel Dörfler 	fSmoothingSlider->SetTarget(this);
5788687ff64SAxel Dörfler 	fProgress->SetTarget(this);
5798687ff64SAxel Dörfler 	fOptimizeColors->SetTarget(this);
5808687ff64SAxel Dörfler 	fSmallerFile->SetTarget(this);
5818687ff64SAxel Dörfler 	fGrayAsRGB24->SetTarget(this);
5829949213aSStephan Aßmus }
5839949213aSStephan Aßmus 
5848687ff64SAxel Dörfler 
5859949213aSStephan Aßmus void
5869949213aSStephan Aßmus TranslatorWriteView::MessageReceived(BMessage* message)
5879949213aSStephan Aßmus {
5888687ff64SAxel Dörfler 	switch (message->what) {
5899949213aSStephan Aßmus 		case VIEW_MSG_SET_QUALITY:
5909949213aSStephan Aßmus 		{
5919949213aSStephan Aßmus 			int32 value;
5929949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
593*b98ef4f9SStephan Aßmus 				fSettings->SetGetInt32(JPEG_SET_QUALITY, &value);
594*b98ef4f9SStephan Aßmus 				fSettings->SaveSettings();
5959949213aSStephan Aßmus 			}
5969949213aSStephan Aßmus 			break;
5979949213aSStephan Aßmus 		}
5989949213aSStephan Aßmus 		case VIEW_MSG_SET_SMOOTHING:
5999949213aSStephan Aßmus 		{
6009949213aSStephan Aßmus 			int32 value;
6019949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
602*b98ef4f9SStephan Aßmus 				fSettings->SetGetInt32(JPEG_SET_SMOOTHING, &value);
603*b98ef4f9SStephan Aßmus 				fSettings->SaveSettings();
6049949213aSStephan Aßmus 			}
6059949213aSStephan Aßmus 			break;
6069949213aSStephan Aßmus 		}
6079949213aSStephan Aßmus 		case VIEW_MSG_SET_PROGRESSIVE:
6089949213aSStephan Aßmus 		{
6099949213aSStephan Aßmus 			int32 value;
6109949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
611*b98ef4f9SStephan Aßmus 				bool boolValue = value;
612*b98ef4f9SStephan Aßmus 				fSettings->SetGetBool(JPEG_SET_PROGRESSIVE, &boolValue);
613*b98ef4f9SStephan Aßmus 				fSettings->SaveSettings();
6149949213aSStephan Aßmus 			}
6159949213aSStephan Aßmus 			break;
6169949213aSStephan Aßmus 		}
6179949213aSStephan Aßmus 		case VIEW_MSG_SET_OPTIMIZECOLORS:
6189949213aSStephan Aßmus 		{
6199949213aSStephan Aßmus 			int32 value;
6209949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
621*b98ef4f9SStephan Aßmus 				bool boolValue = value;
622*b98ef4f9SStephan Aßmus 				fSettings->SetGetBool(JPEG_SET_OPT_COLORS, &boolValue);
623*b98ef4f9SStephan Aßmus 				fSmallerFile->SetEnabled(value);
624*b98ef4f9SStephan Aßmus 				fSettings->SaveSettings();
6259949213aSStephan Aßmus 			}
6269949213aSStephan Aßmus 			break;
6279949213aSStephan Aßmus 		}
6289949213aSStephan Aßmus 		case VIEW_MSG_SET_SMALLERFILE:
6299949213aSStephan Aßmus 		{
6309949213aSStephan Aßmus 			int32 value;
6319949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
632*b98ef4f9SStephan Aßmus 				bool boolValue = value;
633*b98ef4f9SStephan Aßmus 				fSettings->SetGetBool(JPEG_SET_SMALL_FILES, &boolValue);
634*b98ef4f9SStephan Aßmus 				fSettings->SaveSettings();
6359949213aSStephan Aßmus 			}
6369949213aSStephan Aßmus 			break;
6379949213aSStephan Aßmus 		}
6389949213aSStephan Aßmus 		case VIEW_MSG_SET_GRAY1ASRGB24:
6399949213aSStephan Aßmus 		{
6409949213aSStephan Aßmus 			int32 value;
6419949213aSStephan Aßmus 			if (message->FindInt32("be:value", &value) == B_OK) {
642*b98ef4f9SStephan Aßmus 				bool boolValue = value;
643*b98ef4f9SStephan Aßmus 				fSettings->SetGetBool(JPEG_SET_GRAY1_AS_RGB24, &boolValue);
644*b98ef4f9SStephan Aßmus 				fSettings->SaveSettings();
6459949213aSStephan Aßmus 			}
6469949213aSStephan Aßmus 			break;
6479949213aSStephan Aßmus 		}
6489949213aSStephan Aßmus 		default:
6499949213aSStephan Aßmus 			BView::MessageReceived(message);
6509949213aSStephan Aßmus 			break;
6519949213aSStephan Aßmus 	}
6529949213aSStephan Aßmus }
6539949213aSStephan Aßmus 
6549949213aSStephan Aßmus 
655d8e2fb50SAxel Dörfler //	#pragma mark -
6569949213aSStephan Aßmus 
657d8e2fb50SAxel Dörfler 
658*b98ef4f9SStephan Aßmus TranslatorAboutView::TranslatorAboutView(const char* name)
659*b98ef4f9SStephan Aßmus 	:
660*b98ef4f9SStephan Aßmus 	BView(name, 0, new BGroupLayout(B_VERTICAL))
6619949213aSStephan Aßmus {
662*b98ef4f9SStephan Aßmus 	BAlignment labelAlignment = BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP);
663*b98ef4f9SStephan Aßmus 	BStringView* title = new BStringView("Title", gTranslatorName);
6649949213aSStephan Aßmus 	title->SetFont(be_bold_font);
665*b98ef4f9SStephan Aßmus 	title->SetExplicitAlignment(labelAlignment);
6669949213aSStephan Aßmus 
6679949213aSStephan Aßmus 	char versionString[16];
668*b98ef4f9SStephan Aßmus 	sprintf(versionString, "v%d.%d.%d", (int)(gTranslatorVersion >> 8),
669*b98ef4f9SStephan Aßmus 		(int)((gTranslatorVersion >> 4) & 0xf), (int)(gTranslatorVersion & 0xf));
6709949213aSStephan Aßmus 
671*b98ef4f9SStephan Aßmus 	BStringView* version = new BStringView("Version", versionString);
672*b98ef4f9SStephan Aßmus 	version->SetExplicitAlignment(labelAlignment);
6739949213aSStephan Aßmus 
674*b98ef4f9SStephan Aßmus 	BTextView* infoView = new BTextView("info");
675*b98ef4f9SStephan Aßmus 	infoView->SetText(gTranslatorInfo);
676*b98ef4f9SStephan Aßmus 	infoView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
677*b98ef4f9SStephan Aßmus 	infoView->MakeEditable(false);
6789949213aSStephan Aßmus 
679*b98ef4f9SStephan Aßmus 	float padding = 5.0f;
680*b98ef4f9SStephan Aßmus 	AddChild(BGroupLayoutBuilder(B_VERTICAL, padding)
681*b98ef4f9SStephan Aßmus 		.Add(BGroupLayoutBuilder(B_HORIZONTAL, padding)
682*b98ef4f9SStephan Aßmus 			.Add(title)
683*b98ef4f9SStephan Aßmus 			.Add(version)
684*b98ef4f9SStephan Aßmus 			.AddGlue()
685*b98ef4f9SStephan Aßmus 		)
686*b98ef4f9SStephan Aßmus 		.Add(infoView)
687*b98ef4f9SStephan Aßmus 		.SetInsets(padding, padding, padding, padding)
688*b98ef4f9SStephan Aßmus 	);
6899949213aSStephan Aßmus }
6909949213aSStephan Aßmus 
6919949213aSStephan Aßmus 
692*b98ef4f9SStephan Aßmus TranslatorView::TranslatorView(const char* name, TranslatorSettings* settings)
693*b98ef4f9SStephan Aßmus 	:
694*b98ef4f9SStephan Aßmus 	BTabView(name)
6959949213aSStephan Aßmus {
696*b98ef4f9SStephan Aßmus 	AddTab(new TranslatorWriteView("Write", settings->Acquire()));
697*b98ef4f9SStephan Aßmus 	AddTab(new TranslatorReadView("Read", settings->Acquire()));
698*b98ef4f9SStephan Aßmus 	AddTab(new TranslatorAboutView("About"));
6999949213aSStephan Aßmus 
700*b98ef4f9SStephan Aßmus 	settings->Release();
7019949213aSStephan Aßmus 
702*b98ef4f9SStephan Aßmus  	BFont font;
703*b98ef4f9SStephan Aßmus  	GetFont(&font);
704*b98ef4f9SStephan Aßmus  	SetExplicitPreferredSize(
705*b98ef4f9SStephan Aßmus 		BSize((font.Size() * 380) / 12, (font.Size() * 250) / 12));
7069949213aSStephan Aßmus }
7079949213aSStephan Aßmus 
7089949213aSStephan Aßmus 
709d8e2fb50SAxel Dörfler //	#pragma mark - Translator Add-On
7109949213aSStephan Aßmus 
7119949213aSStephan Aßmus 
712*b98ef4f9SStephan Aßmus BView*
713*b98ef4f9SStephan Aßmus JPEGTranslator::NewConfigView(TranslatorSettings* settings)
7149949213aSStephan Aßmus {
715*b98ef4f9SStephan Aßmus 	BView* configView = new TranslatorView("TranslatorView", settings);
716*b98ef4f9SStephan Aßmus 	return configView;
7179949213aSStephan Aßmus }
7189949213aSStephan Aßmus 
719*b98ef4f9SStephan Aßmus 
720d8e2fb50SAxel Dörfler /*! Determine whether or not we can handle this data */
7219949213aSStephan Aßmus status_t
722*b98ef4f9SStephan Aßmus JPEGTranslator::DerivedIdentify(BPositionIO* inSource,
723*b98ef4f9SStephan Aßmus 	const translation_format* inFormat, BMessage* ioExtension,
724*b98ef4f9SStephan Aßmus 	translator_info* outInfo, uint32 outType)
7259949213aSStephan Aßmus {
726d8e2fb50SAxel Dörfler 	if (outType != 0 && outType != B_TRANSLATOR_BITMAP && outType != JPEG_FORMAT)
7279949213aSStephan Aßmus 		return B_NO_TRANSLATOR;
7289949213aSStephan Aßmus 
7299949213aSStephan Aßmus 	// !!! You might need to make this buffer bigger to test for your native format
7309949213aSStephan Aßmus 	off_t position = inSource->Position();
7319949213aSStephan Aßmus 	char header[sizeof(TranslatorBitmap)];
7329949213aSStephan Aßmus 	status_t err = inSource->Read(header, sizeof(TranslatorBitmap));
7339949213aSStephan Aßmus 	inSource->Seek(position, SEEK_SET);
734d8e2fb50SAxel Dörfler 	if (err < B_OK)
735d8e2fb50SAxel Dörfler 		return err;
7369949213aSStephan Aßmus 
7379949213aSStephan Aßmus 	if (B_BENDIAN_TO_HOST_INT32(((TranslatorBitmap *)header)->magic) == B_TRANSLATOR_BITMAP) {
738*b98ef4f9SStephan Aßmus 		if (PopulateInfoFromFormat(outInfo, B_TRANSLATOR_BITMAP) != B_OK)
739*b98ef4f9SStephan Aßmus 			return B_NO_TRANSLATOR;
7409949213aSStephan Aßmus 	} else {
7419949213aSStephan Aßmus 		// First 3 bytes in jpg files are always the same from what i've seen so far
7429949213aSStephan Aßmus 		// check them
7439949213aSStephan Aßmus 		if (header[0] == (char)0xff && header[1] == (char)0xd8 && header[2] == (char)0xff) {
744*b98ef4f9SStephan Aßmus 			if (PopulateInfoFromFormat(outInfo, JPEG_FORMAT) != B_OK)
7459949213aSStephan Aßmus 				return B_NO_TRANSLATOR;
746*b98ef4f9SStephan Aßmus 
7479949213aSStephan Aßmus 		} else
7489949213aSStephan Aßmus 			return B_NO_TRANSLATOR;
7499949213aSStephan Aßmus 	}
7509949213aSStephan Aßmus 
7519949213aSStephan Aßmus 	return B_OK;
7529949213aSStephan Aßmus }
7539949213aSStephan Aßmus 
754*b98ef4f9SStephan Aßmus 
7559949213aSStephan Aßmus status_t
756*b98ef4f9SStephan Aßmus JPEGTranslator::DerivedTranslate(BPositionIO* inSource,
757*b98ef4f9SStephan Aßmus 	const translator_info* inInfo, BMessage* ioExtension, uint32 outType,
758*b98ef4f9SStephan Aßmus 	BPositionIO* outDestination, int32 baseType)
7599949213aSStephan Aßmus {
7609949213aSStephan Aßmus 	// If no specific type was requested, convert to the interchange format
761dbc936acSStephan Aßmus 	if (outType == 0)
762dbc936acSStephan Aßmus 		outType = B_TRANSLATOR_BITMAP;
7639949213aSStephan Aßmus 
764dbc936acSStephan Aßmus 	// Setup a "breakpoint" since throwing exceptions does not seem to work
765dbc936acSStephan Aßmus 	// at all in an add-on. (?)
766dbc936acSStephan Aßmus 	// In the be_jerror.cpp we implement a handler for critical library errors
767dbc936acSStephan Aßmus 	// (be_error_exit()) and there we use the longjmp() function to return to
768dbc936acSStephan Aßmus 	// this place. If this happens, it is as if the setjmp() call is called
769dbc936acSStephan Aßmus 	// a second time, but this time the return value will be 1. The first
770dbc936acSStephan Aßmus 	// invokation will return 0.
771b91634cbSStephan Aßmus 	jmp_buf longJumpBuffer;
772b91634cbSStephan Aßmus 	int jmpRet = setjmp(longJumpBuffer);
773dbc936acSStephan Aßmus 	if (jmpRet == 1)
774dbc936acSStephan Aßmus 		return B_ERROR;
775dbc936acSStephan Aßmus 
776dbc936acSStephan Aßmus 	try {
7779949213aSStephan Aßmus 		// What action to take, based on the findings of Identify()
7789949213aSStephan Aßmus 		if (outType == inInfo->type) {
7799949213aSStephan Aßmus 			return Copy(inSource, outDestination);
780dbc936acSStephan Aßmus 		} else if (inInfo->type == B_TRANSLATOR_BITMAP
781dbc936acSStephan Aßmus 				&& outType == JPEG_FORMAT) {
782b91634cbSStephan Aßmus 			return Compress(inSource, outDestination, &longJumpBuffer);
783dbc936acSStephan Aßmus 		} else if (inInfo->type == JPEG_FORMAT
784dbc936acSStephan Aßmus 				&& outType == B_TRANSLATOR_BITMAP) {
785b91634cbSStephan Aßmus 			return Decompress(inSource, outDestination, ioExtension,
786b91634cbSStephan Aßmus 				&longJumpBuffer);
7879949213aSStephan Aßmus 		}
788dbc936acSStephan Aßmus 	} catch (...) {
789dbc936acSStephan Aßmus 		fprintf(stderr, "libjpeg encoutered a critical error "
790dbc936acSStephan Aßmus 			"(caught C++ exception).\n");
791dbc936acSStephan Aßmus 		return B_ERROR;
792dbc936acSStephan Aßmus 	}
7939949213aSStephan Aßmus 
7949949213aSStephan Aßmus 	return B_NO_TRANSLATOR;
7959949213aSStephan Aßmus }
7969949213aSStephan Aßmus 
797*b98ef4f9SStephan Aßmus 
798d8e2fb50SAxel Dörfler /*!	The user has requested the same format for input and output, so just copy */
799*b98ef4f9SStephan Aßmus status_t
800*b98ef4f9SStephan Aßmus JPEGTranslator::Copy(BPositionIO* in, BPositionIO* out)
8019949213aSStephan Aßmus {
8029949213aSStephan Aßmus 	int block_size = 65536;
8039949213aSStephan Aßmus 	void* buffer = malloc(block_size);
8049949213aSStephan Aßmus 	char temp[1024];
8059949213aSStephan Aßmus 	if (buffer == NULL) {
8069949213aSStephan Aßmus 		buffer = temp;
8079949213aSStephan Aßmus 		block_size = 1024;
8089949213aSStephan Aßmus 	}
8099949213aSStephan Aßmus 	status_t err = B_OK;
8109949213aSStephan Aßmus 
8119949213aSStephan Aßmus 	// Read until end of file or error
8129949213aSStephan Aßmus 	while (1) {
8139949213aSStephan Aßmus 		ssize_t to_read = block_size;
8149949213aSStephan Aßmus 		err = in->Read(buffer, to_read);
8159949213aSStephan Aßmus 		// Explicit check for EOF
8169949213aSStephan Aßmus 		if (err == -1) {
8179949213aSStephan Aßmus 			if (buffer != temp) free(buffer);
8189949213aSStephan Aßmus 			return B_OK;
8199949213aSStephan Aßmus 		}
8209949213aSStephan Aßmus 		if (err <= B_OK) break;
8219949213aSStephan Aßmus 		to_read = err;
8229949213aSStephan Aßmus 		err = out->Write(buffer, to_read);
8239949213aSStephan Aßmus 		if (err != to_read) if (err >= 0) err = B_DEVICE_FULL;
8249949213aSStephan Aßmus 		if (err < B_OK) break;
8259949213aSStephan Aßmus 	}
8269949213aSStephan Aßmus 
8279949213aSStephan Aßmus 	if (buffer != temp) free(buffer);
8289949213aSStephan Aßmus 	return (err >= 0) ? B_OK : err;
8299949213aSStephan Aßmus }
8309949213aSStephan Aßmus 
831d8e2fb50SAxel Dörfler 
832d8e2fb50SAxel Dörfler /*!	Encode into the native format */
833*b98ef4f9SStephan Aßmus status_t
834*b98ef4f9SStephan Aßmus JPEGTranslator::Compress(BPositionIO* in, BPositionIO* out,
835*b98ef4f9SStephan Aßmus 	const jmp_buf* longJumpBuffer)
8369949213aSStephan Aßmus {
837*b98ef4f9SStephan Aßmus 	using namespace conversion;
8389949213aSStephan Aßmus 
8399949213aSStephan Aßmus 	// Read info about bitmap
8409949213aSStephan Aßmus 	TranslatorBitmap header;
8419949213aSStephan Aßmus 	status_t err = in->Read(&header, sizeof(TranslatorBitmap));
842d8e2fb50SAxel Dörfler 	if (err < B_OK)
843d8e2fb50SAxel Dörfler 		return err;
844d8e2fb50SAxel Dörfler 	else if (err < (int)sizeof(TranslatorBitmap))
845d8e2fb50SAxel Dörfler 		return B_ERROR;
8469949213aSStephan Aßmus 
8479949213aSStephan Aßmus 	// Grab dimension, color space, and size information from the stream
8489949213aSStephan Aßmus 	BRect bounds;
8499949213aSStephan Aßmus 	bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left);
8509949213aSStephan Aßmus 	bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top);
8519949213aSStephan Aßmus 	bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right);
8529949213aSStephan Aßmus 	bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom);
8539949213aSStephan Aßmus 
8549949213aSStephan Aßmus 	int32 in_row_bytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes);
8559949213aSStephan Aßmus 
8569949213aSStephan Aßmus 	int width = bounds.IntegerWidth() + 1;
8579949213aSStephan Aßmus 	int height = bounds.IntegerHeight() + 1;
8589949213aSStephan Aßmus 
8599949213aSStephan Aßmus 	// Function pointer to convert function
8609949213aSStephan Aßmus 	// It will point to proper function if needed
8619e34f742SAxel Dörfler 	void (*converter)(uchar* inscanline, uchar* outscanline,
8629e34f742SAxel Dörfler 		int32 inRowBytes) = NULL;
8639949213aSStephan Aßmus 
8649949213aSStephan Aßmus 	// Default color info
8659949213aSStephan Aßmus 	J_COLOR_SPACE jpg_color_space = JCS_RGB;
8669949213aSStephan Aßmus 	int jpg_input_components = 3;
8679949213aSStephan Aßmus 	int32 out_row_bytes;
8689949213aSStephan Aßmus 	int padding = 0;
8699949213aSStephan Aßmus 
870d8e2fb50SAxel Dörfler 	switch ((color_space)B_BENDIAN_TO_HOST_INT32(header.colors)) {
8719949213aSStephan Aßmus 		case B_CMAP8:
8729949213aSStephan Aßmus 			converter = convert_from_cmap8_to_24;
8739949213aSStephan Aßmus 			padding = in_row_bytes - width;
8749949213aSStephan Aßmus 			break;
875d8e2fb50SAxel Dörfler 
8769949213aSStephan Aßmus 		case B_GRAY1:
877*b98ef4f9SStephan Aßmus 			if (fSettings->SetGetBool(JPEG_SET_GRAY1_AS_RGB24, NULL)) {
8789949213aSStephan Aßmus 				converter = convert_from_gray1_to_24;
8799949213aSStephan Aßmus 			} else {
8809949213aSStephan Aßmus 				jpg_input_components = 1;
8819949213aSStephan Aßmus 				jpg_color_space = JCS_GRAYSCALE;
8829949213aSStephan Aßmus 				converter = convert_from_gray1_to_gray8;
8839949213aSStephan Aßmus 			}
8849949213aSStephan Aßmus 			padding = in_row_bytes - (width / 8);
8859949213aSStephan Aßmus 			break;
886d8e2fb50SAxel Dörfler 
8879949213aSStephan Aßmus 		case B_GRAY8:
8889949213aSStephan Aßmus 			jpg_input_components = 1;
8899949213aSStephan Aßmus 			jpg_color_space = JCS_GRAYSCALE;
8909949213aSStephan Aßmus 			padding = in_row_bytes - width;
8919949213aSStephan Aßmus 			break;
892d8e2fb50SAxel Dörfler 
8939949213aSStephan Aßmus 		case B_RGB15:
8949949213aSStephan Aßmus 		case B_RGBA15:
8959949213aSStephan Aßmus 			converter = convert_from_15_to_24;
8969949213aSStephan Aßmus 			padding = in_row_bytes - (width * 2);
8979949213aSStephan Aßmus 			break;
898d8e2fb50SAxel Dörfler 
8999949213aSStephan Aßmus 		case B_RGB15_BIG:
9009949213aSStephan Aßmus 		case B_RGBA15_BIG:
9019949213aSStephan Aßmus 			converter = convert_from_15b_to_24;
9029949213aSStephan Aßmus 			padding = in_row_bytes - (width * 2);
9039949213aSStephan Aßmus 			break;
904d8e2fb50SAxel Dörfler 
9059949213aSStephan Aßmus 		case B_RGB16:
9069949213aSStephan Aßmus 			converter = convert_from_16_to_24;
9079949213aSStephan Aßmus 			padding = in_row_bytes - (width * 2);
9089949213aSStephan Aßmus 			break;
909d8e2fb50SAxel Dörfler 
9109949213aSStephan Aßmus 		case B_RGB16_BIG:
9119949213aSStephan Aßmus 			converter = convert_from_16b_to_24;
9129949213aSStephan Aßmus 			padding = in_row_bytes - (width * 2);
9139949213aSStephan Aßmus 			break;
914d8e2fb50SAxel Dörfler 
9159949213aSStephan Aßmus 		case B_RGB24:
9169949213aSStephan Aßmus 			converter = convert_from_24_to_24;
9179949213aSStephan Aßmus 			padding = in_row_bytes - (width * 3);
9189949213aSStephan Aßmus 			break;
919d8e2fb50SAxel Dörfler 
9209949213aSStephan Aßmus 		case B_RGB24_BIG:
9219949213aSStephan Aßmus 			padding = in_row_bytes - (width * 3);
9229949213aSStephan Aßmus 			break;
923d8e2fb50SAxel Dörfler 
9249949213aSStephan Aßmus 		case B_RGB32:
9259949213aSStephan Aßmus 		case B_RGBA32:
9269949213aSStephan Aßmus 			converter = convert_from_32_to_24;
9279949213aSStephan Aßmus 			padding = in_row_bytes - (width * 4);
9289949213aSStephan Aßmus 			break;
929d8e2fb50SAxel Dörfler 
9309949213aSStephan Aßmus 		case B_RGB32_BIG:
9319949213aSStephan Aßmus 		case B_RGBA32_BIG:
9329949213aSStephan Aßmus 			converter = convert_from_32b_to_24;
9339949213aSStephan Aßmus 			padding = in_row_bytes - (width * 4);
9349949213aSStephan Aßmus 			break;
935d8e2fb50SAxel Dörfler 
9369949213aSStephan Aßmus 		case B_CMYK32:
9379949213aSStephan Aßmus 			jpg_color_space = JCS_CMYK;
9389949213aSStephan Aßmus 			jpg_input_components = 4;
9399949213aSStephan Aßmus 			padding = in_row_bytes - (width * 4);
9409949213aSStephan Aßmus 			break;
941d8e2fb50SAxel Dörfler 
9429949213aSStephan Aßmus 		default:
9439949213aSStephan Aßmus 			fprintf(stderr, "Wrong type: Color space not implemented.\n");
9449949213aSStephan Aßmus 			return B_ERROR;
9459949213aSStephan Aßmus 	}
9469949213aSStephan Aßmus 	out_row_bytes = jpg_input_components * width;
9479949213aSStephan Aßmus 
9489949213aSStephan Aßmus 	// Set basic things needed for jpeg writing
9499949213aSStephan Aßmus 	struct jpeg_compress_struct cinfo;
9509949213aSStephan Aßmus 	struct jpeg_error_mgr jerr;
951*b98ef4f9SStephan Aßmus 	cinfo.err = be_jpeg_std_error(&jerr, fSettings, longJumpBuffer);
9529949213aSStephan Aßmus 	jpeg_create_compress(&cinfo);
9539949213aSStephan Aßmus 	be_jpeg_stdio_dest(&cinfo, out);
9549949213aSStephan Aßmus 
9559949213aSStephan Aßmus 	// Set basic values
9569949213aSStephan Aßmus 	cinfo.image_width = width;
9579949213aSStephan Aßmus 	cinfo.image_height = height;
9589949213aSStephan Aßmus 	cinfo.input_components = jpg_input_components;
9599949213aSStephan Aßmus 	cinfo.in_color_space = jpg_color_space;
9609949213aSStephan Aßmus 	jpeg_set_defaults(&cinfo);
9619949213aSStephan Aßmus 
9629949213aSStephan Aßmus 	// Set better accuracy
9639949213aSStephan Aßmus 	cinfo.dct_method = JDCT_ISLOW;
9649949213aSStephan Aßmus 
9659949213aSStephan Aßmus 	// This is needed to prevent some colors loss
9669949213aSStephan Aßmus 	// With it generated jpegs are as good as from Fireworks (at last! :D)
967*b98ef4f9SStephan Aßmus 	if (fSettings->SetGetBool(JPEG_SET_OPT_COLORS, NULL)) {
9689949213aSStephan Aßmus 		int index = 0;
9699949213aSStephan Aßmus 		while (index < cinfo.num_components) {
9709949213aSStephan Aßmus 			cinfo.comp_info[index].h_samp_factor = 1;
9719949213aSStephan Aßmus 			cinfo.comp_info[index].v_samp_factor = 1;
9729949213aSStephan Aßmus 			// This will make file smaller, but with worse quality more or less
9739949213aSStephan Aßmus 			// like with 93%-94% (but it's subjective opinion) on tested images
9749949213aSStephan Aßmus 			// but with smaller size (between 92% and 93% on tested images)
975*b98ef4f9SStephan Aßmus 			if (fSettings->SetGetBool(JPEG_SET_SMALL_FILES))
9769949213aSStephan Aßmus 				cinfo.comp_info[index].quant_tbl_no = 1;
9779949213aSStephan Aßmus 			// This will make bigger file, but also better quality ;]
9789949213aSStephan Aßmus 			// from my tests it seems like useless - better quality with smaller
9799949213aSStephan Aßmus 			// can be acheived without this
9809949213aSStephan Aßmus //			cinfo.comp_info[index].dc_tbl_no = 1;
9819949213aSStephan Aßmus //			cinfo.comp_info[index].ac_tbl_no = 1;
9829949213aSStephan Aßmus 			index++;
9839949213aSStephan Aßmus 		}
9849949213aSStephan Aßmus 	}
9859949213aSStephan Aßmus 
9869949213aSStephan Aßmus 	// Set quality
987*b98ef4f9SStephan Aßmus 	jpeg_set_quality(&cinfo, fSettings->SetGetInt32(JPEG_SET_QUALITY, NULL), true);
9889949213aSStephan Aßmus 
9899949213aSStephan Aßmus 	// Set progressive compression if needed
9909949213aSStephan Aßmus 	// if not, turn on optimizing in libjpeg
991*b98ef4f9SStephan Aßmus 	if (fSettings->SetGetBool(JPEG_SET_PROGRESSIVE, NULL))
9929949213aSStephan Aßmus 		jpeg_simple_progression(&cinfo);
9939949213aSStephan Aßmus 	else
9949949213aSStephan Aßmus 		cinfo.optimize_coding = TRUE;
9959949213aSStephan Aßmus 
9969949213aSStephan Aßmus 	// Set smoothing (effect like Blur)
997*b98ef4f9SStephan Aßmus 	cinfo.smoothing_factor = fSettings->SetGetInt32(JPEG_SET_SMOOTHING, NULL);
9989949213aSStephan Aßmus 
9999949213aSStephan Aßmus 	// Initialize compression
10009949213aSStephan Aßmus 	jpeg_start_compress(&cinfo, TRUE);
10019949213aSStephan Aßmus 
10029949213aSStephan Aßmus 	// Declare scanlines
10039949213aSStephan Aßmus 	JSAMPROW in_scanline = NULL;
10049949213aSStephan Aßmus 	JSAMPROW out_scanline = NULL;
1005*b98ef4f9SStephan Aßmus 	JSAMPROW writeline;
1006*b98ef4f9SStephan Aßmus 		// Pointer to in_scanline (default) or out_scanline (if there will be conversion)
10079949213aSStephan Aßmus 
10089949213aSStephan Aßmus 	// Allocate scanline
10099949213aSStephan Aßmus 	// Use libjpeg memory allocation functions, so in case of error it will free them itself
1010d8e2fb50SAxel Dörfler 	in_scanline = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo,
1011d8e2fb50SAxel Dörfler 		JPOOL_PERMANENT, in_row_bytes);
10129949213aSStephan Aßmus 
10139949213aSStephan Aßmus 	// We need 2nd scanline storage ony for conversion
10149949213aSStephan Aßmus 	if (converter != NULL) {
10159949213aSStephan Aßmus 		// There will be conversion, allocate second scanline...
10169949213aSStephan Aßmus 		// Use libjpeg memory allocation functions, so in case of error it will free them itself
1017d8e2fb50SAxel Dörfler 	    out_scanline = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo,
1018d8e2fb50SAxel Dörfler 	    	JPOOL_PERMANENT, out_row_bytes);
10199949213aSStephan Aßmus 		// ... and make it the one to write to file
10209949213aSStephan Aßmus 		writeline = out_scanline;
10219949213aSStephan Aßmus 	} else
10229949213aSStephan Aßmus 		writeline = in_scanline;
10239949213aSStephan Aßmus 
10249949213aSStephan Aßmus 	while (cinfo.next_scanline < cinfo.image_height) {
10259949213aSStephan Aßmus 		// Read scanline
10269949213aSStephan Aßmus 		err = in->Read(in_scanline, in_row_bytes);
10279949213aSStephan Aßmus 		if (err < in_row_bytes)
1028d8e2fb50SAxel Dörfler 			return err < B_OK ? Error((j_common_ptr)&cinfo, err)
1029d8e2fb50SAxel Dörfler 				: Error((j_common_ptr)&cinfo, B_ERROR);
10309949213aSStephan Aßmus 
10319949213aSStephan Aßmus 		// Convert if needed
10329949213aSStephan Aßmus 		if (converter != NULL)
10339949213aSStephan Aßmus 			converter(in_scanline, out_scanline, in_row_bytes - padding);
10349949213aSStephan Aßmus 
10359949213aSStephan Aßmus 		// Write scanline
10369949213aSStephan Aßmus 	   	jpeg_write_scanlines(&cinfo, &writeline, 1);
10379949213aSStephan Aßmus 	}
10389949213aSStephan Aßmus 
10399949213aSStephan Aßmus 	jpeg_finish_compress(&cinfo);
10409949213aSStephan Aßmus 	jpeg_destroy_compress(&cinfo);
10419949213aSStephan Aßmus 	return B_OK;
10429949213aSStephan Aßmus }
10439949213aSStephan Aßmus 
1044d8e2fb50SAxel Dörfler 
1045d8e2fb50SAxel Dörfler /*!	Decode the native format */
1046*b98ef4f9SStephan Aßmus status_t
1047*b98ef4f9SStephan Aßmus JPEGTranslator::Decompress(BPositionIO* in, BPositionIO* out,
1048*b98ef4f9SStephan Aßmus 	BMessage* ioExtension, const jmp_buf* longJumpBuffer)
10499949213aSStephan Aßmus {
1050*b98ef4f9SStephan Aßmus 	using namespace conversion;
10519949213aSStephan Aßmus 
10529949213aSStephan Aßmus 	// Set basic things needed for jpeg reading
10539949213aSStephan Aßmus 	struct jpeg_decompress_struct cinfo;
10549949213aSStephan Aßmus 	struct jpeg_error_mgr jerr;
1055*b98ef4f9SStephan Aßmus 	cinfo.err = be_jpeg_std_error(&jerr, fSettings, longJumpBuffer);
10569949213aSStephan Aßmus 	jpeg_create_decompress(&cinfo);
10579949213aSStephan Aßmus 	be_jpeg_stdio_src(&cinfo, in);
10589949213aSStephan Aßmus 
105952e8f46aSAxel Dörfler 	jpeg_save_markers(&cinfo, MARKER_EXIF, 131072);
106052e8f46aSAxel Dörfler 		// make sure the EXIF tag is stored
106152e8f46aSAxel Dörfler 
10629949213aSStephan Aßmus 	// Read info about image
10639949213aSStephan Aßmus 	jpeg_read_header(&cinfo, TRUE);
10649949213aSStephan Aßmus 
106552e8f46aSAxel Dörfler 	BMessage exif;
106652e8f46aSAxel Dörfler 
1067f13b5de6SAxel Dörfler 	// parse EXIF data and add it ioExtension, if any
106852e8f46aSAxel Dörfler 	jpeg_marker_struct* marker = cinfo.marker_list;
106952e8f46aSAxel Dörfler 	while (marker != NULL) {
107052e8f46aSAxel Dörfler 		if (marker->marker == MARKER_EXIF
107152e8f46aSAxel Dörfler 			&& !strncmp((char*)marker->data, "Exif", 4)) {
1072f13b5de6SAxel Dörfler 			if (ioExtension != NULL) {
107352e8f46aSAxel Dörfler 				// Strip EXIF header from TIFF data
107452e8f46aSAxel Dörfler 				ioExtension->AddData("exif", B_RAW_TYPE,
107552e8f46aSAxel Dörfler 					(uint8*)marker->data + 6, marker->data_length - 6);
1076f13b5de6SAxel Dörfler 			}
107752e8f46aSAxel Dörfler 
107852e8f46aSAxel Dörfler 			BMemoryIO io(marker->data + 6, marker->data_length - 6);
107952e8f46aSAxel Dörfler 			convert_exif_to_message(io, exif);
108052e8f46aSAxel Dörfler 		}
108152e8f46aSAxel Dörfler 		marker = marker->next;
108252e8f46aSAxel Dörfler 	}
108352e8f46aSAxel Dörfler 
10849949213aSStephan Aßmus 	// Default color info
108552e8f46aSAxel Dörfler 	color_space outColorSpace = B_RGB32;
108652e8f46aSAxel Dörfler 	int outColorComponents = 4;
10879949213aSStephan Aßmus 
10889949213aSStephan Aßmus 	// Function pointer to convert function
10899949213aSStephan Aßmus 	// It will point to proper function if needed
109052e8f46aSAxel Dörfler 	void (*converter)(uchar* inScanLine, uchar* outScanLine,
10919e34f742SAxel Dörfler 		int32 inRowBytes, int32 xStep) = convert_from_24_to_32;
10929949213aSStephan Aßmus 
10939949213aSStephan Aßmus 	// If color space isn't rgb
10949949213aSStephan Aßmus 	if (cinfo.out_color_space != JCS_RGB) {
1095d8e2fb50SAxel Dörfler 		switch (cinfo.out_color_space) {
10969949213aSStephan Aßmus 			case JCS_UNKNOWN:		/* error/unspecified */
10979949213aSStephan Aßmus 				fprintf(stderr, "From Type: Jpeg uses unknown color type\n");
10989949213aSStephan Aßmus 				break;
10999949213aSStephan Aßmus 			case JCS_GRAYSCALE:		/* monochrome */
11009949213aSStephan Aßmus 				// Check if user wants to read only as RGB32 or not
1101*b98ef4f9SStephan Aßmus 				if (!fSettings->SetGetBool(JPEG_SET_ALWAYS_RGB32, NULL)) {
11029949213aSStephan Aßmus 					// Grayscale
110352e8f46aSAxel Dörfler 					outColorSpace = B_GRAY8;
110452e8f46aSAxel Dörfler 					outColorComponents = 1;
11059e34f742SAxel Dörfler 					converter = translate_8;
11069949213aSStephan Aßmus 				} else {
11079949213aSStephan Aßmus 					// RGB
11089949213aSStephan Aßmus 					cinfo.out_color_space = JCS_RGB;
11099949213aSStephan Aßmus 					cinfo.output_components = 3;
11109949213aSStephan Aßmus 					converter = convert_from_24_to_32;
11119949213aSStephan Aßmus 				}
11129949213aSStephan Aßmus 				break;
11139949213aSStephan Aßmus 			case JCS_YCbCr:		/* Y/Cb/Cr (also known as YUV) */
11149949213aSStephan Aßmus 				cinfo.out_color_space = JCS_RGB;
11159949213aSStephan Aßmus 				converter = convert_from_24_to_32;
11169949213aSStephan Aßmus 				break;
11179949213aSStephan Aßmus 			case JCS_YCCK:		/* Y/Cb/Cr/K */
11189949213aSStephan Aßmus 				// Let libjpeg convert it to CMYK
11199949213aSStephan Aßmus 				cinfo.out_color_space = JCS_CMYK;
11209949213aSStephan Aßmus 				// Fall through to CMYK since we need the same settings
11219949213aSStephan Aßmus 			case JCS_CMYK:		/* C/M/Y/K */
11229949213aSStephan Aßmus 				// Use proper converter
1123*b98ef4f9SStephan Aßmus 				if (fSettings->SetGetBool(JPEG_SET_PHOTOSHOP_CMYK))
11249949213aSStephan Aßmus 					converter = convert_from_CMYK_to_32_photoshop;
11259949213aSStephan Aßmus 				else
11269949213aSStephan Aßmus 					converter = convert_from_CMYK_to_32;
11279949213aSStephan Aßmus 				break;
11289949213aSStephan Aßmus 			default:
11299949213aSStephan Aßmus 				fprintf(stderr, "From Type: Jpeg uses hmm... i don't know really :(\n");
11309949213aSStephan Aßmus 				break;
11319949213aSStephan Aßmus 		}
11329949213aSStephan Aßmus 	}
11339949213aSStephan Aßmus 
11349949213aSStephan Aßmus 	// Initialize decompression
11359949213aSStephan Aßmus 	jpeg_start_decompress(&cinfo);
11369949213aSStephan Aßmus 
11379e34f742SAxel Dörfler 	// retrieve orientation from settings/EXIF
113852e8f46aSAxel Dörfler 	int32 orientation;
11399e34f742SAxel Dörfler 	if (ioExtension == NULL
11409e34f742SAxel Dörfler 		|| ioExtension->FindInt32("exif:orientation", &orientation) != B_OK) {
114152e8f46aSAxel Dörfler 		if (exif.FindInt32("Orientation", &orientation) != B_OK)
114252e8f46aSAxel Dörfler 			orientation = 1;
114352e8f46aSAxel Dörfler 	}
11449949213aSStephan Aßmus 
11459e34f742SAxel Dörfler 	if (orientation != 1 && converter == NULL)
11469e34f742SAxel Dörfler 		converter = translate_8;
11479e34f742SAxel Dörfler 
11489e34f742SAxel Dörfler 	int32 outputWidth = orientation > 4 ? cinfo.output_height : cinfo.output_width;
11499e34f742SAxel Dörfler 	int32 outputHeight = orientation > 4 ? cinfo.output_width : cinfo.output_height;
11509e34f742SAxel Dörfler 
11519e34f742SAxel Dörfler 	int32 destOffset = dest_index(outputWidth, outputHeight,
11529e34f742SAxel Dörfler 		0, 0, orientation) * outColorComponents;
11539e34f742SAxel Dörfler 	int32 xStep = dest_index(outputWidth, outputHeight,
11549e34f742SAxel Dörfler 		1, 0, orientation) * outColorComponents - destOffset;
11559e34f742SAxel Dörfler 	int32 yStep = dest_index(outputWidth, outputHeight,
11569e34f742SAxel Dörfler 		0, 1, orientation) * outColorComponents - destOffset;
11579e34f742SAxel Dörfler 	bool needAll = orientation != 1;
11589e34f742SAxel Dörfler 
11599e34f742SAxel Dörfler 	// Initialize this bounds rect to the size of your image
11609e34f742SAxel Dörfler 	BRect bounds(0, 0, outputWidth - 1, outputHeight - 1);
11619e34f742SAxel Dörfler 
11629e34f742SAxel Dörfler #if 0
11639e34f742SAxel Dörfler printf("destOffset = %ld, xStep = %ld, yStep = %ld, input: %ld x %ld, output: %ld x %ld, orientation %ld\n",
11649e34f742SAxel Dörfler 	destOffset, xStep, yStep, (int32)cinfo.output_width, (int32)cinfo.output_height,
11659e34f742SAxel Dörfler 	bounds.IntegerWidth() + 1, bounds.IntegerHeight() + 1, orientation);
11669e34f742SAxel Dörfler #endif
11679e34f742SAxel Dörfler 
11689949213aSStephan Aßmus 	// Bytes count in one line of image (scanline)
11699e34f742SAxel Dörfler 	int32 inRowBytes = cinfo.output_width * cinfo.output_components;
11709e34f742SAxel Dörfler 	int32 rowBytes = (bounds.IntegerWidth() + 1) * outColorComponents;
11719e34f742SAxel Dörfler 	int32 dataSize = cinfo.output_width * cinfo.output_height
11729e34f742SAxel Dörfler 		* outColorComponents;
11739949213aSStephan Aßmus 
11749949213aSStephan Aßmus 	// Fill out the B_TRANSLATOR_BITMAP's header
11759949213aSStephan Aßmus 	TranslatorBitmap header;
11769949213aSStephan Aßmus 	header.magic = B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP);
11779949213aSStephan Aßmus 	header.bounds.left = B_HOST_TO_BENDIAN_FLOAT(bounds.left);
11789949213aSStephan Aßmus 	header.bounds.top = B_HOST_TO_BENDIAN_FLOAT(bounds.top);
11799949213aSStephan Aßmus 	header.bounds.right = B_HOST_TO_BENDIAN_FLOAT(bounds.right);
11809949213aSStephan Aßmus 	header.bounds.bottom = B_HOST_TO_BENDIAN_FLOAT(bounds.bottom);
118152e8f46aSAxel Dörfler 	header.colors = (color_space)B_HOST_TO_BENDIAN_INT32(outColorSpace);
118252e8f46aSAxel Dörfler 	header.rowBytes = B_HOST_TO_BENDIAN_INT32(rowBytes);
11839e34f742SAxel Dörfler 	header.dataSize = B_HOST_TO_BENDIAN_INT32(dataSize);
11849949213aSStephan Aßmus 
11859949213aSStephan Aßmus 	// Write out the header
11869949213aSStephan Aßmus 	status_t err = out->Write(&header, sizeof(TranslatorBitmap));
1187d8e2fb50SAxel Dörfler 	if (err < B_OK)
1188d8e2fb50SAxel Dörfler 		return Error((j_common_ptr)&cinfo, err);
1189d8e2fb50SAxel Dörfler 	else if (err < (int)sizeof(TranslatorBitmap))
1190d8e2fb50SAxel Dörfler 		return Error((j_common_ptr)&cinfo, B_ERROR);
11919949213aSStephan Aßmus 
11929949213aSStephan Aßmus 	// Declare scanlines
11939e34f742SAxel Dörfler 	JSAMPROW inScanLine = NULL;
11949e34f742SAxel Dörfler 	uint8* dest = NULL;
11959e34f742SAxel Dörfler 	uint8* destLine = NULL;
11969949213aSStephan Aßmus 
11979949213aSStephan Aßmus 	// Allocate scanline
11989949213aSStephan Aßmus 	// Use libjpeg memory allocation functions, so in case of error it will free them itself
11999e34f742SAxel Dörfler     inScanLine = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo,
12009e34f742SAxel Dörfler     	JPOOL_PERMANENT, inRowBytes);
12019949213aSStephan Aßmus 
12029949213aSStephan Aßmus 	// We need 2nd scanline storage only for conversion
12039949213aSStephan Aßmus 	if (converter != NULL) {
12049949213aSStephan Aßmus 		// There will be conversion, allocate second scanline...
1205*b98ef4f9SStephan Aßmus 		// Use libjpeg memory allocation functions, so in case of error it will
1206*b98ef4f9SStephan Aßmus 		// free them itself
12079e34f742SAxel Dörfler 	    dest = (uint8*)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo,
12089e34f742SAxel Dörfler 	    	JPOOL_PERMANENT, needAll ? dataSize : rowBytes);
12099e34f742SAxel Dörfler 	    destLine = dest + destOffset;
12109949213aSStephan Aßmus 	} else
12119e34f742SAxel Dörfler 		destLine = inScanLine;
12129949213aSStephan Aßmus 
12139949213aSStephan Aßmus 	while (cinfo.output_scanline < cinfo.output_height) {
12149949213aSStephan Aßmus 		// Read scanline
12159e34f742SAxel Dörfler 		jpeg_read_scanlines(&cinfo, &inScanLine, 1);
12169949213aSStephan Aßmus 
12179949213aSStephan Aßmus 		// Convert if needed
12189949213aSStephan Aßmus 		if (converter != NULL)
12199e34f742SAxel Dörfler 			converter(inScanLine, destLine, inRowBytes, xStep);
12209949213aSStephan Aßmus 
12219e34f742SAxel Dörfler 		if (!needAll) {
12229949213aSStephan Aßmus 	  		// Write the scanline buffer to the output stream
12239e34f742SAxel Dörfler 			ssize_t bytesWritten = out->Write(destLine, rowBytes);
12249e34f742SAxel Dörfler 			if (bytesWritten < rowBytes) {
12259e34f742SAxel Dörfler 				return bytesWritten < B_OK
12269e34f742SAxel Dörfler 					? Error((j_common_ptr)&cinfo, bytesWritten)
1227d8e2fb50SAxel Dörfler 					: Error((j_common_ptr)&cinfo, B_ERROR);
12289949213aSStephan Aßmus 			}
12299e34f742SAxel Dörfler 		} else
12309e34f742SAxel Dörfler 			destLine += yStep;
12319e34f742SAxel Dörfler 	}
12329e34f742SAxel Dörfler 
12339e34f742SAxel Dörfler 	if (needAll) {
12349e34f742SAxel Dörfler 		ssize_t bytesWritten = out->Write(dest, dataSize);
12359e34f742SAxel Dörfler 		if (bytesWritten < dataSize) {
12369e34f742SAxel Dörfler 			return bytesWritten < B_OK
12379e34f742SAxel Dörfler 				? Error((j_common_ptr)&cinfo, bytesWritten)
12389e34f742SAxel Dörfler 				: Error((j_common_ptr)&cinfo, B_ERROR);
12399e34f742SAxel Dörfler 		}
12409e34f742SAxel Dörfler 	}
12419949213aSStephan Aßmus 
12429949213aSStephan Aßmus 	jpeg_finish_decompress(&cinfo);
12439949213aSStephan Aßmus 	jpeg_destroy_decompress(&cinfo);
12449949213aSStephan Aßmus 	return B_OK;
12459949213aSStephan Aßmus }
12469949213aSStephan Aßmus 
1247*b98ef4f9SStephan Aßmus /*! have the other PopulateInfoFromFormat() check both inputFormats & outputFormats */
1248*b98ef4f9SStephan Aßmus status_t
1249*b98ef4f9SStephan Aßmus JPEGTranslator::PopulateInfoFromFormat(translator_info* info,
1250*b98ef4f9SStephan Aßmus 	uint32 formatType, translator_id id)
1251*b98ef4f9SStephan Aßmus {
1252*b98ef4f9SStephan Aßmus 	int32 formatCount;
1253*b98ef4f9SStephan Aßmus 	const translation_format* formats = OutputFormats(&formatCount);
1254*b98ef4f9SStephan Aßmus 	for (int i = 0; i <= 1 ;formats = InputFormats(&formatCount), i++) {
1255*b98ef4f9SStephan Aßmus 		if (PopulateInfoFromFormat(info, formatType,
1256*b98ef4f9SStephan Aßmus 			formats, formatCount) == B_OK) {
1257*b98ef4f9SStephan Aßmus 			info->translator = id;
1258*b98ef4f9SStephan Aßmus 			return B_OK;
1259*b98ef4f9SStephan Aßmus 		}
1260*b98ef4f9SStephan Aßmus 	}
1261*b98ef4f9SStephan Aßmus 
1262*b98ef4f9SStephan Aßmus 	return B_ERROR;
1263*b98ef4f9SStephan Aßmus }
1264*b98ef4f9SStephan Aßmus 
1265*b98ef4f9SStephan Aßmus 
1266*b98ef4f9SStephan Aßmus status_t
1267*b98ef4f9SStephan Aßmus JPEGTranslator::PopulateInfoFromFormat(translator_info* info,
1268*b98ef4f9SStephan Aßmus 	uint32 formatType, const translation_format* formats, int32 formatCount)
1269*b98ef4f9SStephan Aßmus {
1270*b98ef4f9SStephan Aßmus 	for (int i = 0; i < formatCount; i++) {
1271*b98ef4f9SStephan Aßmus 		if (formats[i].type == formatType) {
1272*b98ef4f9SStephan Aßmus 			info->type = formatType;
1273*b98ef4f9SStephan Aßmus 			info->group = formats[i].group;
1274*b98ef4f9SStephan Aßmus 			info->quality = formats[i].quality;
1275*b98ef4f9SStephan Aßmus 			info->capability = formats[i].capability;
1276*b98ef4f9SStephan Aßmus 			strcpy(info->name, formats[i].name);
1277*b98ef4f9SStephan Aßmus 			strcpy(info->MIME,  formats[i].MIME);
1278*b98ef4f9SStephan Aßmus 			return B_OK;
1279*b98ef4f9SStephan Aßmus 		}
1280*b98ef4f9SStephan Aßmus 	}
1281*b98ef4f9SStephan Aßmus 
1282*b98ef4f9SStephan Aßmus 	return B_ERROR;
1283*b98ef4f9SStephan Aßmus }
1284*b98ef4f9SStephan Aßmus 
1285d8e2fb50SAxel Dörfler /*!
1286d8e2fb50SAxel Dörfler 	Frees jpeg alocated memory
1287d8e2fb50SAxel Dörfler 	Returns given error (B_ERROR by default)
1288d8e2fb50SAxel Dörfler */
1289*b98ef4f9SStephan Aßmus status_t
1290*b98ef4f9SStephan Aßmus JPEGTranslator::Error(j_common_ptr cinfo, status_t error)
12919949213aSStephan Aßmus {
12929949213aSStephan Aßmus 	jpeg_destroy(cinfo);
12939949213aSStephan Aßmus 	return error;
12949949213aSStephan Aßmus }
1295d8e2fb50SAxel Dörfler 
1296d8e2fb50SAxel Dörfler 
1297*b98ef4f9SStephan Aßmus JPEGTranslator::JPEGTranslator()
1298*b98ef4f9SStephan Aßmus 	:
1299*b98ef4f9SStephan Aßmus 	BaseTranslator(gTranslatorName, gTranslatorInfo, gTranslatorVersion,
1300*b98ef4f9SStephan Aßmus 	gInputFormats, gInputFormatCount, gOutputFormats, gOutputFormatCount,
1301*b98ef4f9SStephan Aßmus 	SETTINGS_FILE, gSettings, gSettingsCount,
1302*b98ef4f9SStephan Aßmus 	B_TRANSLATOR_BITMAP, JPEG_FORMAT)
1303*b98ef4f9SStephan Aßmus {}
1304*b98ef4f9SStephan Aßmus 
1305*b98ef4f9SStephan Aßmus 
1306*b98ef4f9SStephan Aßmus BTranslator*
1307*b98ef4f9SStephan Aßmus make_nth_translator(int32 n, image_id you, uint32 flags, ...)
1308*b98ef4f9SStephan Aßmus {
1309*b98ef4f9SStephan Aßmus 	if (n == 0)
1310*b98ef4f9SStephan Aßmus 		return new JPEGTranslator();
1311*b98ef4f9SStephan Aßmus 
1312*b98ef4f9SStephan Aßmus 	return NULL;
1313*b98ef4f9SStephan Aßmus }
1314d8e2fb50SAxel Dörfler 
1315d8e2fb50SAxel Dörfler 
1316d8e2fb50SAxel Dörfler int
1317117da2d7SAxel Dörfler main(int, char**)
1318117da2d7SAxel Dörfler {
1319117da2d7SAxel Dörfler 	BApplication app("application/x-vnd.Haiku-JPEGTranslator");
1320*b98ef4f9SStephan Aßmus 	JPEGTranslator* translator = new JPEGTranslator();
1321*b98ef4f9SStephan Aßmus 	if (LaunchTranslatorWindow(translator, gTranslatorName) == B_OK)
1322d8e2fb50SAxel Dörfler 		app.Run();
1323*b98ef4f9SStephan Aßmus 
1324d8e2fb50SAxel Dörfler 	return 0;
1325d8e2fb50SAxel Dörfler }
1326d8e2fb50SAxel Dörfler 
1327