19949213aSStephan Aßmus /* 29949213aSStephan Aßmus 39949213aSStephan Aßmus Copyright (c) 2002-2003, Marcin 'Shard' Konicki 49949213aSStephan Aßmus All rights reserved. 59949213aSStephan Aßmus 69949213aSStephan Aßmus Redistribution and use in source and binary forms, with or without 79949213aSStephan Aßmus modification, are permitted provided that the following conditions are met: 89949213aSStephan Aßmus 99949213aSStephan Aßmus * Redistributions of source code must retain the above copyright notice, 109949213aSStephan Aßmus this list of conditions and the following disclaimer. 119949213aSStephan Aßmus * Redistributions in binary form must reproduce the above copyright notice, 129949213aSStephan Aßmus this list of conditions and the following disclaimer in the documentation and/or 139949213aSStephan Aßmus other materials provided with the distribution. 149949213aSStephan Aßmus * Name "Marcin Konicki", "Shard" or any combination of them, 159949213aSStephan Aßmus must not be used to endorse or promote products derived from this 169949213aSStephan Aßmus software without specific prior written permission from Marcin Konicki. 179949213aSStephan Aßmus 189949213aSStephan Aßmus THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 199949213aSStephan Aßmus ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 209949213aSStephan Aßmus THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 219949213aSStephan Aßmus ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 229949213aSStephan Aßmus BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 239949213aSStephan Aßmus OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 249949213aSStephan Aßmus PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 259949213aSStephan Aßmus OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 269949213aSStephan Aßmus WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 279949213aSStephan Aßmus OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 289949213aSStephan Aßmus EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 299949213aSStephan Aßmus 309949213aSStephan Aßmus */ 319949213aSStephan Aßmus 329949213aSStephan Aßmus 339949213aSStephan Aßmus #include "JPEGTranslator.h" 3452e8f46aSAxel Dörfler 3570d59669SSiarzhuk Zharski #include <syslog.h> 3670d59669SSiarzhuk Zharski 37b98ef4f9SStephan Aßmus #include <Alignment.h> 3803901b6cSJérôme Duval #include <Catalog.h> 397d48219bSHannah Boneß #include <LayoutBuilder.h> 408687ff64SAxel Dörfler #include <TabView.h> 41b98ef4f9SStephan Aßmus #include <TextView.h> 428687ff64SAxel Dörfler 43e4bd005dSIngo Weinhold #include "be_jerror.h" 44e4bd005dSIngo Weinhold #include "exif_parser.h" 45e4bd005dSIngo Weinhold #include "TranslatorWindow.h" 46e4bd005dSIngo Weinhold 47e4bd005dSIngo Weinhold 48546208a5SOliver Tappe #undef B_TRANSLATION_CONTEXT 49546208a5SOliver Tappe #define B_TRANSLATION_CONTEXT "JPEGTranslator" 509949213aSStephan Aßmus 5152e8f46aSAxel Dörfler #define MARKER_EXIF 0xe1 5252e8f46aSAxel Dörfler 539949213aSStephan Aßmus // Set these accordingly 549949213aSStephan Aßmus #define JPEG_ACRONYM "JPEG" 559949213aSStephan Aßmus #define JPEG_FORMAT 'JPEG' 569949213aSStephan Aßmus #define JPEG_MIME_STRING "image/jpeg" 579949213aSStephan Aßmus #define JPEG_DESCRIPTION "JPEG image" 589949213aSStephan Aßmus 599949213aSStephan Aßmus // The translation kit's native file type 609949213aSStephan Aßmus #define B_TRANSLATOR_BITMAP_MIME_STRING "image/x-be-bitmap" 61c095606eSRyan Leavengood #define B_TRANSLATOR_BITMAP_DESCRIPTION "Be Bitmap Format (JPEGTranslator)" 629949213aSStephan Aßmus 63b98ef4f9SStephan Aßmus 642e49ff35SSiarzhuk Zharski static const int32 sTranslatorVersion = B_TRANSLATION_MAKE_VERSION(1, 2, 0); 652e49ff35SSiarzhuk Zharski 661da233a7SSiarzhuk Zharski static const char* sTranslatorName = B_TRANSLATE("JPEG images"); 671da233a7SSiarzhuk Zharski static const char* sTranslatorInfo = B_TRANSLATE("©2002-2003, Marcin Konicki\n" 68f13b5de6SAxel Dörfler "©2005-2007, Haiku\n" 69758b1d0eSIngo Weinhold "\n" 707fd58091SJérôme Duval "Based on IJG library © 1994-2009, Thomas G. Lane, Guido Vollbeding.\n" 712e49ff35SSiarzhuk Zharski "\thttp://www.ijg.org/files/\n" 72b98ef4f9SStephan Aßmus "\n" 73fcc3e627SStephan Aßmus "with \"lossless\" encoding support patch by Ken Murchison\n" 742e49ff35SSiarzhuk Zharski "\thttp://www.oceana.com/ftp/ljpeg/\n" 75758b1d0eSIngo Weinhold "\n" 76758b1d0eSIngo Weinhold "With some colorspace conversion routines by Magnus Hellman\n" 772e49ff35SSiarzhuk Zharski "\thttp://www.bebits.com/app/802\n"); 789949213aSStephan Aßmus 799949213aSStephan Aßmus // Define the formats we know how to read 80bf243977SPhilippe Houdoin static const translation_format sInputFormats[] = { 819949213aSStephan Aßmus { JPEG_FORMAT, B_TRANSLATOR_BITMAP, 0.5, 0.5, 829949213aSStephan Aßmus JPEG_MIME_STRING, JPEG_DESCRIPTION }, 839949213aSStephan Aßmus { B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.5, 0.5, 847b5743baSPhilippe Houdoin B_TRANSLATOR_BITMAP_MIME_STRING, B_TRANSLATOR_BITMAP_DESCRIPTION } 859949213aSStephan Aßmus }; 869949213aSStephan Aßmus 879949213aSStephan Aßmus // Define the formats we know how to write 88bf243977SPhilippe Houdoin static const translation_format sOutputFormats[] = { 899949213aSStephan Aßmus { JPEG_FORMAT, B_TRANSLATOR_BITMAP, 0.5, 0.5, 909949213aSStephan Aßmus JPEG_MIME_STRING, JPEG_DESCRIPTION }, 919949213aSStephan Aßmus { B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.5, 0.5, 927b5743baSPhilippe Houdoin B_TRANSLATOR_BITMAP_MIME_STRING, B_TRANSLATOR_BITMAP_DESCRIPTION } 939949213aSStephan Aßmus }; 9452e8f46aSAxel Dörfler 95d8e2fb50SAxel Dörfler 96bf243977SPhilippe Houdoin static const TranSetting sDefaultSettings[] = { 97b98ef4f9SStephan Aßmus {JPEG_SET_SMOOTHING, TRAN_SETTING_INT32, 0}, 98b98ef4f9SStephan Aßmus {JPEG_SET_QUALITY, TRAN_SETTING_INT32, 95}, 99b98ef4f9SStephan Aßmus {JPEG_SET_PROGRESSIVE, TRAN_SETTING_BOOL, true}, 100b98ef4f9SStephan Aßmus {JPEG_SET_OPT_COLORS, TRAN_SETTING_BOOL, true}, 101b98ef4f9SStephan Aßmus {JPEG_SET_SMALL_FILES, TRAN_SETTING_BOOL, false}, 102b98ef4f9SStephan Aßmus {JPEG_SET_GRAY1_AS_RGB24, TRAN_SETTING_BOOL, false}, 103b98ef4f9SStephan Aßmus {JPEG_SET_ALWAYS_RGB32, TRAN_SETTING_BOOL, true}, 104b98ef4f9SStephan Aßmus {JPEG_SET_PHOTOSHOP_CMYK, TRAN_SETTING_BOOL, true}, 105b98ef4f9SStephan Aßmus {JPEG_SET_SHOWREADWARNING, TRAN_SETTING_BOOL, true} 106b98ef4f9SStephan Aßmus }; 107bf243977SPhilippe Houdoin 108bf243977SPhilippe Houdoin const uint32 kNumInputFormats = sizeof(sInputFormats) / sizeof(translation_format); 109bf243977SPhilippe Houdoin const uint32 kNumOutputFormats = sizeof(sOutputFormats) / sizeof(translation_format); 110bf243977SPhilippe Houdoin const uint32 kNumDefaultSettings = sizeof(sDefaultSettings) / sizeof(TranSetting); 1119949213aSStephan Aßmus 112d8e2fb50SAxel Dörfler 113b98ef4f9SStephan Aßmus namespace conversion { 114d8e2fb50SAxel Dörfler 115d8e2fb50SAxel Dörfler 1169e34f742SAxel Dörfler static bool 1179e34f742SAxel Dörfler x_flipped(int32 orientation) 1189e34f742SAxel Dörfler { 1199e34f742SAxel Dörfler return orientation == 2 || orientation == 3 1209e34f742SAxel Dörfler || orientation == 6 || orientation == 7; 1219e34f742SAxel Dörfler } 1229e34f742SAxel Dörfler 1239e34f742SAxel Dörfler 1249e34f742SAxel Dörfler static bool 1259e34f742SAxel Dörfler y_flipped(int32 orientation) 1269e34f742SAxel Dörfler { 1279e34f742SAxel Dörfler return orientation == 3 || orientation == 4 1289e34f742SAxel Dörfler || orientation == 7 || orientation == 8; 1299e34f742SAxel Dörfler } 1309e34f742SAxel Dörfler 1319e34f742SAxel Dörfler 1329e34f742SAxel Dörfler static int32 1339e34f742SAxel Dörfler dest_index(uint32 width, uint32 height, uint32 x, uint32 y, int32 orientation) 1349e34f742SAxel Dörfler { 1359e34f742SAxel Dörfler if (orientation > 4) { 1369e34f742SAxel Dörfler uint32 temp = x; 1379e34f742SAxel Dörfler x = y; 1389e34f742SAxel Dörfler y = temp; 1399e34f742SAxel Dörfler } 1409e34f742SAxel Dörfler if (y_flipped(orientation)) 1419e34f742SAxel Dörfler y = height - 1 - y; 1429e34f742SAxel Dörfler if (x_flipped(orientation)) 1439e34f742SAxel Dörfler x = width - 1 - x; 1449e34f742SAxel Dörfler 1459e34f742SAxel Dörfler return y * width + x; 1469e34f742SAxel Dörfler } 1479e34f742SAxel Dörfler 1489e34f742SAxel Dörfler 1499e34f742SAxel Dörfler // #pragma mark - conversion for compression 150d8e2fb50SAxel Dörfler 151d8e2fb50SAxel Dörfler 152d8e2fb50SAxel Dörfler inline void 1539e34f742SAxel Dörfler convert_from_gray1_to_gray8(uint8* in, uint8* out, int32 inRowBytes) 154d8e2fb50SAxel Dörfler { 155d8e2fb50SAxel Dörfler int32 index = 0; 156d8e2fb50SAxel Dörfler int32 index2 = 0; 1579e34f742SAxel Dörfler while (index < inRowBytes) { 158d8e2fb50SAxel Dörfler unsigned char c = in[index++]; 159d8e2fb50SAxel Dörfler for (int b = 128; b; b = b>>1) { 160d8e2fb50SAxel Dörfler unsigned char color; 161d8e2fb50SAxel Dörfler if (c & b) 162d8e2fb50SAxel Dörfler color = 0; 163d8e2fb50SAxel Dörfler else 164d8e2fb50SAxel Dörfler color = 255; 165d8e2fb50SAxel Dörfler out[index2++] = color; 166d8e2fb50SAxel Dörfler } 167d8e2fb50SAxel Dörfler } 168d8e2fb50SAxel Dörfler } 169d8e2fb50SAxel Dörfler 170d8e2fb50SAxel Dörfler 171d8e2fb50SAxel Dörfler inline void 1729e34f742SAxel Dörfler convert_from_gray1_to_24(uint8* in, uint8* out, int32 inRowBytes) 173d8e2fb50SAxel Dörfler { 174d8e2fb50SAxel Dörfler int32 index = 0; 175d8e2fb50SAxel Dörfler int32 index2 = 0; 1769e34f742SAxel Dörfler while (index < inRowBytes) { 177d8e2fb50SAxel Dörfler unsigned char c = in[index++]; 178d8e2fb50SAxel Dörfler for (int b = 128; b; b = b>>1) { 179d8e2fb50SAxel Dörfler unsigned char color; 180d8e2fb50SAxel Dörfler if (c & b) 181d8e2fb50SAxel Dörfler color = 0; 182d8e2fb50SAxel Dörfler else 183d8e2fb50SAxel Dörfler color = 255; 184d8e2fb50SAxel Dörfler out[index2++] = color; 185d8e2fb50SAxel Dörfler out[index2++] = color; 186d8e2fb50SAxel Dörfler out[index2++] = color; 187d8e2fb50SAxel Dörfler } 188d8e2fb50SAxel Dörfler } 189d8e2fb50SAxel Dörfler } 190d8e2fb50SAxel Dörfler 191d8e2fb50SAxel Dörfler 192d8e2fb50SAxel Dörfler inline void 1939e34f742SAxel Dörfler convert_from_cmap8_to_24(uint8* in, uint8* out, int32 inRowBytes) 194d8e2fb50SAxel Dörfler { 195d8e2fb50SAxel Dörfler const color_map * map = system_colors(); 196d8e2fb50SAxel Dörfler int32 index = 0; 197d8e2fb50SAxel Dörfler int32 index2 = 0; 1989e34f742SAxel Dörfler while (index < inRowBytes) { 199d8e2fb50SAxel Dörfler rgb_color color = map->color_list[in[index++]]; 200d8e2fb50SAxel Dörfler 201d8e2fb50SAxel Dörfler out[index2++] = color.red; 202d8e2fb50SAxel Dörfler out[index2++] = color.green; 203d8e2fb50SAxel Dörfler out[index2++] = color.blue; 204d8e2fb50SAxel Dörfler } 205d8e2fb50SAxel Dörfler } 206d8e2fb50SAxel Dörfler 207d8e2fb50SAxel Dörfler 208d8e2fb50SAxel Dörfler inline void 2099e34f742SAxel Dörfler convert_from_15_to_24(uint8* in, uint8* out, int32 inRowBytes) 210d8e2fb50SAxel Dörfler { 211d8e2fb50SAxel Dörfler int32 index = 0; 212d8e2fb50SAxel Dörfler int32 index2 = 0; 213d8e2fb50SAxel Dörfler int16 in_pixel; 2149e34f742SAxel Dörfler while (index < inRowBytes) { 215d8e2fb50SAxel Dörfler in_pixel = in[index] | (in[index + 1] << 8); 216d8e2fb50SAxel Dörfler index += 2; 217d8e2fb50SAxel Dörfler 218d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x7c00)) >> 7) | (((in_pixel & 0x7c00)) >> 12); 219d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x3e0)) >> 2) | (((in_pixel & 0x3e0)) >> 7); 220d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2); 221d8e2fb50SAxel Dörfler } 222d8e2fb50SAxel Dörfler } 223d8e2fb50SAxel Dörfler 224d8e2fb50SAxel Dörfler 225d8e2fb50SAxel Dörfler inline void 2269e34f742SAxel Dörfler convert_from_15b_to_24(uint8* in, uint8* out, int32 inRowBytes) 227d8e2fb50SAxel Dörfler { 228d8e2fb50SAxel Dörfler int32 index = 0; 229d8e2fb50SAxel Dörfler int32 index2 = 0; 230d8e2fb50SAxel Dörfler int16 in_pixel; 2319e34f742SAxel Dörfler while (index < inRowBytes) { 232d8e2fb50SAxel Dörfler in_pixel = in[index + 1] | (in[index] << 8); 233d8e2fb50SAxel Dörfler index += 2; 234d8e2fb50SAxel Dörfler 235d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x7c00)) >> 7) | (((in_pixel & 0x7c00)) >> 12); 236d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x3e0)) >> 2) | (((in_pixel & 0x3e0)) >> 7); 237d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2); 238d8e2fb50SAxel Dörfler } 239d8e2fb50SAxel Dörfler } 240d8e2fb50SAxel Dörfler 241d8e2fb50SAxel Dörfler 242d8e2fb50SAxel Dörfler inline void 2439e34f742SAxel Dörfler convert_from_16_to_24(uint8* in, uint8* out, int32 inRowBytes) 244d8e2fb50SAxel Dörfler { 245d8e2fb50SAxel Dörfler int32 index = 0; 246d8e2fb50SAxel Dörfler int32 index2 = 0; 247d8e2fb50SAxel Dörfler int16 in_pixel; 2489e34f742SAxel Dörfler while (index < inRowBytes) { 249d8e2fb50SAxel Dörfler in_pixel = in[index] | (in[index + 1] << 8); 250d8e2fb50SAxel Dörfler index += 2; 251d8e2fb50SAxel Dörfler 252d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0xf800)) >> 8) | (((in_pixel & 0xf800)) >> 13); 253d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x7e0)) >> 3) | (((in_pixel & 0x7e0)) >> 9); 254d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2); 255d8e2fb50SAxel Dörfler } 256d8e2fb50SAxel Dörfler } 257d8e2fb50SAxel Dörfler 258d8e2fb50SAxel Dörfler 259d8e2fb50SAxel Dörfler inline void 2609e34f742SAxel Dörfler convert_from_16b_to_24(uint8* in, uint8* out, int32 inRowBytes) 261d8e2fb50SAxel Dörfler { 262d8e2fb50SAxel Dörfler int32 index = 0; 263d8e2fb50SAxel Dörfler int32 index2 = 0; 264d8e2fb50SAxel Dörfler int16 in_pixel; 2659e34f742SAxel Dörfler while (index < inRowBytes) { 266d8e2fb50SAxel Dörfler in_pixel = in[index + 1] | (in[index] << 8); 267d8e2fb50SAxel Dörfler index += 2; 268d8e2fb50SAxel Dörfler 269d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0xf800)) >> 8) | (((in_pixel & 0xf800)) >> 13); 270d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x7e0)) >> 3) | (((in_pixel & 0x7e0)) >> 9); 271d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2); 272d8e2fb50SAxel Dörfler } 273d8e2fb50SAxel Dörfler } 274d8e2fb50SAxel Dörfler 275d8e2fb50SAxel Dörfler 276d8e2fb50SAxel Dörfler inline void 2779e34f742SAxel Dörfler convert_from_24_to_24(uint8* in, uint8* out, int32 inRowBytes) 278d8e2fb50SAxel Dörfler { 279d8e2fb50SAxel Dörfler int32 index = 0; 280d8e2fb50SAxel Dörfler int32 index2 = 0; 2819e34f742SAxel Dörfler while (index < inRowBytes) { 282d8e2fb50SAxel Dörfler out[index2++] = in[index + 2]; 283d8e2fb50SAxel Dörfler out[index2++] = in[index + 1]; 284d8e2fb50SAxel Dörfler out[index2++] = in[index]; 285d8e2fb50SAxel Dörfler index+=3; 286d8e2fb50SAxel Dörfler } 287d8e2fb50SAxel Dörfler } 288d8e2fb50SAxel Dörfler 289d8e2fb50SAxel Dörfler 290d8e2fb50SAxel Dörfler inline void 2919e34f742SAxel Dörfler convert_from_32_to_24(uint8* in, uint8* out, int32 inRowBytes) 292d8e2fb50SAxel Dörfler { 29351623681SAxel Dörfler inRowBytes /= 4; 29451623681SAxel Dörfler 2959e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i++) { 2969e34f742SAxel Dörfler out[0] = in[2]; 2979e34f742SAxel Dörfler out[1] = in[1]; 2989e34f742SAxel Dörfler out[2] = in[0]; 2999e34f742SAxel Dörfler 3009e34f742SAxel Dörfler in += 4; 3019e34f742SAxel Dörfler out += 3; 302d8e2fb50SAxel Dörfler } 303d8e2fb50SAxel Dörfler } 304d8e2fb50SAxel Dörfler 305d8e2fb50SAxel Dörfler 306d8e2fb50SAxel Dörfler inline void 3079e34f742SAxel Dörfler convert_from_32b_to_24(uint8* in, uint8* out, int32 inRowBytes) 308d8e2fb50SAxel Dörfler { 30951623681SAxel Dörfler inRowBytes /= 4; 31051623681SAxel Dörfler 3119e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i++) { 31251623681SAxel Dörfler out[0] = in[1]; 31351623681SAxel Dörfler out[1] = in[2]; 31451623681SAxel Dörfler out[2] = in[3]; 3159e34f742SAxel Dörfler 3169e34f742SAxel Dörfler in += 4; 3179e34f742SAxel Dörfler out += 3; 318d8e2fb50SAxel Dörfler } 319d8e2fb50SAxel Dörfler } 320d8e2fb50SAxel Dörfler 321d8e2fb50SAxel Dörfler 3229e34f742SAxel Dörfler // #pragma mark - conversion for decompression 3239e34f742SAxel Dörfler 3249e34f742SAxel Dörfler 325d8e2fb50SAxel Dörfler inline void 3269e34f742SAxel Dörfler convert_from_CMYK_to_32_photoshop(uint8* in, uint8* out, int32 inRowBytes, int32 xStep) 327d8e2fb50SAxel Dörfler { 3289e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i += 4) { 3299e34f742SAxel Dörfler int32 black = in[3]; 3309e34f742SAxel Dörfler out[0] = in[2] * black / 255; 3319e34f742SAxel Dörfler out[1] = in[1] * black / 255; 3329e34f742SAxel Dörfler out[2] = in[0] * black / 255; 3339e34f742SAxel Dörfler out[3] = 255; 3349e34f742SAxel Dörfler 3359e34f742SAxel Dörfler in += 4; 3369e34f742SAxel Dörfler out += xStep; 337d8e2fb50SAxel Dörfler } 338d8e2fb50SAxel Dörfler } 339d8e2fb50SAxel Dörfler 340d8e2fb50SAxel Dörfler 341d8e2fb50SAxel Dörfler //! !!! UNTESTED !!! 342d8e2fb50SAxel Dörfler inline void 3439e34f742SAxel Dörfler convert_from_CMYK_to_32(uint8* in, uint8* out, int32 inRowBytes, int32 xStep) 344d8e2fb50SAxel Dörfler { 3459e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i += 4) { 3469e34f742SAxel Dörfler int32 black = 255 - in[3]; 3479e34f742SAxel Dörfler out[0] = ((255 - in[2]) * black) / 255; 3489e34f742SAxel Dörfler out[1] = ((255 - in[1]) * black) / 255; 3499e34f742SAxel Dörfler out[2] = ((255 - in[0]) * black) / 255; 3509e34f742SAxel Dörfler out[3] = 255; 3519e34f742SAxel Dörfler 3529e34f742SAxel Dörfler in += 4; 3539e34f742SAxel Dörfler out += xStep; 354d8e2fb50SAxel Dörfler } 355d8e2fb50SAxel Dörfler } 356d8e2fb50SAxel Dörfler 357d8e2fb50SAxel Dörfler 358d8e2fb50SAxel Dörfler //! RGB24 8:8:8 to xRGB 8:8:8:8 359d8e2fb50SAxel Dörfler inline void 3609e34f742SAxel Dörfler convert_from_24_to_32(uint8* in, uint8* out, int32 inRowBytes, int32 xStep) 361d8e2fb50SAxel Dörfler { 3629e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i += 3) { 3639e34f742SAxel Dörfler out[0] = in[2]; 3649e34f742SAxel Dörfler out[1] = in[1]; 3659e34f742SAxel Dörfler out[2] = in[0]; 3669e34f742SAxel Dörfler out[3] = 255; 3679e34f742SAxel Dörfler 3689e34f742SAxel Dörfler in += 3; 3699e34f742SAxel Dörfler out += xStep; 3709e34f742SAxel Dörfler } 3719e34f742SAxel Dörfler } 3729e34f742SAxel Dörfler 3739e34f742SAxel Dörfler 3749e34f742SAxel Dörfler //! 8-bit to 8-bit, only need when rotating the image 3759e34f742SAxel Dörfler void 3769e34f742SAxel Dörfler translate_8(uint8* in, uint8* out, int32 inRowBytes, int32 xStep) 3779e34f742SAxel Dörfler { 3789e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i++) { 3799e34f742SAxel Dörfler out[0] = in[0]; 3809e34f742SAxel Dörfler 3819e34f742SAxel Dörfler in++; 3829e34f742SAxel Dörfler out += xStep; 383d8e2fb50SAxel Dörfler } 384d8e2fb50SAxel Dörfler } 385d8e2fb50SAxel Dörfler 386d8e2fb50SAxel Dörfler 387b98ef4f9SStephan Aßmus } // namespace conversion 3888687ff64SAxel Dörfler 3898687ff64SAxel Dörfler 390d8e2fb50SAxel Dörfler // #pragma mark - 391d8e2fb50SAxel Dörfler 392d8e2fb50SAxel Dörfler 393b98ef4f9SStephan Aßmus SSlider::SSlider(const char* name, const char* label, 394d8e2fb50SAxel Dörfler BMessage* message, int32 minValue, int32 maxValue, orientation posture, 395b98ef4f9SStephan Aßmus thumb_style thumbType, uint32 flags) 396b98ef4f9SStephan Aßmus : BSlider(name, label, message, minValue, maxValue, 397b98ef4f9SStephan Aßmus posture, thumbType, flags) 3989949213aSStephan Aßmus { 3998687ff64SAxel Dörfler rgb_color barColor = { 0, 0, 229, 255 }; 4008687ff64SAxel Dörfler UseFillColor(true, &barColor); 4019949213aSStephan Aßmus } 4029949213aSStephan Aßmus 4038687ff64SAxel Dörfler 4048687ff64SAxel Dörfler //! Update status string - show actual value 405b20d13f4SStefano Ceccherini const char* 4069949213aSStephan Aßmus SSlider::UpdateText() const 4079949213aSStephan Aßmus { 408bb4537c8SJérôme Duval snprintf(fStatusLabel, sizeof(fStatusLabel), "%" B_PRId32, Value()); 4098687ff64SAxel Dörfler return fStatusLabel; 4109949213aSStephan Aßmus } 4119949213aSStephan Aßmus 4128687ff64SAxel Dörfler 413d8e2fb50SAxel Dörfler // #pragma mark - 4149949213aSStephan Aßmus 415d8e2fb50SAxel Dörfler 416b98ef4f9SStephan Aßmus TranslatorReadView::TranslatorReadView(const char* name, 417b98ef4f9SStephan Aßmus TranslatorSettings* settings) 418b98ef4f9SStephan Aßmus : 419b98ef4f9SStephan Aßmus BView(name, 0, new BGroupLayout(B_HORIZONTAL)), 420d8e2fb50SAxel Dörfler fSettings(settings) 421b98ef4f9SStephan Aßmus // settings should already be Acquired() 4229949213aSStephan Aßmus { 4232e49ff35SSiarzhuk Zharski fAlwaysRGB32 = new BCheckBox("alwaysrgb32", 4242e49ff35SSiarzhuk Zharski B_TRANSLATE("Read greyscale images as RGB32"), 425d8e2fb50SAxel Dörfler new BMessage(VIEW_MSG_SET_ALWAYSRGB32)); 426b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_ALWAYS_RGB32, NULL)) 427b98ef4f9SStephan Aßmus fAlwaysRGB32->SetValue(B_CONTROL_ON); 4289949213aSStephan Aßmus 4292e49ff35SSiarzhuk Zharski fPhotoshopCMYK = new BCheckBox("photoshopCMYK", 4302e49ff35SSiarzhuk Zharski B_TRANSLATE("Use CMYK code with 0 for 100% ink coverage"), 4318687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_PHOTOSHOPCMYK)); 432b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_PHOTOSHOP_CMYK, NULL)) 433b98ef4f9SStephan Aßmus fPhotoshopCMYK->SetValue(B_CONTROL_ON); 4349949213aSStephan Aßmus 4352e49ff35SSiarzhuk Zharski fShowErrorBox = new BCheckBox("error", 4362e49ff35SSiarzhuk Zharski B_TRANSLATE("Show warning messages"), 4378687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_SHOWREADERRORBOX)); 438b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_SHOWREADWARNING, NULL)) 439b98ef4f9SStephan Aßmus fShowErrorBox->SetValue(B_CONTROL_ON); 4409949213aSStephan Aßmus 441d9c440a5SJanus BLayoutBuilder::Group<>(this, B_VERTICAL) 442d9c440a5SJanus .SetInsets(B_USE_DEFAULT_SPACING) 443b98ef4f9SStephan Aßmus .Add(fAlwaysRGB32) 444b98ef4f9SStephan Aßmus .Add(fPhotoshopCMYK) 445b98ef4f9SStephan Aßmus .Add(fShowErrorBox) 4467d48219bSHannah Boneß .AddGlue(); 447b98ef4f9SStephan Aßmus } 448b98ef4f9SStephan Aßmus 449b98ef4f9SStephan Aßmus 450b98ef4f9SStephan Aßmus TranslatorReadView::~TranslatorReadView() 451b98ef4f9SStephan Aßmus { 452b98ef4f9SStephan Aßmus fSettings->Release(); 4539949213aSStephan Aßmus } 4549949213aSStephan Aßmus 4558687ff64SAxel Dörfler 4569949213aSStephan Aßmus void 4579949213aSStephan Aßmus TranslatorReadView::AttachedToWindow() 4589949213aSStephan Aßmus { 459b98ef4f9SStephan Aßmus BView::AttachedToWindow(); 460b20d13f4SStefano Ceccherini 4618687ff64SAxel Dörfler fAlwaysRGB32->SetTarget(this); 4628687ff64SAxel Dörfler fPhotoshopCMYK->SetTarget(this); 4638687ff64SAxel Dörfler fShowErrorBox->SetTarget(this); 4649949213aSStephan Aßmus } 4659949213aSStephan Aßmus 4668687ff64SAxel Dörfler 4679949213aSStephan Aßmus void 4689949213aSStephan Aßmus TranslatorReadView::MessageReceived(BMessage* message) 4699949213aSStephan Aßmus { 4708687ff64SAxel Dörfler switch (message->what) { 4719949213aSStephan Aßmus case VIEW_MSG_SET_ALWAYSRGB32: 4729949213aSStephan Aßmus { 4739949213aSStephan Aßmus int32 value; 4749949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 475b98ef4f9SStephan Aßmus bool boolValue = value; 476b98ef4f9SStephan Aßmus fSettings->SetGetBool(JPEG_SET_ALWAYS_RGB32, &boolValue); 477b98ef4f9SStephan Aßmus fSettings->SaveSettings(); 4789949213aSStephan Aßmus } 4799949213aSStephan Aßmus break; 4809949213aSStephan Aßmus } 4819949213aSStephan Aßmus case VIEW_MSG_SET_PHOTOSHOPCMYK: 4829949213aSStephan Aßmus { 4839949213aSStephan Aßmus int32 value; 4849949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 485b98ef4f9SStephan Aßmus bool boolValue = value; 486b98ef4f9SStephan Aßmus fSettings->SetGetBool(JPEG_SET_PHOTOSHOP_CMYK, &boolValue); 487b98ef4f9SStephan Aßmus fSettings->SaveSettings(); 4889949213aSStephan Aßmus } 4899949213aSStephan Aßmus break; 4909949213aSStephan Aßmus } 4919949213aSStephan Aßmus case VIEW_MSG_SET_SHOWREADERRORBOX: 4929949213aSStephan Aßmus { 4939949213aSStephan Aßmus int32 value; 4949949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 495b98ef4f9SStephan Aßmus bool boolValue = value; 496b98ef4f9SStephan Aßmus fSettings->SetGetBool(JPEG_SET_SHOWREADWARNING, &boolValue); 497b98ef4f9SStephan Aßmus fSettings->SaveSettings(); 4989949213aSStephan Aßmus } 4999949213aSStephan Aßmus break; 5009949213aSStephan Aßmus } 5019949213aSStephan Aßmus default: 5029949213aSStephan Aßmus BView::MessageReceived(message); 5039949213aSStephan Aßmus break; 5049949213aSStephan Aßmus } 5059949213aSStephan Aßmus } 5069949213aSStephan Aßmus 5079949213aSStephan Aßmus 5088687ff64SAxel Dörfler // #pragma mark - TranslatorWriteView 5099949213aSStephan Aßmus 5108687ff64SAxel Dörfler 511b98ef4f9SStephan Aßmus TranslatorWriteView::TranslatorWriteView(const char* name, 512b98ef4f9SStephan Aßmus TranslatorSettings* settings) 513b98ef4f9SStephan Aßmus : 514b98ef4f9SStephan Aßmus BView(name, 0, new BGroupLayout(B_VERTICAL)), 515d8e2fb50SAxel Dörfler fSettings(settings) 516b98ef4f9SStephan Aßmus // settings should already be Acquired() 5179949213aSStephan Aßmus { 5182e49ff35SSiarzhuk Zharski fQualitySlider = new SSlider("quality", B_TRANSLATE("Output quality"), 5198687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_QUALITY), 0, 100); 5208687ff64SAxel Dörfler fQualitySlider->SetHashMarks(B_HASH_MARKS_BOTTOM); 5218687ff64SAxel Dörfler fQualitySlider->SetHashMarkCount(10); 52203901b6cSJérôme Duval fQualitySlider->SetLimitLabels(B_TRANSLATE("Low"), B_TRANSLATE("High")); 523b98ef4f9SStephan Aßmus fQualitySlider->SetValue(fSettings->SetGetInt32(JPEG_SET_QUALITY, NULL)); 5249949213aSStephan Aßmus 5252e49ff35SSiarzhuk Zharski fSmoothingSlider = new SSlider("smoothing", 5262e49ff35SSiarzhuk Zharski B_TRANSLATE("Output smoothing strength"), 5278687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_SMOOTHING), 0, 100); 5288687ff64SAxel Dörfler fSmoothingSlider->SetHashMarks(B_HASH_MARKS_BOTTOM); 5298687ff64SAxel Dörfler fSmoothingSlider->SetHashMarkCount(10); 53003901b6cSJérôme Duval fSmoothingSlider->SetLimitLabels(B_TRANSLATE("None"), B_TRANSLATE("High")); 531b98ef4f9SStephan Aßmus fSmoothingSlider->SetValue( 532b98ef4f9SStephan Aßmus fSettings->SetGetInt32(JPEG_SET_SMOOTHING, NULL)); 5339949213aSStephan Aßmus 5342e49ff35SSiarzhuk Zharski fProgress = new BCheckBox("progress", 5352e49ff35SSiarzhuk Zharski B_TRANSLATE("Use progressive compression"), 5368687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_PROGRESSIVE)); 537b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_PROGRESSIVE, NULL)) 538b98ef4f9SStephan Aßmus fProgress->SetValue(B_CONTROL_ON); 5399949213aSStephan Aßmus 5402e49ff35SSiarzhuk Zharski fSmallerFile = new BCheckBox("smallerfile", 5412e49ff35SSiarzhuk Zharski B_TRANSLATE("Make file smaller (sligthtly worse quality)"), 5428687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_SMALLERFILE)); 543b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_SMALL_FILES)) 544b98ef4f9SStephan Aßmus fSmallerFile->SetValue(B_CONTROL_ON); 545b98ef4f9SStephan Aßmus 5462e49ff35SSiarzhuk Zharski fOptimizeColors = new BCheckBox("optimizecolors", 5472e49ff35SSiarzhuk Zharski B_TRANSLATE("Prevent colors 'washing out'"), 548b98ef4f9SStephan Aßmus new BMessage(VIEW_MSG_SET_OPTIMIZECOLORS)); 549b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_OPT_COLORS, NULL)) 550b98ef4f9SStephan Aßmus fOptimizeColors->SetValue(B_CONTROL_ON); 551b98ef4f9SStephan Aßmus else 5528687ff64SAxel Dörfler fSmallerFile->SetEnabled(false); 5539949213aSStephan Aßmus 5542e49ff35SSiarzhuk Zharski fGrayAsRGB24 = new BCheckBox("gray1asrgb24", 5552e49ff35SSiarzhuk Zharski B_TRANSLATE("Write black-and-white images as RGB24"), 5568687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_GRAY1ASRGB24)); 557b98ef4f9SStephan Aßmus if (fSettings->SetGetBool(JPEG_SET_GRAY1_AS_RGB24)) 558b98ef4f9SStephan Aßmus fGrayAsRGB24->SetValue(B_CONTROL_ON); 5599949213aSStephan Aßmus 560d9c440a5SJanus BLayoutBuilder::Group<>(this, B_VERTICAL) 561d9c440a5SJanus .SetInsets(B_USE_DEFAULT_SPACING) 562b98ef4f9SStephan Aßmus .Add(fQualitySlider) 563b98ef4f9SStephan Aßmus .Add(fSmoothingSlider) 564b98ef4f9SStephan Aßmus .Add(fProgress) 565b98ef4f9SStephan Aßmus .Add(fOptimizeColors) 566b98ef4f9SStephan Aßmus .Add(fSmallerFile) 567b98ef4f9SStephan Aßmus .Add(fGrayAsRGB24) 5687d48219bSHannah Boneß .AddGlue(); 569b98ef4f9SStephan Aßmus } 5709949213aSStephan Aßmus 571b98ef4f9SStephan Aßmus 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 6743292b902SHumdinger char versionString[100]; 6753292b902SHumdinger snprintf(versionString, sizeof(versionString), 6763292b902SHumdinger B_TRANSLATE("Version %d.%d.%d"), 6773292b902SHumdinger (int)(sTranslatorVersion >> 8), 6783292b902SHumdinger (int)((sTranslatorVersion >> 4) & 0xf), 6793292b902SHumdinger (int)(sTranslatorVersion & 0xf)); 6809949213aSStephan Aßmus 681b98ef4f9SStephan Aßmus BStringView* version = new BStringView("Version", versionString); 682b98ef4f9SStephan Aßmus version->SetExplicitAlignment(labelAlignment); 6839949213aSStephan Aßmus 684b98ef4f9SStephan Aßmus BTextView* infoView = new BTextView("info"); 6852e49ff35SSiarzhuk Zharski infoView->SetText(sTranslatorInfo); 686f0650dc9Slooncraz infoView->SetViewUIColor(B_PANEL_BACKGROUND_COLOR); 687*5f61e00aSDale Cieslak rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR); 688*5f61e00aSDale Cieslak infoView->SetFontAndColor(be_plain_font, B_FONT_ALL, &textColor); 689b98ef4f9SStephan Aßmus infoView->MakeEditable(false); 6909949213aSStephan Aßmus 691d9c440a5SJanus BLayoutBuilder::Group<>(this, B_VERTICAL, 0) 692d9c440a5SJanus .SetInsets(B_USE_DEFAULT_SPACING) 693b98ef4f9SStephan Aßmus .Add(title) 694b98ef4f9SStephan Aßmus .Add(version) 6957d48219bSHannah Boneß .Add(infoView); 6969949213aSStephan Aßmus } 6979949213aSStephan Aßmus 6989949213aSStephan Aßmus 699b98ef4f9SStephan Aßmus TranslatorView::TranslatorView(const char* name, TranslatorSettings* settings) 700b98ef4f9SStephan Aßmus : 701d9c440a5SJanus BTabView(name, B_WIDTH_FROM_LABEL) 7029949213aSStephan Aßmus { 703d9c440a5SJanus SetBorder(B_NO_BORDER); 704d9c440a5SJanus 70570d59669SSiarzhuk Zharski AddTab(new TranslatorWriteView(B_TRANSLATE("Write"), settings->Acquire())); 70670d59669SSiarzhuk Zharski AddTab(new TranslatorReadView(B_TRANSLATE("Read"), settings->Acquire())); 70770d59669SSiarzhuk Zharski AddTab(new TranslatorAboutView(B_TRANSLATE("About"))); 7089949213aSStephan Aßmus 709b98ef4f9SStephan Aßmus settings->Release(); 7109949213aSStephan Aßmus 711b98ef4f9SStephan Aßmus BFont font; 712b98ef4f9SStephan Aßmus GetFont(&font); 713b98ef4f9SStephan Aßmus SetExplicitPreferredSize( 714b98ef4f9SStephan Aßmus BSize((font.Size() * 380) / 12, (font.Size() * 250) / 12)); 7159949213aSStephan Aßmus } 7169949213aSStephan Aßmus 7179949213aSStephan Aßmus 718d8e2fb50SAxel Dörfler // #pragma mark - Translator Add-On 7199949213aSStephan Aßmus 7209949213aSStephan Aßmus 721b98ef4f9SStephan Aßmus BView* 722b98ef4f9SStephan Aßmus JPEGTranslator::NewConfigView(TranslatorSettings* settings) 7239949213aSStephan Aßmus { 724b98ef4f9SStephan Aßmus BView* configView = new TranslatorView("TranslatorView", settings); 725b98ef4f9SStephan Aßmus return configView; 7269949213aSStephan Aßmus } 7279949213aSStephan Aßmus 728b98ef4f9SStephan Aßmus 729d8e2fb50SAxel Dörfler /*! Determine whether or not we can handle this data */ 7309949213aSStephan Aßmus status_t 731b98ef4f9SStephan Aßmus JPEGTranslator::DerivedIdentify(BPositionIO* inSource, 732b98ef4f9SStephan Aßmus const translation_format* inFormat, BMessage* ioExtension, 733b98ef4f9SStephan Aßmus translator_info* outInfo, uint32 outType) 7349949213aSStephan Aßmus { 735d8e2fb50SAxel Dörfler if (outType != 0 && outType != B_TRANSLATOR_BITMAP && outType != JPEG_FORMAT) 7369949213aSStephan Aßmus return B_NO_TRANSLATOR; 7379949213aSStephan Aßmus 7389949213aSStephan Aßmus // !!! You might need to make this buffer bigger to test for your native format 7399949213aSStephan Aßmus off_t position = inSource->Position(); 7409949213aSStephan Aßmus char header[sizeof(TranslatorBitmap)]; 7419949213aSStephan Aßmus status_t err = inSource->Read(header, sizeof(TranslatorBitmap)); 7429949213aSStephan Aßmus inSource->Seek(position, SEEK_SET); 743d8e2fb50SAxel Dörfler if (err < B_OK) 744d8e2fb50SAxel Dörfler return err; 7459949213aSStephan Aßmus 7469949213aSStephan Aßmus if (B_BENDIAN_TO_HOST_INT32(((TranslatorBitmap *)header)->magic) == B_TRANSLATOR_BITMAP) { 747b98ef4f9SStephan Aßmus if (PopulateInfoFromFormat(outInfo, B_TRANSLATOR_BITMAP) != B_OK) 748b98ef4f9SStephan Aßmus return B_NO_TRANSLATOR; 7499949213aSStephan Aßmus } else { 7509949213aSStephan Aßmus // First 3 bytes in jpg files are always the same from what i've seen so far 7519949213aSStephan Aßmus // check them 7529949213aSStephan Aßmus if (header[0] == (char)0xff && header[1] == (char)0xd8 && header[2] == (char)0xff) { 753b98ef4f9SStephan Aßmus if (PopulateInfoFromFormat(outInfo, JPEG_FORMAT) != B_OK) 7549949213aSStephan Aßmus return B_NO_TRANSLATOR; 755b98ef4f9SStephan Aßmus 7569949213aSStephan Aßmus } else 7579949213aSStephan Aßmus return B_NO_TRANSLATOR; 7589949213aSStephan Aßmus } 7599949213aSStephan Aßmus 7609949213aSStephan Aßmus return B_OK; 7619949213aSStephan Aßmus } 7629949213aSStephan Aßmus 763b98ef4f9SStephan Aßmus 7649949213aSStephan Aßmus status_t 765b98ef4f9SStephan Aßmus JPEGTranslator::DerivedTranslate(BPositionIO* inSource, 766b98ef4f9SStephan Aßmus const translator_info* inInfo, BMessage* ioExtension, uint32 outType, 767b98ef4f9SStephan Aßmus BPositionIO* outDestination, int32 baseType) 7689949213aSStephan Aßmus { 769dbc936acSStephan Aßmus // Setup a "breakpoint" since throwing exceptions does not seem to work 770dbc936acSStephan Aßmus // at all in an add-on. (?) 771dbc936acSStephan Aßmus // In the be_jerror.cpp we implement a handler for critical library errors 772dbc936acSStephan Aßmus // (be_error_exit()) and there we use the longjmp() function to return to 773dbc936acSStephan Aßmus // this place. If this happens, it is as if the setjmp() call is called 774dbc936acSStephan Aßmus // a second time, but this time the return value will be 1. The first 775dbc936acSStephan Aßmus // invokation will return 0. 776b91634cbSStephan Aßmus jmp_buf longJumpBuffer; 777b91634cbSStephan Aßmus int jmpRet = setjmp(longJumpBuffer); 778dbc936acSStephan Aßmus if (jmpRet == 1) 779dbc936acSStephan Aßmus return B_ERROR; 780dbc936acSStephan Aßmus 781dbc936acSStephan Aßmus try { 7829949213aSStephan Aßmus // What action to take, based on the findings of Identify() 7839949213aSStephan Aßmus if (outType == inInfo->type) { 7849949213aSStephan Aßmus return Copy(inSource, outDestination); 785dbc936acSStephan Aßmus } else if (inInfo->type == B_TRANSLATOR_BITMAP 786dbc936acSStephan Aßmus && outType == JPEG_FORMAT) { 787b91634cbSStephan Aßmus return Compress(inSource, outDestination, &longJumpBuffer); 788dbc936acSStephan Aßmus } else if (inInfo->type == JPEG_FORMAT 789863a6388SAdrien Destugues && (outType == B_TRANSLATOR_BITMAP || outType == 0)) { 790863a6388SAdrien Destugues // This is the default if no specific outType was requested. 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; 956e4bd005dSIngo Weinhold struct be_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; 1060e4bd005dSIngo Weinhold struct be_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)")); 1286c7eabc40SMurai Takashi strlcpy(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