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" 349949213aSStephan Aßmus 3552e8f46aSAxel Dörfler #include "exif_parser.h" 3652e8f46aSAxel Dörfler 378687ff64SAxel Dörfler #include <TabView.h> 388687ff64SAxel Dörfler 399949213aSStephan Aßmus 4052e8f46aSAxel Dörfler #define MARKER_EXIF 0xe1 4152e8f46aSAxel Dörfler 429949213aSStephan Aßmus // Set these accordingly 439949213aSStephan Aßmus #define JPEG_ACRONYM "JPEG" 449949213aSStephan Aßmus #define JPEG_FORMAT 'JPEG' 459949213aSStephan Aßmus #define JPEG_MIME_STRING "image/jpeg" 469949213aSStephan Aßmus #define JPEG_DESCRIPTION "JPEG image" 479949213aSStephan Aßmus 489949213aSStephan Aßmus // The translation kit's native file type 499949213aSStephan Aßmus #define B_TRANSLATOR_BITMAP_MIME_STRING "image/x-be-bitmap" 509949213aSStephan Aßmus #define B_TRANSLATOR_BITMAP_DESCRIPTION "Be Bitmap image" 519949213aSStephan Aßmus 529949213aSStephan Aßmus // Translation Kit required globals 53109d4881SStephan Aßmus char translatorName[] = "JPEG Images"; 548687ff64SAxel Dörfler char translatorInfo[] = 558687ff64SAxel Dörfler "©2002-2003, Marcin Konicki\n" 56f13b5de6SAxel Dörfler "©2005-2007, Haiku\n" 57758b1d0eSIngo Weinhold "\n" 588687ff64SAxel Dörfler "Based on IJG library © 1991-1998, Thomas G. Lane\n" 59758b1d0eSIngo Weinhold " http://www.ijg.org/files/\n" 60758b1d0eSIngo Weinhold "with \"Lossless\" encoding support patch by Ken Murchison\n" 61758b1d0eSIngo Weinhold " http://www.oceana.com/ftp/ljpeg/\n" 62758b1d0eSIngo Weinhold "\n" 63758b1d0eSIngo Weinhold "With some colorspace conversion routines by Magnus Hellman\n" 648687ff64SAxel Dörfler " http://www.bebits.com/app/802\n"; 65d8e2fb50SAxel Dörfler 66f13b5de6SAxel Dörfler int32 translatorVersion = 0x120; 679949213aSStephan Aßmus 689949213aSStephan Aßmus // Define the formats we know how to read 699949213aSStephan Aßmus translation_format inputFormats[] = { 709949213aSStephan Aßmus { JPEG_FORMAT, B_TRANSLATOR_BITMAP, 0.5, 0.5, 719949213aSStephan Aßmus JPEG_MIME_STRING, JPEG_DESCRIPTION }, 729949213aSStephan Aßmus { B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.5, 0.5, 739949213aSStephan Aßmus B_TRANSLATOR_BITMAP_MIME_STRING, B_TRANSLATOR_BITMAP_DESCRIPTION }, 74d8e2fb50SAxel Dörfler {} 759949213aSStephan Aßmus }; 769949213aSStephan Aßmus 779949213aSStephan Aßmus // Define the formats we know how to write 789949213aSStephan Aßmus translation_format outputFormats[] = { 799949213aSStephan Aßmus { JPEG_FORMAT, B_TRANSLATOR_BITMAP, 0.5, 0.5, 809949213aSStephan Aßmus JPEG_MIME_STRING, JPEG_DESCRIPTION }, 819949213aSStephan Aßmus { B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.5, 0.5, 829949213aSStephan Aßmus B_TRANSLATOR_BITMAP_MIME_STRING, B_TRANSLATOR_BITMAP_DESCRIPTION }, 83d8e2fb50SAxel Dörfler {} 849949213aSStephan Aßmus }; 859949213aSStephan Aßmus 8652e8f46aSAxel Dörfler // Main functions of translator :) 8752e8f46aSAxel Dörfler static status_t Copy(BPositionIO *in, BPositionIO *out); 8852e8f46aSAxel Dörfler static status_t Compress(BPositionIO *in, BPositionIO *out); 8952e8f46aSAxel Dörfler static status_t Decompress(BPositionIO *in, BPositionIO *out, BMessage* ioExtension); 9052e8f46aSAxel Dörfler static status_t Error(j_common_ptr cinfo, status_t error = B_ERROR); 9152e8f46aSAxel Dörfler 92d8e2fb50SAxel Dörfler 93d8e2fb50SAxel Dörfler bool gAreSettingsRunning = false; 949949213aSStephan Aßmus 959949213aSStephan Aßmus 96d8e2fb50SAxel Dörfler //! Make settings to defaults 97d8e2fb50SAxel Dörfler void 98d8e2fb50SAxel Dörfler LoadDefaultSettings(jpeg_settings *settings) 99d8e2fb50SAxel Dörfler { 100d8e2fb50SAxel Dörfler settings->Smoothing = 0; 101d8e2fb50SAxel Dörfler settings->Quality = 95; 102d8e2fb50SAxel Dörfler settings->Progressive = true; 103d8e2fb50SAxel Dörfler settings->OptimizeColors = true; 104d8e2fb50SAxel Dörfler settings->SmallerFile = false; 105d8e2fb50SAxel Dörfler settings->B_GRAY1_as_B_RGB24 = false; 106d8e2fb50SAxel Dörfler settings->Always_B_RGB32 = true; 107d8e2fb50SAxel Dörfler settings->PhotoshopCMYK = true; 108d8e2fb50SAxel Dörfler settings->ShowReadWarningBox = true; 109d8e2fb50SAxel Dörfler } 1109949213aSStephan Aßmus 111d8e2fb50SAxel Dörfler 112d8e2fb50SAxel Dörfler //! Save settings to config file 113d8e2fb50SAxel Dörfler void 114d8e2fb50SAxel Dörfler SaveSettings(jpeg_settings *settings) 115d8e2fb50SAxel Dörfler { 116d8e2fb50SAxel Dörfler // Make path to settings file 117d8e2fb50SAxel Dörfler BPath path; 118117da2d7SAxel Dörfler if (find_directory(B_USER_SETTINGS_DIRECTORY, &path, true) != B_OK) 119117da2d7SAxel Dörfler return; 120117da2d7SAxel Dörfler 121d8e2fb50SAxel Dörfler path.Append(SETTINGS_FILE); 122d8e2fb50SAxel Dörfler 123d8e2fb50SAxel Dörfler // Open settings file (create it if there's no file) and write settings 124d8e2fb50SAxel Dörfler FILE *file = NULL; 125d8e2fb50SAxel Dörfler if ((file = fopen(path.Path(), "wb+"))) { 126d8e2fb50SAxel Dörfler fwrite(settings, sizeof(jpeg_settings), 1, file); 127d8e2fb50SAxel Dörfler fclose(file); 128d8e2fb50SAxel Dörfler } 129d8e2fb50SAxel Dörfler } 130d8e2fb50SAxel Dörfler 131d8e2fb50SAxel Dörfler 132d8e2fb50SAxel Dörfler //! Return true if settings were run, false if not 133d8e2fb50SAxel Dörfler bool 134d8e2fb50SAxel Dörfler SettingsChangedAlert() 135d8e2fb50SAxel Dörfler { 136d8e2fb50SAxel Dörfler // If settings view wasn't already initialized (settings not running) 137d8e2fb50SAxel Dörfler // and user wants to run settings 138d8e2fb50SAxel Dörfler if (!gAreSettingsRunning 139d8e2fb50SAxel Dörfler && (new BAlert("Different settings file", 140d8e2fb50SAxel Dörfler "JPEG settings were set to default because of incompatible settings file.", 141d8e2fb50SAxel Dörfler "Configure settings", "OK", NULL, B_WIDTH_AS_USUAL, 142d8e2fb50SAxel Dörfler B_WARNING_ALERT))->Go() == 0) { 143d8e2fb50SAxel Dörfler // Create settings window (with no quit on close!), launch 144d8e2fb50SAxel Dörfler // it and wait until it's closed 145d8e2fb50SAxel Dörfler TranslatorWindow *window = new TranslatorWindow(false); 146d8e2fb50SAxel Dörfler window->Show(); 147c016311bSAxel Dörfler 148c016311bSAxel Dörfler status_t err; 149d8e2fb50SAxel Dörfler wait_for_thread(window->Thread(), &err); 150d8e2fb50SAxel Dörfler return true; 151d8e2fb50SAxel Dörfler } 152d8e2fb50SAxel Dörfler 153d8e2fb50SAxel Dörfler return false; 154d8e2fb50SAxel Dörfler } 155d8e2fb50SAxel Dörfler 156d8e2fb50SAxel Dörfler 157d8e2fb50SAxel Dörfler /*! 158d8e2fb50SAxel Dörfler Load settings from config file 159d8e2fb50SAxel Dörfler If can't find it make them default and try to save 160d8e2fb50SAxel Dörfler */ 161d8e2fb50SAxel Dörfler void 162d8e2fb50SAxel Dörfler LoadSettings(jpeg_settings *settings) 163d8e2fb50SAxel Dörfler { 164d8e2fb50SAxel Dörfler // Make path to settings file 165d8e2fb50SAxel Dörfler BPath path; 166d8e2fb50SAxel Dörfler if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) { 167117da2d7SAxel Dörfler LoadDefaultSettings(settings); 168117da2d7SAxel Dörfler return; 169117da2d7SAxel Dörfler } 170117da2d7SAxel Dörfler 171d8e2fb50SAxel Dörfler path.Append(SETTINGS_FILE); 172d8e2fb50SAxel Dörfler 173d8e2fb50SAxel Dörfler // Open settings file (create it if there's no file) and write settings 174d8e2fb50SAxel Dörfler FILE *file = NULL; 175c016311bSAxel Dörfler if ((file = fopen(path.Path(), "rb")) != NULL) { 176d8e2fb50SAxel Dörfler if (!fread(settings, sizeof(jpeg_settings), 1, file)) { 177d8e2fb50SAxel Dörfler // settings struct has changed size 178d8e2fb50SAxel Dörfler // Load default settings, and Save them 179d8e2fb50SAxel Dörfler fclose(file); 180d8e2fb50SAxel Dörfler LoadDefaultSettings(settings); 181d8e2fb50SAxel Dörfler SaveSettings(settings); 182d8e2fb50SAxel Dörfler // Tell user settings were changed to default, and ask to run settings panel or not 183d8e2fb50SAxel Dörfler if (SettingsChangedAlert()) 184d8e2fb50SAxel Dörfler // User configured settings, load them again 185d8e2fb50SAxel Dörfler LoadSettings(settings); 186d8e2fb50SAxel Dörfler } else 187d8e2fb50SAxel Dörfler fclose(file); 188c016311bSAxel Dörfler } else if ((file = fopen(path.Path(), "wb+")) != NULL) { 189d8e2fb50SAxel Dörfler LoadDefaultSettings(settings); 190d8e2fb50SAxel Dörfler fwrite(settings, sizeof(jpeg_settings), 1, file); 191d8e2fb50SAxel Dörfler fclose(file); 192d8e2fb50SAxel Dörfler } 193d8e2fb50SAxel Dörfler } 194d8e2fb50SAxel Dörfler 195d8e2fb50SAxel Dörfler 1969e34f742SAxel Dörfler static bool 1979e34f742SAxel Dörfler x_flipped(int32 orientation) 1989e34f742SAxel Dörfler { 1999e34f742SAxel Dörfler return orientation == 2 || orientation == 3 2009e34f742SAxel Dörfler || orientation == 6 || orientation == 7; 2019e34f742SAxel Dörfler } 2029e34f742SAxel Dörfler 2039e34f742SAxel Dörfler 2049e34f742SAxel Dörfler static bool 2059e34f742SAxel Dörfler y_flipped(int32 orientation) 2069e34f742SAxel Dörfler { 2079e34f742SAxel Dörfler return orientation == 3 || orientation == 4 2089e34f742SAxel Dörfler || orientation == 7 || orientation == 8; 2099e34f742SAxel Dörfler } 2109e34f742SAxel Dörfler 2119e34f742SAxel Dörfler 2129e34f742SAxel Dörfler static int32 2139e34f742SAxel Dörfler dest_index(uint32 width, uint32 height, uint32 x, uint32 y, int32 orientation) 2149e34f742SAxel Dörfler { 2159e34f742SAxel Dörfler if (orientation > 4) { 2169e34f742SAxel Dörfler uint32 temp = x; 2179e34f742SAxel Dörfler x = y; 2189e34f742SAxel Dörfler y = temp; 2199e34f742SAxel Dörfler } 2209e34f742SAxel Dörfler if (y_flipped(orientation)) 2219e34f742SAxel Dörfler y = height - 1 - y; 2229e34f742SAxel Dörfler if (x_flipped(orientation)) 2239e34f742SAxel Dörfler x = width - 1 - x; 2249e34f742SAxel Dörfler 2259e34f742SAxel Dörfler return y * width + x; 2269e34f742SAxel Dörfler } 2279e34f742SAxel Dörfler 2289e34f742SAxel Dörfler 2299e34f742SAxel Dörfler // #pragma mark - conversion for compression 230d8e2fb50SAxel Dörfler 231d8e2fb50SAxel Dörfler 232d8e2fb50SAxel Dörfler inline void 2339e34f742SAxel Dörfler convert_from_gray1_to_gray8(uint8* in, uint8* out, int32 inRowBytes) 234d8e2fb50SAxel Dörfler { 235d8e2fb50SAxel Dörfler int32 index = 0; 236d8e2fb50SAxel Dörfler int32 index2 = 0; 2379e34f742SAxel Dörfler while (index < inRowBytes) { 238d8e2fb50SAxel Dörfler unsigned char c = in[index++]; 239d8e2fb50SAxel Dörfler for (int b = 128; b; b = b>>1) { 240d8e2fb50SAxel Dörfler unsigned char color; 241d8e2fb50SAxel Dörfler if (c & b) 242d8e2fb50SAxel Dörfler color = 0; 243d8e2fb50SAxel Dörfler else 244d8e2fb50SAxel Dörfler color = 255; 245d8e2fb50SAxel Dörfler out[index2++] = color; 246d8e2fb50SAxel Dörfler } 247d8e2fb50SAxel Dörfler } 248d8e2fb50SAxel Dörfler } 249d8e2fb50SAxel Dörfler 250d8e2fb50SAxel Dörfler 251d8e2fb50SAxel Dörfler inline void 2529e34f742SAxel Dörfler convert_from_gray1_to_24(uint8* in, uint8* out, int32 inRowBytes) 253d8e2fb50SAxel Dörfler { 254d8e2fb50SAxel Dörfler int32 index = 0; 255d8e2fb50SAxel Dörfler int32 index2 = 0; 2569e34f742SAxel Dörfler while (index < inRowBytes) { 257d8e2fb50SAxel Dörfler unsigned char c = in[index++]; 258d8e2fb50SAxel Dörfler for (int b = 128; b; b = b>>1) { 259d8e2fb50SAxel Dörfler unsigned char color; 260d8e2fb50SAxel Dörfler if (c & b) 261d8e2fb50SAxel Dörfler color = 0; 262d8e2fb50SAxel Dörfler else 263d8e2fb50SAxel Dörfler color = 255; 264d8e2fb50SAxel Dörfler out[index2++] = color; 265d8e2fb50SAxel Dörfler out[index2++] = color; 266d8e2fb50SAxel Dörfler out[index2++] = color; 267d8e2fb50SAxel Dörfler } 268d8e2fb50SAxel Dörfler } 269d8e2fb50SAxel Dörfler } 270d8e2fb50SAxel Dörfler 271d8e2fb50SAxel Dörfler 272d8e2fb50SAxel Dörfler inline void 2739e34f742SAxel Dörfler convert_from_cmap8_to_24(uint8* in, uint8* out, int32 inRowBytes) 274d8e2fb50SAxel Dörfler { 275d8e2fb50SAxel Dörfler const color_map * map = system_colors(); 276d8e2fb50SAxel Dörfler int32 index = 0; 277d8e2fb50SAxel Dörfler int32 index2 = 0; 2789e34f742SAxel Dörfler while (index < inRowBytes) { 279d8e2fb50SAxel Dörfler rgb_color color = map->color_list[in[index++]]; 280d8e2fb50SAxel Dörfler 281d8e2fb50SAxel Dörfler out[index2++] = color.red; 282d8e2fb50SAxel Dörfler out[index2++] = color.green; 283d8e2fb50SAxel Dörfler out[index2++] = color.blue; 284d8e2fb50SAxel Dörfler } 285d8e2fb50SAxel Dörfler } 286d8e2fb50SAxel Dörfler 287d8e2fb50SAxel Dörfler 288d8e2fb50SAxel Dörfler inline void 2899e34f742SAxel Dörfler convert_from_15_to_24(uint8* in, uint8* out, int32 inRowBytes) 290d8e2fb50SAxel Dörfler { 291d8e2fb50SAxel Dörfler int32 index = 0; 292d8e2fb50SAxel Dörfler int32 index2 = 0; 293d8e2fb50SAxel Dörfler int16 in_pixel; 2949e34f742SAxel Dörfler while (index < inRowBytes) { 295d8e2fb50SAxel Dörfler in_pixel = in[index] | (in[index+1] << 8); 296d8e2fb50SAxel Dörfler index += 2; 297d8e2fb50SAxel Dörfler 298d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x7c00)) >> 7) | (((in_pixel & 0x7c00)) >> 12); 299d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x3e0)) >> 2) | (((in_pixel & 0x3e0)) >> 7); 300d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2); 301d8e2fb50SAxel Dörfler } 302d8e2fb50SAxel Dörfler } 303d8e2fb50SAxel Dörfler 304d8e2fb50SAxel Dörfler 305d8e2fb50SAxel Dörfler inline void 3069e34f742SAxel Dörfler convert_from_15b_to_24(uint8* in, uint8* out, int32 inRowBytes) 307d8e2fb50SAxel Dörfler { 308d8e2fb50SAxel Dörfler int32 index = 0; 309d8e2fb50SAxel Dörfler int32 index2 = 0; 310d8e2fb50SAxel Dörfler int16 in_pixel; 3119e34f742SAxel Dörfler while (index < inRowBytes) { 312d8e2fb50SAxel Dörfler in_pixel = in[index+1] | (in[index] << 8); 313d8e2fb50SAxel Dörfler index += 2; 314d8e2fb50SAxel Dörfler 315d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x7c00)) >> 7) | (((in_pixel & 0x7c00)) >> 12); 316d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x3e0)) >> 2) | (((in_pixel & 0x3e0)) >> 7); 317d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2); 318d8e2fb50SAxel Dörfler } 319d8e2fb50SAxel Dörfler } 320d8e2fb50SAxel Dörfler 321d8e2fb50SAxel Dörfler 322d8e2fb50SAxel Dörfler inline void 3239e34f742SAxel Dörfler convert_from_16_to_24(uint8* in, uint8* out, int32 inRowBytes) 324d8e2fb50SAxel Dörfler { 325d8e2fb50SAxel Dörfler int32 index = 0; 326d8e2fb50SAxel Dörfler int32 index2 = 0; 327d8e2fb50SAxel Dörfler int16 in_pixel; 3289e34f742SAxel Dörfler while (index < inRowBytes) { 329d8e2fb50SAxel Dörfler in_pixel = in[index] | (in[index+1] << 8); 330d8e2fb50SAxel Dörfler index += 2; 331d8e2fb50SAxel Dörfler 332d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0xf800)) >> 8) | (((in_pixel & 0xf800)) >> 13); 333d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x7e0)) >> 3) | (((in_pixel & 0x7e0)) >> 9); 334d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2); 335d8e2fb50SAxel Dörfler } 336d8e2fb50SAxel Dörfler } 337d8e2fb50SAxel Dörfler 338d8e2fb50SAxel Dörfler 339d8e2fb50SAxel Dörfler inline void 3409e34f742SAxel Dörfler convert_from_16b_to_24(uint8* in, uint8* out, int32 inRowBytes) 341d8e2fb50SAxel Dörfler { 342d8e2fb50SAxel Dörfler int32 index = 0; 343d8e2fb50SAxel Dörfler int32 index2 = 0; 344d8e2fb50SAxel Dörfler int16 in_pixel; 3459e34f742SAxel Dörfler while (index < inRowBytes) { 346d8e2fb50SAxel Dörfler in_pixel = in[index+1] | (in[index] << 8); 347d8e2fb50SAxel Dörfler index += 2; 348d8e2fb50SAxel Dörfler 349d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0xf800)) >> 8) | (((in_pixel & 0xf800)) >> 13); 350d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x7e0)) >> 3) | (((in_pixel & 0x7e0)) >> 9); 351d8e2fb50SAxel Dörfler out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2); 352d8e2fb50SAxel Dörfler } 353d8e2fb50SAxel Dörfler } 354d8e2fb50SAxel Dörfler 355d8e2fb50SAxel Dörfler 356d8e2fb50SAxel Dörfler inline void 3579e34f742SAxel Dörfler convert_from_24_to_24(uint8* in, uint8* out, int32 inRowBytes) 358d8e2fb50SAxel Dörfler { 359d8e2fb50SAxel Dörfler int32 index = 0; 360d8e2fb50SAxel Dörfler int32 index2 = 0; 3619e34f742SAxel Dörfler while (index < inRowBytes) { 362d8e2fb50SAxel Dörfler out[index2++] = in[index+2]; 363d8e2fb50SAxel Dörfler out[index2++] = in[index+1]; 364d8e2fb50SAxel Dörfler out[index2++] = in[index]; 365d8e2fb50SAxel Dörfler index+=3; 366d8e2fb50SAxel Dörfler } 367d8e2fb50SAxel Dörfler } 368d8e2fb50SAxel Dörfler 369d8e2fb50SAxel Dörfler 370d8e2fb50SAxel Dörfler inline void 3719e34f742SAxel Dörfler convert_from_32_to_24(uint8* in, uint8* out, int32 inRowBytes) 372d8e2fb50SAxel Dörfler { 37351623681SAxel Dörfler inRowBytes /= 4; 37451623681SAxel Dörfler 3759e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i++) { 3769e34f742SAxel Dörfler out[0] = in[2]; 3779e34f742SAxel Dörfler out[1] = in[1]; 3789e34f742SAxel Dörfler out[2] = in[0]; 3799e34f742SAxel Dörfler 3809e34f742SAxel Dörfler in += 4; 3819e34f742SAxel Dörfler out += 3; 382d8e2fb50SAxel Dörfler } 383d8e2fb50SAxel Dörfler } 384d8e2fb50SAxel Dörfler 385d8e2fb50SAxel Dörfler 386d8e2fb50SAxel Dörfler inline void 3879e34f742SAxel Dörfler convert_from_32b_to_24(uint8* in, uint8* out, int32 inRowBytes) 388d8e2fb50SAxel Dörfler { 38951623681SAxel Dörfler inRowBytes /= 4; 39051623681SAxel Dörfler 3919e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i++) { 39251623681SAxel Dörfler out[0] = in[1]; 39351623681SAxel Dörfler out[1] = in[2]; 39451623681SAxel Dörfler out[2] = in[3]; 3959e34f742SAxel Dörfler 3969e34f742SAxel Dörfler in += 4; 3979e34f742SAxel Dörfler out += 3; 398d8e2fb50SAxel Dörfler } 399d8e2fb50SAxel Dörfler } 400d8e2fb50SAxel Dörfler 401d8e2fb50SAxel Dörfler 4029e34f742SAxel Dörfler // #pragma mark - conversion for decompression 4039e34f742SAxel Dörfler 4049e34f742SAxel Dörfler 405d8e2fb50SAxel Dörfler inline void 4069e34f742SAxel Dörfler convert_from_CMYK_to_32_photoshop(uint8* in, uint8* out, int32 inRowBytes, int32 xStep) 407d8e2fb50SAxel Dörfler { 4089e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i += 4) { 4099e34f742SAxel Dörfler int32 black = in[3]; 4109e34f742SAxel Dörfler out[0] = in[2] * black / 255; 4119e34f742SAxel Dörfler out[1] = in[1] * black / 255; 4129e34f742SAxel Dörfler out[2] = in[0] * black / 255; 4139e34f742SAxel Dörfler out[3] = 255; 4149e34f742SAxel Dörfler 4159e34f742SAxel Dörfler in += 4; 4169e34f742SAxel Dörfler out += xStep; 417d8e2fb50SAxel Dörfler } 418d8e2fb50SAxel Dörfler } 419d8e2fb50SAxel Dörfler 420d8e2fb50SAxel Dörfler 421d8e2fb50SAxel Dörfler //! !!! UNTESTED !!! 422d8e2fb50SAxel Dörfler inline void 4239e34f742SAxel Dörfler convert_from_CMYK_to_32(uint8* in, uint8* out, int32 inRowBytes, int32 xStep) 424d8e2fb50SAxel Dörfler { 4259e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i += 4) { 4269e34f742SAxel Dörfler int32 black = 255 - in[3]; 4279e34f742SAxel Dörfler out[0] = ((255 - in[2]) * black) / 255; 4289e34f742SAxel Dörfler out[1] = ((255 - in[1]) * black) / 255; 4299e34f742SAxel Dörfler out[2] = ((255 - in[0]) * black) / 255; 4309e34f742SAxel Dörfler out[3] = 255; 4319e34f742SAxel Dörfler 4329e34f742SAxel Dörfler in += 4; 4339e34f742SAxel Dörfler out += xStep; 434d8e2fb50SAxel Dörfler } 435d8e2fb50SAxel Dörfler } 436d8e2fb50SAxel Dörfler 437d8e2fb50SAxel Dörfler 438d8e2fb50SAxel Dörfler //! RGB24 8:8:8 to xRGB 8:8:8:8 439d8e2fb50SAxel Dörfler inline void 4409e34f742SAxel Dörfler convert_from_24_to_32(uint8* in, uint8* out, int32 inRowBytes, int32 xStep) 441d8e2fb50SAxel Dörfler { 4429e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i += 3) { 4439e34f742SAxel Dörfler out[0] = in[2]; 4449e34f742SAxel Dörfler out[1] = in[1]; 4459e34f742SAxel Dörfler out[2] = in[0]; 4469e34f742SAxel Dörfler out[3] = 255; 4479e34f742SAxel Dörfler 4489e34f742SAxel Dörfler in += 3; 4499e34f742SAxel Dörfler out += xStep; 4509e34f742SAxel Dörfler } 4519e34f742SAxel Dörfler } 4529e34f742SAxel Dörfler 4539e34f742SAxel Dörfler 4549e34f742SAxel Dörfler //! 8-bit to 8-bit, only need when rotating the image 4559e34f742SAxel Dörfler void 4569e34f742SAxel Dörfler translate_8(uint8* in, uint8* out, int32 inRowBytes, int32 xStep) 4579e34f742SAxel Dörfler { 4589e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i++) { 4599e34f742SAxel Dörfler out[0] = in[0]; 4609e34f742SAxel Dörfler 4619e34f742SAxel Dörfler in++; 4629e34f742SAxel Dörfler out += xStep; 463d8e2fb50SAxel Dörfler } 464d8e2fb50SAxel Dörfler } 465d8e2fb50SAxel Dörfler 466d8e2fb50SAxel Dörfler 4678687ff64SAxel Dörfler // #pragma mark - SView 4688687ff64SAxel Dörfler 4698687ff64SAxel Dörfler 4708687ff64SAxel Dörfler SView::SView(const char *name, float x, float y) 4718687ff64SAxel Dörfler : BView(BRect(x, y, x, y), name, B_FOLLOW_NONE, B_WILL_DRAW) 4728687ff64SAxel Dörfler { 4738687ff64SAxel Dörfler fPreferredWidth = 0; 4748687ff64SAxel Dörfler fPreferredHeight = 0; 4758687ff64SAxel Dörfler 4768687ff64SAxel Dörfler SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 4778687ff64SAxel Dörfler SetLowColor(ViewColor()); 4788687ff64SAxel Dörfler 4798687ff64SAxel Dörfler SetFont(be_plain_font); 4808687ff64SAxel Dörfler } 4818687ff64SAxel Dörfler 4828687ff64SAxel Dörfler 4838687ff64SAxel Dörfler void 4848687ff64SAxel Dörfler SView::GetPreferredSize(float* _width, float* _height) 4858687ff64SAxel Dörfler { 4868687ff64SAxel Dörfler if (_width) 4878687ff64SAxel Dörfler *_width = fPreferredWidth; 4888687ff64SAxel Dörfler if (_height) 4898687ff64SAxel Dörfler *_height = fPreferredHeight; 4908687ff64SAxel Dörfler } 4918687ff64SAxel Dörfler 4928687ff64SAxel Dörfler 4938687ff64SAxel Dörfler void 4948687ff64SAxel Dörfler SView::ResizeToPreferred() 4958687ff64SAxel Dörfler { 4968687ff64SAxel Dörfler ResizeTo(fPreferredWidth, fPreferredHeight); 4978687ff64SAxel Dörfler } 4988687ff64SAxel Dörfler 4998687ff64SAxel Dörfler 5008687ff64SAxel Dörfler void 5018687ff64SAxel Dörfler SView::ResizePreferredBy(float width, float height) 5028687ff64SAxel Dörfler { 5038687ff64SAxel Dörfler fPreferredWidth += width; 5048687ff64SAxel Dörfler fPreferredHeight += height; 5058687ff64SAxel Dörfler } 5068687ff64SAxel Dörfler 5078687ff64SAxel Dörfler 5088687ff64SAxel Dörfler void 509f9810471SAxel Dörfler SView::AddChild(BView *child, BView *before) 5108687ff64SAxel Dörfler { 5118687ff64SAxel Dörfler BView::AddChild(child, before); 5128687ff64SAxel Dörfler child->ResizeToPreferred(); 5138687ff64SAxel Dörfler BRect frame = child->Frame(); 5148687ff64SAxel Dörfler 5158687ff64SAxel Dörfler if (frame.right > fPreferredWidth) 5168687ff64SAxel Dörfler fPreferredWidth = frame.right; 5178687ff64SAxel Dörfler if (frame.bottom > fPreferredHeight) 5188687ff64SAxel Dörfler fPreferredHeight = frame.bottom; 5198687ff64SAxel Dörfler } 5208687ff64SAxel Dörfler 5218687ff64SAxel Dörfler 522d8e2fb50SAxel Dörfler // #pragma mark - 523d8e2fb50SAxel Dörfler 524d8e2fb50SAxel Dörfler 525d8e2fb50SAxel Dörfler SSlider::SSlider(BRect frame, const char *name, const char *label, 526d8e2fb50SAxel Dörfler BMessage *message, int32 minValue, int32 maxValue, orientation posture, 527d8e2fb50SAxel Dörfler thumb_style thumbType, uint32 resizingMode, uint32 flags) 528d8e2fb50SAxel Dörfler : BSlider(frame, name, label, message, minValue, maxValue, 529d8e2fb50SAxel Dörfler posture, thumbType, resizingMode, flags) 5309949213aSStephan Aßmus { 5318687ff64SAxel Dörfler rgb_color barColor = { 0, 0, 229, 255 }; 5328687ff64SAxel Dörfler UseFillColor(true, &barColor); 5339949213aSStephan Aßmus } 5349949213aSStephan Aßmus 5358687ff64SAxel Dörfler 5368687ff64SAxel Dörfler //! Update status string - show actual value 5379949213aSStephan Aßmus char* 5389949213aSStephan Aßmus SSlider::UpdateText() const 5399949213aSStephan Aßmus { 5408687ff64SAxel Dörfler snprintf(fStatusLabel, sizeof(fStatusLabel), "%ld", Value()); 5418687ff64SAxel Dörfler return fStatusLabel; 5429949213aSStephan Aßmus } 5439949213aSStephan Aßmus 5448687ff64SAxel Dörfler 5458687ff64SAxel Dörfler //! BSlider::ResizeToPreferred + Resize width if it's too small to show label and status 5469949213aSStephan Aßmus void 5479949213aSStephan Aßmus SSlider::ResizeToPreferred() 5489949213aSStephan Aßmus { 5499949213aSStephan Aßmus int32 width = (int32)ceil(StringWidth(Label()) + StringWidth("9999")); 5508687ff64SAxel Dörfler if (width < 230) 5518687ff64SAxel Dörfler width = 230; 5528687ff64SAxel Dörfler 5539949213aSStephan Aßmus float w, h; 5549949213aSStephan Aßmus GetPreferredSize(&w, &h); 5559949213aSStephan Aßmus ResizeTo(width, h); 5569949213aSStephan Aßmus } 5579949213aSStephan Aßmus 5589949213aSStephan Aßmus 559d8e2fb50SAxel Dörfler // #pragma mark - 5609949213aSStephan Aßmus 561d8e2fb50SAxel Dörfler 562d8e2fb50SAxel Dörfler TranslatorReadView::TranslatorReadView(const char *name, jpeg_settings *settings, 563d8e2fb50SAxel Dörfler float x, float y) 5649949213aSStephan Aßmus : SView(name, x, y), 565d8e2fb50SAxel Dörfler fSettings(settings) 5669949213aSStephan Aßmus { 5678687ff64SAxel Dörfler fAlwaysRGB32 = new BCheckBox(BRect(10, GetPreferredHeight(), 10, 568d8e2fb50SAxel Dörfler GetPreferredHeight()), "alwaysrgb32", VIEW_LABEL_ALWAYSRGB32, 569d8e2fb50SAxel Dörfler new BMessage(VIEW_MSG_SET_ALWAYSRGB32)); 5708687ff64SAxel Dörfler fAlwaysRGB32->SetFont(be_plain_font); 571d8e2fb50SAxel Dörfler if (fSettings->Always_B_RGB32) 5728687ff64SAxel Dörfler fAlwaysRGB32->SetValue(1); 5739949213aSStephan Aßmus 5748687ff64SAxel Dörfler AddChild(fAlwaysRGB32); 5759949213aSStephan Aßmus 5768687ff64SAxel Dörfler fPhotoshopCMYK = new BCheckBox(BRect(10, GetPreferredHeight(), 10, 5778687ff64SAxel Dörfler GetPreferredHeight()), "photoshopCMYK", VIEW_LABEL_PHOTOSHOPCMYK, 5788687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_PHOTOSHOPCMYK)); 5798687ff64SAxel Dörfler fPhotoshopCMYK->SetFont(be_plain_font); 580d8e2fb50SAxel Dörfler if (fSettings->PhotoshopCMYK) 5818687ff64SAxel Dörfler fPhotoshopCMYK->SetValue(1); 5829949213aSStephan Aßmus 5838687ff64SAxel Dörfler AddChild(fPhotoshopCMYK); 5849949213aSStephan Aßmus 5858687ff64SAxel Dörfler fShowErrorBox = new BCheckBox(BRect(10, GetPreferredHeight(), 10, 5868687ff64SAxel Dörfler GetPreferredHeight()), "error", VIEW_LABEL_SHOWREADERRORBOX, 5878687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_SHOWREADERRORBOX)); 5888687ff64SAxel Dörfler fShowErrorBox->SetFont(be_plain_font); 589d8e2fb50SAxel Dörfler if (fSettings->ShowReadWarningBox) 5908687ff64SAxel Dörfler fShowErrorBox->SetValue(1); 5919949213aSStephan Aßmus 5928687ff64SAxel Dörfler AddChild(fShowErrorBox); 5939949213aSStephan Aßmus 5949949213aSStephan Aßmus ResizeToPreferred(); 5959949213aSStephan Aßmus } 5969949213aSStephan Aßmus 5978687ff64SAxel Dörfler 5989949213aSStephan Aßmus void 5999949213aSStephan Aßmus TranslatorReadView::AttachedToWindow() 6009949213aSStephan Aßmus { 6018687ff64SAxel Dörfler fAlwaysRGB32->SetTarget(this); 6028687ff64SAxel Dörfler fPhotoshopCMYK->SetTarget(this); 6038687ff64SAxel Dörfler fShowErrorBox->SetTarget(this); 6049949213aSStephan Aßmus } 6059949213aSStephan Aßmus 6068687ff64SAxel Dörfler 6079949213aSStephan Aßmus void 6089949213aSStephan Aßmus TranslatorReadView::MessageReceived(BMessage* message) 6099949213aSStephan Aßmus { 6108687ff64SAxel Dörfler switch (message->what) { 6119949213aSStephan Aßmus case VIEW_MSG_SET_ALWAYSRGB32: 6129949213aSStephan Aßmus { 6139949213aSStephan Aßmus int32 value; 6149949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 615d8e2fb50SAxel Dörfler fSettings->Always_B_RGB32 = value; 616d8e2fb50SAxel Dörfler SaveSettings(fSettings); 6179949213aSStephan Aßmus } 6189949213aSStephan Aßmus break; 6199949213aSStephan Aßmus } 6209949213aSStephan Aßmus case VIEW_MSG_SET_PHOTOSHOPCMYK: 6219949213aSStephan Aßmus { 6229949213aSStephan Aßmus int32 value; 6239949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 624d8e2fb50SAxel Dörfler fSettings->PhotoshopCMYK = value; 625d8e2fb50SAxel Dörfler SaveSettings(fSettings); 6269949213aSStephan Aßmus } 6279949213aSStephan Aßmus break; 6289949213aSStephan Aßmus } 6299949213aSStephan Aßmus case VIEW_MSG_SET_SHOWREADERRORBOX: 6309949213aSStephan Aßmus { 6319949213aSStephan Aßmus int32 value; 6329949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 633d8e2fb50SAxel Dörfler fSettings->ShowReadWarningBox = value; 634d8e2fb50SAxel Dörfler SaveSettings(fSettings); 6359949213aSStephan Aßmus } 6369949213aSStephan Aßmus break; 6379949213aSStephan Aßmus } 6389949213aSStephan Aßmus default: 6399949213aSStephan Aßmus BView::MessageReceived(message); 6409949213aSStephan Aßmus break; 6419949213aSStephan Aßmus } 6429949213aSStephan Aßmus } 6439949213aSStephan Aßmus 6449949213aSStephan Aßmus 6458687ff64SAxel Dörfler // #pragma mark - TranslatorWriteView 6469949213aSStephan Aßmus 6478687ff64SAxel Dörfler 6488687ff64SAxel Dörfler TranslatorWriteView::TranslatorWriteView(const char *name, jpeg_settings *settings, 6498687ff64SAxel Dörfler float x, float y) 6509949213aSStephan Aßmus : SView(name, x, y), 651d8e2fb50SAxel Dörfler fSettings(settings) 6529949213aSStephan Aßmus { 6538687ff64SAxel Dörfler fQualitySlider = new SSlider(BRect(10, GetPreferredHeight(), 10, 6548687ff64SAxel Dörfler GetPreferredHeight()), "quality", VIEW_LABEL_QUALITY, 6558687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_QUALITY), 0, 100); 6568687ff64SAxel Dörfler fQualitySlider->SetHashMarks(B_HASH_MARKS_BOTTOM); 6578687ff64SAxel Dörfler fQualitySlider->SetHashMarkCount(10); 6588687ff64SAxel Dörfler fQualitySlider->SetLimitLabels("Low", "High"); 6598687ff64SAxel Dörfler fQualitySlider->SetFont(be_plain_font); 6608687ff64SAxel Dörfler fQualitySlider->SetValue(fSettings->Quality); 6618687ff64SAxel Dörfler AddChild(fQualitySlider); 6629949213aSStephan Aßmus 6638687ff64SAxel Dörfler fSmoothingSlider = new SSlider(BRect(10, GetPreferredHeight()+10, 10, 6648687ff64SAxel Dörfler GetPreferredHeight()), "smoothing", VIEW_LABEL_SMOOTHING, 6658687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_SMOOTHING), 0, 100); 6668687ff64SAxel Dörfler fSmoothingSlider->SetHashMarks(B_HASH_MARKS_BOTTOM); 6678687ff64SAxel Dörfler fSmoothingSlider->SetHashMarkCount(10); 6688687ff64SAxel Dörfler fSmoothingSlider->SetLimitLabels("None", "High"); 6698687ff64SAxel Dörfler fSmoothingSlider->SetFont(be_plain_font); 6708687ff64SAxel Dörfler fSmoothingSlider->SetValue(fSettings->Smoothing); 6718687ff64SAxel Dörfler AddChild(fSmoothingSlider); 6729949213aSStephan Aßmus 6738687ff64SAxel Dörfler fProgress = new BCheckBox(BRect(10, GetPreferredHeight()+10, 10, 6748687ff64SAxel Dörfler GetPreferredHeight()), "progress", VIEW_LABEL_PROGRESSIVE, 6758687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_PROGRESSIVE)); 6768687ff64SAxel Dörfler fProgress->SetFont(be_plain_font); 677d8e2fb50SAxel Dörfler if (fSettings->Progressive) 6788687ff64SAxel Dörfler fProgress->SetValue(1); 6799949213aSStephan Aßmus 6808687ff64SAxel Dörfler AddChild(fProgress); 6819949213aSStephan Aßmus 6828687ff64SAxel Dörfler fOptimizeColors = new BCheckBox(BRect(10, GetPreferredHeight()+5, 10, 6838687ff64SAxel Dörfler GetPreferredHeight() + 5), "optimizecolors", VIEW_LABEL_OPTIMIZECOLORS, 6848687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_OPTIMIZECOLORS)); 6858687ff64SAxel Dörfler fOptimizeColors->SetFont(be_plain_font); 686d8e2fb50SAxel Dörfler if (fSettings->OptimizeColors) 6878687ff64SAxel Dörfler fOptimizeColors->SetValue(1); 6889949213aSStephan Aßmus 6898687ff64SAxel Dörfler AddChild(fOptimizeColors); 6909949213aSStephan Aßmus 6918687ff64SAxel Dörfler fSmallerFile = new BCheckBox(BRect(25, GetPreferredHeight()+5, 25, 6928687ff64SAxel Dörfler GetPreferredHeight() + 5), "smallerfile", VIEW_LABEL_SMALLERFILE, 6938687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_SMALLERFILE)); 6948687ff64SAxel Dörfler fSmallerFile->SetFont(be_plain_font); 695d8e2fb50SAxel Dörfler if (fSettings->SmallerFile) 6968687ff64SAxel Dörfler fSmallerFile->SetValue(1); 697d8e2fb50SAxel Dörfler if (!fSettings->OptimizeColors) 6988687ff64SAxel Dörfler fSmallerFile->SetEnabled(false); 6999949213aSStephan Aßmus 7008687ff64SAxel Dörfler AddChild(fSmallerFile); 7019949213aSStephan Aßmus 7028687ff64SAxel Dörfler fGrayAsRGB24 = new BCheckBox(BRect(10, GetPreferredHeight()+5, 25, 7038687ff64SAxel Dörfler GetPreferredHeight()+5), "gray1asrgb24", VIEW_LABEL_GRAY1ASRGB24, 7048687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_GRAY1ASRGB24)); 7058687ff64SAxel Dörfler fGrayAsRGB24->SetFont(be_plain_font); 706d8e2fb50SAxel Dörfler if (fSettings->B_GRAY1_as_B_RGB24) 7078687ff64SAxel Dörfler fGrayAsRGB24->SetValue(1); 7089949213aSStephan Aßmus 7098687ff64SAxel Dörfler AddChild(fGrayAsRGB24); 7109949213aSStephan Aßmus 7119949213aSStephan Aßmus ResizeToPreferred(); 7129949213aSStephan Aßmus } 7139949213aSStephan Aßmus 7148687ff64SAxel Dörfler 7159949213aSStephan Aßmus void 7169949213aSStephan Aßmus TranslatorWriteView::AttachedToWindow() 7179949213aSStephan Aßmus { 7188687ff64SAxel Dörfler fQualitySlider->SetTarget(this); 7198687ff64SAxel Dörfler fSmoothingSlider->SetTarget(this); 7208687ff64SAxel Dörfler fProgress->SetTarget(this); 7218687ff64SAxel Dörfler fOptimizeColors->SetTarget(this); 7228687ff64SAxel Dörfler fSmallerFile->SetTarget(this); 7238687ff64SAxel Dörfler fGrayAsRGB24->SetTarget(this); 7249949213aSStephan Aßmus } 7259949213aSStephan Aßmus 7268687ff64SAxel Dörfler 7279949213aSStephan Aßmus void 7289949213aSStephan Aßmus TranslatorWriteView::MessageReceived(BMessage *message) 7299949213aSStephan Aßmus { 7308687ff64SAxel Dörfler switch (message->what) { 7319949213aSStephan Aßmus case VIEW_MSG_SET_QUALITY: 7329949213aSStephan Aßmus { 7339949213aSStephan Aßmus int32 value; 7349949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 735d8e2fb50SAxel Dörfler fSettings->Quality = value; 736d8e2fb50SAxel Dörfler SaveSettings(fSettings); 7379949213aSStephan Aßmus } 7389949213aSStephan Aßmus break; 7399949213aSStephan Aßmus } 7409949213aSStephan Aßmus case VIEW_MSG_SET_SMOOTHING: 7419949213aSStephan Aßmus { 7429949213aSStephan Aßmus int32 value; 7439949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 744d8e2fb50SAxel Dörfler fSettings->Smoothing = value; 745d8e2fb50SAxel Dörfler SaveSettings(fSettings); 7469949213aSStephan Aßmus } 7479949213aSStephan Aßmus break; 7489949213aSStephan Aßmus } 7499949213aSStephan Aßmus case VIEW_MSG_SET_PROGRESSIVE: 7509949213aSStephan Aßmus { 7519949213aSStephan Aßmus int32 value; 7529949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 753d8e2fb50SAxel Dörfler fSettings->Progressive = value; 754d8e2fb50SAxel Dörfler SaveSettings(fSettings); 7559949213aSStephan Aßmus } 7569949213aSStephan Aßmus break; 7579949213aSStephan Aßmus } 7589949213aSStephan Aßmus case VIEW_MSG_SET_OPTIMIZECOLORS: 7599949213aSStephan Aßmus { 7609949213aSStephan Aßmus int32 value; 7619949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 762d8e2fb50SAxel Dörfler fSettings->OptimizeColors = value; 763d8e2fb50SAxel Dörfler SaveSettings(fSettings); 7649949213aSStephan Aßmus } 7658687ff64SAxel Dörfler fSmallerFile->SetEnabled(fSettings->OptimizeColors); 7669949213aSStephan Aßmus break; 7679949213aSStephan Aßmus } 7689949213aSStephan Aßmus case VIEW_MSG_SET_SMALLERFILE: 7699949213aSStephan Aßmus { 7709949213aSStephan Aßmus int32 value; 7719949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 772d8e2fb50SAxel Dörfler fSettings->SmallerFile = value; 773d8e2fb50SAxel Dörfler SaveSettings(fSettings); 7749949213aSStephan Aßmus } 7759949213aSStephan Aßmus break; 7769949213aSStephan Aßmus } 7779949213aSStephan Aßmus case VIEW_MSG_SET_GRAY1ASRGB24: 7789949213aSStephan Aßmus { 7799949213aSStephan Aßmus int32 value; 7809949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 781d8e2fb50SAxel Dörfler fSettings->B_GRAY1_as_B_RGB24 = value; 782d8e2fb50SAxel Dörfler SaveSettings(fSettings); 7839949213aSStephan Aßmus } 7849949213aSStephan Aßmus break; 7859949213aSStephan Aßmus } 7869949213aSStephan Aßmus default: 7879949213aSStephan Aßmus BView::MessageReceived(message); 7889949213aSStephan Aßmus break; 7899949213aSStephan Aßmus } 7909949213aSStephan Aßmus } 7919949213aSStephan Aßmus 7929949213aSStephan Aßmus 793d8e2fb50SAxel Dörfler // #pragma mark - 7949949213aSStephan Aßmus 795d8e2fb50SAxel Dörfler 7969949213aSStephan Aßmus TranslatorAboutView::TranslatorAboutView(const char *name, float x, float y) 7979949213aSStephan Aßmus : SView(name, x, y) 7989949213aSStephan Aßmus { 7998687ff64SAxel Dörfler BStringView *title = new BStringView(BRect(10, 0, 10, 0), "Title", 8008687ff64SAxel Dörfler translatorName); 8019949213aSStephan Aßmus title->SetFont(be_bold_font); 8029949213aSStephan Aßmus 8039949213aSStephan Aßmus AddChild(title); 8049949213aSStephan Aßmus 8059949213aSStephan Aßmus BRect rect = title->Bounds(); 8069949213aSStephan Aßmus float space = title->StringWidth(" "); 8079949213aSStephan Aßmus 8089949213aSStephan Aßmus char versionString[16]; 809d8e2fb50SAxel Dörfler sprintf(versionString, "v%d.%d.%d", (int)(translatorVersion >> 8), 810d8e2fb50SAxel Dörfler (int)((translatorVersion >> 4) & 0xf), (int)(translatorVersion & 0xf)); 8119949213aSStephan Aßmus 812d8e2fb50SAxel Dörfler BStringView *version = new BStringView(BRect(rect.right+space, rect.top, 813d8e2fb50SAxel Dörfler rect.right+space, rect.top), "Version", versionString); 8149949213aSStephan Aßmus version->SetFont(be_plain_font); 8159949213aSStephan Aßmus version->SetFontSize(9); 8169949213aSStephan Aßmus // Make version be in the same line as title 8179949213aSStephan Aßmus version->ResizeToPreferred(); 8189949213aSStephan Aßmus version->MoveBy(0, rect.bottom-version->Frame().bottom); 8199949213aSStephan Aßmus 8209949213aSStephan Aßmus AddChild(version); 8219949213aSStephan Aßmus 8228687ff64SAxel Dörfler // Now for each line in translatorInfo add a BStringView 8238687ff64SAxel Dörfler char* current = translatorInfo; 8248687ff64SAxel Dörfler int32 index = 1; 8258687ff64SAxel Dörfler while (current != NULL && current[0]) { 8268687ff64SAxel Dörfler char text[128]; 8278687ff64SAxel Dörfler char* newLine = strchr(current, '\n'); 8288687ff64SAxel Dörfler if (newLine == NULL) { 8298687ff64SAxel Dörfler strlcpy(text, current, sizeof(text)); 8308687ff64SAxel Dörfler current = NULL; 8318687ff64SAxel Dörfler } else { 8328687ff64SAxel Dörfler strlcpy(text, current, min_c((int32)sizeof(text), newLine + 1 - current)); 8338687ff64SAxel Dörfler current = newLine + 1; 8348687ff64SAxel Dörfler } 8359949213aSStephan Aßmus 8368687ff64SAxel Dörfler BStringView* string = new BStringView(BRect(10, GetPreferredHeight(), 8378687ff64SAxel Dörfler 10, GetPreferredHeight()), "copyright", text); 8388687ff64SAxel Dörfler if (index > 3) 8398687ff64SAxel Dörfler string->SetFontSize(9); 8408687ff64SAxel Dörfler AddChild(string); 8418687ff64SAxel Dörfler 8428687ff64SAxel Dörfler index++; 8439949213aSStephan Aßmus } 8449949213aSStephan Aßmus 8459949213aSStephan Aßmus ResizeToPreferred(); 8469949213aSStephan Aßmus } 8479949213aSStephan Aßmus 8489949213aSStephan Aßmus 849d8e2fb50SAxel Dörfler // #pragma mark - 8509949213aSStephan Aßmus 851d8e2fb50SAxel Dörfler 8529949213aSStephan Aßmus TranslatorView::TranslatorView(const char *name) 853d8e2fb50SAxel Dörfler : SView(name), 854d8e2fb50SAxel Dörfler fTabWidth(30), 855d8e2fb50SAxel Dörfler fActiveChild(0) 8569949213aSStephan Aßmus { 8579949213aSStephan Aßmus // Set global var to true 858d8e2fb50SAxel Dörfler gAreSettingsRunning = true; 8599949213aSStephan Aßmus 860d8e2fb50SAxel Dörfler // Load settings to global settings struct 861d8e2fb50SAxel Dörfler LoadSettings(&fSettings); 8629949213aSStephan Aßmus 8638687ff64SAxel Dörfler font_height fontHeight; 8648687ff64SAxel Dörfler GetFontHeight(&fontHeight); 8658687ff64SAxel Dörfler fTabHeight = (int32)ceilf(fontHeight.ascent + fontHeight.descent + fontHeight.leading) + 7; 8669949213aSStephan Aßmus // Add left and top margins 8678687ff64SAxel Dörfler float top = fTabHeight + 20; 8689949213aSStephan Aßmus float left = 0; 8699949213aSStephan Aßmus 8709949213aSStephan Aßmus // This will remember longest string width 8719949213aSStephan Aßmus int32 nameWidth = 0; 8729949213aSStephan Aßmus 873d8e2fb50SAxel Dörfler SView *view = new TranslatorWriteView("Write", &fSettings, left, top); 8749949213aSStephan Aßmus AddChild(view); 875d8e2fb50SAxel Dörfler nameWidth = (int32)StringWidth(view->Name()); 8768687ff64SAxel Dörfler fTabs.AddItem(new BTab(view)); 8779949213aSStephan Aßmus 878d8e2fb50SAxel Dörfler view = new TranslatorReadView("Read", &fSettings, left, top); 8799949213aSStephan Aßmus AddChild(view); 8809949213aSStephan Aßmus if (nameWidth < StringWidth(view->Name())) 881d8e2fb50SAxel Dörfler nameWidth = (int32)StringWidth(view->Name()); 8828687ff64SAxel Dörfler fTabs.AddItem(new BTab(view)); 8839949213aSStephan Aßmus 8849949213aSStephan Aßmus view = new TranslatorAboutView("About", left, top); 8859949213aSStephan Aßmus AddChild(view); 8869949213aSStephan Aßmus if (nameWidth < StringWidth(view->Name())) 887d8e2fb50SAxel Dörfler nameWidth = (int32)StringWidth(view->Name()); 8888687ff64SAxel Dörfler fTabs.AddItem(new BTab(view)); 8899949213aSStephan Aßmus 890d8e2fb50SAxel Dörfler fTabWidth += nameWidth; 891d8e2fb50SAxel Dörfler if (fTabWidth * CountChildren() > GetPreferredWidth()) 892d8e2fb50SAxel Dörfler ResizePreferredBy((fTabWidth * CountChildren()) - GetPreferredWidth(), 0); 8939949213aSStephan Aßmus 8949949213aSStephan Aßmus // Add right and bottom margins 8959949213aSStephan Aßmus ResizePreferredBy(10, 15); 8969949213aSStephan Aßmus 8979949213aSStephan Aßmus ResizeToPreferred(); 8989949213aSStephan Aßmus 8999949213aSStephan Aßmus // Make TranslatorView resize itself with parent 9009949213aSStephan Aßmus SetFlags(Flags() | B_FOLLOW_ALL); 9019949213aSStephan Aßmus } 9029949213aSStephan Aßmus 903d8e2fb50SAxel Dörfler 904d8e2fb50SAxel Dörfler TranslatorView::~TranslatorView() 905d8e2fb50SAxel Dörfler { 906d8e2fb50SAxel Dörfler gAreSettingsRunning = false; 9078687ff64SAxel Dörfler 9088687ff64SAxel Dörfler BTab* tab; 9098687ff64SAxel Dörfler while ((tab = (BTab*)fTabs.RemoveItem((int32)0)) != NULL) { 9108687ff64SAxel Dörfler delete tab; 9118687ff64SAxel Dörfler } 912d8e2fb50SAxel Dörfler } 913d8e2fb50SAxel Dörfler 914d8e2fb50SAxel Dörfler 915d8e2fb50SAxel Dörfler //! Attached to window - resize parent to preferred 9169949213aSStephan Aßmus void 9179949213aSStephan Aßmus TranslatorView::AttachedToWindow() 9189949213aSStephan Aßmus { 9199949213aSStephan Aßmus // Hide all children except first one 920d8e2fb50SAxel Dörfler BView *child; 9219949213aSStephan Aßmus int32 index = 1; 922d8e2fb50SAxel Dörfler while ((child = ChildAt(index++)) != NULL) 9239949213aSStephan Aßmus child->Hide(); 9249949213aSStephan Aßmus 9258687ff64SAxel Dörfler } 9268687ff64SAxel Dörfler 9278687ff64SAxel Dörfler 9288687ff64SAxel Dörfler BRect 9298687ff64SAxel Dörfler TranslatorView::_TabFrame(int32 index) const 9308687ff64SAxel Dörfler { 9318687ff64SAxel Dörfler return BRect(index * fTabWidth, 10, (index + 1) * fTabWidth, 10 + fTabHeight); 9329949213aSStephan Aßmus } 9339949213aSStephan Aßmus 934d8e2fb50SAxel Dörfler 9359949213aSStephan Aßmus void 9369949213aSStephan Aßmus TranslatorView::Draw(BRect updateRect) 9379949213aSStephan Aßmus { 9389949213aSStephan Aßmus // This is needed because DataTranslations app hides children 9399949213aSStephan Aßmus // after user changes translator 940d8e2fb50SAxel Dörfler if (ChildAt(fActiveChild)->IsHidden()) 941d8e2fb50SAxel Dörfler ChildAt(fActiveChild)->Show(); 9429949213aSStephan Aßmus 9439949213aSStephan Aßmus // Clear 9449949213aSStephan Aßmus SetHighColor(ViewColor()); 9458687ff64SAxel Dörfler BRect frame = _TabFrame(0); 9468687ff64SAxel Dörfler FillRect(BRect(frame.left, frame.top, Bounds().right, frame.bottom - 1)); 9479949213aSStephan Aßmus 948d8e2fb50SAxel Dörfler int32 index = 0; 9498687ff64SAxel Dörfler BTab* tab; 9508687ff64SAxel Dörfler while ((tab = (BTab*)fTabs.ItemAt(index)) != NULL) { 9518687ff64SAxel Dörfler tab_position position; 9528687ff64SAxel Dörfler if (fActiveChild == index) 9538687ff64SAxel Dörfler position = B_TAB_FRONT; 9548687ff64SAxel Dörfler else if (index == 0) 9558687ff64SAxel Dörfler position = B_TAB_FIRST; 9569949213aSStephan Aßmus else 9578687ff64SAxel Dörfler position = B_TAB_ANY; 9589949213aSStephan Aßmus 9598687ff64SAxel Dörfler tab->DrawTab(this, _TabFrame(index), position, index + 1 != fActiveChild); 9609949213aSStephan Aßmus index++; 9619949213aSStephan Aßmus } 962d8e2fb50SAxel Dörfler 9638687ff64SAxel Dörfler // Draw bottom edge 9648687ff64SAxel Dörfler SetHighColor(tint_color(ViewColor(), B_LIGHTEN_MAX_TINT)); 9658687ff64SAxel Dörfler 9668687ff64SAxel Dörfler BRect selectedFrame = _TabFrame(fActiveChild); 9678687ff64SAxel Dörfler float offset = ceilf(frame.Height() / 2.0); 9688687ff64SAxel Dörfler 9698687ff64SAxel Dörfler if (selectedFrame.left > frame.left) { 9708687ff64SAxel Dörfler StrokeLine(BPoint(frame.left, frame.bottom), 9718687ff64SAxel Dörfler BPoint(selectedFrame.left, frame.bottom)); 9728687ff64SAxel Dörfler } 9738687ff64SAxel Dörfler if (selectedFrame.right + offset < Bounds().right) { 9748687ff64SAxel Dörfler StrokeLine(BPoint(selectedFrame.right + offset, frame.bottom), 9758687ff64SAxel Dörfler BPoint(Bounds().right, frame.bottom)); 9768687ff64SAxel Dörfler } 9779949213aSStephan Aßmus } 9789949213aSStephan Aßmus 979d8e2fb50SAxel Dörfler 980d8e2fb50SAxel Dörfler //! MouseDown, check if on tab, if so change tab if needed 9819949213aSStephan Aßmus void 9829949213aSStephan Aßmus TranslatorView::MouseDown(BPoint where) 9839949213aSStephan Aßmus { 9848687ff64SAxel Dörfler BRect frame = _TabFrame(fTabs.CountItems() - 1); 9858687ff64SAxel Dörfler frame.left = 0; 9868687ff64SAxel Dörfler if (!frame.Contains(where)) 9878687ff64SAxel Dörfler return; 9888687ff64SAxel Dörfler 9898687ff64SAxel Dörfler for (int32 index = fTabs.CountItems(); index-- > 0;) { 9908687ff64SAxel Dörfler if (!_TabFrame(index).Contains(where)) 9918687ff64SAxel Dörfler continue; 9928687ff64SAxel Dörfler 993d8e2fb50SAxel Dörfler if (fActiveChild != index) { 9949949213aSStephan Aßmus // Hide current visible child 995d8e2fb50SAxel Dörfler ChildAt(fActiveChild)->Hide(); 9968687ff64SAxel Dörfler 9979949213aSStephan Aßmus // This loop is needed because it looks like in DataTranslations 9989949213aSStephan Aßmus // view gets hidden more than one time when user changes translator 9998687ff64SAxel Dörfler while (ChildAt(index)->IsHidden()) { 10009949213aSStephan Aßmus ChildAt(index)->Show(); 10018687ff64SAxel Dörfler } 10028687ff64SAxel Dörfler 10039949213aSStephan Aßmus // Remember which one is currently visible 1004d8e2fb50SAxel Dörfler fActiveChild = index; 10058687ff64SAxel Dörfler Invalidate(frame); 10068687ff64SAxel Dörfler break; 10079949213aSStephan Aßmus } 10089949213aSStephan Aßmus } 1009d8e2fb50SAxel Dörfler } 10109949213aSStephan Aßmus 10119949213aSStephan Aßmus 1012d8e2fb50SAxel Dörfler // #pragma mark - 10139949213aSStephan Aßmus 1014d8e2fb50SAxel Dörfler 1015d8e2fb50SAxel Dörfler TranslatorWindow::TranslatorWindow(bool quitOnClose) 1016117da2d7SAxel Dörfler : BWindow(BRect(100, 100, 100, 100), "JPEG Settings", B_TITLED_WINDOW, 1017117da2d7SAxel Dörfler B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS) 10189949213aSStephan Aßmus { 10199949213aSStephan Aßmus BRect extent(0, 0, 0, 0); 10209949213aSStephan Aßmus BView *config = NULL; 10219949213aSStephan Aßmus MakeConfig(NULL, &config, &extent); 10229949213aSStephan Aßmus 10239949213aSStephan Aßmus AddChild(config); 10249949213aSStephan Aßmus ResizeTo(extent.Width(), extent.Height()); 10259949213aSStephan Aßmus 10269949213aSStephan Aßmus // Make application quit after this window close 1027d8e2fb50SAxel Dörfler if (quitOnClose) 10289949213aSStephan Aßmus SetFlags(Flags() | B_QUIT_ON_WINDOW_CLOSE); 10299949213aSStephan Aßmus } 10309949213aSStephan Aßmus 10319949213aSStephan Aßmus 1032d8e2fb50SAxel Dörfler // #pragma mark - Translator Add-On 10339949213aSStephan Aßmus 10349949213aSStephan Aßmus 10359949213aSStephan Aßmus 1036d8e2fb50SAxel Dörfler /*! Hook to create and return our configuration view */ 10379949213aSStephan Aßmus status_t 10389949213aSStephan Aßmus MakeConfig(BMessage *ioExtension, BView **outView, BRect *outExtent) 10399949213aSStephan Aßmus { 10409949213aSStephan Aßmus *outView = new TranslatorView("TranslatorView"); 10419949213aSStephan Aßmus *outExtent = (*outView)->Frame(); 10429949213aSStephan Aßmus return B_OK; 10439949213aSStephan Aßmus } 10449949213aSStephan Aßmus 1045d8e2fb50SAxel Dörfler /*! Determine whether or not we can handle this data */ 10469949213aSStephan Aßmus status_t 1047d8e2fb50SAxel Dörfler Identify(BPositionIO *inSource, const translation_format *inFormat, 1048d8e2fb50SAxel Dörfler BMessage *ioExtension, translator_info *outInfo, uint32 outType) 10499949213aSStephan Aßmus { 1050d8e2fb50SAxel Dörfler if (outType != 0 && outType != B_TRANSLATOR_BITMAP && outType != JPEG_FORMAT) 10519949213aSStephan Aßmus return B_NO_TRANSLATOR; 10529949213aSStephan Aßmus 10539949213aSStephan Aßmus // !!! You might need to make this buffer bigger to test for your native format 10549949213aSStephan Aßmus off_t position = inSource->Position(); 10559949213aSStephan Aßmus char header[sizeof(TranslatorBitmap)]; 10569949213aSStephan Aßmus status_t err = inSource->Read(header, sizeof(TranslatorBitmap)); 10579949213aSStephan Aßmus inSource->Seek(position, SEEK_SET); 1058d8e2fb50SAxel Dörfler if (err < B_OK) 1059d8e2fb50SAxel Dörfler return err; 10609949213aSStephan Aßmus 10619949213aSStephan Aßmus if (B_BENDIAN_TO_HOST_INT32(((TranslatorBitmap *)header)->magic) == B_TRANSLATOR_BITMAP) { 10629949213aSStephan Aßmus outInfo->type = inputFormats[1].type; 10639949213aSStephan Aßmus outInfo->translator = 0; 10649949213aSStephan Aßmus outInfo->group = inputFormats[1].group; 10659949213aSStephan Aßmus outInfo->quality = inputFormats[1].quality; 10669949213aSStephan Aßmus outInfo->capability = inputFormats[1].capability; 10679949213aSStephan Aßmus strcpy(outInfo->name, inputFormats[1].name); 10689949213aSStephan Aßmus strcpy(outInfo->MIME, inputFormats[1].MIME); 10699949213aSStephan Aßmus } else { 10709949213aSStephan Aßmus // First 3 bytes in jpg files are always the same from what i've seen so far 10719949213aSStephan Aßmus // check them 10729949213aSStephan Aßmus if (header[0] == (char)0xff && header[1] == (char)0xd8 && header[2] == (char)0xff) { 10739949213aSStephan Aßmus /* this below would be safer but it slows down whole thing 10749949213aSStephan Aßmus 10759949213aSStephan Aßmus struct jpeg_decompress_struct cinfo; 10769949213aSStephan Aßmus struct jpeg_error_mgr jerr; 10779949213aSStephan Aßmus cinfo.err = jpeg_std_error(&jerr); 10789949213aSStephan Aßmus jpeg_create_decompress(&cinfo); 10799949213aSStephan Aßmus be_jpeg_stdio_src(&cinfo, inSource); 10809949213aSStephan Aßmus // now try to read header 10819949213aSStephan Aßmus // it can't be read before checking first 3 bytes 10829949213aSStephan Aßmus // because it will hang up if there is no header (not jpeg file) 10839949213aSStephan Aßmus int result = jpeg_read_header(&cinfo, FALSE); 10849949213aSStephan Aßmus jpeg_destroy_decompress(&cinfo); 10859949213aSStephan Aßmus if (result == JPEG_HEADER_OK) { 10869949213aSStephan Aßmus */ outInfo->type = inputFormats[0].type; 10879949213aSStephan Aßmus outInfo->translator = 0; 10889949213aSStephan Aßmus outInfo->group = inputFormats[0].group; 10899949213aSStephan Aßmus outInfo->quality = inputFormats[0].quality; 10909949213aSStephan Aßmus outInfo->capability = inputFormats[0].capability; 10919949213aSStephan Aßmus strcpy(outInfo->name, inputFormats[0].name); 10929949213aSStephan Aßmus strcpy(outInfo->MIME, inputFormats[0].MIME); 10939949213aSStephan Aßmus return B_OK; 10949949213aSStephan Aßmus /* } else 10959949213aSStephan Aßmus return B_NO_TRANSLATOR; 10969949213aSStephan Aßmus */ 10979949213aSStephan Aßmus } else 10989949213aSStephan Aßmus return B_NO_TRANSLATOR; 10999949213aSStephan Aßmus } 11009949213aSStephan Aßmus 11019949213aSStephan Aßmus return B_OK; 11029949213aSStephan Aßmus } 11039949213aSStephan Aßmus 1104*dbc936acSStephan Aßmus static jmp_buf sLongJumpBuffer; 1105*dbc936acSStephan Aßmus jmp_buf* gLongJumpBuffer = &sLongJumpBuffer; 1106*dbc936acSStephan Aßmus 1107d8e2fb50SAxel Dörfler /*! Arguably the most important method in the add-on */ 11089949213aSStephan Aßmus status_t 1109d8e2fb50SAxel Dörfler Translate(BPositionIO *inSource, const translator_info *inInfo, 1110d8e2fb50SAxel Dörfler BMessage *ioExtension, uint32 outType, BPositionIO *outDestination) 11119949213aSStephan Aßmus { 11129949213aSStephan Aßmus // If no specific type was requested, convert to the interchange format 1113*dbc936acSStephan Aßmus if (outType == 0) 1114*dbc936acSStephan Aßmus outType = B_TRANSLATOR_BITMAP; 11159949213aSStephan Aßmus 1116*dbc936acSStephan Aßmus // Setup a "breakpoint" since throwing exceptions does not seem to work 1117*dbc936acSStephan Aßmus // at all in an add-on. (?) 1118*dbc936acSStephan Aßmus // In the be_jerror.cpp we implement a handler for critical library errors 1119*dbc936acSStephan Aßmus // (be_error_exit()) and there we use the longjmp() function to return to 1120*dbc936acSStephan Aßmus // this place. If this happens, it is as if the setjmp() call is called 1121*dbc936acSStephan Aßmus // a second time, but this time the return value will be 1. The first 1122*dbc936acSStephan Aßmus // invokation will return 0. 1123*dbc936acSStephan Aßmus int jmpRet = setjmp(sLongJumpBuffer); 1124*dbc936acSStephan Aßmus if (jmpRet == 1) 1125*dbc936acSStephan Aßmus return B_ERROR; 1126*dbc936acSStephan Aßmus 1127*dbc936acSStephan Aßmus try { 11289949213aSStephan Aßmus // What action to take, based on the findings of Identify() 11299949213aSStephan Aßmus if (outType == inInfo->type) { 11309949213aSStephan Aßmus return Copy(inSource, outDestination); 1131*dbc936acSStephan Aßmus } else if (inInfo->type == B_TRANSLATOR_BITMAP 1132*dbc936acSStephan Aßmus && outType == JPEG_FORMAT) { 11339949213aSStephan Aßmus return Compress(inSource, outDestination); 1134*dbc936acSStephan Aßmus } else if (inInfo->type == JPEG_FORMAT 1135*dbc936acSStephan Aßmus && outType == B_TRANSLATOR_BITMAP) { 113652e8f46aSAxel Dörfler return Decompress(inSource, outDestination, ioExtension); 11379949213aSStephan Aßmus } 1138*dbc936acSStephan Aßmus } catch (...) { 1139*dbc936acSStephan Aßmus fprintf(stderr, "libjpeg encoutered a critical error " 1140*dbc936acSStephan Aßmus "(caught C++ exception).\n"); 1141*dbc936acSStephan Aßmus return B_ERROR; 1142*dbc936acSStephan Aßmus } 11439949213aSStephan Aßmus 11449949213aSStephan Aßmus return B_NO_TRANSLATOR; 11459949213aSStephan Aßmus } 11469949213aSStephan Aßmus 1147d8e2fb50SAxel Dörfler /*! The user has requested the same format for input and output, so just copy */ 114852e8f46aSAxel Dörfler static status_t 11499949213aSStephan Aßmus Copy(BPositionIO *in, BPositionIO *out) 11509949213aSStephan Aßmus { 11519949213aSStephan Aßmus int block_size = 65536; 11529949213aSStephan Aßmus void *buffer = malloc(block_size); 11539949213aSStephan Aßmus char temp[1024]; 11549949213aSStephan Aßmus if (buffer == NULL) { 11559949213aSStephan Aßmus buffer = temp; 11569949213aSStephan Aßmus block_size = 1024; 11579949213aSStephan Aßmus } 11589949213aSStephan Aßmus status_t err = B_OK; 11599949213aSStephan Aßmus 11609949213aSStephan Aßmus // Read until end of file or error 11619949213aSStephan Aßmus while (1) { 11629949213aSStephan Aßmus ssize_t to_read = block_size; 11639949213aSStephan Aßmus err = in->Read(buffer, to_read); 11649949213aSStephan Aßmus // Explicit check for EOF 11659949213aSStephan Aßmus if (err == -1) { 11669949213aSStephan Aßmus if (buffer != temp) free(buffer); 11679949213aSStephan Aßmus return B_OK; 11689949213aSStephan Aßmus } 11699949213aSStephan Aßmus if (err <= B_OK) break; 11709949213aSStephan Aßmus to_read = err; 11719949213aSStephan Aßmus err = out->Write(buffer, to_read); 11729949213aSStephan Aßmus if (err != to_read) if (err >= 0) err = B_DEVICE_FULL; 11739949213aSStephan Aßmus if (err < B_OK) break; 11749949213aSStephan Aßmus } 11759949213aSStephan Aßmus 11769949213aSStephan Aßmus if (buffer != temp) free(buffer); 11779949213aSStephan Aßmus return (err >= 0) ? B_OK : err; 11789949213aSStephan Aßmus } 11799949213aSStephan Aßmus 1180d8e2fb50SAxel Dörfler 1181d8e2fb50SAxel Dörfler /*! Encode into the native format */ 118252e8f46aSAxel Dörfler static status_t 11839949213aSStephan Aßmus Compress(BPositionIO *in, BPositionIO *out) 11849949213aSStephan Aßmus { 11859949213aSStephan Aßmus // Load Settings 1186d8e2fb50SAxel Dörfler jpeg_settings settings; 1187d8e2fb50SAxel Dörfler LoadSettings(&settings); 11889949213aSStephan Aßmus 11899949213aSStephan Aßmus // Read info about bitmap 11909949213aSStephan Aßmus TranslatorBitmap header; 11919949213aSStephan Aßmus status_t err = in->Read(&header, sizeof(TranslatorBitmap)); 1192d8e2fb50SAxel Dörfler if (err < B_OK) 1193d8e2fb50SAxel Dörfler return err; 1194d8e2fb50SAxel Dörfler else if (err < (int)sizeof(TranslatorBitmap)) 1195d8e2fb50SAxel Dörfler return B_ERROR; 11969949213aSStephan Aßmus 11979949213aSStephan Aßmus // Grab dimension, color space, and size information from the stream 11989949213aSStephan Aßmus BRect bounds; 11999949213aSStephan Aßmus bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left); 12009949213aSStephan Aßmus bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top); 12019949213aSStephan Aßmus bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right); 12029949213aSStephan Aßmus bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom); 12039949213aSStephan Aßmus 12049949213aSStephan Aßmus int32 in_row_bytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes); 12059949213aSStephan Aßmus 12069949213aSStephan Aßmus int width = bounds.IntegerWidth() + 1; 12079949213aSStephan Aßmus int height = bounds.IntegerHeight() + 1; 12089949213aSStephan Aßmus 12099949213aSStephan Aßmus // Function pointer to convert function 12109949213aSStephan Aßmus // It will point to proper function if needed 12119e34f742SAxel Dörfler void (*converter)(uchar *inscanline, uchar *outscanline, 12129e34f742SAxel Dörfler int32 inRowBytes) = NULL; 12139949213aSStephan Aßmus 12149949213aSStephan Aßmus // Default color info 12159949213aSStephan Aßmus J_COLOR_SPACE jpg_color_space = JCS_RGB; 12169949213aSStephan Aßmus int jpg_input_components = 3; 12179949213aSStephan Aßmus int32 out_row_bytes; 12189949213aSStephan Aßmus int padding = 0; 12199949213aSStephan Aßmus 1220d8e2fb50SAxel Dörfler switch ((color_space)B_BENDIAN_TO_HOST_INT32(header.colors)) { 12219949213aSStephan Aßmus case B_CMAP8: 12229949213aSStephan Aßmus converter = convert_from_cmap8_to_24; 12239949213aSStephan Aßmus padding = in_row_bytes - width; 12249949213aSStephan Aßmus break; 1225d8e2fb50SAxel Dörfler 12269949213aSStephan Aßmus case B_GRAY1: 1227d8e2fb50SAxel Dörfler if (settings.B_GRAY1_as_B_RGB24) { 12289949213aSStephan Aßmus converter = convert_from_gray1_to_24; 12299949213aSStephan Aßmus } else { 12309949213aSStephan Aßmus jpg_input_components = 1; 12319949213aSStephan Aßmus jpg_color_space = JCS_GRAYSCALE; 12329949213aSStephan Aßmus converter = convert_from_gray1_to_gray8; 12339949213aSStephan Aßmus } 12349949213aSStephan Aßmus padding = in_row_bytes - (width/8); 12359949213aSStephan Aßmus break; 1236d8e2fb50SAxel Dörfler 12379949213aSStephan Aßmus case B_GRAY8: 12389949213aSStephan Aßmus jpg_input_components = 1; 12399949213aSStephan Aßmus jpg_color_space = JCS_GRAYSCALE; 12409949213aSStephan Aßmus padding = in_row_bytes - width; 12419949213aSStephan Aßmus break; 1242d8e2fb50SAxel Dörfler 12439949213aSStephan Aßmus case B_RGB15: 12449949213aSStephan Aßmus case B_RGBA15: 12459949213aSStephan Aßmus converter = convert_from_15_to_24; 12469949213aSStephan Aßmus padding = in_row_bytes - (width * 2); 12479949213aSStephan Aßmus break; 1248d8e2fb50SAxel Dörfler 12499949213aSStephan Aßmus case B_RGB15_BIG: 12509949213aSStephan Aßmus case B_RGBA15_BIG: 12519949213aSStephan Aßmus converter = convert_from_15b_to_24; 12529949213aSStephan Aßmus padding = in_row_bytes - (width * 2); 12539949213aSStephan Aßmus break; 1254d8e2fb50SAxel Dörfler 12559949213aSStephan Aßmus case B_RGB16: 12569949213aSStephan Aßmus converter = convert_from_16_to_24; 12579949213aSStephan Aßmus padding = in_row_bytes - (width * 2); 12589949213aSStephan Aßmus break; 1259d8e2fb50SAxel Dörfler 12609949213aSStephan Aßmus case B_RGB16_BIG: 12619949213aSStephan Aßmus converter = convert_from_16b_to_24; 12629949213aSStephan Aßmus padding = in_row_bytes - (width * 2); 12639949213aSStephan Aßmus break; 1264d8e2fb50SAxel Dörfler 12659949213aSStephan Aßmus case B_RGB24: 12669949213aSStephan Aßmus converter = convert_from_24_to_24; 12679949213aSStephan Aßmus padding = in_row_bytes - (width * 3); 12689949213aSStephan Aßmus break; 1269d8e2fb50SAxel Dörfler 12709949213aSStephan Aßmus case B_RGB24_BIG: 12719949213aSStephan Aßmus padding = in_row_bytes - (width * 3); 12729949213aSStephan Aßmus break; 1273d8e2fb50SAxel Dörfler 12749949213aSStephan Aßmus case B_RGB32: 12759949213aSStephan Aßmus case B_RGBA32: 12769949213aSStephan Aßmus converter = convert_from_32_to_24; 12779949213aSStephan Aßmus padding = in_row_bytes - (width * 4); 12789949213aSStephan Aßmus break; 1279d8e2fb50SAxel Dörfler 12809949213aSStephan Aßmus case B_RGB32_BIG: 12819949213aSStephan Aßmus case B_RGBA32_BIG: 12829949213aSStephan Aßmus converter = convert_from_32b_to_24; 12839949213aSStephan Aßmus padding = in_row_bytes - (width * 4); 12849949213aSStephan Aßmus break; 1285d8e2fb50SAxel Dörfler 12869949213aSStephan Aßmus case B_CMYK32: 12879949213aSStephan Aßmus jpg_color_space = JCS_CMYK; 12889949213aSStephan Aßmus jpg_input_components = 4; 12899949213aSStephan Aßmus padding = in_row_bytes - (width * 4); 12909949213aSStephan Aßmus break; 1291d8e2fb50SAxel Dörfler 12929949213aSStephan Aßmus default: 12939949213aSStephan Aßmus fprintf(stderr, "Wrong type: Color space not implemented.\n"); 12949949213aSStephan Aßmus return B_ERROR; 12959949213aSStephan Aßmus } 12969949213aSStephan Aßmus out_row_bytes = jpg_input_components * width; 12979949213aSStephan Aßmus 12989949213aSStephan Aßmus // Set basic things needed for jpeg writing 12999949213aSStephan Aßmus struct jpeg_compress_struct cinfo; 13009949213aSStephan Aßmus struct jpeg_error_mgr jerr; 1301d8e2fb50SAxel Dörfler cinfo.err = be_jpeg_std_error(&jerr, &settings); 13029949213aSStephan Aßmus jpeg_create_compress(&cinfo); 13039949213aSStephan Aßmus be_jpeg_stdio_dest(&cinfo, out); 13049949213aSStephan Aßmus 13059949213aSStephan Aßmus // Set basic values 13069949213aSStephan Aßmus cinfo.image_width = width; 13079949213aSStephan Aßmus cinfo.image_height = height; 13089949213aSStephan Aßmus cinfo.input_components = jpg_input_components; 13099949213aSStephan Aßmus cinfo.in_color_space = jpg_color_space; 13109949213aSStephan Aßmus jpeg_set_defaults(&cinfo); 13119949213aSStephan Aßmus 13129949213aSStephan Aßmus // Set better accuracy 13139949213aSStephan Aßmus cinfo.dct_method = JDCT_ISLOW; 13149949213aSStephan Aßmus 13159949213aSStephan Aßmus // This is needed to prevent some colors loss 13169949213aSStephan Aßmus // With it generated jpegs are as good as from Fireworks (at last! :D) 1317d8e2fb50SAxel Dörfler if (settings.OptimizeColors) { 13189949213aSStephan Aßmus int index = 0; 13199949213aSStephan Aßmus while (index < cinfo.num_components) { 13209949213aSStephan Aßmus cinfo.comp_info[index].h_samp_factor = 1; 13219949213aSStephan Aßmus cinfo.comp_info[index].v_samp_factor = 1; 13229949213aSStephan Aßmus // This will make file smaller, but with worse quality more or less 13239949213aSStephan Aßmus // like with 93%-94% (but it's subjective opinion) on tested images 13249949213aSStephan Aßmus // but with smaller size (between 92% and 93% on tested images) 1325d8e2fb50SAxel Dörfler if (settings.SmallerFile) 13269949213aSStephan Aßmus cinfo.comp_info[index].quant_tbl_no = 1; 13279949213aSStephan Aßmus // This will make bigger file, but also better quality ;] 13289949213aSStephan Aßmus // from my tests it seems like useless - better quality with smaller 13299949213aSStephan Aßmus // can be acheived without this 13309949213aSStephan Aßmus // cinfo.comp_info[index].dc_tbl_no = 1; 13319949213aSStephan Aßmus // cinfo.comp_info[index].ac_tbl_no = 1; 13329949213aSStephan Aßmus index++; 13339949213aSStephan Aßmus } 13349949213aSStephan Aßmus } 13359949213aSStephan Aßmus 13369949213aSStephan Aßmus // Set quality 1337d8e2fb50SAxel Dörfler jpeg_set_quality(&cinfo, settings.Quality, true); 13389949213aSStephan Aßmus 13399949213aSStephan Aßmus // Set progressive compression if needed 13409949213aSStephan Aßmus // if not, turn on optimizing in libjpeg 1341d8e2fb50SAxel Dörfler if (settings.Progressive) 13429949213aSStephan Aßmus jpeg_simple_progression(&cinfo); 13439949213aSStephan Aßmus else 13449949213aSStephan Aßmus cinfo.optimize_coding = TRUE; 13459949213aSStephan Aßmus 13469949213aSStephan Aßmus // Set smoothing (effect like Blur) 1347d8e2fb50SAxel Dörfler cinfo.smoothing_factor = settings.Smoothing; 13489949213aSStephan Aßmus 13499949213aSStephan Aßmus // Initialize compression 13509949213aSStephan Aßmus jpeg_start_compress(&cinfo, TRUE); 13519949213aSStephan Aßmus 13529949213aSStephan Aßmus // Declare scanlines 13539949213aSStephan Aßmus JSAMPROW in_scanline = NULL; 13549949213aSStephan Aßmus JSAMPROW out_scanline = NULL; 13559949213aSStephan Aßmus JSAMPROW writeline; // Pointer to in_scanline (default) or out_scanline (if there will be conversion) 13569949213aSStephan Aßmus 13579949213aSStephan Aßmus // Allocate scanline 13589949213aSStephan Aßmus // Use libjpeg memory allocation functions, so in case of error it will free them itself 1359d8e2fb50SAxel Dörfler in_scanline = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo, 1360d8e2fb50SAxel Dörfler JPOOL_PERMANENT, in_row_bytes); 13619949213aSStephan Aßmus 13629949213aSStephan Aßmus // We need 2nd scanline storage ony for conversion 13639949213aSStephan Aßmus if (converter != NULL) { 13649949213aSStephan Aßmus // There will be conversion, allocate second scanline... 13659949213aSStephan Aßmus // Use libjpeg memory allocation functions, so in case of error it will free them itself 1366d8e2fb50SAxel Dörfler out_scanline = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo, 1367d8e2fb50SAxel Dörfler JPOOL_PERMANENT, out_row_bytes); 13689949213aSStephan Aßmus // ... and make it the one to write to file 13699949213aSStephan Aßmus writeline = out_scanline; 13709949213aSStephan Aßmus } else 13719949213aSStephan Aßmus writeline = in_scanline; 13729949213aSStephan Aßmus 13739949213aSStephan Aßmus while (cinfo.next_scanline < cinfo.image_height) { 13749949213aSStephan Aßmus // Read scanline 13759949213aSStephan Aßmus err = in->Read(in_scanline, in_row_bytes); 13769949213aSStephan Aßmus if (err < in_row_bytes) 1377d8e2fb50SAxel Dörfler return err < B_OK ? Error((j_common_ptr)&cinfo, err) 1378d8e2fb50SAxel Dörfler : Error((j_common_ptr)&cinfo, B_ERROR); 13799949213aSStephan Aßmus 13809949213aSStephan Aßmus // Convert if needed 13819949213aSStephan Aßmus if (converter != NULL) 13829949213aSStephan Aßmus converter(in_scanline, out_scanline, in_row_bytes - padding); 13839949213aSStephan Aßmus 13849949213aSStephan Aßmus // Write scanline 13859949213aSStephan Aßmus jpeg_write_scanlines(&cinfo, &writeline, 1); 13869949213aSStephan Aßmus } 13879949213aSStephan Aßmus 13889949213aSStephan Aßmus jpeg_finish_compress(&cinfo); 13899949213aSStephan Aßmus jpeg_destroy_compress(&cinfo); 13909949213aSStephan Aßmus return B_OK; 13919949213aSStephan Aßmus } 13929949213aSStephan Aßmus 1393d8e2fb50SAxel Dörfler 1394d8e2fb50SAxel Dörfler /*! Decode the native format */ 139552e8f46aSAxel Dörfler static status_t 139652e8f46aSAxel Dörfler Decompress(BPositionIO *in, BPositionIO *out, BMessage* ioExtension) 13979949213aSStephan Aßmus { 13989949213aSStephan Aßmus // Load Settings 1399d8e2fb50SAxel Dörfler jpeg_settings settings; 1400d8e2fb50SAxel Dörfler LoadSettings(&settings); 14019949213aSStephan Aßmus 14029949213aSStephan Aßmus // Set basic things needed for jpeg reading 14039949213aSStephan Aßmus struct jpeg_decompress_struct cinfo; 14049949213aSStephan Aßmus struct jpeg_error_mgr jerr; 1405d8e2fb50SAxel Dörfler cinfo.err = be_jpeg_std_error(&jerr, &settings); 14069949213aSStephan Aßmus jpeg_create_decompress(&cinfo); 14079949213aSStephan Aßmus be_jpeg_stdio_src(&cinfo, in); 14089949213aSStephan Aßmus 140952e8f46aSAxel Dörfler jpeg_save_markers(&cinfo, MARKER_EXIF, 131072); 141052e8f46aSAxel Dörfler // make sure the EXIF tag is stored 141152e8f46aSAxel Dörfler 14129949213aSStephan Aßmus // Read info about image 14139949213aSStephan Aßmus jpeg_read_header(&cinfo, TRUE); 14149949213aSStephan Aßmus 141552e8f46aSAxel Dörfler BMessage exif; 141652e8f46aSAxel Dörfler 1417f13b5de6SAxel Dörfler // parse EXIF data and add it ioExtension, if any 141852e8f46aSAxel Dörfler jpeg_marker_struct* marker = cinfo.marker_list; 141952e8f46aSAxel Dörfler while (marker != NULL) { 142052e8f46aSAxel Dörfler if (marker->marker == MARKER_EXIF 142152e8f46aSAxel Dörfler && !strncmp((char*)marker->data, "Exif", 4)) { 1422f13b5de6SAxel Dörfler if (ioExtension != NULL) { 142352e8f46aSAxel Dörfler // Strip EXIF header from TIFF data 142452e8f46aSAxel Dörfler ioExtension->AddData("exif", B_RAW_TYPE, 142552e8f46aSAxel Dörfler (uint8 *)marker->data + 6, marker->data_length - 6); 1426f13b5de6SAxel Dörfler } 142752e8f46aSAxel Dörfler 142852e8f46aSAxel Dörfler BMemoryIO io(marker->data + 6, marker->data_length - 6); 142952e8f46aSAxel Dörfler convert_exif_to_message(io, exif); 143052e8f46aSAxel Dörfler } 143152e8f46aSAxel Dörfler marker = marker->next; 143252e8f46aSAxel Dörfler } 143352e8f46aSAxel Dörfler 14349949213aSStephan Aßmus // Default color info 143552e8f46aSAxel Dörfler color_space outColorSpace = B_RGB32; 143652e8f46aSAxel Dörfler int outColorComponents = 4; 14379949213aSStephan Aßmus 14389949213aSStephan Aßmus // Function pointer to convert function 14399949213aSStephan Aßmus // It will point to proper function if needed 144052e8f46aSAxel Dörfler void (*converter)(uchar *inScanLine, uchar *outScanLine, 14419e34f742SAxel Dörfler int32 inRowBytes, int32 xStep) = convert_from_24_to_32; 14429949213aSStephan Aßmus 14439949213aSStephan Aßmus // If color space isn't rgb 14449949213aSStephan Aßmus if (cinfo.out_color_space != JCS_RGB) { 1445d8e2fb50SAxel Dörfler switch (cinfo.out_color_space) { 14469949213aSStephan Aßmus case JCS_UNKNOWN: /* error/unspecified */ 14479949213aSStephan Aßmus fprintf(stderr, "From Type: Jpeg uses unknown color type\n"); 14489949213aSStephan Aßmus break; 14499949213aSStephan Aßmus case JCS_GRAYSCALE: /* monochrome */ 14509949213aSStephan Aßmus // Check if user wants to read only as RGB32 or not 1451d8e2fb50SAxel Dörfler if (!settings.Always_B_RGB32) { 14529949213aSStephan Aßmus // Grayscale 145352e8f46aSAxel Dörfler outColorSpace = B_GRAY8; 145452e8f46aSAxel Dörfler outColorComponents = 1; 14559e34f742SAxel Dörfler converter = translate_8; 14569949213aSStephan Aßmus } else { 14579949213aSStephan Aßmus // RGB 14589949213aSStephan Aßmus cinfo.out_color_space = JCS_RGB; 14599949213aSStephan Aßmus cinfo.output_components = 3; 14609949213aSStephan Aßmus converter = convert_from_24_to_32; 14619949213aSStephan Aßmus } 14629949213aSStephan Aßmus break; 14639949213aSStephan Aßmus case JCS_YCbCr: /* Y/Cb/Cr (also known as YUV) */ 14649949213aSStephan Aßmus cinfo.out_color_space = JCS_RGB; 14659949213aSStephan Aßmus converter = convert_from_24_to_32; 14669949213aSStephan Aßmus break; 14679949213aSStephan Aßmus case JCS_YCCK: /* Y/Cb/Cr/K */ 14689949213aSStephan Aßmus // Let libjpeg convert it to CMYK 14699949213aSStephan Aßmus cinfo.out_color_space = JCS_CMYK; 14709949213aSStephan Aßmus // Fall through to CMYK since we need the same settings 14719949213aSStephan Aßmus case JCS_CMYK: /* C/M/Y/K */ 14729949213aSStephan Aßmus // Use proper converter 1473d8e2fb50SAxel Dörfler if (settings.PhotoshopCMYK) 14749949213aSStephan Aßmus converter = convert_from_CMYK_to_32_photoshop; 14759949213aSStephan Aßmus else 14769949213aSStephan Aßmus converter = convert_from_CMYK_to_32; 14779949213aSStephan Aßmus break; 14789949213aSStephan Aßmus default: 14799949213aSStephan Aßmus fprintf(stderr, "From Type: Jpeg uses hmm... i don't know really :(\n"); 14809949213aSStephan Aßmus break; 14819949213aSStephan Aßmus } 14829949213aSStephan Aßmus } 14839949213aSStephan Aßmus 14849949213aSStephan Aßmus // Initialize decompression 14859949213aSStephan Aßmus jpeg_start_decompress(&cinfo); 14869949213aSStephan Aßmus 14879e34f742SAxel Dörfler // retrieve orientation from settings/EXIF 148852e8f46aSAxel Dörfler int32 orientation; 14899e34f742SAxel Dörfler if (ioExtension == NULL 14909e34f742SAxel Dörfler || ioExtension->FindInt32("exif:orientation", &orientation) != B_OK) { 149152e8f46aSAxel Dörfler if (exif.FindInt32("Orientation", &orientation) != B_OK) 149252e8f46aSAxel Dörfler orientation = 1; 149352e8f46aSAxel Dörfler } 14949949213aSStephan Aßmus 14959e34f742SAxel Dörfler if (orientation != 1 && converter == NULL) 14969e34f742SAxel Dörfler converter = translate_8; 14979e34f742SAxel Dörfler 14989e34f742SAxel Dörfler int32 outputWidth = orientation > 4 ? cinfo.output_height : cinfo.output_width; 14999e34f742SAxel Dörfler int32 outputHeight = orientation > 4 ? cinfo.output_width : cinfo.output_height; 15009e34f742SAxel Dörfler 15019e34f742SAxel Dörfler int32 destOffset = dest_index(outputWidth, outputHeight, 15029e34f742SAxel Dörfler 0, 0, orientation) * outColorComponents; 15039e34f742SAxel Dörfler int32 xStep = dest_index(outputWidth, outputHeight, 15049e34f742SAxel Dörfler 1, 0, orientation) * outColorComponents - destOffset; 15059e34f742SAxel Dörfler int32 yStep = dest_index(outputWidth, outputHeight, 15069e34f742SAxel Dörfler 0, 1, orientation) * outColorComponents - destOffset; 15079e34f742SAxel Dörfler bool needAll = orientation != 1; 15089e34f742SAxel Dörfler 15099e34f742SAxel Dörfler // Initialize this bounds rect to the size of your image 15109e34f742SAxel Dörfler BRect bounds(0, 0, outputWidth - 1, outputHeight - 1); 15119e34f742SAxel Dörfler 15129e34f742SAxel Dörfler #if 0 15139e34f742SAxel Dörfler printf("destOffset = %ld, xStep = %ld, yStep = %ld, input: %ld x %ld, output: %ld x %ld, orientation %ld\n", 15149e34f742SAxel Dörfler destOffset, xStep, yStep, (int32)cinfo.output_width, (int32)cinfo.output_height, 15159e34f742SAxel Dörfler bounds.IntegerWidth() + 1, bounds.IntegerHeight() + 1, orientation); 15169e34f742SAxel Dörfler #endif 15179e34f742SAxel Dörfler 15189949213aSStephan Aßmus // Bytes count in one line of image (scanline) 15199e34f742SAxel Dörfler int32 inRowBytes = cinfo.output_width * cinfo.output_components; 15209e34f742SAxel Dörfler int32 rowBytes = (bounds.IntegerWidth() + 1) * outColorComponents; 15219e34f742SAxel Dörfler int32 dataSize = cinfo.output_width * cinfo.output_height 15229e34f742SAxel Dörfler * outColorComponents; 15239949213aSStephan Aßmus 15249949213aSStephan Aßmus // Fill out the B_TRANSLATOR_BITMAP's header 15259949213aSStephan Aßmus TranslatorBitmap header; 15269949213aSStephan Aßmus header.magic = B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP); 15279949213aSStephan Aßmus header.bounds.left = B_HOST_TO_BENDIAN_FLOAT(bounds.left); 15289949213aSStephan Aßmus header.bounds.top = B_HOST_TO_BENDIAN_FLOAT(bounds.top); 15299949213aSStephan Aßmus header.bounds.right = B_HOST_TO_BENDIAN_FLOAT(bounds.right); 15309949213aSStephan Aßmus header.bounds.bottom = B_HOST_TO_BENDIAN_FLOAT(bounds.bottom); 153152e8f46aSAxel Dörfler header.colors = (color_space)B_HOST_TO_BENDIAN_INT32(outColorSpace); 153252e8f46aSAxel Dörfler header.rowBytes = B_HOST_TO_BENDIAN_INT32(rowBytes); 15339e34f742SAxel Dörfler header.dataSize = B_HOST_TO_BENDIAN_INT32(dataSize); 15349949213aSStephan Aßmus 15359949213aSStephan Aßmus // Write out the header 15369949213aSStephan Aßmus status_t err = out->Write(&header, sizeof(TranslatorBitmap)); 1537d8e2fb50SAxel Dörfler if (err < B_OK) 1538d8e2fb50SAxel Dörfler return Error((j_common_ptr)&cinfo, err); 1539d8e2fb50SAxel Dörfler else if (err < (int)sizeof(TranslatorBitmap)) 1540d8e2fb50SAxel Dörfler return Error((j_common_ptr)&cinfo, B_ERROR); 15419949213aSStephan Aßmus 15429949213aSStephan Aßmus // Declare scanlines 15439e34f742SAxel Dörfler JSAMPROW inScanLine = NULL; 15449e34f742SAxel Dörfler uint8* dest = NULL; 15459e34f742SAxel Dörfler uint8* destLine = NULL; 15469949213aSStephan Aßmus 15479949213aSStephan Aßmus // Allocate scanline 15489949213aSStephan Aßmus // Use libjpeg memory allocation functions, so in case of error it will free them itself 15499e34f742SAxel Dörfler inScanLine = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo, 15509e34f742SAxel Dörfler JPOOL_PERMANENT, inRowBytes); 15519949213aSStephan Aßmus 15529949213aSStephan Aßmus // We need 2nd scanline storage only for conversion 15539949213aSStephan Aßmus if (converter != NULL) { 15549949213aSStephan Aßmus // There will be conversion, allocate second scanline... 15559e34f742SAxel Dörfler // Use libjpeg memory allocation functions, so in case of error it will free 15569e34f742SAxel Dörfler // them itself 15579e34f742SAxel Dörfler dest = (uint8*)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo, 15589e34f742SAxel Dörfler JPOOL_PERMANENT, needAll ? dataSize : rowBytes); 15599e34f742SAxel Dörfler destLine = dest + destOffset; 15609949213aSStephan Aßmus } else 15619e34f742SAxel Dörfler destLine = inScanLine; 15629949213aSStephan Aßmus 15639949213aSStephan Aßmus while (cinfo.output_scanline < cinfo.output_height) { 15649949213aSStephan Aßmus // Read scanline 15659e34f742SAxel Dörfler jpeg_read_scanlines(&cinfo, &inScanLine, 1); 15669949213aSStephan Aßmus 15679949213aSStephan Aßmus // Convert if needed 15689949213aSStephan Aßmus if (converter != NULL) 15699e34f742SAxel Dörfler converter(inScanLine, destLine, inRowBytes, xStep); 15709949213aSStephan Aßmus 15719e34f742SAxel Dörfler if (!needAll) { 15729949213aSStephan Aßmus // Write the scanline buffer to the output stream 15739e34f742SAxel Dörfler ssize_t bytesWritten = out->Write(destLine, rowBytes); 15749e34f742SAxel Dörfler if (bytesWritten < rowBytes) { 15759e34f742SAxel Dörfler return bytesWritten < B_OK 15769e34f742SAxel Dörfler ? Error((j_common_ptr)&cinfo, bytesWritten) 1577d8e2fb50SAxel Dörfler : Error((j_common_ptr)&cinfo, B_ERROR); 15789949213aSStephan Aßmus } 15799e34f742SAxel Dörfler } else 15809e34f742SAxel Dörfler destLine += yStep; 15819e34f742SAxel Dörfler } 15829e34f742SAxel Dörfler 15839e34f742SAxel Dörfler if (needAll) { 15849e34f742SAxel Dörfler ssize_t bytesWritten = out->Write(dest, dataSize); 15859e34f742SAxel Dörfler if (bytesWritten < dataSize) { 15869e34f742SAxel Dörfler return bytesWritten < B_OK 15879e34f742SAxel Dörfler ? Error((j_common_ptr)&cinfo, bytesWritten) 15889e34f742SAxel Dörfler : Error((j_common_ptr)&cinfo, B_ERROR); 15899e34f742SAxel Dörfler } 15909e34f742SAxel Dörfler } 15919949213aSStephan Aßmus 15929949213aSStephan Aßmus jpeg_finish_decompress(&cinfo); 15939949213aSStephan Aßmus jpeg_destroy_decompress(&cinfo); 15949949213aSStephan Aßmus return B_OK; 15959949213aSStephan Aßmus } 15969949213aSStephan Aßmus 1597d8e2fb50SAxel Dörfler /*! 1598d8e2fb50SAxel Dörfler Frees jpeg alocated memory 1599d8e2fb50SAxel Dörfler Returns given error (B_ERROR by default) 1600d8e2fb50SAxel Dörfler */ 160152e8f46aSAxel Dörfler static status_t 16029949213aSStephan Aßmus Error(j_common_ptr cinfo, status_t error) 16039949213aSStephan Aßmus { 16049949213aSStephan Aßmus jpeg_destroy(cinfo); 16059949213aSStephan Aßmus return error; 16069949213aSStephan Aßmus } 1607d8e2fb50SAxel Dörfler 1608d8e2fb50SAxel Dörfler 1609d8e2fb50SAxel Dörfler // #pragma mark - 1610d8e2fb50SAxel Dörfler 1611d8e2fb50SAxel Dörfler 1612d8e2fb50SAxel Dörfler int 1613117da2d7SAxel Dörfler main(int, char**) 1614117da2d7SAxel Dörfler { 1615117da2d7SAxel Dörfler BApplication app("application/x-vnd.Haiku-JPEGTranslator"); 1616d8e2fb50SAxel Dörfler 1617d8e2fb50SAxel Dörfler TranslatorWindow *window = new TranslatorWindow(); 1618d8e2fb50SAxel Dörfler window->Show(); 1619d8e2fb50SAxel Dörfler 1620d8e2fb50SAxel Dörfler app.Run(); 1621d8e2fb50SAxel Dörfler return 0; 1622d8e2fb50SAxel Dörfler } 1623d8e2fb50SAxel Dörfler 1624