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"
3452e8f46aSAxel Dörfler
3570d59669SSiarzhuk Zharski #include <syslog.h>
3670d59669SSiarzhuk Zharski
37b98ef4f9SStephan Aßmus #include <Alignment.h>
3803901b6cSJérôme Duval #include <Catalog.h>
397d48219bSHannah Boneß #include <LayoutBuilder.h>
408687ff64SAxel Dörfler #include <TabView.h>
41b98ef4f9SStephan Aßmus #include <TextView.h>
428687ff64SAxel Dörfler
43e4bd005dSIngo Weinhold #include "be_jerror.h"
44e4bd005dSIngo Weinhold #include "exif_parser.h"
45e4bd005dSIngo Weinhold #include "TranslatorWindow.h"
46e4bd005dSIngo Weinhold
47e4bd005dSIngo Weinhold
48546208a5SOliver Tappe #undef B_TRANSLATION_CONTEXT
49546208a5SOliver Tappe #define B_TRANSLATION_CONTEXT "JPEGTranslator"
509949213aSStephan Aßmus
5152e8f46aSAxel Dörfler #define MARKER_EXIF 0xe1
5252e8f46aSAxel Dörfler
539949213aSStephan Aßmus // Set these accordingly
549949213aSStephan Aßmus #define JPEG_ACRONYM "JPEG"
559949213aSStephan Aßmus #define JPEG_FORMAT 'JPEG'
569949213aSStephan Aßmus #define JPEG_MIME_STRING "image/jpeg"
579949213aSStephan Aßmus #define JPEG_DESCRIPTION "JPEG image"
589949213aSStephan Aßmus
599949213aSStephan Aßmus // The translation kit's native file type
609949213aSStephan Aßmus #define B_TRANSLATOR_BITMAP_MIME_STRING "image/x-be-bitmap"
61c095606eSRyan Leavengood #define B_TRANSLATOR_BITMAP_DESCRIPTION "Be Bitmap Format (JPEGTranslator)"
629949213aSStephan Aßmus
63b98ef4f9SStephan Aßmus
642e49ff35SSiarzhuk Zharski static const int32 sTranslatorVersion = B_TRANSLATION_MAKE_VERSION(1, 2, 0);
652e49ff35SSiarzhuk Zharski
661da233a7SSiarzhuk Zharski static const char* sTranslatorName = B_TRANSLATE("JPEG images");
671da233a7SSiarzhuk Zharski static const char* sTranslatorInfo = B_TRANSLATE("©2002-2003, Marcin Konicki\n"
68f13b5de6SAxel Dörfler "©2005-2007, Haiku\n"
69758b1d0eSIngo Weinhold "\n"
707fd58091SJérôme Duval "Based on IJG library © 1994-2009, Thomas G. Lane, Guido Vollbeding.\n"
712e49ff35SSiarzhuk Zharski "\thttp://www.ijg.org/files/\n"
72b98ef4f9SStephan Aßmus "\n"
73fcc3e627SStephan Aßmus "with \"lossless\" encoding support patch by Ken Murchison\n"
742e49ff35SSiarzhuk Zharski "\thttp://www.oceana.com/ftp/ljpeg/\n"
75758b1d0eSIngo Weinhold "\n"
76758b1d0eSIngo Weinhold "With some colorspace conversion routines by Magnus Hellman\n"
772e49ff35SSiarzhuk Zharski "\thttp://www.bebits.com/app/802\n");
789949213aSStephan Aßmus
799949213aSStephan Aßmus // Define the formats we know how to read
80bf243977SPhilippe Houdoin static const translation_format sInputFormats[] = {
819949213aSStephan Aßmus { JPEG_FORMAT, B_TRANSLATOR_BITMAP, 0.5, 0.5,
829949213aSStephan Aßmus JPEG_MIME_STRING, JPEG_DESCRIPTION },
839949213aSStephan Aßmus { B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.5, 0.5,
847b5743baSPhilippe Houdoin B_TRANSLATOR_BITMAP_MIME_STRING, B_TRANSLATOR_BITMAP_DESCRIPTION }
859949213aSStephan Aßmus };
869949213aSStephan Aßmus
879949213aSStephan Aßmus // Define the formats we know how to write
88bf243977SPhilippe Houdoin static const translation_format sOutputFormats[] = {
899949213aSStephan Aßmus { JPEG_FORMAT, B_TRANSLATOR_BITMAP, 0.5, 0.5,
909949213aSStephan Aßmus JPEG_MIME_STRING, JPEG_DESCRIPTION },
919949213aSStephan Aßmus { B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.5, 0.5,
927b5743baSPhilippe Houdoin B_TRANSLATOR_BITMAP_MIME_STRING, B_TRANSLATOR_BITMAP_DESCRIPTION }
939949213aSStephan Aßmus };
9452e8f46aSAxel Dörfler
95d8e2fb50SAxel Dörfler
96bf243977SPhilippe Houdoin static const TranSetting sDefaultSettings[] = {
97b98ef4f9SStephan Aßmus {JPEG_SET_SMOOTHING, TRAN_SETTING_INT32, 0},
98b98ef4f9SStephan Aßmus {JPEG_SET_QUALITY, TRAN_SETTING_INT32, 95},
99b98ef4f9SStephan Aßmus {JPEG_SET_PROGRESSIVE, TRAN_SETTING_BOOL, true},
100b98ef4f9SStephan Aßmus {JPEG_SET_OPT_COLORS, TRAN_SETTING_BOOL, true},
101b98ef4f9SStephan Aßmus {JPEG_SET_SMALL_FILES, TRAN_SETTING_BOOL, false},
102b98ef4f9SStephan Aßmus {JPEG_SET_GRAY1_AS_RGB24, TRAN_SETTING_BOOL, false},
103b98ef4f9SStephan Aßmus {JPEG_SET_ALWAYS_RGB32, TRAN_SETTING_BOOL, true},
104b98ef4f9SStephan Aßmus {JPEG_SET_PHOTOSHOP_CMYK, TRAN_SETTING_BOOL, true},
105b98ef4f9SStephan Aßmus {JPEG_SET_SHOWREADWARNING, TRAN_SETTING_BOOL, true}
106b98ef4f9SStephan Aßmus };
107bf243977SPhilippe Houdoin
108bf243977SPhilippe Houdoin const uint32 kNumInputFormats = sizeof(sInputFormats) / sizeof(translation_format);
109bf243977SPhilippe Houdoin const uint32 kNumOutputFormats = sizeof(sOutputFormats) / sizeof(translation_format);
110bf243977SPhilippe Houdoin const uint32 kNumDefaultSettings = sizeof(sDefaultSettings) / sizeof(TranSetting);
1119949213aSStephan Aßmus
112d8e2fb50SAxel Dörfler
113b98ef4f9SStephan Aßmus namespace conversion {
114d8e2fb50SAxel Dörfler
115d8e2fb50SAxel Dörfler
1169e34f742SAxel Dörfler static bool
x_flipped(int32 orientation)1179e34f742SAxel Dörfler x_flipped(int32 orientation)
1189e34f742SAxel Dörfler {
1199e34f742SAxel Dörfler return orientation == 2 || orientation == 3
1209e34f742SAxel Dörfler || orientation == 6 || orientation == 7;
1219e34f742SAxel Dörfler }
1229e34f742SAxel Dörfler
1239e34f742SAxel Dörfler
1249e34f742SAxel Dörfler static bool
y_flipped(int32 orientation)1259e34f742SAxel Dörfler y_flipped(int32 orientation)
1269e34f742SAxel Dörfler {
1279e34f742SAxel Dörfler return orientation == 3 || orientation == 4
1289e34f742SAxel Dörfler || orientation == 7 || orientation == 8;
1299e34f742SAxel Dörfler }
1309e34f742SAxel Dörfler
1319e34f742SAxel Dörfler
1329e34f742SAxel Dörfler static int32
dest_index(uint32 width,uint32 height,uint32 x,uint32 y,int32 orientation)1339e34f742SAxel Dörfler dest_index(uint32 width, uint32 height, uint32 x, uint32 y, int32 orientation)
1349e34f742SAxel Dörfler {
1359e34f742SAxel Dörfler if (orientation > 4) {
1369e34f742SAxel Dörfler uint32 temp = x;
1379e34f742SAxel Dörfler x = y;
1389e34f742SAxel Dörfler y = temp;
1399e34f742SAxel Dörfler }
1409e34f742SAxel Dörfler if (y_flipped(orientation))
1419e34f742SAxel Dörfler y = height - 1 - y;
1429e34f742SAxel Dörfler if (x_flipped(orientation))
1439e34f742SAxel Dörfler x = width - 1 - x;
1449e34f742SAxel Dörfler
1459e34f742SAxel Dörfler return y * width + x;
1469e34f742SAxel Dörfler }
1479e34f742SAxel Dörfler
1489e34f742SAxel Dörfler
1499e34f742SAxel Dörfler // #pragma mark - conversion for compression
150d8e2fb50SAxel Dörfler
151d8e2fb50SAxel Dörfler
152d8e2fb50SAxel Dörfler inline void
convert_from_gray1_to_gray8(uint8 * in,uint8 * out,int32 inRowBytes)1539e34f742SAxel Dörfler convert_from_gray1_to_gray8(uint8* in, uint8* out, int32 inRowBytes)
154d8e2fb50SAxel Dörfler {
155d8e2fb50SAxel Dörfler int32 index = 0;
156d8e2fb50SAxel Dörfler int32 index2 = 0;
1579e34f742SAxel Dörfler while (index < inRowBytes) {
158d8e2fb50SAxel Dörfler unsigned char c = in[index++];
159d8e2fb50SAxel Dörfler for (int b = 128; b; b = b>>1) {
160d8e2fb50SAxel Dörfler unsigned char color;
161d8e2fb50SAxel Dörfler if (c & b)
162d8e2fb50SAxel Dörfler color = 0;
163d8e2fb50SAxel Dörfler else
164d8e2fb50SAxel Dörfler color = 255;
165d8e2fb50SAxel Dörfler out[index2++] = color;
166d8e2fb50SAxel Dörfler }
167d8e2fb50SAxel Dörfler }
168d8e2fb50SAxel Dörfler }
169d8e2fb50SAxel Dörfler
170d8e2fb50SAxel Dörfler
171d8e2fb50SAxel Dörfler inline void
convert_from_gray1_to_24(uint8 * in,uint8 * out,int32 inRowBytes)1729e34f742SAxel Dörfler convert_from_gray1_to_24(uint8* in, uint8* out, int32 inRowBytes)
173d8e2fb50SAxel Dörfler {
174d8e2fb50SAxel Dörfler int32 index = 0;
175d8e2fb50SAxel Dörfler int32 index2 = 0;
1769e34f742SAxel Dörfler while (index < inRowBytes) {
177d8e2fb50SAxel Dörfler unsigned char c = in[index++];
178d8e2fb50SAxel Dörfler for (int b = 128; b; b = b>>1) {
179d8e2fb50SAxel Dörfler unsigned char color;
180d8e2fb50SAxel Dörfler if (c & b)
181d8e2fb50SAxel Dörfler color = 0;
182d8e2fb50SAxel Dörfler else
183d8e2fb50SAxel Dörfler color = 255;
184d8e2fb50SAxel Dörfler out[index2++] = color;
185d8e2fb50SAxel Dörfler out[index2++] = color;
186d8e2fb50SAxel Dörfler out[index2++] = color;
187d8e2fb50SAxel Dörfler }
188d8e2fb50SAxel Dörfler }
189d8e2fb50SAxel Dörfler }
190d8e2fb50SAxel Dörfler
191d8e2fb50SAxel Dörfler
192d8e2fb50SAxel Dörfler inline void
convert_from_cmap8_to_24(uint8 * in,uint8 * out,int32 inRowBytes)1939e34f742SAxel Dörfler convert_from_cmap8_to_24(uint8* in, uint8* out, int32 inRowBytes)
194d8e2fb50SAxel Dörfler {
195d8e2fb50SAxel Dörfler const color_map * map = system_colors();
196d8e2fb50SAxel Dörfler int32 index = 0;
197d8e2fb50SAxel Dörfler int32 index2 = 0;
1989e34f742SAxel Dörfler while (index < inRowBytes) {
199d8e2fb50SAxel Dörfler rgb_color color = map->color_list[in[index++]];
200d8e2fb50SAxel Dörfler
201d8e2fb50SAxel Dörfler out[index2++] = color.red;
202d8e2fb50SAxel Dörfler out[index2++] = color.green;
203d8e2fb50SAxel Dörfler out[index2++] = color.blue;
204d8e2fb50SAxel Dörfler }
205d8e2fb50SAxel Dörfler }
206d8e2fb50SAxel Dörfler
207d8e2fb50SAxel Dörfler
208d8e2fb50SAxel Dörfler inline void
convert_from_15_to_24(uint8 * in,uint8 * out,int32 inRowBytes)2099e34f742SAxel Dörfler convert_from_15_to_24(uint8* in, uint8* out, int32 inRowBytes)
210d8e2fb50SAxel Dörfler {
211d8e2fb50SAxel Dörfler int32 index = 0;
212d8e2fb50SAxel Dörfler int32 index2 = 0;
213d8e2fb50SAxel Dörfler int16 in_pixel;
2149e34f742SAxel Dörfler while (index < inRowBytes) {
215d8e2fb50SAxel Dörfler in_pixel = in[index] | (in[index + 1] << 8);
216d8e2fb50SAxel Dörfler index += 2;
217d8e2fb50SAxel Dörfler
218d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x7c00)) >> 7) | (((in_pixel & 0x7c00)) >> 12);
219d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x3e0)) >> 2) | (((in_pixel & 0x3e0)) >> 7);
220d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2);
221d8e2fb50SAxel Dörfler }
222d8e2fb50SAxel Dörfler }
223d8e2fb50SAxel Dörfler
224d8e2fb50SAxel Dörfler
225d8e2fb50SAxel Dörfler inline void
convert_from_15b_to_24(uint8 * in,uint8 * out,int32 inRowBytes)2269e34f742SAxel Dörfler convert_from_15b_to_24(uint8* in, uint8* out, int32 inRowBytes)
227d8e2fb50SAxel Dörfler {
228d8e2fb50SAxel Dörfler int32 index = 0;
229d8e2fb50SAxel Dörfler int32 index2 = 0;
230d8e2fb50SAxel Dörfler int16 in_pixel;
2319e34f742SAxel Dörfler while (index < inRowBytes) {
232d8e2fb50SAxel Dörfler in_pixel = in[index + 1] | (in[index] << 8);
233d8e2fb50SAxel Dörfler index += 2;
234d8e2fb50SAxel Dörfler
235d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x7c00)) >> 7) | (((in_pixel & 0x7c00)) >> 12);
236d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x3e0)) >> 2) | (((in_pixel & 0x3e0)) >> 7);
237d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2);
238d8e2fb50SAxel Dörfler }
239d8e2fb50SAxel Dörfler }
240d8e2fb50SAxel Dörfler
241d8e2fb50SAxel Dörfler
242d8e2fb50SAxel Dörfler inline void
convert_from_16_to_24(uint8 * in,uint8 * out,int32 inRowBytes)2439e34f742SAxel Dörfler convert_from_16_to_24(uint8* in, uint8* out, int32 inRowBytes)
244d8e2fb50SAxel Dörfler {
245d8e2fb50SAxel Dörfler int32 index = 0;
246d8e2fb50SAxel Dörfler int32 index2 = 0;
247d8e2fb50SAxel Dörfler int16 in_pixel;
2489e34f742SAxel Dörfler while (index < inRowBytes) {
249d8e2fb50SAxel Dörfler in_pixel = in[index] | (in[index + 1] << 8);
250d8e2fb50SAxel Dörfler index += 2;
251d8e2fb50SAxel Dörfler
252d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0xf800)) >> 8) | (((in_pixel & 0xf800)) >> 13);
253d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x7e0)) >> 3) | (((in_pixel & 0x7e0)) >> 9);
254d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2);
255d8e2fb50SAxel Dörfler }
256d8e2fb50SAxel Dörfler }
257d8e2fb50SAxel Dörfler
258d8e2fb50SAxel Dörfler
259d8e2fb50SAxel Dörfler inline void
convert_from_16b_to_24(uint8 * in,uint8 * out,int32 inRowBytes)2609e34f742SAxel Dörfler convert_from_16b_to_24(uint8* in, uint8* out, int32 inRowBytes)
261d8e2fb50SAxel Dörfler {
262d8e2fb50SAxel Dörfler int32 index = 0;
263d8e2fb50SAxel Dörfler int32 index2 = 0;
264d8e2fb50SAxel Dörfler int16 in_pixel;
2659e34f742SAxel Dörfler while (index < inRowBytes) {
266d8e2fb50SAxel Dörfler in_pixel = in[index + 1] | (in[index] << 8);
267d8e2fb50SAxel Dörfler index += 2;
268d8e2fb50SAxel Dörfler
269d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0xf800)) >> 8) | (((in_pixel & 0xf800)) >> 13);
270d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x7e0)) >> 3) | (((in_pixel & 0x7e0)) >> 9);
271d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2);
272d8e2fb50SAxel Dörfler }
273d8e2fb50SAxel Dörfler }
274d8e2fb50SAxel Dörfler
275d8e2fb50SAxel Dörfler
276d8e2fb50SAxel Dörfler inline void
convert_from_24_to_24(uint8 * in,uint8 * out,int32 inRowBytes)2779e34f742SAxel Dörfler convert_from_24_to_24(uint8* in, uint8* out, int32 inRowBytes)
278d8e2fb50SAxel Dörfler {
279d8e2fb50SAxel Dörfler int32 index = 0;
280d8e2fb50SAxel Dörfler int32 index2 = 0;
2819e34f742SAxel Dörfler while (index < inRowBytes) {
282d8e2fb50SAxel Dörfler out[index2++] = in[index + 2];
283d8e2fb50SAxel Dörfler out[index2++] = in[index + 1];
284d8e2fb50SAxel Dörfler out[index2++] = in[index];
285d8e2fb50SAxel Dörfler index+=3;
286d8e2fb50SAxel Dörfler }
287d8e2fb50SAxel Dörfler }
288d8e2fb50SAxel Dörfler
289d8e2fb50SAxel Dörfler
290d8e2fb50SAxel Dörfler inline void
convert_from_32_to_24(uint8 * in,uint8 * out,int32 inRowBytes)2919e34f742SAxel Dörfler convert_from_32_to_24(uint8* in, uint8* out, int32 inRowBytes)
292d8e2fb50SAxel Dörfler {
29351623681SAxel Dörfler inRowBytes /= 4;
29451623681SAxel Dörfler
2959e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i++) {
2969e34f742SAxel Dörfler out[0] = in[2];
2979e34f742SAxel Dörfler out[1] = in[1];
2989e34f742SAxel Dörfler out[2] = in[0];
2999e34f742SAxel Dörfler
3009e34f742SAxel Dörfler in += 4;
3019e34f742SAxel Dörfler out += 3;
302d8e2fb50SAxel Dörfler }
303d8e2fb50SAxel Dörfler }
304d8e2fb50SAxel Dörfler
305d8e2fb50SAxel Dörfler
306d8e2fb50SAxel Dörfler inline void
convert_from_32b_to_24(uint8 * in,uint8 * out,int32 inRowBytes)3079e34f742SAxel Dörfler convert_from_32b_to_24(uint8* in, uint8* out, int32 inRowBytes)
308d8e2fb50SAxel Dörfler {
30951623681SAxel Dörfler inRowBytes /= 4;
31051623681SAxel Dörfler
3119e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i++) {
31251623681SAxel Dörfler out[0] = in[1];
31351623681SAxel Dörfler out[1] = in[2];
31451623681SAxel Dörfler out[2] = in[3];
3159e34f742SAxel Dörfler
3169e34f742SAxel Dörfler in += 4;
3179e34f742SAxel Dörfler out += 3;
318d8e2fb50SAxel Dörfler }
319d8e2fb50SAxel Dörfler }
320d8e2fb50SAxel Dörfler
321d8e2fb50SAxel Dörfler
3229e34f742SAxel Dörfler // #pragma mark - conversion for decompression
3239e34f742SAxel Dörfler
3249e34f742SAxel Dörfler
325d8e2fb50SAxel Dörfler inline void
convert_from_CMYK_to_32_photoshop(uint8 * in,uint8 * out,int32 inRowBytes,int32 xStep)3269e34f742SAxel Dörfler convert_from_CMYK_to_32_photoshop(uint8* in, uint8* out, int32 inRowBytes, int32 xStep)
327d8e2fb50SAxel Dörfler {
3289e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i += 4) {
3299e34f742SAxel Dörfler int32 black = in[3];
3309e34f742SAxel Dörfler out[0] = in[2] * black / 255;
3319e34f742SAxel Dörfler out[1] = in[1] * black / 255;
3329e34f742SAxel Dörfler out[2] = in[0] * black / 255;
3339e34f742SAxel Dörfler out[3] = 255;
3349e34f742SAxel Dörfler
3359e34f742SAxel Dörfler in += 4;
3369e34f742SAxel Dörfler out += xStep;
337d8e2fb50SAxel Dörfler }
338d8e2fb50SAxel Dörfler }
339d8e2fb50SAxel Dörfler
340d8e2fb50SAxel Dörfler
341d8e2fb50SAxel Dörfler //! !!! UNTESTED !!!
342d8e2fb50SAxel Dörfler inline void
convert_from_CMYK_to_32(uint8 * in,uint8 * out,int32 inRowBytes,int32 xStep)3439e34f742SAxel Dörfler convert_from_CMYK_to_32(uint8* in, uint8* out, int32 inRowBytes, int32 xStep)
344d8e2fb50SAxel Dörfler {
3459e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i += 4) {
3469e34f742SAxel Dörfler int32 black = 255 - in[3];
3479e34f742SAxel Dörfler out[0] = ((255 - in[2]) * black) / 255;
3489e34f742SAxel Dörfler out[1] = ((255 - in[1]) * black) / 255;
3499e34f742SAxel Dörfler out[2] = ((255 - in[0]) * black) / 255;
3509e34f742SAxel Dörfler out[3] = 255;
3519e34f742SAxel Dörfler
3529e34f742SAxel Dörfler in += 4;
3539e34f742SAxel Dörfler out += xStep;
354d8e2fb50SAxel Dörfler }
355d8e2fb50SAxel Dörfler }
356d8e2fb50SAxel Dörfler
357d8e2fb50SAxel Dörfler
358d8e2fb50SAxel Dörfler //! RGB24 8:8:8 to xRGB 8:8:8:8
359d8e2fb50SAxel Dörfler inline void
convert_from_24_to_32(uint8 * in,uint8 * out,int32 inRowBytes,int32 xStep)3609e34f742SAxel Dörfler convert_from_24_to_32(uint8* in, uint8* out, int32 inRowBytes, int32 xStep)
361d8e2fb50SAxel Dörfler {
3629e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i += 3) {
3639e34f742SAxel Dörfler out[0] = in[2];
3649e34f742SAxel Dörfler out[1] = in[1];
3659e34f742SAxel Dörfler out[2] = in[0];
3669e34f742SAxel Dörfler out[3] = 255;
3679e34f742SAxel Dörfler
3689e34f742SAxel Dörfler in += 3;
3699e34f742SAxel Dörfler out += xStep;
3709e34f742SAxel Dörfler }
3719e34f742SAxel Dörfler }
3729e34f742SAxel Dörfler
3739e34f742SAxel Dörfler
3749e34f742SAxel Dörfler //! 8-bit to 8-bit, only need when rotating the image
3759e34f742SAxel Dörfler void
translate_8(uint8 * in,uint8 * out,int32 inRowBytes,int32 xStep)3769e34f742SAxel Dörfler translate_8(uint8* in, uint8* out, int32 inRowBytes, int32 xStep)
3779e34f742SAxel Dörfler {
3789e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i++) {
3799e34f742SAxel Dörfler out[0] = in[0];
3809e34f742SAxel Dörfler
3819e34f742SAxel Dörfler in++;
3829e34f742SAxel Dörfler out += xStep;
383d8e2fb50SAxel Dörfler }
384d8e2fb50SAxel Dörfler }
385d8e2fb50SAxel Dörfler
386d8e2fb50SAxel Dörfler
387b98ef4f9SStephan Aßmus } // namespace conversion
3888687ff64SAxel Dörfler
3898687ff64SAxel Dörfler
390d8e2fb50SAxel Dörfler // #pragma mark -
391d8e2fb50SAxel Dörfler
392d8e2fb50SAxel Dörfler
SSlider(const char * name,const char * label,BMessage * message,int32 minValue,int32 maxValue,orientation posture,thumb_style thumbType,uint32 flags)393b98ef4f9SStephan Aßmus SSlider::SSlider(const char* name, const char* label,
394d8e2fb50SAxel Dörfler BMessage* message, int32 minValue, int32 maxValue, orientation posture,
395b98ef4f9SStephan Aßmus thumb_style thumbType, uint32 flags)
396b98ef4f9SStephan Aßmus : BSlider(name, label, message, minValue, maxValue,
397b98ef4f9SStephan Aßmus posture, thumbType, flags)
3989949213aSStephan Aßmus {
3998687ff64SAxel Dörfler rgb_color barColor = { 0, 0, 229, 255 };
4008687ff64SAxel Dörfler UseFillColor(true, &barColor);
4019949213aSStephan Aßmus }
4029949213aSStephan Aßmus
4038687ff64SAxel Dörfler
4048687ff64SAxel Dörfler //! Update status string - show actual value
405b20d13f4SStefano Ceccherini const char*
UpdateText() const4069949213aSStephan Aßmus SSlider::UpdateText() const
4079949213aSStephan Aßmus {
408bb4537c8SJérôme Duval snprintf(fStatusLabel, sizeof(fStatusLabel), "%" B_PRId32, Value());
4098687ff64SAxel Dörfler return fStatusLabel;
4109949213aSStephan Aßmus }
4119949213aSStephan Aßmus
4128687ff64SAxel Dörfler
413d8e2fb50SAxel Dörfler // #pragma mark -
4149949213aSStephan Aßmus
415d8e2fb50SAxel Dörfler
TranslatorReadView(const char * name,TranslatorSettings * settings)416b98ef4f9SStephan Aßmus TranslatorReadView::TranslatorReadView(const char* name,
417b98ef4f9SStephan Aßmus TranslatorSettings* settings)
418b98ef4f9SStephan Aßmus :
419b98ef4f9SStephan Aßmus BView(name, 0, new BGroupLayout(B_HORIZONTAL)),
420d8e2fb50SAxel Dörfler fSettings(settings)
421b98ef4f9SStephan Aßmus // settings should already be Acquired()
4229949213aSStephan Aßmus {
4232e49ff35SSiarzhuk Zharski fAlwaysRGB32 = new BCheckBox("alwaysrgb32",
4242e49ff35SSiarzhuk Zharski B_TRANSLATE("Read greyscale images as RGB32"),
425d8e2fb50SAxel Dörfler new BMessage(VIEW_MSG_SET_ALWAYSRGB32));
426b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_ALWAYS_RGB32, NULL))
427b98ef4f9SStephan Aßmus fAlwaysRGB32->SetValue(B_CONTROL_ON);
4289949213aSStephan Aßmus
4292e49ff35SSiarzhuk Zharski fPhotoshopCMYK = new BCheckBox("photoshopCMYK",
4302e49ff35SSiarzhuk Zharski B_TRANSLATE("Use CMYK code with 0 for 100% ink coverage"),
4318687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_PHOTOSHOPCMYK));
432b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_PHOTOSHOP_CMYK, NULL))
433b98ef4f9SStephan Aßmus fPhotoshopCMYK->SetValue(B_CONTROL_ON);
4349949213aSStephan Aßmus
4352e49ff35SSiarzhuk Zharski fShowErrorBox = new BCheckBox("error",
4362e49ff35SSiarzhuk Zharski B_TRANSLATE("Show warning messages"),
4378687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_SHOWREADERRORBOX));
438b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_SHOWREADWARNING, NULL))
439b98ef4f9SStephan Aßmus fShowErrorBox->SetValue(B_CONTROL_ON);
4409949213aSStephan Aßmus
441d9c440a5SJanus BLayoutBuilder::Group<>(this, B_VERTICAL)
442d9c440a5SJanus .SetInsets(B_USE_DEFAULT_SPACING)
443b98ef4f9SStephan Aßmus .Add(fAlwaysRGB32)
444b98ef4f9SStephan Aßmus .Add(fPhotoshopCMYK)
445b98ef4f9SStephan Aßmus .Add(fShowErrorBox)
4467d48219bSHannah Boneß .AddGlue();
447b98ef4f9SStephan Aßmus }
448b98ef4f9SStephan Aßmus
449b98ef4f9SStephan Aßmus
~TranslatorReadView()450b98ef4f9SStephan Aßmus TranslatorReadView::~TranslatorReadView()
451b98ef4f9SStephan Aßmus {
452b98ef4f9SStephan Aßmus fSettings->Release();
4539949213aSStephan Aßmus }
4549949213aSStephan Aßmus
4558687ff64SAxel Dörfler
4569949213aSStephan Aßmus void
AttachedToWindow()4579949213aSStephan Aßmus TranslatorReadView::AttachedToWindow()
4589949213aSStephan Aßmus {
459b98ef4f9SStephan Aßmus BView::AttachedToWindow();
460b20d13f4SStefano Ceccherini
4618687ff64SAxel Dörfler fAlwaysRGB32->SetTarget(this);
4628687ff64SAxel Dörfler fPhotoshopCMYK->SetTarget(this);
4638687ff64SAxel Dörfler fShowErrorBox->SetTarget(this);
4649949213aSStephan Aßmus }
4659949213aSStephan Aßmus
4668687ff64SAxel Dörfler
4679949213aSStephan Aßmus void
MessageReceived(BMessage * message)4689949213aSStephan Aßmus TranslatorReadView::MessageReceived(BMessage* message)
4699949213aSStephan Aßmus {
4708687ff64SAxel Dörfler switch (message->what) {
4719949213aSStephan Aßmus case VIEW_MSG_SET_ALWAYSRGB32:
4729949213aSStephan Aßmus {
4739949213aSStephan Aßmus int32 value;
4749949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) {
475b98ef4f9SStephan Aßmus bool boolValue = value;
476b98ef4f9SStephan Aßmus fSettings->SetGetBool(JPEG_SET_ALWAYS_RGB32, &boolValue);
477b98ef4f9SStephan Aßmus fSettings->SaveSettings();
4789949213aSStephan Aßmus }
4799949213aSStephan Aßmus break;
4809949213aSStephan Aßmus }
4819949213aSStephan Aßmus case VIEW_MSG_SET_PHOTOSHOPCMYK:
4829949213aSStephan Aßmus {
4839949213aSStephan Aßmus int32 value;
4849949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) {
485b98ef4f9SStephan Aßmus bool boolValue = value;
486b98ef4f9SStephan Aßmus fSettings->SetGetBool(JPEG_SET_PHOTOSHOP_CMYK, &boolValue);
487b98ef4f9SStephan Aßmus fSettings->SaveSettings();
4889949213aSStephan Aßmus }
4899949213aSStephan Aßmus break;
4909949213aSStephan Aßmus }
4919949213aSStephan Aßmus case VIEW_MSG_SET_SHOWREADERRORBOX:
4929949213aSStephan Aßmus {
4939949213aSStephan Aßmus int32 value;
4949949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) {
495b98ef4f9SStephan Aßmus bool boolValue = value;
496b98ef4f9SStephan Aßmus fSettings->SetGetBool(JPEG_SET_SHOWREADWARNING, &boolValue);
497b98ef4f9SStephan Aßmus fSettings->SaveSettings();
4989949213aSStephan Aßmus }
4999949213aSStephan Aßmus break;
5009949213aSStephan Aßmus }
5019949213aSStephan Aßmus default:
5029949213aSStephan Aßmus BView::MessageReceived(message);
5039949213aSStephan Aßmus break;
5049949213aSStephan Aßmus }
5059949213aSStephan Aßmus }
5069949213aSStephan Aßmus
5079949213aSStephan Aßmus
5088687ff64SAxel Dörfler // #pragma mark - TranslatorWriteView
5099949213aSStephan Aßmus
5108687ff64SAxel Dörfler
TranslatorWriteView(const char * name,TranslatorSettings * settings)511b98ef4f9SStephan Aßmus TranslatorWriteView::TranslatorWriteView(const char* name,
512b98ef4f9SStephan Aßmus TranslatorSettings* settings)
513b98ef4f9SStephan Aßmus :
514b98ef4f9SStephan Aßmus BView(name, 0, new BGroupLayout(B_VERTICAL)),
515d8e2fb50SAxel Dörfler fSettings(settings)
516b98ef4f9SStephan Aßmus // settings should already be Acquired()
5179949213aSStephan Aßmus {
5182e49ff35SSiarzhuk Zharski fQualitySlider = new SSlider("quality", B_TRANSLATE("Output quality"),
5198687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_QUALITY), 0, 100);
5208687ff64SAxel Dörfler fQualitySlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
5218687ff64SAxel Dörfler fQualitySlider->SetHashMarkCount(10);
52203901b6cSJérôme Duval fQualitySlider->SetLimitLabels(B_TRANSLATE("Low"), B_TRANSLATE("High"));
523b98ef4f9SStephan Aßmus fQualitySlider->SetValue(fSettings->SetGetInt32(JPEG_SET_QUALITY, NULL));
5249949213aSStephan Aßmus
5252e49ff35SSiarzhuk Zharski fSmoothingSlider = new SSlider("smoothing",
5262e49ff35SSiarzhuk Zharski B_TRANSLATE("Output smoothing strength"),
5278687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_SMOOTHING), 0, 100);
5288687ff64SAxel Dörfler fSmoothingSlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
5298687ff64SAxel Dörfler fSmoothingSlider->SetHashMarkCount(10);
53003901b6cSJérôme Duval fSmoothingSlider->SetLimitLabels(B_TRANSLATE("None"), B_TRANSLATE("High"));
531b98ef4f9SStephan Aßmus fSmoothingSlider->SetValue(
532b98ef4f9SStephan Aßmus fSettings->SetGetInt32(JPEG_SET_SMOOTHING, NULL));
5339949213aSStephan Aßmus
5342e49ff35SSiarzhuk Zharski fProgress = new BCheckBox("progress",
5352e49ff35SSiarzhuk Zharski B_TRANSLATE("Use progressive compression"),
5368687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_PROGRESSIVE));
537b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_PROGRESSIVE, NULL))
538b98ef4f9SStephan Aßmus fProgress->SetValue(B_CONTROL_ON);
5399949213aSStephan Aßmus
5402e49ff35SSiarzhuk Zharski fSmallerFile = new BCheckBox("smallerfile",
5412e49ff35SSiarzhuk Zharski B_TRANSLATE("Make file smaller (sligthtly worse quality)"),
5428687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_SMALLERFILE));
543b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_SMALL_FILES))
544b98ef4f9SStephan Aßmus fSmallerFile->SetValue(B_CONTROL_ON);
545b98ef4f9SStephan Aßmus
5462e49ff35SSiarzhuk Zharski fOptimizeColors = new BCheckBox("optimizecolors",
5472e49ff35SSiarzhuk Zharski B_TRANSLATE("Prevent colors 'washing out'"),
548b98ef4f9SStephan Aßmus new BMessage(VIEW_MSG_SET_OPTIMIZECOLORS));
549b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_OPT_COLORS, NULL))
550b98ef4f9SStephan Aßmus fOptimizeColors->SetValue(B_CONTROL_ON);
551b98ef4f9SStephan Aßmus else
5528687ff64SAxel Dörfler fSmallerFile->SetEnabled(false);
5539949213aSStephan Aßmus
5542e49ff35SSiarzhuk Zharski fGrayAsRGB24 = new BCheckBox("gray1asrgb24",
5552e49ff35SSiarzhuk Zharski B_TRANSLATE("Write black-and-white images as RGB24"),
5568687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_GRAY1ASRGB24));
557b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_GRAY1_AS_RGB24))
558b98ef4f9SStephan Aßmus fGrayAsRGB24->SetValue(B_CONTROL_ON);
5599949213aSStephan Aßmus
560d9c440a5SJanus BLayoutBuilder::Group<>(this, B_VERTICAL)
561d9c440a5SJanus .SetInsets(B_USE_DEFAULT_SPACING)
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)
5687d48219bSHannah Boneß .AddGlue();
569b98ef4f9SStephan Aßmus }
5709949213aSStephan Aßmus
571b98ef4f9SStephan Aßmus
~TranslatorWriteView()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
AttachedToWindow()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
MessageReceived(BMessage * message)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
TranslatorAboutView(const char * name)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
6743292b902SHumdinger char versionString[100];
6753292b902SHumdinger snprintf(versionString, sizeof(versionString),
6763292b902SHumdinger B_TRANSLATE("Version %d.%d.%d"),
6773292b902SHumdinger (int)(sTranslatorVersion >> 8),
6783292b902SHumdinger (int)((sTranslatorVersion >> 4) & 0xf),
6793292b902SHumdinger (int)(sTranslatorVersion & 0xf));
6809949213aSStephan Aßmus
681b98ef4f9SStephan Aßmus BStringView* version = new BStringView("Version", versionString);
682b98ef4f9SStephan Aßmus version->SetExplicitAlignment(labelAlignment);
6839949213aSStephan Aßmus
684b98ef4f9SStephan Aßmus BTextView* infoView = new BTextView("info");
6852e49ff35SSiarzhuk Zharski infoView->SetText(sTranslatorInfo);
686f0650dc9Slooncraz infoView->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
687*5f61e00aSDale Cieslak rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR);
688*5f61e00aSDale Cieslak infoView->SetFontAndColor(be_plain_font, B_FONT_ALL, &textColor);
689b98ef4f9SStephan Aßmus infoView->MakeEditable(false);
6909949213aSStephan Aßmus
691d9c440a5SJanus BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
692d9c440a5SJanus .SetInsets(B_USE_DEFAULT_SPACING)
693b98ef4f9SStephan Aßmus .Add(title)
694b98ef4f9SStephan Aßmus .Add(version)
6957d48219bSHannah Boneß .Add(infoView);
6969949213aSStephan Aßmus }
6979949213aSStephan Aßmus
6989949213aSStephan Aßmus
TranslatorView(const char * name,TranslatorSettings * settings)699b98ef4f9SStephan Aßmus TranslatorView::TranslatorView(const char* name, TranslatorSettings* settings)
700b98ef4f9SStephan Aßmus :
701d9c440a5SJanus BTabView(name, B_WIDTH_FROM_LABEL)
7029949213aSStephan Aßmus {
703d9c440a5SJanus SetBorder(B_NO_BORDER);
704d9c440a5SJanus
70570d59669SSiarzhuk Zharski AddTab(new TranslatorWriteView(B_TRANSLATE("Write"), settings->Acquire()));
70670d59669SSiarzhuk Zharski AddTab(new TranslatorReadView(B_TRANSLATE("Read"), settings->Acquire()));
70770d59669SSiarzhuk Zharski AddTab(new TranslatorAboutView(B_TRANSLATE("About")));
7089949213aSStephan Aßmus
709b98ef4f9SStephan Aßmus settings->Release();
7109949213aSStephan Aßmus }
7119949213aSStephan Aßmus
7129949213aSStephan Aßmus
713d8e2fb50SAxel Dörfler // #pragma mark - Translator Add-On
7149949213aSStephan Aßmus
7159949213aSStephan Aßmus
716b98ef4f9SStephan Aßmus BView*
NewConfigView(TranslatorSettings * settings)717b98ef4f9SStephan Aßmus JPEGTranslator::NewConfigView(TranslatorSettings* settings)
7189949213aSStephan Aßmus {
719b98ef4f9SStephan Aßmus BView* configView = new TranslatorView("TranslatorView", settings);
720b98ef4f9SStephan Aßmus return configView;
7219949213aSStephan Aßmus }
7229949213aSStephan Aßmus
723b98ef4f9SStephan Aßmus
724d8e2fb50SAxel Dörfler /*! Determine whether or not we can handle this data */
7259949213aSStephan Aßmus status_t
DerivedIdentify(BPositionIO * inSource,const translation_format * inFormat,BMessage * ioExtension,translator_info * outInfo,uint32 outType)726b98ef4f9SStephan Aßmus JPEGTranslator::DerivedIdentify(BPositionIO* inSource,
727b98ef4f9SStephan Aßmus const translation_format* inFormat, BMessage* ioExtension,
728b98ef4f9SStephan Aßmus translator_info* outInfo, uint32 outType)
7299949213aSStephan Aßmus {
730d8e2fb50SAxel Dörfler if (outType != 0 && outType != B_TRANSLATOR_BITMAP && outType != JPEG_FORMAT)
7319949213aSStephan Aßmus return B_NO_TRANSLATOR;
7329949213aSStephan Aßmus
7339949213aSStephan Aßmus // !!! You might need to make this buffer bigger to test for your native format
7349949213aSStephan Aßmus off_t position = inSource->Position();
7359949213aSStephan Aßmus char header[sizeof(TranslatorBitmap)];
7369949213aSStephan Aßmus status_t err = inSource->Read(header, sizeof(TranslatorBitmap));
7379949213aSStephan Aßmus inSource->Seek(position, SEEK_SET);
738d8e2fb50SAxel Dörfler if (err < B_OK)
739d8e2fb50SAxel Dörfler return err;
7409949213aSStephan Aßmus
7419949213aSStephan Aßmus if (B_BENDIAN_TO_HOST_INT32(((TranslatorBitmap *)header)->magic) == B_TRANSLATOR_BITMAP) {
742b98ef4f9SStephan Aßmus if (PopulateInfoFromFormat(outInfo, B_TRANSLATOR_BITMAP) != B_OK)
743b98ef4f9SStephan Aßmus return B_NO_TRANSLATOR;
7449949213aSStephan Aßmus } else {
7459949213aSStephan Aßmus // First 3 bytes in jpg files are always the same from what i've seen so far
7469949213aSStephan Aßmus // check them
7479949213aSStephan Aßmus if (header[0] == (char)0xff && header[1] == (char)0xd8 && header[2] == (char)0xff) {
748b98ef4f9SStephan Aßmus if (PopulateInfoFromFormat(outInfo, JPEG_FORMAT) != B_OK)
7499949213aSStephan Aßmus return B_NO_TRANSLATOR;
750b98ef4f9SStephan Aßmus
7519949213aSStephan Aßmus } else
7529949213aSStephan Aßmus return B_NO_TRANSLATOR;
7539949213aSStephan Aßmus }
7549949213aSStephan Aßmus
7559949213aSStephan Aßmus return B_OK;
7569949213aSStephan Aßmus }
7579949213aSStephan Aßmus
758b98ef4f9SStephan Aßmus
7599949213aSStephan Aßmus status_t
DerivedTranslate(BPositionIO * inSource,const translator_info * inInfo,BMessage * ioExtension,uint32 outType,BPositionIO * outDestination,int32 baseType)760b98ef4f9SStephan Aßmus JPEGTranslator::DerivedTranslate(BPositionIO* inSource,
761b98ef4f9SStephan Aßmus const translator_info* inInfo, BMessage* ioExtension, uint32 outType,
762b98ef4f9SStephan Aßmus BPositionIO* outDestination, int32 baseType)
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
784863a6388SAdrien Destugues && (outType == B_TRANSLATOR_BITMAP || outType == 0)) {
785863a6388SAdrien Destugues // This is the default if no specific outType was requested.
786b91634cbSStephan Aßmus return Decompress(inSource, outDestination, ioExtension,
787b91634cbSStephan Aßmus &longJumpBuffer);
7889949213aSStephan Aßmus }
789dbc936acSStephan Aßmus } catch (...) {
79070d59669SSiarzhuk Zharski syslog(LOG_ERR, "libjpeg encountered a critical error (caught C++ "
79170d59669SSiarzhuk Zharski "exception).\n");
792dbc936acSStephan Aßmus return B_ERROR;
793dbc936acSStephan Aßmus }
7949949213aSStephan Aßmus
7959949213aSStephan Aßmus return B_NO_TRANSLATOR;
7969949213aSStephan Aßmus }
7979949213aSStephan Aßmus
798b98ef4f9SStephan Aßmus
799d8e2fb50SAxel Dörfler /*! The user has requested the same format for input and output, so just copy */
800b98ef4f9SStephan Aßmus status_t
Copy(BPositionIO * in,BPositionIO * out)801b98ef4f9SStephan Aßmus JPEGTranslator::Copy(BPositionIO* in, BPositionIO* out)
8029949213aSStephan Aßmus {
8039949213aSStephan Aßmus int block_size = 65536;
8049949213aSStephan Aßmus void* buffer = malloc(block_size);
8059949213aSStephan Aßmus char temp[1024];
8069949213aSStephan Aßmus if (buffer == NULL) {
8079949213aSStephan Aßmus buffer = temp;
8089949213aSStephan Aßmus block_size = 1024;
8099949213aSStephan Aßmus }
8109949213aSStephan Aßmus status_t err = B_OK;
8119949213aSStephan Aßmus
8129949213aSStephan Aßmus // Read until end of file or error
8139949213aSStephan Aßmus while (1) {
8149949213aSStephan Aßmus ssize_t to_read = block_size;
8159949213aSStephan Aßmus err = in->Read(buffer, to_read);
8169949213aSStephan Aßmus // Explicit check for EOF
8179949213aSStephan Aßmus if (err == -1) {
8189949213aSStephan Aßmus if (buffer != temp) free(buffer);
8199949213aSStephan Aßmus return B_OK;
8209949213aSStephan Aßmus }
8219949213aSStephan Aßmus if (err <= B_OK) break;
8229949213aSStephan Aßmus to_read = err;
8239949213aSStephan Aßmus err = out->Write(buffer, to_read);
8249949213aSStephan Aßmus if (err != to_read) if (err >= 0) err = B_DEVICE_FULL;
8259949213aSStephan Aßmus if (err < B_OK) break;
8269949213aSStephan Aßmus }
8279949213aSStephan Aßmus
8289949213aSStephan Aßmus if (buffer != temp) free(buffer);
8299949213aSStephan Aßmus return (err >= 0) ? B_OK : err;
8309949213aSStephan Aßmus }
8319949213aSStephan Aßmus
832d8e2fb50SAxel Dörfler
833d8e2fb50SAxel Dörfler /*! Encode into the native format */
834b98ef4f9SStephan Aßmus status_t
Compress(BPositionIO * in,BPositionIO * out,const jmp_buf * longJumpBuffer)835b98ef4f9SStephan Aßmus JPEGTranslator::Compress(BPositionIO* in, BPositionIO* out,
836b98ef4f9SStephan Aßmus const jmp_buf* longJumpBuffer)
8379949213aSStephan Aßmus {
838b98ef4f9SStephan Aßmus using namespace conversion;
8399949213aSStephan Aßmus
8409949213aSStephan Aßmus // Read info about bitmap
8419949213aSStephan Aßmus TranslatorBitmap header;
8429949213aSStephan Aßmus status_t err = in->Read(&header, sizeof(TranslatorBitmap));
843d8e2fb50SAxel Dörfler if (err < B_OK)
844d8e2fb50SAxel Dörfler return err;
845d8e2fb50SAxel Dörfler else if (err < (int)sizeof(TranslatorBitmap))
846d8e2fb50SAxel Dörfler return B_ERROR;
8479949213aSStephan Aßmus
8489949213aSStephan Aßmus // Grab dimension, color space, and size information from the stream
8499949213aSStephan Aßmus BRect bounds;
8509949213aSStephan Aßmus bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left);
8519949213aSStephan Aßmus bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top);
8529949213aSStephan Aßmus bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right);
8539949213aSStephan Aßmus bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom);
8549949213aSStephan Aßmus
8559949213aSStephan Aßmus int32 in_row_bytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes);
8569949213aSStephan Aßmus
8579949213aSStephan Aßmus int width = bounds.IntegerWidth() + 1;
8589949213aSStephan Aßmus int height = bounds.IntegerHeight() + 1;
8599949213aSStephan Aßmus
8609949213aSStephan Aßmus // Function pointer to convert function
8619949213aSStephan Aßmus // It will point to proper function if needed
8629e34f742SAxel Dörfler void (*converter)(uchar* inscanline, uchar* outscanline,
8639e34f742SAxel Dörfler int32 inRowBytes) = NULL;
8649949213aSStephan Aßmus
8659949213aSStephan Aßmus // Default color info
8669949213aSStephan Aßmus J_COLOR_SPACE jpg_color_space = JCS_RGB;
8679949213aSStephan Aßmus int jpg_input_components = 3;
8689949213aSStephan Aßmus int32 out_row_bytes;
8699949213aSStephan Aßmus int padding = 0;
8709949213aSStephan Aßmus
871d8e2fb50SAxel Dörfler switch ((color_space)B_BENDIAN_TO_HOST_INT32(header.colors)) {
8729949213aSStephan Aßmus case B_CMAP8:
8739949213aSStephan Aßmus converter = convert_from_cmap8_to_24;
8749949213aSStephan Aßmus padding = in_row_bytes - width;
8759949213aSStephan Aßmus break;
876d8e2fb50SAxel Dörfler
8779949213aSStephan Aßmus case B_GRAY1:
878b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_GRAY1_AS_RGB24, NULL)) {
8799949213aSStephan Aßmus converter = convert_from_gray1_to_24;
8809949213aSStephan Aßmus } else {
8819949213aSStephan Aßmus jpg_input_components = 1;
8829949213aSStephan Aßmus jpg_color_space = JCS_GRAYSCALE;
8839949213aSStephan Aßmus converter = convert_from_gray1_to_gray8;
8849949213aSStephan Aßmus }
8859949213aSStephan Aßmus padding = in_row_bytes - (width / 8);
8869949213aSStephan Aßmus break;
887d8e2fb50SAxel Dörfler
8889949213aSStephan Aßmus case B_GRAY8:
8899949213aSStephan Aßmus jpg_input_components = 1;
8909949213aSStephan Aßmus jpg_color_space = JCS_GRAYSCALE;
8919949213aSStephan Aßmus padding = in_row_bytes - width;
8929949213aSStephan Aßmus break;
893d8e2fb50SAxel Dörfler
8949949213aSStephan Aßmus case B_RGB15:
8959949213aSStephan Aßmus case B_RGBA15:
8969949213aSStephan Aßmus converter = convert_from_15_to_24;
8979949213aSStephan Aßmus padding = in_row_bytes - (width * 2);
8989949213aSStephan Aßmus break;
899d8e2fb50SAxel Dörfler
9009949213aSStephan Aßmus case B_RGB15_BIG:
9019949213aSStephan Aßmus case B_RGBA15_BIG:
9029949213aSStephan Aßmus converter = convert_from_15b_to_24;
9039949213aSStephan Aßmus padding = in_row_bytes - (width * 2);
9049949213aSStephan Aßmus break;
905d8e2fb50SAxel Dörfler
9069949213aSStephan Aßmus case B_RGB16:
9079949213aSStephan Aßmus converter = convert_from_16_to_24;
9089949213aSStephan Aßmus padding = in_row_bytes - (width * 2);
9099949213aSStephan Aßmus break;
910d8e2fb50SAxel Dörfler
9119949213aSStephan Aßmus case B_RGB16_BIG:
9129949213aSStephan Aßmus converter = convert_from_16b_to_24;
9139949213aSStephan Aßmus padding = in_row_bytes - (width * 2);
9149949213aSStephan Aßmus break;
915d8e2fb50SAxel Dörfler
9169949213aSStephan Aßmus case B_RGB24:
9179949213aSStephan Aßmus converter = convert_from_24_to_24;
9189949213aSStephan Aßmus padding = in_row_bytes - (width * 3);
9199949213aSStephan Aßmus break;
920d8e2fb50SAxel Dörfler
9219949213aSStephan Aßmus case B_RGB24_BIG:
9229949213aSStephan Aßmus padding = in_row_bytes - (width * 3);
9239949213aSStephan Aßmus break;
924d8e2fb50SAxel Dörfler
9259949213aSStephan Aßmus case B_RGB32:
9269949213aSStephan Aßmus case B_RGBA32:
9279949213aSStephan Aßmus converter = convert_from_32_to_24;
9289949213aSStephan Aßmus padding = in_row_bytes - (width * 4);
9299949213aSStephan Aßmus break;
930d8e2fb50SAxel Dörfler
9319949213aSStephan Aßmus case B_RGB32_BIG:
9329949213aSStephan Aßmus case B_RGBA32_BIG:
9339949213aSStephan Aßmus converter = convert_from_32b_to_24;
9349949213aSStephan Aßmus padding = in_row_bytes - (width * 4);
9359949213aSStephan Aßmus break;
936d8e2fb50SAxel Dörfler
9379949213aSStephan Aßmus case B_CMYK32:
9389949213aSStephan Aßmus jpg_color_space = JCS_CMYK;
9399949213aSStephan Aßmus jpg_input_components = 4;
9409949213aSStephan Aßmus padding = in_row_bytes - (width * 4);
9419949213aSStephan Aßmus break;
942d8e2fb50SAxel Dörfler
9439949213aSStephan Aßmus default:
94470d59669SSiarzhuk Zharski syslog(LOG_ERR, "Wrong type: Color space not implemented.\n");
9459949213aSStephan Aßmus return B_ERROR;
9469949213aSStephan Aßmus }
9479949213aSStephan Aßmus out_row_bytes = jpg_input_components * width;
9489949213aSStephan Aßmus
9499949213aSStephan Aßmus // Set basic things needed for jpeg writing
9509949213aSStephan Aßmus struct jpeg_compress_struct cinfo;
951e4bd005dSIngo Weinhold struct be_jpeg_error_mgr jerr;
952b98ef4f9SStephan Aßmus cinfo.err = be_jpeg_std_error(&jerr, fSettings, longJumpBuffer);
9539949213aSStephan Aßmus jpeg_create_compress(&cinfo);
9549949213aSStephan Aßmus be_jpeg_stdio_dest(&cinfo, out);
9559949213aSStephan Aßmus
9569949213aSStephan Aßmus // Set basic values
9579949213aSStephan Aßmus cinfo.image_width = width;
9589949213aSStephan Aßmus cinfo.image_height = height;
9599949213aSStephan Aßmus cinfo.input_components = jpg_input_components;
9609949213aSStephan Aßmus cinfo.in_color_space = jpg_color_space;
9619949213aSStephan Aßmus jpeg_set_defaults(&cinfo);
9629949213aSStephan Aßmus
9639949213aSStephan Aßmus // Set better accuracy
9649949213aSStephan Aßmus cinfo.dct_method = JDCT_ISLOW;
9659949213aSStephan Aßmus
9669949213aSStephan Aßmus // This is needed to prevent some colors loss
9679949213aSStephan Aßmus // With it generated jpegs are as good as from Fireworks (at last! :D)
968b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_OPT_COLORS, NULL)) {
9699949213aSStephan Aßmus int index = 0;
9709949213aSStephan Aßmus while (index < cinfo.num_components) {
9719949213aSStephan Aßmus cinfo.comp_info[index].h_samp_factor = 1;
9729949213aSStephan Aßmus cinfo.comp_info[index].v_samp_factor = 1;
9739949213aSStephan Aßmus // This will make file smaller, but with worse quality more or less
9749949213aSStephan Aßmus // like with 93%-94% (but it's subjective opinion) on tested images
9759949213aSStephan Aßmus // but with smaller size (between 92% and 93% on tested images)
976b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_SMALL_FILES))
9779949213aSStephan Aßmus cinfo.comp_info[index].quant_tbl_no = 1;
9789949213aSStephan Aßmus // This will make bigger file, but also better quality ;]
9799949213aSStephan Aßmus // from my tests it seems like useless - better quality with smaller
9809949213aSStephan Aßmus // can be acheived without this
9819949213aSStephan Aßmus // cinfo.comp_info[index].dc_tbl_no = 1;
9829949213aSStephan Aßmus // cinfo.comp_info[index].ac_tbl_no = 1;
9839949213aSStephan Aßmus index++;
9849949213aSStephan Aßmus }
9859949213aSStephan Aßmus }
9869949213aSStephan Aßmus
9879949213aSStephan Aßmus // Set quality
988b98ef4f9SStephan Aßmus jpeg_set_quality(&cinfo, fSettings->SetGetInt32(JPEG_SET_QUALITY, NULL), true);
9899949213aSStephan Aßmus
9909949213aSStephan Aßmus // Set progressive compression if needed
9919949213aSStephan Aßmus // if not, turn on optimizing in libjpeg
992b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_PROGRESSIVE, NULL))
9939949213aSStephan Aßmus jpeg_simple_progression(&cinfo);
9949949213aSStephan Aßmus else
9959949213aSStephan Aßmus cinfo.optimize_coding = TRUE;
9969949213aSStephan Aßmus
9979949213aSStephan Aßmus // Set smoothing (effect like Blur)
998b98ef4f9SStephan Aßmus cinfo.smoothing_factor = fSettings->SetGetInt32(JPEG_SET_SMOOTHING, NULL);
9999949213aSStephan Aßmus
10009949213aSStephan Aßmus // Initialize compression
10019949213aSStephan Aßmus jpeg_start_compress(&cinfo, TRUE);
10029949213aSStephan Aßmus
10039949213aSStephan Aßmus // Declare scanlines
10049949213aSStephan Aßmus JSAMPROW in_scanline = NULL;
10059949213aSStephan Aßmus JSAMPROW out_scanline = NULL;
1006b98ef4f9SStephan Aßmus JSAMPROW writeline;
1007b98ef4f9SStephan Aßmus // Pointer to in_scanline (default) or out_scanline (if there will be conversion)
10089949213aSStephan Aßmus
10099949213aSStephan Aßmus // Allocate scanline
10109949213aSStephan Aßmus // Use libjpeg memory allocation functions, so in case of error it will free them itself
1011d8e2fb50SAxel Dörfler in_scanline = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo,
1012d8e2fb50SAxel Dörfler JPOOL_PERMANENT, in_row_bytes);
10139949213aSStephan Aßmus
10149949213aSStephan Aßmus // We need 2nd scanline storage ony for conversion
10159949213aSStephan Aßmus if (converter != NULL) {
10169949213aSStephan Aßmus // There will be conversion, allocate second scanline...
10179949213aSStephan Aßmus // Use libjpeg memory allocation functions, so in case of error it will free them itself
1018d8e2fb50SAxel Dörfler out_scanline = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo,
1019d8e2fb50SAxel Dörfler JPOOL_PERMANENT, out_row_bytes);
10209949213aSStephan Aßmus // ... and make it the one to write to file
10219949213aSStephan Aßmus writeline = out_scanline;
10229949213aSStephan Aßmus } else
10239949213aSStephan Aßmus writeline = in_scanline;
10249949213aSStephan Aßmus
10259949213aSStephan Aßmus while (cinfo.next_scanline < cinfo.image_height) {
10269949213aSStephan Aßmus // Read scanline
10279949213aSStephan Aßmus err = in->Read(in_scanline, in_row_bytes);
10289949213aSStephan Aßmus if (err < in_row_bytes)
1029d8e2fb50SAxel Dörfler return err < B_OK ? Error((j_common_ptr)&cinfo, err)
1030d8e2fb50SAxel Dörfler : Error((j_common_ptr)&cinfo, B_ERROR);
10319949213aSStephan Aßmus
10329949213aSStephan Aßmus // Convert if needed
10339949213aSStephan Aßmus if (converter != NULL)
10349949213aSStephan Aßmus converter(in_scanline, out_scanline, in_row_bytes - padding);
10359949213aSStephan Aßmus
10369949213aSStephan Aßmus // Write scanline
10379949213aSStephan Aßmus jpeg_write_scanlines(&cinfo, &writeline, 1);
10389949213aSStephan Aßmus }
10399949213aSStephan Aßmus
10409949213aSStephan Aßmus jpeg_finish_compress(&cinfo);
10419949213aSStephan Aßmus jpeg_destroy_compress(&cinfo);
10429949213aSStephan Aßmus return B_OK;
10439949213aSStephan Aßmus }
10449949213aSStephan Aßmus
1045d8e2fb50SAxel Dörfler
1046d8e2fb50SAxel Dörfler /*! Decode the native format */
1047b98ef4f9SStephan Aßmus status_t
Decompress(BPositionIO * in,BPositionIO * out,BMessage * ioExtension,const jmp_buf * longJumpBuffer)1048b98ef4f9SStephan Aßmus JPEGTranslator::Decompress(BPositionIO* in, BPositionIO* out,
1049b98ef4f9SStephan Aßmus BMessage* ioExtension, const jmp_buf* longJumpBuffer)
10509949213aSStephan Aßmus {
1051b98ef4f9SStephan Aßmus using namespace conversion;
10529949213aSStephan Aßmus
10539949213aSStephan Aßmus // Set basic things needed for jpeg reading
10549949213aSStephan Aßmus struct jpeg_decompress_struct cinfo;
1055e4bd005dSIngo Weinhold struct be_jpeg_error_mgr jerr;
1056b98ef4f9SStephan Aßmus cinfo.err = be_jpeg_std_error(&jerr, fSettings, longJumpBuffer);
10579949213aSStephan Aßmus jpeg_create_decompress(&cinfo);
10589949213aSStephan Aßmus be_jpeg_stdio_src(&cinfo, in);
10599949213aSStephan Aßmus
106052e8f46aSAxel Dörfler jpeg_save_markers(&cinfo, MARKER_EXIF, 131072);
106152e8f46aSAxel Dörfler // make sure the EXIF tag is stored
106252e8f46aSAxel Dörfler
10639949213aSStephan Aßmus // Read info about image
10649949213aSStephan Aßmus jpeg_read_header(&cinfo, TRUE);
10659949213aSStephan Aßmus
106652e8f46aSAxel Dörfler BMessage exif;
106752e8f46aSAxel Dörfler
1068f13b5de6SAxel Dörfler // parse EXIF data and add it ioExtension, if any
106952e8f46aSAxel Dörfler jpeg_marker_struct* marker = cinfo.marker_list;
107052e8f46aSAxel Dörfler while (marker != NULL) {
107152e8f46aSAxel Dörfler if (marker->marker == MARKER_EXIF
107252e8f46aSAxel Dörfler && !strncmp((char*)marker->data, "Exif", 4)) {
1073f13b5de6SAxel Dörfler if (ioExtension != NULL) {
107452e8f46aSAxel Dörfler // Strip EXIF header from TIFF data
107552e8f46aSAxel Dörfler ioExtension->AddData("exif", B_RAW_TYPE,
107652e8f46aSAxel Dörfler (uint8*)marker->data + 6, marker->data_length - 6);
1077f13b5de6SAxel Dörfler }
107852e8f46aSAxel Dörfler
107952e8f46aSAxel Dörfler BMemoryIO io(marker->data + 6, marker->data_length - 6);
108052e8f46aSAxel Dörfler convert_exif_to_message(io, exif);
108152e8f46aSAxel Dörfler }
108252e8f46aSAxel Dörfler marker = marker->next;
108352e8f46aSAxel Dörfler }
108452e8f46aSAxel Dörfler
10859949213aSStephan Aßmus // Default color info
108652e8f46aSAxel Dörfler color_space outColorSpace = B_RGB32;
108752e8f46aSAxel Dörfler int outColorComponents = 4;
10889949213aSStephan Aßmus
10899949213aSStephan Aßmus // Function pointer to convert function
10909949213aSStephan Aßmus // It will point to proper function if needed
109152e8f46aSAxel Dörfler void (*converter)(uchar* inScanLine, uchar* outScanLine,
10929e34f742SAxel Dörfler int32 inRowBytes, int32 xStep) = convert_from_24_to_32;
10939949213aSStephan Aßmus
10949949213aSStephan Aßmus // If color space isn't rgb
10959949213aSStephan Aßmus if (cinfo.out_color_space != JCS_RGB) {
1096d8e2fb50SAxel Dörfler switch (cinfo.out_color_space) {
10979949213aSStephan Aßmus case JCS_UNKNOWN: /* error/unspecified */
109870d59669SSiarzhuk Zharski syslog(LOG_ERR, "From Type: Jpeg uses unknown color type\n");
10999949213aSStephan Aßmus break;
11009949213aSStephan Aßmus case JCS_GRAYSCALE: /* monochrome */
11019949213aSStephan Aßmus // Check if user wants to read only as RGB32 or not
1102b98ef4f9SStephan Aßmus if (!fSettings->SetGetBool(JPEG_SET_ALWAYS_RGB32, NULL)) {
11039949213aSStephan Aßmus // Grayscale
110452e8f46aSAxel Dörfler outColorSpace = B_GRAY8;
110552e8f46aSAxel Dörfler outColorComponents = 1;
11069e34f742SAxel Dörfler converter = translate_8;
11079949213aSStephan Aßmus } else {
11089949213aSStephan Aßmus // RGB
11099949213aSStephan Aßmus cinfo.out_color_space = JCS_RGB;
11109949213aSStephan Aßmus cinfo.output_components = 3;
11119949213aSStephan Aßmus converter = convert_from_24_to_32;
11129949213aSStephan Aßmus }
11139949213aSStephan Aßmus break;
11149949213aSStephan Aßmus case JCS_YCbCr: /* Y/Cb/Cr (also known as YUV) */
11159949213aSStephan Aßmus cinfo.out_color_space = JCS_RGB;
11169949213aSStephan Aßmus converter = convert_from_24_to_32;
11179949213aSStephan Aßmus break;
11189949213aSStephan Aßmus case JCS_YCCK: /* Y/Cb/Cr/K */
11199949213aSStephan Aßmus // Let libjpeg convert it to CMYK
11209949213aSStephan Aßmus cinfo.out_color_space = JCS_CMYK;
11219949213aSStephan Aßmus // Fall through to CMYK since we need the same settings
11229949213aSStephan Aßmus case JCS_CMYK: /* C/M/Y/K */
11239949213aSStephan Aßmus // Use proper converter
1124b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_PHOTOSHOP_CMYK))
11259949213aSStephan Aßmus converter = convert_from_CMYK_to_32_photoshop;
11269949213aSStephan Aßmus else
11279949213aSStephan Aßmus converter = convert_from_CMYK_to_32;
11289949213aSStephan Aßmus break;
11299949213aSStephan Aßmus default:
113070d59669SSiarzhuk Zharski syslog(LOG_ERR,
113170d59669SSiarzhuk Zharski "From Type: Jpeg uses hmm... i don't know really :(\n");
11329949213aSStephan Aßmus break;
11339949213aSStephan Aßmus }
11349949213aSStephan Aßmus }
11359949213aSStephan Aßmus
11369949213aSStephan Aßmus // Initialize decompression
11379949213aSStephan Aßmus jpeg_start_decompress(&cinfo);
11389949213aSStephan Aßmus
11399e34f742SAxel Dörfler // retrieve orientation from settings/EXIF
114052e8f46aSAxel Dörfler int32 orientation;
11419e34f742SAxel Dörfler if (ioExtension == NULL
11429e34f742SAxel Dörfler || ioExtension->FindInt32("exif:orientation", &orientation) != B_OK) {
114352e8f46aSAxel Dörfler if (exif.FindInt32("Orientation", &orientation) != B_OK)
114452e8f46aSAxel Dörfler orientation = 1;
114552e8f46aSAxel Dörfler }
11469949213aSStephan Aßmus
11479e34f742SAxel Dörfler if (orientation != 1 && converter == NULL)
11489e34f742SAxel Dörfler converter = translate_8;
11499e34f742SAxel Dörfler
11509e34f742SAxel Dörfler int32 outputWidth = orientation > 4 ? cinfo.output_height : cinfo.output_width;
11519e34f742SAxel Dörfler int32 outputHeight = orientation > 4 ? cinfo.output_width : cinfo.output_height;
11529e34f742SAxel Dörfler
11539e34f742SAxel Dörfler int32 destOffset = dest_index(outputWidth, outputHeight,
11549e34f742SAxel Dörfler 0, 0, orientation) * outColorComponents;
11559e34f742SAxel Dörfler int32 xStep = dest_index(outputWidth, outputHeight,
11569e34f742SAxel Dörfler 1, 0, orientation) * outColorComponents - destOffset;
11579e34f742SAxel Dörfler int32 yStep = dest_index(outputWidth, outputHeight,
11589e34f742SAxel Dörfler 0, 1, orientation) * outColorComponents - destOffset;
11599e34f742SAxel Dörfler bool needAll = orientation != 1;
11609e34f742SAxel Dörfler
11619e34f742SAxel Dörfler // Initialize this bounds rect to the size of your image
11629e34f742SAxel Dörfler BRect bounds(0, 0, outputWidth - 1, outputHeight - 1);
11639e34f742SAxel Dörfler
11649e34f742SAxel Dörfler #if 0
11659e34f742SAxel Dörfler printf("destOffset = %ld, xStep = %ld, yStep = %ld, input: %ld x %ld, output: %ld x %ld, orientation %ld\n",
11669e34f742SAxel Dörfler destOffset, xStep, yStep, (int32)cinfo.output_width, (int32)cinfo.output_height,
11679e34f742SAxel Dörfler bounds.IntegerWidth() + 1, bounds.IntegerHeight() + 1, orientation);
11689e34f742SAxel Dörfler #endif
11699e34f742SAxel Dörfler
11709949213aSStephan Aßmus // Bytes count in one line of image (scanline)
11719e34f742SAxel Dörfler int32 inRowBytes = cinfo.output_width * cinfo.output_components;
11729e34f742SAxel Dörfler int32 rowBytes = (bounds.IntegerWidth() + 1) * outColorComponents;
11739e34f742SAxel Dörfler int32 dataSize = cinfo.output_width * cinfo.output_height
11749e34f742SAxel Dörfler * outColorComponents;
11759949213aSStephan Aßmus
11769949213aSStephan Aßmus // Fill out the B_TRANSLATOR_BITMAP's header
11779949213aSStephan Aßmus TranslatorBitmap header;
11789949213aSStephan Aßmus header.magic = B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP);
11799949213aSStephan Aßmus header.bounds.left = B_HOST_TO_BENDIAN_FLOAT(bounds.left);
11809949213aSStephan Aßmus header.bounds.top = B_HOST_TO_BENDIAN_FLOAT(bounds.top);
11819949213aSStephan Aßmus header.bounds.right = B_HOST_TO_BENDIAN_FLOAT(bounds.right);
11829949213aSStephan Aßmus header.bounds.bottom = B_HOST_TO_BENDIAN_FLOAT(bounds.bottom);
118352e8f46aSAxel Dörfler header.colors = (color_space)B_HOST_TO_BENDIAN_INT32(outColorSpace);
118452e8f46aSAxel Dörfler header.rowBytes = B_HOST_TO_BENDIAN_INT32(rowBytes);
11859e34f742SAxel Dörfler header.dataSize = B_HOST_TO_BENDIAN_INT32(dataSize);
11869949213aSStephan Aßmus
11879949213aSStephan Aßmus // Write out the header
11889949213aSStephan Aßmus status_t err = out->Write(&header, sizeof(TranslatorBitmap));
1189d8e2fb50SAxel Dörfler if (err < B_OK)
1190d8e2fb50SAxel Dörfler return Error((j_common_ptr)&cinfo, err);
1191d8e2fb50SAxel Dörfler else if (err < (int)sizeof(TranslatorBitmap))
1192d8e2fb50SAxel Dörfler return Error((j_common_ptr)&cinfo, B_ERROR);
11939949213aSStephan Aßmus
11949949213aSStephan Aßmus // Declare scanlines
11959e34f742SAxel Dörfler JSAMPROW inScanLine = NULL;
11969e34f742SAxel Dörfler uint8* dest = NULL;
11979e34f742SAxel Dörfler uint8* destLine = NULL;
11989949213aSStephan Aßmus
11999949213aSStephan Aßmus // Allocate scanline
12009949213aSStephan Aßmus // Use libjpeg memory allocation functions, so in case of error it will free them itself
12019e34f742SAxel Dörfler inScanLine = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo,
12029e34f742SAxel Dörfler JPOOL_PERMANENT, inRowBytes);
12039949213aSStephan Aßmus
12049949213aSStephan Aßmus // We need 2nd scanline storage only for conversion
12059949213aSStephan Aßmus if (converter != NULL) {
12069949213aSStephan Aßmus // There will be conversion, allocate second scanline...
1207b98ef4f9SStephan Aßmus // Use libjpeg memory allocation functions, so in case of error it will
1208b98ef4f9SStephan Aßmus // free them itself
12099e34f742SAxel Dörfler dest = (uint8*)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo,
12109e34f742SAxel Dörfler JPOOL_PERMANENT, needAll ? dataSize : rowBytes);
12119e34f742SAxel Dörfler destLine = dest + destOffset;
12129949213aSStephan Aßmus } else
12139e34f742SAxel Dörfler destLine = inScanLine;
12149949213aSStephan Aßmus
12159949213aSStephan Aßmus while (cinfo.output_scanline < cinfo.output_height) {
12169949213aSStephan Aßmus // Read scanline
12179e34f742SAxel Dörfler jpeg_read_scanlines(&cinfo, &inScanLine, 1);
12189949213aSStephan Aßmus
12199949213aSStephan Aßmus // Convert if needed
12209949213aSStephan Aßmus if (converter != NULL)
12219e34f742SAxel Dörfler converter(inScanLine, destLine, inRowBytes, xStep);
12229949213aSStephan Aßmus
12239e34f742SAxel Dörfler if (!needAll) {
12249949213aSStephan Aßmus // Write the scanline buffer to the output stream
12259e34f742SAxel Dörfler ssize_t bytesWritten = out->Write(destLine, rowBytes);
12269e34f742SAxel Dörfler if (bytesWritten < rowBytes) {
12279e34f742SAxel Dörfler return bytesWritten < B_OK
12289e34f742SAxel Dörfler ? Error((j_common_ptr)&cinfo, bytesWritten)
1229d8e2fb50SAxel Dörfler : Error((j_common_ptr)&cinfo, B_ERROR);
12309949213aSStephan Aßmus }
12319e34f742SAxel Dörfler } else
12329e34f742SAxel Dörfler destLine += yStep;
12339e34f742SAxel Dörfler }
12349e34f742SAxel Dörfler
12359e34f742SAxel Dörfler if (needAll) {
12369e34f742SAxel Dörfler ssize_t bytesWritten = out->Write(dest, dataSize);
12379e34f742SAxel Dörfler if (bytesWritten < dataSize) {
12389e34f742SAxel Dörfler return bytesWritten < B_OK
12399e34f742SAxel Dörfler ? Error((j_common_ptr)&cinfo, bytesWritten)
12409e34f742SAxel Dörfler : Error((j_common_ptr)&cinfo, B_ERROR);
12419e34f742SAxel Dörfler }
12429e34f742SAxel Dörfler }
12439949213aSStephan Aßmus
12449949213aSStephan Aßmus jpeg_finish_decompress(&cinfo);
12459949213aSStephan Aßmus jpeg_destroy_decompress(&cinfo);
12469949213aSStephan Aßmus return B_OK;
12479949213aSStephan Aßmus }
12489949213aSStephan Aßmus
1249b98ef4f9SStephan Aßmus /*! have the other PopulateInfoFromFormat() check both inputFormats & outputFormats */
1250b98ef4f9SStephan Aßmus status_t
PopulateInfoFromFormat(translator_info * info,uint32 formatType,translator_id id)1251b98ef4f9SStephan Aßmus JPEGTranslator::PopulateInfoFromFormat(translator_info* info,
1252b98ef4f9SStephan Aßmus uint32 formatType, translator_id id)
1253b98ef4f9SStephan Aßmus {
1254b98ef4f9SStephan Aßmus int32 formatCount;
1255b98ef4f9SStephan Aßmus const translation_format* formats = OutputFormats(&formatCount);
1256b98ef4f9SStephan Aßmus for (int i = 0; i <= 1 ;formats = InputFormats(&formatCount), i++) {
1257b98ef4f9SStephan Aßmus if (PopulateInfoFromFormat(info, formatType,
1258b98ef4f9SStephan Aßmus formats, formatCount) == B_OK) {
1259b98ef4f9SStephan Aßmus info->translator = id;
1260b98ef4f9SStephan Aßmus return B_OK;
1261b98ef4f9SStephan Aßmus }
1262b98ef4f9SStephan Aßmus }
1263b98ef4f9SStephan Aßmus
1264b98ef4f9SStephan Aßmus return B_ERROR;
1265b98ef4f9SStephan Aßmus }
1266b98ef4f9SStephan Aßmus
1267b98ef4f9SStephan Aßmus
1268b98ef4f9SStephan Aßmus status_t
PopulateInfoFromFormat(translator_info * info,uint32 formatType,const translation_format * formats,int32 formatCount)1269b98ef4f9SStephan Aßmus JPEGTranslator::PopulateInfoFromFormat(translator_info* info,
1270b98ef4f9SStephan Aßmus uint32 formatType, const translation_format* formats, int32 formatCount)
1271b98ef4f9SStephan Aßmus {
1272b98ef4f9SStephan Aßmus for (int i = 0; i < formatCount; i++) {
1273b98ef4f9SStephan Aßmus if (formats[i].type == formatType) {
1274b98ef4f9SStephan Aßmus info->type = formatType;
1275b98ef4f9SStephan Aßmus info->group = formats[i].group;
1276b98ef4f9SStephan Aßmus info->quality = formats[i].quality;
1277b98ef4f9SStephan Aßmus info->capability = formats[i].capability;
127870d59669SSiarzhuk Zharski BString str1(formats[i].name);
127970d59669SSiarzhuk Zharski str1.ReplaceFirst("Be Bitmap Format (JPEGTranslator)",
128070d59669SSiarzhuk Zharski B_TRANSLATE("Be Bitmap Format (JPEGTranslator)"));
1281c7eabc40SMurai Takashi strlcpy(info->name, str1.String(), sizeof(info->name));
1282b98ef4f9SStephan Aßmus strcpy(info->MIME, formats[i].MIME);
1283b98ef4f9SStephan Aßmus return B_OK;
1284b98ef4f9SStephan Aßmus }
1285b98ef4f9SStephan Aßmus }
1286b98ef4f9SStephan Aßmus
1287b98ef4f9SStephan Aßmus return B_ERROR;
1288b98ef4f9SStephan Aßmus }
1289b98ef4f9SStephan Aßmus
1290d8e2fb50SAxel Dörfler /*!
1291d8e2fb50SAxel Dörfler Frees jpeg alocated memory
1292d8e2fb50SAxel Dörfler Returns given error (B_ERROR by default)
1293d8e2fb50SAxel Dörfler */
1294b98ef4f9SStephan Aßmus status_t
Error(j_common_ptr cinfo,status_t error)1295b98ef4f9SStephan Aßmus JPEGTranslator::Error(j_common_ptr cinfo, status_t error)
12969949213aSStephan Aßmus {
12979949213aSStephan Aßmus jpeg_destroy(cinfo);
12989949213aSStephan Aßmus return error;
12999949213aSStephan Aßmus }
1300d8e2fb50SAxel Dörfler
1301d8e2fb50SAxel Dörfler
JPEGTranslator()1302b98ef4f9SStephan Aßmus JPEGTranslator::JPEGTranslator()
1303bf243977SPhilippe Houdoin : BaseTranslator(sTranslatorName, sTranslatorInfo, sTranslatorVersion,
1304bf243977SPhilippe Houdoin sInputFormats, kNumInputFormats,
1305bf243977SPhilippe Houdoin sOutputFormats, kNumOutputFormats,
1306bf243977SPhilippe Houdoin SETTINGS_FILE,
1307bf243977SPhilippe Houdoin sDefaultSettings, kNumDefaultSettings,
1308b98ef4f9SStephan Aßmus B_TRANSLATOR_BITMAP, JPEG_FORMAT)
1309b98ef4f9SStephan Aßmus {}
1310b98ef4f9SStephan Aßmus
1311b98ef4f9SStephan Aßmus
1312b98ef4f9SStephan Aßmus BTranslator*
make_nth_translator(int32 n,image_id you,uint32 flags,...)1313b98ef4f9SStephan Aßmus make_nth_translator(int32 n, image_id you, uint32 flags, ...)
1314b98ef4f9SStephan Aßmus {
1315b98ef4f9SStephan Aßmus if (n == 0)
1316b98ef4f9SStephan Aßmus return new JPEGTranslator();
1317b98ef4f9SStephan Aßmus
1318b98ef4f9SStephan Aßmus return NULL;
1319b98ef4f9SStephan Aßmus }
1320d8e2fb50SAxel Dörfler
1321d8e2fb50SAxel Dörfler
1322d8e2fb50SAxel Dörfler int
main(int,char **)1323117da2d7SAxel Dörfler main(int, char**)
1324117da2d7SAxel Dörfler {
1325117da2d7SAxel Dörfler BApplication app("application/x-vnd.Haiku-JPEGTranslator");
1326b98ef4f9SStephan Aßmus JPEGTranslator* translator = new JPEGTranslator();
1327bf243977SPhilippe Houdoin if (LaunchTranslatorWindow(translator, sTranslatorName) == B_OK)
1328d8e2fb50SAxel Dörfler app.Run();
1329b98ef4f9SStephan Aßmus
1330d8e2fb50SAxel Dörfler return 0;
1331d8e2fb50SAxel Dörfler }
1332d8e2fb50SAxel Dörfler
1333