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