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