19949213aSStephan Aßmus /* 29949213aSStephan Aßmus 39949213aSStephan Aßmus Copyright (c) 2002-2003, Marcin 'Shard' Konicki 49949213aSStephan Aßmus All rights reserved. 59949213aSStephan Aßmus 69949213aSStephan Aßmus Redistribution and use in source and binary forms, with or without 79949213aSStephan Aßmus modification, are permitted provided that the following conditions are met: 89949213aSStephan Aßmus 99949213aSStephan Aßmus * Redistributions of source code must retain the above copyright notice, 109949213aSStephan Aßmus this list of conditions and the following disclaimer. 119949213aSStephan Aßmus * Redistributions in binary form must reproduce the above copyright notice, 129949213aSStephan Aßmus this list of conditions and the following disclaimer in the documentation and/or 139949213aSStephan Aßmus other materials provided with the distribution. 149949213aSStephan Aßmus * Name "Marcin Konicki", "Shard" or any combination of them, 159949213aSStephan Aßmus must not be used to endorse or promote products derived from this 169949213aSStephan Aßmus software without specific prior written permission from Marcin Konicki. 179949213aSStephan Aßmus 189949213aSStephan Aßmus THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 199949213aSStephan Aßmus ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 209949213aSStephan Aßmus THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 219949213aSStephan Aßmus ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 229949213aSStephan Aßmus BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 239949213aSStephan Aßmus OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 249949213aSStephan Aßmus PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 259949213aSStephan Aßmus OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 269949213aSStephan Aßmus WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 279949213aSStephan Aßmus OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 289949213aSStephan Aßmus EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 299949213aSStephan Aßmus 309949213aSStephan Aßmus */ 319949213aSStephan Aßmus 329949213aSStephan Aßmus 339949213aSStephan Aßmus #include "JPEGTranslator.h" 34b98ef4f9SStephan Aßmus #include "TranslatorWindow.h" 3552e8f46aSAxel Dörfler #include "exif_parser.h" 3652e8f46aSAxel Dörfler 3770d59669SSiarzhuk Zharski #include <syslog.h> 3870d59669SSiarzhuk Zharski 39b98ef4f9SStephan Aßmus #include <Alignment.h> 4003901b6cSJérôme Duval #include <Catalog.h> 41b98ef4f9SStephan Aßmus #include <GridLayoutBuilder.h> 42b98ef4f9SStephan Aßmus #include <GroupLayoutBuilder.h> 438687ff64SAxel Dörfler #include <TabView.h> 44b98ef4f9SStephan Aßmus #include <TextView.h> 458687ff64SAxel Dörfler 4603901b6cSJérôme Duval #undef B_TRANSLATE_CONTEXT 4703901b6cSJérôme Duval #define B_TRANSLATE_CONTEXT "JPEGTranslator" 489949213aSStephan Aßmus 4952e8f46aSAxel Dörfler #define MARKER_EXIF 0xe1 5052e8f46aSAxel Dörfler 519949213aSStephan Aßmus // Set these accordingly 529949213aSStephan Aßmus #define JPEG_ACRONYM "JPEG" 539949213aSStephan Aßmus #define JPEG_FORMAT 'JPEG' 549949213aSStephan Aßmus #define JPEG_MIME_STRING "image/jpeg" 559949213aSStephan Aßmus #define JPEG_DESCRIPTION "JPEG image" 569949213aSStephan Aßmus 579949213aSStephan Aßmus // The translation kit's native file type 589949213aSStephan Aßmus #define B_TRANSLATOR_BITMAP_MIME_STRING "image/x-be-bitmap" 59c095606eSRyan Leavengood #define B_TRANSLATOR_BITMAP_DESCRIPTION "Be Bitmap Format (JPEGTranslator)" 609949213aSStephan Aßmus 61b98ef4f9SStephan Aßmus 622e49ff35SSiarzhuk Zharski static const int32 sTranslatorVersion = B_TRANSLATION_MAKE_VERSION(1, 2, 0); 632e49ff35SSiarzhuk Zharski 64*1da233a7SSiarzhuk Zharski static const char* sTranslatorName = B_TRANSLATE("JPEG images"); 65*1da233a7SSiarzhuk Zharski static const char* sTranslatorInfo = B_TRANSLATE("©2002-2003, Marcin Konicki\n" 66f13b5de6SAxel Dörfler "©2005-2007, Haiku\n" 67758b1d0eSIngo Weinhold "\n" 687fd58091SJérôme Duval "Based on IJG library © 1994-2009, Thomas G. Lane, Guido Vollbeding.\n" 692e49ff35SSiarzhuk Zharski "\thttp://www.ijg.org/files/\n" 70b98ef4f9SStephan Aßmus "\n" 71fcc3e627SStephan Aßmus "with \"lossless\" encoding support patch by Ken Murchison\n" 722e49ff35SSiarzhuk Zharski "\thttp://www.oceana.com/ftp/ljpeg/\n" 73758b1d0eSIngo Weinhold "\n" 74758b1d0eSIngo Weinhold "With some colorspace conversion routines by Magnus Hellman\n" 752e49ff35SSiarzhuk Zharski "\thttp://www.bebits.com/app/802\n"); 769949213aSStephan Aßmus 779949213aSStephan Aßmus // Define the formats we know how to read 78bf243977SPhilippe Houdoin static const translation_format sInputFormats[] = { 799949213aSStephan Aßmus { JPEG_FORMAT, B_TRANSLATOR_BITMAP, 0.5, 0.5, 809949213aSStephan Aßmus JPEG_MIME_STRING, JPEG_DESCRIPTION }, 819949213aSStephan Aßmus { B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.5, 0.5, 827b5743baSPhilippe Houdoin B_TRANSLATOR_BITMAP_MIME_STRING, B_TRANSLATOR_BITMAP_DESCRIPTION } 839949213aSStephan Aßmus }; 849949213aSStephan Aßmus 859949213aSStephan Aßmus // Define the formats we know how to write 86bf243977SPhilippe Houdoin static const translation_format sOutputFormats[] = { 879949213aSStephan Aßmus { JPEG_FORMAT, B_TRANSLATOR_BITMAP, 0.5, 0.5, 889949213aSStephan Aßmus JPEG_MIME_STRING, JPEG_DESCRIPTION }, 899949213aSStephan Aßmus { B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.5, 0.5, 907b5743baSPhilippe Houdoin B_TRANSLATOR_BITMAP_MIME_STRING, B_TRANSLATOR_BITMAP_DESCRIPTION } 919949213aSStephan Aßmus }; 9252e8f46aSAxel Dörfler 93d8e2fb50SAxel Dörfler 94bf243977SPhilippe Houdoin static const TranSetting sDefaultSettings[] = { 95b98ef4f9SStephan Aßmus {JPEG_SET_SMOOTHING, TRAN_SETTING_INT32, 0}, 96b98ef4f9SStephan Aßmus {JPEG_SET_QUALITY, TRAN_SETTING_INT32, 95}, 97b98ef4f9SStephan Aßmus {JPEG_SET_PROGRESSIVE, TRAN_SETTING_BOOL, true}, 98b98ef4f9SStephan Aßmus {JPEG_SET_OPT_COLORS, TRAN_SETTING_BOOL, true}, 99b98ef4f9SStephan Aßmus {JPEG_SET_SMALL_FILES, TRAN_SETTING_BOOL, false}, 100b98ef4f9SStephan Aßmus {JPEG_SET_GRAY1_AS_RGB24, TRAN_SETTING_BOOL, false}, 101b98ef4f9SStephan Aßmus {JPEG_SET_ALWAYS_RGB32, TRAN_SETTING_BOOL, true}, 102b98ef4f9SStephan Aßmus {JPEG_SET_PHOTOSHOP_CMYK, TRAN_SETTING_BOOL, true}, 103b98ef4f9SStephan Aßmus {JPEG_SET_SHOWREADWARNING, TRAN_SETTING_BOOL, true} 104b98ef4f9SStephan Aßmus }; 105bf243977SPhilippe Houdoin 106bf243977SPhilippe Houdoin const uint32 kNumInputFormats = sizeof(sInputFormats) / sizeof(translation_format); 107bf243977SPhilippe Houdoin const uint32 kNumOutputFormats = sizeof(sOutputFormats) / sizeof(translation_format); 108bf243977SPhilippe Houdoin const uint32 kNumDefaultSettings = sizeof(sDefaultSettings) / sizeof(TranSetting); 1099949213aSStephan Aßmus 110d8e2fb50SAxel Dörfler 111b98ef4f9SStephan Aßmus namespace conversion { 112d8e2fb50SAxel Dörfler 113d8e2fb50SAxel Dörfler 1149e34f742SAxel Dörfler static bool 1159e34f742SAxel Dörfler x_flipped(int32 orientation) 1169e34f742SAxel Dörfler { 1179e34f742SAxel Dörfler return orientation == 2 || orientation == 3 1189e34f742SAxel Dörfler || orientation == 6 || orientation == 7; 1199e34f742SAxel Dörfler } 1209e34f742SAxel Dörfler 1219e34f742SAxel Dörfler 1229e34f742SAxel Dörfler static bool 1239e34f742SAxel Dörfler y_flipped(int32 orientation) 1249e34f742SAxel Dörfler { 1259e34f742SAxel Dörfler return orientation == 3 || orientation == 4 1269e34f742SAxel Dörfler || orientation == 7 || orientation == 8; 1279e34f742SAxel Dörfler } 1289e34f742SAxel Dörfler 1299e34f742SAxel Dörfler 1309e34f742SAxel Dörfler static int32 1319e34f742SAxel Dörfler dest_index(uint32 width, uint32 height, uint32 x, uint32 y, int32 orientation) 1329e34f742SAxel Dörfler { 1339e34f742SAxel Dörfler if (orientation > 4) { 1349e34f742SAxel Dörfler uint32 temp = x; 1359e34f742SAxel Dörfler x = y; 1369e34f742SAxel Dörfler y = temp; 1379e34f742SAxel Dörfler } 1389e34f742SAxel Dörfler if (y_flipped(orientation)) 1399e34f742SAxel Dörfler y = height - 1 - y; 1409e34f742SAxel Dörfler if (x_flipped(orientation)) 1419e34f742SAxel Dörfler x = width - 1 - x; 1429e34f742SAxel Dörfler 1439e34f742SAxel Dörfler return y * width + x; 1449e34f742SAxel Dörfler } 1459e34f742SAxel Dörfler 1469e34f742SAxel Dörfler 1479e34f742SAxel Dörfler // #pragma mark - conversion for compression 148d8e2fb50SAxel Dörfler 149d8e2fb50SAxel Dörfler 150d8e2fb50SAxel Dörfler inline void 1519e34f742SAxel Dörfler convert_from_gray1_to_gray8(uint8* in, uint8* out, int32 inRowBytes) 152d8e2fb50SAxel Dörfler { 153d8e2fb50SAxel Dörfler int32 index = 0; 154d8e2fb50SAxel Dörfler int32 index2 = 0; 1559e34f742SAxel Dörfler while (index < inRowBytes) { 156d8e2fb50SAxel Dörfler unsigned char c = in[index++]; 157d8e2fb50SAxel Dörfler for (int b = 128; b; b = b>>1) { 158d8e2fb50SAxel Dörfler unsigned char color; 159d8e2fb50SAxel Dörfler if (c & b) 160d8e2fb50SAxel Dörfler color = 0; 161d8e2fb50SAxel Dörfler else 162d8e2fb50SAxel Dörfler color = 255; 163d8e2fb50SAxel Dörfler out[index2++] = color; 164d8e2fb50SAxel Dörfler } 165d8e2fb50SAxel Dörfler } 166d8e2fb50SAxel Dörfler } 167d8e2fb50SAxel Dörfler 168d8e2fb50SAxel Dörfler 169d8e2fb50SAxel Dörfler inline void 1709e34f742SAxel Dörfler convert_from_gray1_to_24(uint8* in, uint8* out, int32 inRowBytes) 171d8e2fb50SAxel Dörfler { 172d8e2fb50SAxel Dörfler int32 index = 0; 173d8e2fb50SAxel Dörfler int32 index2 = 0; 1749e34f742SAxel Dörfler while (index < inRowBytes) { 175d8e2fb50SAxel Dörfler unsigned char c = in[index++]; 176d8e2fb50SAxel Dörfler for (int b = 128; b; b = b>>1) { 177d8e2fb50SAxel Dörfler unsigned char color; 178d8e2fb50SAxel Dörfler if (c & b) 179d8e2fb50SAxel Dörfler color = 0; 180d8e2fb50SAxel Dörfler else 181d8e2fb50SAxel Dörfler color = 255; 182d8e2fb50SAxel Dörfler out[index2++] = color; 183d8e2fb50SAxel Dörfler out[index2++] = color; 184d8e2fb50SAxel Dörfler out[index2++] = color; 185d8e2fb50SAxel Dörfler } 186d8e2fb50SAxel Dörfler } 187d8e2fb50SAxel Dörfler } 188d8e2fb50SAxel Dörfler 189d8e2fb50SAxel Dörfler 190d8e2fb50SAxel Dörfler inline void 1919e34f742SAxel Dörfler convert_from_cmap8_to_24(uint8* in, uint8* out, int32 inRowBytes) 192d8e2fb50SAxel Dörfler { 193d8e2fb50SAxel Dörfler const color_map * map = system_colors(); 194d8e2fb50SAxel Dörfler int32 index = 0; 195d8e2fb50SAxel Dörfler int32 index2 = 0; 1969e34f742SAxel Dörfler while (index < inRowBytes) { 197d8e2fb50SAxel Dörfler rgb_color color = map->color_list[in[index++]]; 198d8e2fb50SAxel Dörfler 199d8e2fb50SAxel Dörfler out[index2++] = color.red; 200d8e2fb50SAxel Dörfler out[index2++] = color.green; 201d8e2fb50SAxel Dörfler out[index2++] = color.blue; 202d8e2fb50SAxel Dörfler } 203d8e2fb50SAxel Dörfler } 204d8e2fb50SAxel Dörfler 205d8e2fb50SAxel Dörfler 206d8e2fb50SAxel Dörfler inline void 2079e34f742SAxel Dörfler convert_from_15_to_24(uint8* in, uint8* out, int32 inRowBytes) 208d8e2fb50SAxel Dörfler { 209d8e2fb50SAxel Dörfler int32 index = 0; 210d8e2fb50SAxel Dörfler int32 index2 = 0; 211d8e2fb50SAxel Dörfler int16 in_pixel; 2129e34f742SAxel Dörfler while (index < inRowBytes) { 213d8e2fb50SAxel Dörfler in_pixel = in[index] | (in[index + 1] << 8); 214d8e2fb50SAxel Dörfler index += 2; 215d8e2fb50SAxel Dörfler 216d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x7c00)) >> 7) | (((in_pixel & 0x7c00)) >> 12); 217d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x3e0)) >> 2) | (((in_pixel & 0x3e0)) >> 7); 218d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2); 219d8e2fb50SAxel Dörfler } 220d8e2fb50SAxel Dörfler } 221d8e2fb50SAxel Dörfler 222d8e2fb50SAxel Dörfler 223d8e2fb50SAxel Dörfler inline void 2249e34f742SAxel Dörfler convert_from_15b_to_24(uint8* in, uint8* out, int32 inRowBytes) 225d8e2fb50SAxel Dörfler { 226d8e2fb50SAxel Dörfler int32 index = 0; 227d8e2fb50SAxel Dörfler int32 index2 = 0; 228d8e2fb50SAxel Dörfler int16 in_pixel; 2299e34f742SAxel Dörfler while (index < inRowBytes) { 230d8e2fb50SAxel Dörfler in_pixel = in[index + 1] | (in[index] << 8); 231d8e2fb50SAxel Dörfler index += 2; 232d8e2fb50SAxel Dörfler 233d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x7c00)) >> 7) | (((in_pixel & 0x7c00)) >> 12); 234d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x3e0)) >> 2) | (((in_pixel & 0x3e0)) >> 7); 235d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2); 236d8e2fb50SAxel Dörfler } 237d8e2fb50SAxel Dörfler } 238d8e2fb50SAxel Dörfler 239d8e2fb50SAxel Dörfler 240d8e2fb50SAxel Dörfler inline void 2419e34f742SAxel Dörfler convert_from_16_to_24(uint8* in, uint8* out, int32 inRowBytes) 242d8e2fb50SAxel Dörfler { 243d8e2fb50SAxel Dörfler int32 index = 0; 244d8e2fb50SAxel Dörfler int32 index2 = 0; 245d8e2fb50SAxel Dörfler int16 in_pixel; 2469e34f742SAxel Dörfler while (index < inRowBytes) { 247d8e2fb50SAxel Dörfler in_pixel = in[index] | (in[index + 1] << 8); 248d8e2fb50SAxel Dörfler index += 2; 249d8e2fb50SAxel Dörfler 250d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0xf800)) >> 8) | (((in_pixel & 0xf800)) >> 13); 251d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x7e0)) >> 3) | (((in_pixel & 0x7e0)) >> 9); 252d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2); 253d8e2fb50SAxel Dörfler } 254d8e2fb50SAxel Dörfler } 255d8e2fb50SAxel Dörfler 256d8e2fb50SAxel Dörfler 257d8e2fb50SAxel Dörfler inline void 2589e34f742SAxel Dörfler convert_from_16b_to_24(uint8* in, uint8* out, int32 inRowBytes) 259d8e2fb50SAxel Dörfler { 260d8e2fb50SAxel Dörfler int32 index = 0; 261d8e2fb50SAxel Dörfler int32 index2 = 0; 262d8e2fb50SAxel Dörfler int16 in_pixel; 2639e34f742SAxel Dörfler while (index < inRowBytes) { 264d8e2fb50SAxel Dörfler in_pixel = in[index + 1] | (in[index] << 8); 265d8e2fb50SAxel Dörfler index += 2; 266d8e2fb50SAxel Dörfler 267d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0xf800)) >> 8) | (((in_pixel & 0xf800)) >> 13); 268d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x7e0)) >> 3) | (((in_pixel & 0x7e0)) >> 9); 269d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2); 270d8e2fb50SAxel Dörfler } 271d8e2fb50SAxel Dörfler } 272d8e2fb50SAxel Dörfler 273d8e2fb50SAxel Dörfler 274d8e2fb50SAxel Dörfler inline void 2759e34f742SAxel Dörfler convert_from_24_to_24(uint8* in, uint8* out, int32 inRowBytes) 276d8e2fb50SAxel Dörfler { 277d8e2fb50SAxel Dörfler int32 index = 0; 278d8e2fb50SAxel Dörfler int32 index2 = 0; 2799e34f742SAxel Dörfler while (index < inRowBytes) { 280d8e2fb50SAxel Dörfler out[index2++] = in[index + 2]; 281d8e2fb50SAxel Dörfler out[index2++] = in[index + 1]; 282d8e2fb50SAxel Dörfler out[index2++] = in[index]; 283d8e2fb50SAxel Dörfler index+=3; 284d8e2fb50SAxel Dörfler } 285d8e2fb50SAxel Dörfler } 286d8e2fb50SAxel Dörfler 287d8e2fb50SAxel Dörfler 288d8e2fb50SAxel Dörfler inline void 2899e34f742SAxel Dörfler convert_from_32_to_24(uint8* in, uint8* out, int32 inRowBytes) 290d8e2fb50SAxel Dörfler { 29151623681SAxel Dörfler inRowBytes /= 4; 29251623681SAxel Dörfler 2939e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i++) { 2949e34f742SAxel Dörfler out[0] = in[2]; 2959e34f742SAxel Dörfler out[1] = in[1]; 2969e34f742SAxel Dörfler out[2] = in[0]; 2979e34f742SAxel Dörfler 2989e34f742SAxel Dörfler in += 4; 2999e34f742SAxel Dörfler out += 3; 300d8e2fb50SAxel Dörfler } 301d8e2fb50SAxel Dörfler } 302d8e2fb50SAxel Dörfler 303d8e2fb50SAxel Dörfler 304d8e2fb50SAxel Dörfler inline void 3059e34f742SAxel Dörfler convert_from_32b_to_24(uint8* in, uint8* out, int32 inRowBytes) 306d8e2fb50SAxel Dörfler { 30751623681SAxel Dörfler inRowBytes /= 4; 30851623681SAxel Dörfler 3099e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i++) { 31051623681SAxel Dörfler out[0] = in[1]; 31151623681SAxel Dörfler out[1] = in[2]; 31251623681SAxel Dörfler out[2] = in[3]; 3139e34f742SAxel Dörfler 3149e34f742SAxel Dörfler in += 4; 3159e34f742SAxel Dörfler out += 3; 316d8e2fb50SAxel Dörfler } 317d8e2fb50SAxel Dörfler } 318d8e2fb50SAxel Dörfler 319d8e2fb50SAxel Dörfler 3209e34f742SAxel Dörfler // #pragma mark - conversion for decompression 3219e34f742SAxel Dörfler 3229e34f742SAxel Dörfler 323d8e2fb50SAxel Dörfler inline void 3249e34f742SAxel Dörfler convert_from_CMYK_to_32_photoshop(uint8* in, uint8* out, int32 inRowBytes, int32 xStep) 325d8e2fb50SAxel Dörfler { 3269e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i += 4) { 3279e34f742SAxel Dörfler int32 black = in[3]; 3289e34f742SAxel Dörfler out[0] = in[2] * black / 255; 3299e34f742SAxel Dörfler out[1] = in[1] * black / 255; 3309e34f742SAxel Dörfler out[2] = in[0] * black / 255; 3319e34f742SAxel Dörfler out[3] = 255; 3329e34f742SAxel Dörfler 3339e34f742SAxel Dörfler in += 4; 3349e34f742SAxel Dörfler out += xStep; 335d8e2fb50SAxel Dörfler } 336d8e2fb50SAxel Dörfler } 337d8e2fb50SAxel Dörfler 338d8e2fb50SAxel Dörfler 339d8e2fb50SAxel Dörfler //! !!! UNTESTED !!! 340d8e2fb50SAxel Dörfler inline void 3419e34f742SAxel Dörfler convert_from_CMYK_to_32(uint8* in, uint8* out, int32 inRowBytes, int32 xStep) 342d8e2fb50SAxel Dörfler { 3439e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i += 4) { 3449e34f742SAxel Dörfler int32 black = 255 - in[3]; 3459e34f742SAxel Dörfler out[0] = ((255 - in[2]) * black) / 255; 3469e34f742SAxel Dörfler out[1] = ((255 - in[1]) * black) / 255; 3479e34f742SAxel Dörfler out[2] = ((255 - in[0]) * black) / 255; 3489e34f742SAxel Dörfler out[3] = 255; 3499e34f742SAxel Dörfler 3509e34f742SAxel Dörfler in += 4; 3519e34f742SAxel Dörfler out += xStep; 352d8e2fb50SAxel Dörfler } 353d8e2fb50SAxel Dörfler } 354d8e2fb50SAxel Dörfler 355d8e2fb50SAxel Dörfler 356d8e2fb50SAxel Dörfler //! RGB24 8:8:8 to xRGB 8:8:8:8 357d8e2fb50SAxel Dörfler inline void 3589e34f742SAxel Dörfler convert_from_24_to_32(uint8* in, uint8* out, int32 inRowBytes, int32 xStep) 359d8e2fb50SAxel Dörfler { 3609e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i += 3) { 3619e34f742SAxel Dörfler out[0] = in[2]; 3629e34f742SAxel Dörfler out[1] = in[1]; 3639e34f742SAxel Dörfler out[2] = in[0]; 3649e34f742SAxel Dörfler out[3] = 255; 3659e34f742SAxel Dörfler 3669e34f742SAxel Dörfler in += 3; 3679e34f742SAxel Dörfler out += xStep; 3689e34f742SAxel Dörfler } 3699e34f742SAxel Dörfler } 3709e34f742SAxel Dörfler 3719e34f742SAxel Dörfler 3729e34f742SAxel Dörfler //! 8-bit to 8-bit, only need when rotating the image 3739e34f742SAxel Dörfler void 3749e34f742SAxel Dörfler translate_8(uint8* in, uint8* out, int32 inRowBytes, int32 xStep) 3759e34f742SAxel Dörfler { 3769e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i++) { 3779e34f742SAxel Dörfler out[0] = in[0]; 3789e34f742SAxel Dörfler 3799e34f742SAxel Dörfler in++; 3809e34f742SAxel Dörfler out += xStep; 381d8e2fb50SAxel Dörfler } 382d8e2fb50SAxel Dörfler } 383d8e2fb50SAxel Dörfler 384d8e2fb50SAxel Dörfler 385b98ef4f9SStephan Aßmus } // namespace conversion 3868687ff64SAxel Dörfler 3878687ff64SAxel Dörfler 388d8e2fb50SAxel Dörfler // #pragma mark - 389d8e2fb50SAxel Dörfler 390d8e2fb50SAxel Dörfler 391b98ef4f9SStephan Aßmus SSlider::SSlider(const char* name, const char* label, 392d8e2fb50SAxel Dörfler BMessage* message, int32 minValue, int32 maxValue, orientation posture, 393b98ef4f9SStephan Aßmus thumb_style thumbType, uint32 flags) 394b98ef4f9SStephan Aßmus : BSlider(name, label, message, minValue, maxValue, 395b98ef4f9SStephan Aßmus posture, thumbType, flags) 3969949213aSStephan Aßmus { 3978687ff64SAxel Dörfler rgb_color barColor = { 0, 0, 229, 255 }; 3988687ff64SAxel Dörfler UseFillColor(true, &barColor); 3999949213aSStephan Aßmus } 4009949213aSStephan Aßmus 4018687ff64SAxel Dörfler 4028687ff64SAxel Dörfler //! Update status string - show actual value 403b20d13f4SStefano Ceccherini const char* 4049949213aSStephan Aßmus SSlider::UpdateText() const 4059949213aSStephan Aßmus { 4068687ff64SAxel Dörfler snprintf(fStatusLabel, sizeof(fStatusLabel), "%ld", Value()); 4078687ff64SAxel Dörfler return fStatusLabel; 4089949213aSStephan Aßmus } 4099949213aSStephan Aßmus 4108687ff64SAxel Dörfler 411d8e2fb50SAxel Dörfler // #pragma mark - 4129949213aSStephan Aßmus 413d8e2fb50SAxel Dörfler 414b98ef4f9SStephan Aßmus TranslatorReadView::TranslatorReadView(const char* name, 415b98ef4f9SStephan Aßmus TranslatorSettings* settings) 416b98ef4f9SStephan Aßmus : 417b98ef4f9SStephan Aßmus BView(name, 0, new BGroupLayout(B_HORIZONTAL)), 418d8e2fb50SAxel Dörfler fSettings(settings) 419b98ef4f9SStephan Aßmus // settings should already be Acquired() 4209949213aSStephan Aßmus { 4212e49ff35SSiarzhuk Zharski fAlwaysRGB32 = new BCheckBox("alwaysrgb32", 4222e49ff35SSiarzhuk Zharski B_TRANSLATE("Read greyscale images as RGB32"), 423d8e2fb50SAxel Dörfler new BMessage(VIEW_MSG_SET_ALWAYSRGB32)); 424b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_ALWAYS_RGB32, NULL)) 425b98ef4f9SStephan Aßmus fAlwaysRGB32->SetValue(B_CONTROL_ON); 4269949213aSStephan Aßmus 4272e49ff35SSiarzhuk Zharski fPhotoshopCMYK = new BCheckBox("photoshopCMYK", 4282e49ff35SSiarzhuk Zharski B_TRANSLATE("Use CMYK code with 0 for 100% ink coverage"), 4298687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_PHOTOSHOPCMYK)); 430b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_PHOTOSHOP_CMYK, NULL)) 431b98ef4f9SStephan Aßmus fPhotoshopCMYK->SetValue(B_CONTROL_ON); 4329949213aSStephan Aßmus 4332e49ff35SSiarzhuk Zharski fShowErrorBox = new BCheckBox("error", 4342e49ff35SSiarzhuk Zharski B_TRANSLATE("Show warning messages"), 4358687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_SHOWREADERRORBOX)); 436b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_SHOWREADWARNING, NULL)) 437b98ef4f9SStephan Aßmus fShowErrorBox->SetValue(B_CONTROL_ON); 4389949213aSStephan Aßmus 439b98ef4f9SStephan Aßmus float padding = 5.0f; 440b98ef4f9SStephan Aßmus AddChild(BGroupLayoutBuilder(B_VERTICAL, padding) 441b98ef4f9SStephan Aßmus .Add(fAlwaysRGB32) 442b98ef4f9SStephan Aßmus .Add(fPhotoshopCMYK) 443b98ef4f9SStephan Aßmus .Add(fShowErrorBox) 444b98ef4f9SStephan Aßmus .AddGlue() 445b98ef4f9SStephan Aßmus .SetInsets(padding, padding, padding, padding) 446b98ef4f9SStephan Aßmus ); 4479949213aSStephan Aßmus 448b98ef4f9SStephan Aßmus } 449b98ef4f9SStephan Aßmus 450b98ef4f9SStephan Aßmus 451b98ef4f9SStephan Aßmus TranslatorReadView::~TranslatorReadView() 452b98ef4f9SStephan Aßmus { 453b98ef4f9SStephan Aßmus fSettings->Release(); 4549949213aSStephan Aßmus } 4559949213aSStephan Aßmus 4568687ff64SAxel Dörfler 4579949213aSStephan Aßmus void 4589949213aSStephan Aßmus TranslatorReadView::AttachedToWindow() 4599949213aSStephan Aßmus { 460b98ef4f9SStephan Aßmus BView::AttachedToWindow(); 461b20d13f4SStefano Ceccherini 4628687ff64SAxel Dörfler fAlwaysRGB32->SetTarget(this); 4638687ff64SAxel Dörfler fPhotoshopCMYK->SetTarget(this); 4648687ff64SAxel Dörfler fShowErrorBox->SetTarget(this); 4659949213aSStephan Aßmus } 4669949213aSStephan Aßmus 4678687ff64SAxel Dörfler 4689949213aSStephan Aßmus void 4699949213aSStephan Aßmus TranslatorReadView::MessageReceived(BMessage* message) 4709949213aSStephan Aßmus { 4718687ff64SAxel Dörfler switch (message->what) { 4729949213aSStephan Aßmus case VIEW_MSG_SET_ALWAYSRGB32: 4739949213aSStephan Aßmus { 4749949213aSStephan Aßmus int32 value; 4759949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 476b98ef4f9SStephan Aßmus bool boolValue = value; 477b98ef4f9SStephan Aßmus fSettings->SetGetBool(JPEG_SET_ALWAYS_RGB32, &boolValue); 478b98ef4f9SStephan Aßmus fSettings->SaveSettings(); 4799949213aSStephan Aßmus } 4809949213aSStephan Aßmus break; 4819949213aSStephan Aßmus } 4829949213aSStephan Aßmus case VIEW_MSG_SET_PHOTOSHOPCMYK: 4839949213aSStephan Aßmus { 4849949213aSStephan Aßmus int32 value; 4859949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 486b98ef4f9SStephan Aßmus bool boolValue = value; 487b98ef4f9SStephan Aßmus fSettings->SetGetBool(JPEG_SET_PHOTOSHOP_CMYK, &boolValue); 488b98ef4f9SStephan Aßmus fSettings->SaveSettings(); 4899949213aSStephan Aßmus } 4909949213aSStephan Aßmus break; 4919949213aSStephan Aßmus } 4929949213aSStephan Aßmus case VIEW_MSG_SET_SHOWREADERRORBOX: 4939949213aSStephan Aßmus { 4949949213aSStephan Aßmus int32 value; 4959949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 496b98ef4f9SStephan Aßmus bool boolValue = value; 497b98ef4f9SStephan Aßmus fSettings->SetGetBool(JPEG_SET_SHOWREADWARNING, &boolValue); 498b98ef4f9SStephan Aßmus fSettings->SaveSettings(); 4999949213aSStephan Aßmus } 5009949213aSStephan Aßmus break; 5019949213aSStephan Aßmus } 5029949213aSStephan Aßmus default: 5039949213aSStephan Aßmus BView::MessageReceived(message); 5049949213aSStephan Aßmus break; 5059949213aSStephan Aßmus } 5069949213aSStephan Aßmus } 5079949213aSStephan Aßmus 5089949213aSStephan Aßmus 5098687ff64SAxel Dörfler // #pragma mark - TranslatorWriteView 5109949213aSStephan Aßmus 5118687ff64SAxel Dörfler 512b98ef4f9SStephan Aßmus TranslatorWriteView::TranslatorWriteView(const char* name, 513b98ef4f9SStephan Aßmus TranslatorSettings* settings) 514b98ef4f9SStephan Aßmus : 515b98ef4f9SStephan Aßmus BView(name, 0, new BGroupLayout(B_VERTICAL)), 516d8e2fb50SAxel Dörfler fSettings(settings) 517b98ef4f9SStephan Aßmus // settings should already be Acquired() 5189949213aSStephan Aßmus { 5192e49ff35SSiarzhuk Zharski fQualitySlider = new SSlider("quality", B_TRANSLATE("Output quality"), 5208687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_QUALITY), 0, 100); 5218687ff64SAxel Dörfler fQualitySlider->SetHashMarks(B_HASH_MARKS_BOTTOM); 5228687ff64SAxel Dörfler fQualitySlider->SetHashMarkCount(10); 52303901b6cSJérôme Duval fQualitySlider->SetLimitLabels(B_TRANSLATE("Low"), B_TRANSLATE("High")); 524b98ef4f9SStephan Aßmus fQualitySlider->SetValue(fSettings->SetGetInt32(JPEG_SET_QUALITY, NULL)); 5259949213aSStephan Aßmus 5262e49ff35SSiarzhuk Zharski fSmoothingSlider = new SSlider("smoothing", 5272e49ff35SSiarzhuk Zharski B_TRANSLATE("Output smoothing strength"), 5288687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_SMOOTHING), 0, 100); 5298687ff64SAxel Dörfler fSmoothingSlider->SetHashMarks(B_HASH_MARKS_BOTTOM); 5308687ff64SAxel Dörfler fSmoothingSlider->SetHashMarkCount(10); 53103901b6cSJérôme Duval fSmoothingSlider->SetLimitLabels(B_TRANSLATE("None"), B_TRANSLATE("High")); 532b98ef4f9SStephan Aßmus fSmoothingSlider->SetValue( 533b98ef4f9SStephan Aßmus fSettings->SetGetInt32(JPEG_SET_SMOOTHING, NULL)); 5349949213aSStephan Aßmus 5352e49ff35SSiarzhuk Zharski fProgress = new BCheckBox("progress", 5362e49ff35SSiarzhuk Zharski B_TRANSLATE("Use progressive compression"), 5378687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_PROGRESSIVE)); 538b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_PROGRESSIVE, NULL)) 539b98ef4f9SStephan Aßmus fProgress->SetValue(B_CONTROL_ON); 5409949213aSStephan Aßmus 5412e49ff35SSiarzhuk Zharski fSmallerFile = new BCheckBox("smallerfile", 5422e49ff35SSiarzhuk Zharski B_TRANSLATE("Make file smaller (sligthtly worse quality)"), 5438687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_SMALLERFILE)); 544b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_SMALL_FILES)) 545b98ef4f9SStephan Aßmus fSmallerFile->SetValue(B_CONTROL_ON); 546b98ef4f9SStephan Aßmus 5472e49ff35SSiarzhuk Zharski fOptimizeColors = new BCheckBox("optimizecolors", 5482e49ff35SSiarzhuk Zharski B_TRANSLATE("Prevent colors 'washing out'"), 549b98ef4f9SStephan Aßmus new BMessage(VIEW_MSG_SET_OPTIMIZECOLORS)); 550b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_OPT_COLORS, NULL)) 551b98ef4f9SStephan Aßmus fOptimizeColors->SetValue(B_CONTROL_ON); 552b98ef4f9SStephan Aßmus else 5538687ff64SAxel Dörfler fSmallerFile->SetEnabled(false); 5549949213aSStephan Aßmus 5552e49ff35SSiarzhuk Zharski fGrayAsRGB24 = new BCheckBox("gray1asrgb24", 5562e49ff35SSiarzhuk Zharski B_TRANSLATE("Write black-and-white images as RGB24"), 5578687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_GRAY1ASRGB24)); 558b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_GRAY1_AS_RGB24)) 559b98ef4f9SStephan Aßmus fGrayAsRGB24->SetValue(B_CONTROL_ON); 5609949213aSStephan Aßmus 561b98ef4f9SStephan Aßmus float padding = 5.0f; 562b98ef4f9SStephan Aßmus AddChild(BGroupLayoutBuilder(B_VERTICAL, padding) 563b98ef4f9SStephan Aßmus .Add(fQualitySlider) 564b98ef4f9SStephan Aßmus .Add(fSmoothingSlider) 565b98ef4f9SStephan Aßmus .Add(fProgress) 566b98ef4f9SStephan Aßmus .Add(fOptimizeColors) 567b98ef4f9SStephan Aßmus .Add(fSmallerFile) 568b98ef4f9SStephan Aßmus .Add(fGrayAsRGB24) 569b98ef4f9SStephan Aßmus .AddGlue() 570b98ef4f9SStephan Aßmus .SetInsets(padding, padding, padding, padding) 571b98ef4f9SStephan Aßmus ); 572b98ef4f9SStephan Aßmus } 5739949213aSStephan Aßmus 574b98ef4f9SStephan Aßmus 575b98ef4f9SStephan Aßmus TranslatorWriteView::~TranslatorWriteView() 576b98ef4f9SStephan Aßmus { 577b98ef4f9SStephan Aßmus fSettings->Release(); 5789949213aSStephan Aßmus } 5799949213aSStephan Aßmus 5808687ff64SAxel Dörfler 5819949213aSStephan Aßmus void 5829949213aSStephan Aßmus TranslatorWriteView::AttachedToWindow() 5839949213aSStephan Aßmus { 584b98ef4f9SStephan Aßmus BView::AttachedToWindow(); 585b20d13f4SStefano Ceccherini 5868687ff64SAxel Dörfler fQualitySlider->SetTarget(this); 5878687ff64SAxel Dörfler fSmoothingSlider->SetTarget(this); 5888687ff64SAxel Dörfler fProgress->SetTarget(this); 5898687ff64SAxel Dörfler fOptimizeColors->SetTarget(this); 5908687ff64SAxel Dörfler fSmallerFile->SetTarget(this); 5918687ff64SAxel Dörfler fGrayAsRGB24->SetTarget(this); 5929949213aSStephan Aßmus } 5939949213aSStephan Aßmus 5948687ff64SAxel Dörfler 5959949213aSStephan Aßmus void 5969949213aSStephan Aßmus TranslatorWriteView::MessageReceived(BMessage* message) 5979949213aSStephan Aßmus { 5988687ff64SAxel Dörfler switch (message->what) { 5999949213aSStephan Aßmus case VIEW_MSG_SET_QUALITY: 6009949213aSStephan Aßmus { 6019949213aSStephan Aßmus int32 value; 6029949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 603b98ef4f9SStephan Aßmus fSettings->SetGetInt32(JPEG_SET_QUALITY, &value); 604b98ef4f9SStephan Aßmus fSettings->SaveSettings(); 6059949213aSStephan Aßmus } 6069949213aSStephan Aßmus break; 6079949213aSStephan Aßmus } 6089949213aSStephan Aßmus case VIEW_MSG_SET_SMOOTHING: 6099949213aSStephan Aßmus { 6109949213aSStephan Aßmus int32 value; 6119949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 612b98ef4f9SStephan Aßmus fSettings->SetGetInt32(JPEG_SET_SMOOTHING, &value); 613b98ef4f9SStephan Aßmus fSettings->SaveSettings(); 6149949213aSStephan Aßmus } 6159949213aSStephan Aßmus break; 6169949213aSStephan Aßmus } 6179949213aSStephan Aßmus case VIEW_MSG_SET_PROGRESSIVE: 6189949213aSStephan Aßmus { 6199949213aSStephan Aßmus int32 value; 6209949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 621b98ef4f9SStephan Aßmus bool boolValue = value; 622b98ef4f9SStephan Aßmus fSettings->SetGetBool(JPEG_SET_PROGRESSIVE, &boolValue); 623b98ef4f9SStephan Aßmus fSettings->SaveSettings(); 6249949213aSStephan Aßmus } 6259949213aSStephan Aßmus break; 6269949213aSStephan Aßmus } 6279949213aSStephan Aßmus case VIEW_MSG_SET_OPTIMIZECOLORS: 6289949213aSStephan Aßmus { 6299949213aSStephan Aßmus int32 value; 6309949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 631b98ef4f9SStephan Aßmus bool boolValue = value; 632b98ef4f9SStephan Aßmus fSettings->SetGetBool(JPEG_SET_OPT_COLORS, &boolValue); 633b98ef4f9SStephan Aßmus fSmallerFile->SetEnabled(value); 634b98ef4f9SStephan Aßmus fSettings->SaveSettings(); 6359949213aSStephan Aßmus } 6369949213aSStephan Aßmus break; 6379949213aSStephan Aßmus } 6389949213aSStephan Aßmus case VIEW_MSG_SET_SMALLERFILE: 6399949213aSStephan Aßmus { 6409949213aSStephan Aßmus int32 value; 6419949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 642b98ef4f9SStephan Aßmus bool boolValue = value; 643b98ef4f9SStephan Aßmus fSettings->SetGetBool(JPEG_SET_SMALL_FILES, &boolValue); 644b98ef4f9SStephan Aßmus fSettings->SaveSettings(); 6459949213aSStephan Aßmus } 6469949213aSStephan Aßmus break; 6479949213aSStephan Aßmus } 6489949213aSStephan Aßmus case VIEW_MSG_SET_GRAY1ASRGB24: 6499949213aSStephan Aßmus { 6509949213aSStephan Aßmus int32 value; 6519949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 652b98ef4f9SStephan Aßmus bool boolValue = value; 653b98ef4f9SStephan Aßmus fSettings->SetGetBool(JPEG_SET_GRAY1_AS_RGB24, &boolValue); 654b98ef4f9SStephan Aßmus fSettings->SaveSettings(); 6559949213aSStephan Aßmus } 6569949213aSStephan Aßmus break; 6579949213aSStephan Aßmus } 6589949213aSStephan Aßmus default: 6599949213aSStephan Aßmus BView::MessageReceived(message); 6609949213aSStephan Aßmus break; 6619949213aSStephan Aßmus } 6629949213aSStephan Aßmus } 6639949213aSStephan Aßmus 6649949213aSStephan Aßmus 665d8e2fb50SAxel Dörfler // #pragma mark - 6669949213aSStephan Aßmus 667d8e2fb50SAxel Dörfler 668b98ef4f9SStephan Aßmus TranslatorAboutView::TranslatorAboutView(const char* name) 669b98ef4f9SStephan Aßmus : 670b98ef4f9SStephan Aßmus BView(name, 0, new BGroupLayout(B_VERTICAL)) 6719949213aSStephan Aßmus { 672b98ef4f9SStephan Aßmus BAlignment labelAlignment = BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP); 673*1da233a7SSiarzhuk Zharski BStringView* title = new BStringView("Title", sTranslatorName); 6749949213aSStephan Aßmus title->SetFont(be_bold_font); 675b98ef4f9SStephan Aßmus title->SetExplicitAlignment(labelAlignment); 6769949213aSStephan Aßmus 6779949213aSStephan Aßmus char versionString[16]; 678bf243977SPhilippe Houdoin sprintf(versionString, "v%d.%d.%d", (int)(sTranslatorVersion >> 8), 679bf243977SPhilippe Houdoin (int)((sTranslatorVersion >> 4) & 0xf), (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); 686b98ef4f9SStephan Aßmus infoView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 687b98ef4f9SStephan Aßmus infoView->MakeEditable(false); 6889949213aSStephan Aßmus 689b98ef4f9SStephan Aßmus float padding = 5.0f; 690b98ef4f9SStephan Aßmus AddChild(BGroupLayoutBuilder(B_VERTICAL, padding) 691b98ef4f9SStephan Aßmus .Add(BGroupLayoutBuilder(B_HORIZONTAL, padding) 692b98ef4f9SStephan Aßmus .Add(title) 693b98ef4f9SStephan Aßmus .Add(version) 694b98ef4f9SStephan Aßmus .AddGlue() 695b98ef4f9SStephan Aßmus ) 696b98ef4f9SStephan Aßmus .Add(infoView) 697b98ef4f9SStephan Aßmus .SetInsets(padding, padding, padding, padding) 698b98ef4f9SStephan Aßmus ); 6999949213aSStephan Aßmus } 7009949213aSStephan Aßmus 7019949213aSStephan Aßmus 702b98ef4f9SStephan Aßmus TranslatorView::TranslatorView(const char* name, TranslatorSettings* settings) 703b98ef4f9SStephan Aßmus : 704b98ef4f9SStephan Aßmus BTabView(name) 7059949213aSStephan Aßmus { 70670d59669SSiarzhuk Zharski AddTab(new TranslatorWriteView(B_TRANSLATE("Write"), settings->Acquire())); 70770d59669SSiarzhuk Zharski AddTab(new TranslatorReadView(B_TRANSLATE("Read"), settings->Acquire())); 70870d59669SSiarzhuk Zharski AddTab(new TranslatorAboutView(B_TRANSLATE("About"))); 7099949213aSStephan Aßmus 710b98ef4f9SStephan Aßmus settings->Release(); 7119949213aSStephan Aßmus 712b98ef4f9SStephan Aßmus BFont font; 713b98ef4f9SStephan Aßmus GetFont(&font); 714b98ef4f9SStephan Aßmus SetExplicitPreferredSize( 715b98ef4f9SStephan Aßmus BSize((font.Size() * 380) / 12, (font.Size() * 250) / 12)); 7169949213aSStephan Aßmus } 7179949213aSStephan Aßmus 7189949213aSStephan Aßmus 719d8e2fb50SAxel Dörfler // #pragma mark - Translator Add-On 7209949213aSStephan Aßmus 7219949213aSStephan Aßmus 722b98ef4f9SStephan Aßmus BView* 723b98ef4f9SStephan Aßmus JPEGTranslator::NewConfigView(TranslatorSettings* settings) 7249949213aSStephan Aßmus { 725b98ef4f9SStephan Aßmus BView* configView = new TranslatorView("TranslatorView", settings); 726b98ef4f9SStephan Aßmus return configView; 7279949213aSStephan Aßmus } 7289949213aSStephan Aßmus 729b98ef4f9SStephan Aßmus 730d8e2fb50SAxel Dörfler /*! Determine whether or not we can handle this data */ 7319949213aSStephan Aßmus status_t 732b98ef4f9SStephan Aßmus JPEGTranslator::DerivedIdentify(BPositionIO* inSource, 733b98ef4f9SStephan Aßmus const translation_format* inFormat, BMessage* ioExtension, 734b98ef4f9SStephan Aßmus translator_info* outInfo, uint32 outType) 7359949213aSStephan Aßmus { 736d8e2fb50SAxel Dörfler if (outType != 0 && outType != B_TRANSLATOR_BITMAP && outType != JPEG_FORMAT) 7379949213aSStephan Aßmus return B_NO_TRANSLATOR; 7389949213aSStephan Aßmus 7399949213aSStephan Aßmus // !!! You might need to make this buffer bigger to test for your native format 7409949213aSStephan Aßmus off_t position = inSource->Position(); 7419949213aSStephan Aßmus char header[sizeof(TranslatorBitmap)]; 7429949213aSStephan Aßmus status_t err = inSource->Read(header, sizeof(TranslatorBitmap)); 7439949213aSStephan Aßmus inSource->Seek(position, SEEK_SET); 744d8e2fb50SAxel Dörfler if (err < B_OK) 745d8e2fb50SAxel Dörfler return err; 7469949213aSStephan Aßmus 7479949213aSStephan Aßmus if (B_BENDIAN_TO_HOST_INT32(((TranslatorBitmap *)header)->magic) == B_TRANSLATOR_BITMAP) { 748b98ef4f9SStephan Aßmus if (PopulateInfoFromFormat(outInfo, B_TRANSLATOR_BITMAP) != B_OK) 749b98ef4f9SStephan Aßmus return B_NO_TRANSLATOR; 7509949213aSStephan Aßmus } else { 7519949213aSStephan Aßmus // First 3 bytes in jpg files are always the same from what i've seen so far 7529949213aSStephan Aßmus // check them 7539949213aSStephan Aßmus if (header[0] == (char)0xff && header[1] == (char)0xd8 && header[2] == (char)0xff) { 754b98ef4f9SStephan Aßmus if (PopulateInfoFromFormat(outInfo, JPEG_FORMAT) != B_OK) 7559949213aSStephan Aßmus return B_NO_TRANSLATOR; 756b98ef4f9SStephan Aßmus 7579949213aSStephan Aßmus } else 7589949213aSStephan Aßmus return B_NO_TRANSLATOR; 7599949213aSStephan Aßmus } 7609949213aSStephan Aßmus 7619949213aSStephan Aßmus return B_OK; 7629949213aSStephan Aßmus } 7639949213aSStephan Aßmus 764b98ef4f9SStephan Aßmus 7659949213aSStephan Aßmus status_t 766b98ef4f9SStephan Aßmus JPEGTranslator::DerivedTranslate(BPositionIO* inSource, 767b98ef4f9SStephan Aßmus const translator_info* inInfo, BMessage* ioExtension, uint32 outType, 768b98ef4f9SStephan Aßmus BPositionIO* outDestination, int32 baseType) 7699949213aSStephan Aßmus { 7709949213aSStephan Aßmus // If no specific type was requested, convert to the interchange format 771dbc936acSStephan Aßmus if (outType == 0) 772dbc936acSStephan Aßmus outType = B_TRANSLATOR_BITMAP; 7739949213aSStephan Aßmus 774dbc936acSStephan Aßmus // Setup a "breakpoint" since throwing exceptions does not seem to work 775dbc936acSStephan Aßmus // at all in an add-on. (?) 776dbc936acSStephan Aßmus // In the be_jerror.cpp we implement a handler for critical library errors 777dbc936acSStephan Aßmus // (be_error_exit()) and there we use the longjmp() function to return to 778dbc936acSStephan Aßmus // this place. If this happens, it is as if the setjmp() call is called 779dbc936acSStephan Aßmus // a second time, but this time the return value will be 1. The first 780dbc936acSStephan Aßmus // invokation will return 0. 781b91634cbSStephan Aßmus jmp_buf longJumpBuffer; 782b91634cbSStephan Aßmus int jmpRet = setjmp(longJumpBuffer); 783dbc936acSStephan Aßmus if (jmpRet == 1) 784dbc936acSStephan Aßmus return B_ERROR; 785dbc936acSStephan Aßmus 786dbc936acSStephan Aßmus try { 7879949213aSStephan Aßmus // What action to take, based on the findings of Identify() 7889949213aSStephan Aßmus if (outType == inInfo->type) { 7899949213aSStephan Aßmus return Copy(inSource, outDestination); 790dbc936acSStephan Aßmus } else if (inInfo->type == B_TRANSLATOR_BITMAP 791dbc936acSStephan Aßmus && outType == JPEG_FORMAT) { 792b91634cbSStephan Aßmus return Compress(inSource, outDestination, &longJumpBuffer); 793dbc936acSStephan Aßmus } else if (inInfo->type == JPEG_FORMAT 794dbc936acSStephan Aßmus && outType == B_TRANSLATOR_BITMAP) { 795b91634cbSStephan Aßmus return Decompress(inSource, outDestination, ioExtension, 796b91634cbSStephan Aßmus &longJumpBuffer); 7979949213aSStephan Aßmus } 798dbc936acSStephan Aßmus } catch (...) { 79970d59669SSiarzhuk Zharski syslog(LOG_ERR, "libjpeg encountered a critical error (caught C++ " 80070d59669SSiarzhuk Zharski "exception).\n"); 801dbc936acSStephan Aßmus return B_ERROR; 802dbc936acSStephan Aßmus } 8039949213aSStephan Aßmus 8049949213aSStephan Aßmus return B_NO_TRANSLATOR; 8059949213aSStephan Aßmus } 8069949213aSStephan Aßmus 807b98ef4f9SStephan Aßmus 808d8e2fb50SAxel Dörfler /*! The user has requested the same format for input and output, so just copy */ 809b98ef4f9SStephan Aßmus status_t 810b98ef4f9SStephan Aßmus JPEGTranslator::Copy(BPositionIO* in, BPositionIO* out) 8119949213aSStephan Aßmus { 8129949213aSStephan Aßmus int block_size = 65536; 8139949213aSStephan Aßmus void* buffer = malloc(block_size); 8149949213aSStephan Aßmus char temp[1024]; 8159949213aSStephan Aßmus if (buffer == NULL) { 8169949213aSStephan Aßmus buffer = temp; 8179949213aSStephan Aßmus block_size = 1024; 8189949213aSStephan Aßmus } 8199949213aSStephan Aßmus status_t err = B_OK; 8209949213aSStephan Aßmus 8219949213aSStephan Aßmus // Read until end of file or error 8229949213aSStephan Aßmus while (1) { 8239949213aSStephan Aßmus ssize_t to_read = block_size; 8249949213aSStephan Aßmus err = in->Read(buffer, to_read); 8259949213aSStephan Aßmus // Explicit check for EOF 8269949213aSStephan Aßmus if (err == -1) { 8279949213aSStephan Aßmus if (buffer != temp) free(buffer); 8289949213aSStephan Aßmus return B_OK; 8299949213aSStephan Aßmus } 8309949213aSStephan Aßmus if (err <= B_OK) break; 8319949213aSStephan Aßmus to_read = err; 8329949213aSStephan Aßmus err = out->Write(buffer, to_read); 8339949213aSStephan Aßmus if (err != to_read) if (err >= 0) err = B_DEVICE_FULL; 8349949213aSStephan Aßmus if (err < B_OK) break; 8359949213aSStephan Aßmus } 8369949213aSStephan Aßmus 8379949213aSStephan Aßmus if (buffer != temp) free(buffer); 8389949213aSStephan Aßmus return (err >= 0) ? B_OK : err; 8399949213aSStephan Aßmus } 8409949213aSStephan Aßmus 841d8e2fb50SAxel Dörfler 842d8e2fb50SAxel Dörfler /*! Encode into the native format */ 843b98ef4f9SStephan Aßmus status_t 844b98ef4f9SStephan Aßmus JPEGTranslator::Compress(BPositionIO* in, BPositionIO* out, 845b98ef4f9SStephan Aßmus const jmp_buf* longJumpBuffer) 8469949213aSStephan Aßmus { 847b98ef4f9SStephan Aßmus using namespace conversion; 8489949213aSStephan Aßmus 8499949213aSStephan Aßmus // Read info about bitmap 8509949213aSStephan Aßmus TranslatorBitmap header; 8519949213aSStephan Aßmus status_t err = in->Read(&header, sizeof(TranslatorBitmap)); 852d8e2fb50SAxel Dörfler if (err < B_OK) 853d8e2fb50SAxel Dörfler return err; 854d8e2fb50SAxel Dörfler else if (err < (int)sizeof(TranslatorBitmap)) 855d8e2fb50SAxel Dörfler return B_ERROR; 8569949213aSStephan Aßmus 8579949213aSStephan Aßmus // Grab dimension, color space, and size information from the stream 8589949213aSStephan Aßmus BRect bounds; 8599949213aSStephan Aßmus bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left); 8609949213aSStephan Aßmus bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top); 8619949213aSStephan Aßmus bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right); 8629949213aSStephan Aßmus bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom); 8639949213aSStephan Aßmus 8649949213aSStephan Aßmus int32 in_row_bytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes); 8659949213aSStephan Aßmus 8669949213aSStephan Aßmus int width = bounds.IntegerWidth() + 1; 8679949213aSStephan Aßmus int height = bounds.IntegerHeight() + 1; 8689949213aSStephan Aßmus 8699949213aSStephan Aßmus // Function pointer to convert function 8709949213aSStephan Aßmus // It will point to proper function if needed 8719e34f742SAxel Dörfler void (*converter)(uchar* inscanline, uchar* outscanline, 8729e34f742SAxel Dörfler int32 inRowBytes) = NULL; 8739949213aSStephan Aßmus 8749949213aSStephan Aßmus // Default color info 8759949213aSStephan Aßmus J_COLOR_SPACE jpg_color_space = JCS_RGB; 8769949213aSStephan Aßmus int jpg_input_components = 3; 8779949213aSStephan Aßmus int32 out_row_bytes; 8789949213aSStephan Aßmus int padding = 0; 8799949213aSStephan Aßmus 880d8e2fb50SAxel Dörfler switch ((color_space)B_BENDIAN_TO_HOST_INT32(header.colors)) { 8819949213aSStephan Aßmus case B_CMAP8: 8829949213aSStephan Aßmus converter = convert_from_cmap8_to_24; 8839949213aSStephan Aßmus padding = in_row_bytes - width; 8849949213aSStephan Aßmus break; 885d8e2fb50SAxel Dörfler 8869949213aSStephan Aßmus case B_GRAY1: 887b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_GRAY1_AS_RGB24, NULL)) { 8889949213aSStephan Aßmus converter = convert_from_gray1_to_24; 8899949213aSStephan Aßmus } else { 8909949213aSStephan Aßmus jpg_input_components = 1; 8919949213aSStephan Aßmus jpg_color_space = JCS_GRAYSCALE; 8929949213aSStephan Aßmus converter = convert_from_gray1_to_gray8; 8939949213aSStephan Aßmus } 8949949213aSStephan Aßmus padding = in_row_bytes - (width / 8); 8959949213aSStephan Aßmus break; 896d8e2fb50SAxel Dörfler 8979949213aSStephan Aßmus case B_GRAY8: 8989949213aSStephan Aßmus jpg_input_components = 1; 8999949213aSStephan Aßmus jpg_color_space = JCS_GRAYSCALE; 9009949213aSStephan Aßmus padding = in_row_bytes - width; 9019949213aSStephan Aßmus break; 902d8e2fb50SAxel Dörfler 9039949213aSStephan Aßmus case B_RGB15: 9049949213aSStephan Aßmus case B_RGBA15: 9059949213aSStephan Aßmus converter = convert_from_15_to_24; 9069949213aSStephan Aßmus padding = in_row_bytes - (width * 2); 9079949213aSStephan Aßmus break; 908d8e2fb50SAxel Dörfler 9099949213aSStephan Aßmus case B_RGB15_BIG: 9109949213aSStephan Aßmus case B_RGBA15_BIG: 9119949213aSStephan Aßmus converter = convert_from_15b_to_24; 9129949213aSStephan Aßmus padding = in_row_bytes - (width * 2); 9139949213aSStephan Aßmus break; 914d8e2fb50SAxel Dörfler 9159949213aSStephan Aßmus case B_RGB16: 9169949213aSStephan Aßmus converter = convert_from_16_to_24; 9179949213aSStephan Aßmus padding = in_row_bytes - (width * 2); 9189949213aSStephan Aßmus break; 919d8e2fb50SAxel Dörfler 9209949213aSStephan Aßmus case B_RGB16_BIG: 9219949213aSStephan Aßmus converter = convert_from_16b_to_24; 9229949213aSStephan Aßmus padding = in_row_bytes - (width * 2); 9239949213aSStephan Aßmus break; 924d8e2fb50SAxel Dörfler 9259949213aSStephan Aßmus case B_RGB24: 9269949213aSStephan Aßmus converter = convert_from_24_to_24; 9279949213aSStephan Aßmus padding = in_row_bytes - (width * 3); 9289949213aSStephan Aßmus break; 929d8e2fb50SAxel Dörfler 9309949213aSStephan Aßmus case B_RGB24_BIG: 9319949213aSStephan Aßmus padding = in_row_bytes - (width * 3); 9329949213aSStephan Aßmus break; 933d8e2fb50SAxel Dörfler 9349949213aSStephan Aßmus case B_RGB32: 9359949213aSStephan Aßmus case B_RGBA32: 9369949213aSStephan Aßmus converter = convert_from_32_to_24; 9379949213aSStephan Aßmus padding = in_row_bytes - (width * 4); 9389949213aSStephan Aßmus break; 939d8e2fb50SAxel Dörfler 9409949213aSStephan Aßmus case B_RGB32_BIG: 9419949213aSStephan Aßmus case B_RGBA32_BIG: 9429949213aSStephan Aßmus converter = convert_from_32b_to_24; 9439949213aSStephan Aßmus padding = in_row_bytes - (width * 4); 9449949213aSStephan Aßmus break; 945d8e2fb50SAxel Dörfler 9469949213aSStephan Aßmus case B_CMYK32: 9479949213aSStephan Aßmus jpg_color_space = JCS_CMYK; 9489949213aSStephan Aßmus jpg_input_components = 4; 9499949213aSStephan Aßmus padding = in_row_bytes - (width * 4); 9509949213aSStephan Aßmus break; 951d8e2fb50SAxel Dörfler 9529949213aSStephan Aßmus default: 95370d59669SSiarzhuk Zharski syslog(LOG_ERR, "Wrong type: Color space not implemented.\n"); 9549949213aSStephan Aßmus return B_ERROR; 9559949213aSStephan Aßmus } 9569949213aSStephan Aßmus out_row_bytes = jpg_input_components * width; 9579949213aSStephan Aßmus 9589949213aSStephan Aßmus // Set basic things needed for jpeg writing 9599949213aSStephan Aßmus struct jpeg_compress_struct cinfo; 9609949213aSStephan Aßmus struct jpeg_error_mgr jerr; 961b98ef4f9SStephan Aßmus cinfo.err = be_jpeg_std_error(&jerr, fSettings, longJumpBuffer); 9629949213aSStephan Aßmus jpeg_create_compress(&cinfo); 9639949213aSStephan Aßmus be_jpeg_stdio_dest(&cinfo, out); 9649949213aSStephan Aßmus 9659949213aSStephan Aßmus // Set basic values 9669949213aSStephan Aßmus cinfo.image_width = width; 9679949213aSStephan Aßmus cinfo.image_height = height; 9689949213aSStephan Aßmus cinfo.input_components = jpg_input_components; 9699949213aSStephan Aßmus cinfo.in_color_space = jpg_color_space; 9709949213aSStephan Aßmus jpeg_set_defaults(&cinfo); 9719949213aSStephan Aßmus 9729949213aSStephan Aßmus // Set better accuracy 9739949213aSStephan Aßmus cinfo.dct_method = JDCT_ISLOW; 9749949213aSStephan Aßmus 9759949213aSStephan Aßmus // This is needed to prevent some colors loss 9769949213aSStephan Aßmus // With it generated jpegs are as good as from Fireworks (at last! :D) 977b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_OPT_COLORS, NULL)) { 9789949213aSStephan Aßmus int index = 0; 9799949213aSStephan Aßmus while (index < cinfo.num_components) { 9809949213aSStephan Aßmus cinfo.comp_info[index].h_samp_factor = 1; 9819949213aSStephan Aßmus cinfo.comp_info[index].v_samp_factor = 1; 9829949213aSStephan Aßmus // This will make file smaller, but with worse quality more or less 9839949213aSStephan Aßmus // like with 93%-94% (but it's subjective opinion) on tested images 9849949213aSStephan Aßmus // but with smaller size (between 92% and 93% on tested images) 985b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_SMALL_FILES)) 9869949213aSStephan Aßmus cinfo.comp_info[index].quant_tbl_no = 1; 9879949213aSStephan Aßmus // This will make bigger file, but also better quality ;] 9889949213aSStephan Aßmus // from my tests it seems like useless - better quality with smaller 9899949213aSStephan Aßmus // can be acheived without this 9909949213aSStephan Aßmus // cinfo.comp_info[index].dc_tbl_no = 1; 9919949213aSStephan Aßmus // cinfo.comp_info[index].ac_tbl_no = 1; 9929949213aSStephan Aßmus index++; 9939949213aSStephan Aßmus } 9949949213aSStephan Aßmus } 9959949213aSStephan Aßmus 9969949213aSStephan Aßmus // Set quality 997b98ef4f9SStephan Aßmus jpeg_set_quality(&cinfo, fSettings->SetGetInt32(JPEG_SET_QUALITY, NULL), true); 9989949213aSStephan Aßmus 9999949213aSStephan Aßmus // Set progressive compression if needed 10009949213aSStephan Aßmus // if not, turn on optimizing in libjpeg 1001b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_PROGRESSIVE, NULL)) 10029949213aSStephan Aßmus jpeg_simple_progression(&cinfo); 10039949213aSStephan Aßmus else 10049949213aSStephan Aßmus cinfo.optimize_coding = TRUE; 10059949213aSStephan Aßmus 10069949213aSStephan Aßmus // Set smoothing (effect like Blur) 1007b98ef4f9SStephan Aßmus cinfo.smoothing_factor = fSettings->SetGetInt32(JPEG_SET_SMOOTHING, NULL); 10089949213aSStephan Aßmus 10099949213aSStephan Aßmus // Initialize compression 10109949213aSStephan Aßmus jpeg_start_compress(&cinfo, TRUE); 10119949213aSStephan Aßmus 10129949213aSStephan Aßmus // Declare scanlines 10139949213aSStephan Aßmus JSAMPROW in_scanline = NULL; 10149949213aSStephan Aßmus JSAMPROW out_scanline = NULL; 1015b98ef4f9SStephan Aßmus JSAMPROW writeline; 1016b98ef4f9SStephan Aßmus // Pointer to in_scanline (default) or out_scanline (if there will be conversion) 10179949213aSStephan Aßmus 10189949213aSStephan Aßmus // Allocate scanline 10199949213aSStephan Aßmus // Use libjpeg memory allocation functions, so in case of error it will free them itself 1020d8e2fb50SAxel Dörfler in_scanline = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo, 1021d8e2fb50SAxel Dörfler JPOOL_PERMANENT, in_row_bytes); 10229949213aSStephan Aßmus 10239949213aSStephan Aßmus // We need 2nd scanline storage ony for conversion 10249949213aSStephan Aßmus if (converter != NULL) { 10259949213aSStephan Aßmus // There will be conversion, allocate second scanline... 10269949213aSStephan Aßmus // Use libjpeg memory allocation functions, so in case of error it will free them itself 1027d8e2fb50SAxel Dörfler out_scanline = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo, 1028d8e2fb50SAxel Dörfler JPOOL_PERMANENT, out_row_bytes); 10299949213aSStephan Aßmus // ... and make it the one to write to file 10309949213aSStephan Aßmus writeline = out_scanline; 10319949213aSStephan Aßmus } else 10329949213aSStephan Aßmus writeline = in_scanline; 10339949213aSStephan Aßmus 10349949213aSStephan Aßmus while (cinfo.next_scanline < cinfo.image_height) { 10359949213aSStephan Aßmus // Read scanline 10369949213aSStephan Aßmus err = in->Read(in_scanline, in_row_bytes); 10379949213aSStephan Aßmus if (err < in_row_bytes) 1038d8e2fb50SAxel Dörfler return err < B_OK ? Error((j_common_ptr)&cinfo, err) 1039d8e2fb50SAxel Dörfler : Error((j_common_ptr)&cinfo, B_ERROR); 10409949213aSStephan Aßmus 10419949213aSStephan Aßmus // Convert if needed 10429949213aSStephan Aßmus if (converter != NULL) 10439949213aSStephan Aßmus converter(in_scanline, out_scanline, in_row_bytes - padding); 10449949213aSStephan Aßmus 10459949213aSStephan Aßmus // Write scanline 10469949213aSStephan Aßmus jpeg_write_scanlines(&cinfo, &writeline, 1); 10479949213aSStephan Aßmus } 10489949213aSStephan Aßmus 10499949213aSStephan Aßmus jpeg_finish_compress(&cinfo); 10509949213aSStephan Aßmus jpeg_destroy_compress(&cinfo); 10519949213aSStephan Aßmus return B_OK; 10529949213aSStephan Aßmus } 10539949213aSStephan Aßmus 1054d8e2fb50SAxel Dörfler 1055d8e2fb50SAxel Dörfler /*! Decode the native format */ 1056b98ef4f9SStephan Aßmus status_t 1057b98ef4f9SStephan Aßmus JPEGTranslator::Decompress(BPositionIO* in, BPositionIO* out, 1058b98ef4f9SStephan Aßmus BMessage* ioExtension, const jmp_buf* longJumpBuffer) 10599949213aSStephan Aßmus { 1060b98ef4f9SStephan Aßmus using namespace conversion; 10619949213aSStephan Aßmus 10629949213aSStephan Aßmus // Set basic things needed for jpeg reading 10639949213aSStephan Aßmus struct jpeg_decompress_struct cinfo; 10649949213aSStephan Aßmus struct jpeg_error_mgr jerr; 1065b98ef4f9SStephan Aßmus cinfo.err = be_jpeg_std_error(&jerr, fSettings, longJumpBuffer); 10669949213aSStephan Aßmus jpeg_create_decompress(&cinfo); 10679949213aSStephan Aßmus be_jpeg_stdio_src(&cinfo, in); 10689949213aSStephan Aßmus 106952e8f46aSAxel Dörfler jpeg_save_markers(&cinfo, MARKER_EXIF, 131072); 107052e8f46aSAxel Dörfler // make sure the EXIF tag is stored 107152e8f46aSAxel Dörfler 10729949213aSStephan Aßmus // Read info about image 10739949213aSStephan Aßmus jpeg_read_header(&cinfo, TRUE); 10749949213aSStephan Aßmus 107552e8f46aSAxel Dörfler BMessage exif; 107652e8f46aSAxel Dörfler 1077f13b5de6SAxel Dörfler // parse EXIF data and add it ioExtension, if any 107852e8f46aSAxel Dörfler jpeg_marker_struct* marker = cinfo.marker_list; 107952e8f46aSAxel Dörfler while (marker != NULL) { 108052e8f46aSAxel Dörfler if (marker->marker == MARKER_EXIF 108152e8f46aSAxel Dörfler && !strncmp((char*)marker->data, "Exif", 4)) { 1082f13b5de6SAxel Dörfler if (ioExtension != NULL) { 108352e8f46aSAxel Dörfler // Strip EXIF header from TIFF data 108452e8f46aSAxel Dörfler ioExtension->AddData("exif", B_RAW_TYPE, 108552e8f46aSAxel Dörfler (uint8*)marker->data + 6, marker->data_length - 6); 1086f13b5de6SAxel Dörfler } 108752e8f46aSAxel Dörfler 108852e8f46aSAxel Dörfler BMemoryIO io(marker->data + 6, marker->data_length - 6); 108952e8f46aSAxel Dörfler convert_exif_to_message(io, exif); 109052e8f46aSAxel Dörfler } 109152e8f46aSAxel Dörfler marker = marker->next; 109252e8f46aSAxel Dörfler } 109352e8f46aSAxel Dörfler 10949949213aSStephan Aßmus // Default color info 109552e8f46aSAxel Dörfler color_space outColorSpace = B_RGB32; 109652e8f46aSAxel Dörfler int outColorComponents = 4; 10979949213aSStephan Aßmus 10989949213aSStephan Aßmus // Function pointer to convert function 10999949213aSStephan Aßmus // It will point to proper function if needed 110052e8f46aSAxel Dörfler void (*converter)(uchar* inScanLine, uchar* outScanLine, 11019e34f742SAxel Dörfler int32 inRowBytes, int32 xStep) = convert_from_24_to_32; 11029949213aSStephan Aßmus 11039949213aSStephan Aßmus // If color space isn't rgb 11049949213aSStephan Aßmus if (cinfo.out_color_space != JCS_RGB) { 1105d8e2fb50SAxel Dörfler switch (cinfo.out_color_space) { 11069949213aSStephan Aßmus case JCS_UNKNOWN: /* error/unspecified */ 110770d59669SSiarzhuk Zharski syslog(LOG_ERR, "From Type: Jpeg uses unknown color type\n"); 11089949213aSStephan Aßmus break; 11099949213aSStephan Aßmus case JCS_GRAYSCALE: /* monochrome */ 11109949213aSStephan Aßmus // Check if user wants to read only as RGB32 or not 1111b98ef4f9SStephan Aßmus if (!fSettings->SetGetBool(JPEG_SET_ALWAYS_RGB32, NULL)) { 11129949213aSStephan Aßmus // Grayscale 111352e8f46aSAxel Dörfler outColorSpace = B_GRAY8; 111452e8f46aSAxel Dörfler outColorComponents = 1; 11159e34f742SAxel Dörfler converter = translate_8; 11169949213aSStephan Aßmus } else { 11179949213aSStephan Aßmus // RGB 11189949213aSStephan Aßmus cinfo.out_color_space = JCS_RGB; 11199949213aSStephan Aßmus cinfo.output_components = 3; 11209949213aSStephan Aßmus converter = convert_from_24_to_32; 11219949213aSStephan Aßmus } 11229949213aSStephan Aßmus break; 11239949213aSStephan Aßmus case JCS_YCbCr: /* Y/Cb/Cr (also known as YUV) */ 11249949213aSStephan Aßmus cinfo.out_color_space = JCS_RGB; 11259949213aSStephan Aßmus converter = convert_from_24_to_32; 11269949213aSStephan Aßmus break; 11279949213aSStephan Aßmus case JCS_YCCK: /* Y/Cb/Cr/K */ 11289949213aSStephan Aßmus // Let libjpeg convert it to CMYK 11299949213aSStephan Aßmus cinfo.out_color_space = JCS_CMYK; 11309949213aSStephan Aßmus // Fall through to CMYK since we need the same settings 11319949213aSStephan Aßmus case JCS_CMYK: /* C/M/Y/K */ 11329949213aSStephan Aßmus // Use proper converter 1133b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_PHOTOSHOP_CMYK)) 11349949213aSStephan Aßmus converter = convert_from_CMYK_to_32_photoshop; 11359949213aSStephan Aßmus else 11369949213aSStephan Aßmus converter = convert_from_CMYK_to_32; 11379949213aSStephan Aßmus break; 11389949213aSStephan Aßmus default: 113970d59669SSiarzhuk Zharski syslog(LOG_ERR, 114070d59669SSiarzhuk Zharski "From Type: Jpeg uses hmm... i don't know really :(\n"); 11419949213aSStephan Aßmus break; 11429949213aSStephan Aßmus } 11439949213aSStephan Aßmus } 11449949213aSStephan Aßmus 11459949213aSStephan Aßmus // Initialize decompression 11469949213aSStephan Aßmus jpeg_start_decompress(&cinfo); 11479949213aSStephan Aßmus 11489e34f742SAxel Dörfler // retrieve orientation from settings/EXIF 114952e8f46aSAxel Dörfler int32 orientation; 11509e34f742SAxel Dörfler if (ioExtension == NULL 11519e34f742SAxel Dörfler || ioExtension->FindInt32("exif:orientation", &orientation) != B_OK) { 115252e8f46aSAxel Dörfler if (exif.FindInt32("Orientation", &orientation) != B_OK) 115352e8f46aSAxel Dörfler orientation = 1; 115452e8f46aSAxel Dörfler } 11559949213aSStephan Aßmus 11569e34f742SAxel Dörfler if (orientation != 1 && converter == NULL) 11579e34f742SAxel Dörfler converter = translate_8; 11589e34f742SAxel Dörfler 11599e34f742SAxel Dörfler int32 outputWidth = orientation > 4 ? cinfo.output_height : cinfo.output_width; 11609e34f742SAxel Dörfler int32 outputHeight = orientation > 4 ? cinfo.output_width : cinfo.output_height; 11619e34f742SAxel Dörfler 11629e34f742SAxel Dörfler int32 destOffset = dest_index(outputWidth, outputHeight, 11639e34f742SAxel Dörfler 0, 0, orientation) * outColorComponents; 11649e34f742SAxel Dörfler int32 xStep = dest_index(outputWidth, outputHeight, 11659e34f742SAxel Dörfler 1, 0, orientation) * outColorComponents - destOffset; 11669e34f742SAxel Dörfler int32 yStep = dest_index(outputWidth, outputHeight, 11679e34f742SAxel Dörfler 0, 1, orientation) * outColorComponents - destOffset; 11689e34f742SAxel Dörfler bool needAll = orientation != 1; 11699e34f742SAxel Dörfler 11709e34f742SAxel Dörfler // Initialize this bounds rect to the size of your image 11719e34f742SAxel Dörfler BRect bounds(0, 0, outputWidth - 1, outputHeight - 1); 11729e34f742SAxel Dörfler 11739e34f742SAxel Dörfler #if 0 11749e34f742SAxel Dörfler printf("destOffset = %ld, xStep = %ld, yStep = %ld, input: %ld x %ld, output: %ld x %ld, orientation %ld\n", 11759e34f742SAxel Dörfler destOffset, xStep, yStep, (int32)cinfo.output_width, (int32)cinfo.output_height, 11769e34f742SAxel Dörfler bounds.IntegerWidth() + 1, bounds.IntegerHeight() + 1, orientation); 11779e34f742SAxel Dörfler #endif 11789e34f742SAxel Dörfler 11799949213aSStephan Aßmus // Bytes count in one line of image (scanline) 11809e34f742SAxel Dörfler int32 inRowBytes = cinfo.output_width * cinfo.output_components; 11819e34f742SAxel Dörfler int32 rowBytes = (bounds.IntegerWidth() + 1) * outColorComponents; 11829e34f742SAxel Dörfler int32 dataSize = cinfo.output_width * cinfo.output_height 11839e34f742SAxel Dörfler * outColorComponents; 11849949213aSStephan Aßmus 11859949213aSStephan Aßmus // Fill out the B_TRANSLATOR_BITMAP's header 11869949213aSStephan Aßmus TranslatorBitmap header; 11879949213aSStephan Aßmus header.magic = B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP); 11889949213aSStephan Aßmus header.bounds.left = B_HOST_TO_BENDIAN_FLOAT(bounds.left); 11899949213aSStephan Aßmus header.bounds.top = B_HOST_TO_BENDIAN_FLOAT(bounds.top); 11909949213aSStephan Aßmus header.bounds.right = B_HOST_TO_BENDIAN_FLOAT(bounds.right); 11919949213aSStephan Aßmus header.bounds.bottom = B_HOST_TO_BENDIAN_FLOAT(bounds.bottom); 119252e8f46aSAxel Dörfler header.colors = (color_space)B_HOST_TO_BENDIAN_INT32(outColorSpace); 119352e8f46aSAxel Dörfler header.rowBytes = B_HOST_TO_BENDIAN_INT32(rowBytes); 11949e34f742SAxel Dörfler header.dataSize = B_HOST_TO_BENDIAN_INT32(dataSize); 11959949213aSStephan Aßmus 11969949213aSStephan Aßmus // Write out the header 11979949213aSStephan Aßmus status_t err = out->Write(&header, sizeof(TranslatorBitmap)); 1198d8e2fb50SAxel Dörfler if (err < B_OK) 1199d8e2fb50SAxel Dörfler return Error((j_common_ptr)&cinfo, err); 1200d8e2fb50SAxel Dörfler else if (err < (int)sizeof(TranslatorBitmap)) 1201d8e2fb50SAxel Dörfler return Error((j_common_ptr)&cinfo, B_ERROR); 12029949213aSStephan Aßmus 12039949213aSStephan Aßmus // Declare scanlines 12049e34f742SAxel Dörfler JSAMPROW inScanLine = NULL; 12059e34f742SAxel Dörfler uint8* dest = NULL; 12069e34f742SAxel Dörfler uint8* destLine = NULL; 12079949213aSStephan Aßmus 12089949213aSStephan Aßmus // Allocate scanline 12099949213aSStephan Aßmus // Use libjpeg memory allocation functions, so in case of error it will free them itself 12109e34f742SAxel Dörfler inScanLine = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo, 12119e34f742SAxel Dörfler JPOOL_PERMANENT, inRowBytes); 12129949213aSStephan Aßmus 12139949213aSStephan Aßmus // We need 2nd scanline storage only for conversion 12149949213aSStephan Aßmus if (converter != NULL) { 12159949213aSStephan Aßmus // There will be conversion, allocate second scanline... 1216b98ef4f9SStephan Aßmus // Use libjpeg memory allocation functions, so in case of error it will 1217b98ef4f9SStephan Aßmus // free them itself 12189e34f742SAxel Dörfler dest = (uint8*)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo, 12199e34f742SAxel Dörfler JPOOL_PERMANENT, needAll ? dataSize : rowBytes); 12209e34f742SAxel Dörfler destLine = dest + destOffset; 12219949213aSStephan Aßmus } else 12229e34f742SAxel Dörfler destLine = inScanLine; 12239949213aSStephan Aßmus 12249949213aSStephan Aßmus while (cinfo.output_scanline < cinfo.output_height) { 12259949213aSStephan Aßmus // Read scanline 12269e34f742SAxel Dörfler jpeg_read_scanlines(&cinfo, &inScanLine, 1); 12279949213aSStephan Aßmus 12289949213aSStephan Aßmus // Convert if needed 12299949213aSStephan Aßmus if (converter != NULL) 12309e34f742SAxel Dörfler converter(inScanLine, destLine, inRowBytes, xStep); 12319949213aSStephan Aßmus 12329e34f742SAxel Dörfler if (!needAll) { 12339949213aSStephan Aßmus // Write the scanline buffer to the output stream 12349e34f742SAxel Dörfler ssize_t bytesWritten = out->Write(destLine, rowBytes); 12359e34f742SAxel Dörfler if (bytesWritten < rowBytes) { 12369e34f742SAxel Dörfler return bytesWritten < B_OK 12379e34f742SAxel Dörfler ? Error((j_common_ptr)&cinfo, bytesWritten) 1238d8e2fb50SAxel Dörfler : Error((j_common_ptr)&cinfo, B_ERROR); 12399949213aSStephan Aßmus } 12409e34f742SAxel Dörfler } else 12419e34f742SAxel Dörfler destLine += yStep; 12429e34f742SAxel Dörfler } 12439e34f742SAxel Dörfler 12449e34f742SAxel Dörfler if (needAll) { 12459e34f742SAxel Dörfler ssize_t bytesWritten = out->Write(dest, dataSize); 12469e34f742SAxel Dörfler if (bytesWritten < dataSize) { 12479e34f742SAxel Dörfler return bytesWritten < B_OK 12489e34f742SAxel Dörfler ? Error((j_common_ptr)&cinfo, bytesWritten) 12499e34f742SAxel Dörfler : Error((j_common_ptr)&cinfo, B_ERROR); 12509e34f742SAxel Dörfler } 12519e34f742SAxel Dörfler } 12529949213aSStephan Aßmus 12539949213aSStephan Aßmus jpeg_finish_decompress(&cinfo); 12549949213aSStephan Aßmus jpeg_destroy_decompress(&cinfo); 12559949213aSStephan Aßmus return B_OK; 12569949213aSStephan Aßmus } 12579949213aSStephan Aßmus 1258b98ef4f9SStephan Aßmus /*! have the other PopulateInfoFromFormat() check both inputFormats & outputFormats */ 1259b98ef4f9SStephan Aßmus status_t 1260b98ef4f9SStephan Aßmus JPEGTranslator::PopulateInfoFromFormat(translator_info* info, 1261b98ef4f9SStephan Aßmus uint32 formatType, translator_id id) 1262b98ef4f9SStephan Aßmus { 1263b98ef4f9SStephan Aßmus int32 formatCount; 1264b98ef4f9SStephan Aßmus const translation_format* formats = OutputFormats(&formatCount); 1265b98ef4f9SStephan Aßmus for (int i = 0; i <= 1 ;formats = InputFormats(&formatCount), i++) { 1266b98ef4f9SStephan Aßmus if (PopulateInfoFromFormat(info, formatType, 1267b98ef4f9SStephan Aßmus formats, formatCount) == B_OK) { 1268b98ef4f9SStephan Aßmus info->translator = id; 1269b98ef4f9SStephan Aßmus return B_OK; 1270b98ef4f9SStephan Aßmus } 1271b98ef4f9SStephan Aßmus } 1272b98ef4f9SStephan Aßmus 1273b98ef4f9SStephan Aßmus return B_ERROR; 1274b98ef4f9SStephan Aßmus } 1275b98ef4f9SStephan Aßmus 1276b98ef4f9SStephan Aßmus 1277b98ef4f9SStephan Aßmus status_t 1278b98ef4f9SStephan Aßmus JPEGTranslator::PopulateInfoFromFormat(translator_info* info, 1279b98ef4f9SStephan Aßmus uint32 formatType, const translation_format* formats, int32 formatCount) 1280b98ef4f9SStephan Aßmus { 1281b98ef4f9SStephan Aßmus for (int i = 0; i < formatCount; i++) { 1282b98ef4f9SStephan Aßmus if (formats[i].type == formatType) { 1283b98ef4f9SStephan Aßmus info->type = formatType; 1284b98ef4f9SStephan Aßmus info->group = formats[i].group; 1285b98ef4f9SStephan Aßmus info->quality = formats[i].quality; 1286b98ef4f9SStephan Aßmus info->capability = formats[i].capability; 128770d59669SSiarzhuk Zharski BString str1(formats[i].name); 128870d59669SSiarzhuk Zharski str1.ReplaceFirst("Be Bitmap Format (JPEGTranslator)", 128970d59669SSiarzhuk Zharski B_TRANSLATE("Be Bitmap Format (JPEGTranslator)")); 129070d59669SSiarzhuk Zharski strncpy(info->name, str1.String(), sizeof(info->name)); 1291b98ef4f9SStephan Aßmus strcpy(info->MIME, formats[i].MIME); 1292b98ef4f9SStephan Aßmus return B_OK; 1293b98ef4f9SStephan Aßmus } 1294b98ef4f9SStephan Aßmus } 1295b98ef4f9SStephan Aßmus 1296b98ef4f9SStephan Aßmus return B_ERROR; 1297b98ef4f9SStephan Aßmus } 1298b98ef4f9SStephan Aßmus 1299d8e2fb50SAxel Dörfler /*! 1300d8e2fb50SAxel Dörfler Frees jpeg alocated memory 1301d8e2fb50SAxel Dörfler Returns given error (B_ERROR by default) 1302d8e2fb50SAxel Dörfler */ 1303b98ef4f9SStephan Aßmus status_t 1304b98ef4f9SStephan Aßmus JPEGTranslator::Error(j_common_ptr cinfo, status_t error) 13059949213aSStephan Aßmus { 13069949213aSStephan Aßmus jpeg_destroy(cinfo); 13079949213aSStephan Aßmus return error; 13089949213aSStephan Aßmus } 1309d8e2fb50SAxel Dörfler 1310d8e2fb50SAxel Dörfler 1311b98ef4f9SStephan Aßmus JPEGTranslator::JPEGTranslator() 1312bf243977SPhilippe Houdoin : BaseTranslator(sTranslatorName, sTranslatorInfo, sTranslatorVersion, 1313bf243977SPhilippe Houdoin sInputFormats, kNumInputFormats, 1314bf243977SPhilippe Houdoin sOutputFormats, kNumOutputFormats, 1315bf243977SPhilippe Houdoin SETTINGS_FILE, 1316bf243977SPhilippe Houdoin sDefaultSettings, kNumDefaultSettings, 1317b98ef4f9SStephan Aßmus B_TRANSLATOR_BITMAP, JPEG_FORMAT) 1318b98ef4f9SStephan Aßmus {} 1319b98ef4f9SStephan Aßmus 1320b98ef4f9SStephan Aßmus 1321b98ef4f9SStephan Aßmus BTranslator* 1322b98ef4f9SStephan Aßmus make_nth_translator(int32 n, image_id you, uint32 flags, ...) 1323b98ef4f9SStephan Aßmus { 1324b98ef4f9SStephan Aßmus if (n == 0) 1325b98ef4f9SStephan Aßmus return new JPEGTranslator(); 1326b98ef4f9SStephan Aßmus 1327b98ef4f9SStephan Aßmus return NULL; 1328b98ef4f9SStephan Aßmus } 1329d8e2fb50SAxel Dörfler 1330d8e2fb50SAxel Dörfler 1331d8e2fb50SAxel Dörfler int 1332117da2d7SAxel Dörfler main(int, char**) 1333117da2d7SAxel Dörfler { 1334117da2d7SAxel Dörfler BApplication app("application/x-vnd.Haiku-JPEGTranslator"); 1335b98ef4f9SStephan Aßmus JPEGTranslator* translator = new JPEGTranslator(); 1336bf243977SPhilippe Houdoin if (LaunchTranslatorWindow(translator, sTranslatorName) == B_OK) 1337d8e2fb50SAxel Dörfler app.Run(); 1338b98ef4f9SStephan Aßmus 1339d8e2fb50SAxel Dörfler return 0; 1340d8e2fb50SAxel Dörfler } 1341d8e2fb50SAxel Dörfler 1342