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" 56*f13b5de6SAxel 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 66*f13b5de6SAxel 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 { 3739e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i++) { 3749e34f742SAxel Dörfler out[0] = in[2]; 3759e34f742SAxel Dörfler out[1] = in[1]; 3769e34f742SAxel Dörfler out[2] = in[0]; 3779e34f742SAxel Dörfler 3789e34f742SAxel Dörfler in += 4; 3799e34f742SAxel Dörfler out += 3; 380d8e2fb50SAxel Dörfler } 381d8e2fb50SAxel Dörfler } 382d8e2fb50SAxel Dörfler 383d8e2fb50SAxel Dörfler 384d8e2fb50SAxel Dörfler inline void 3859e34f742SAxel Dörfler convert_from_32b_to_24(uint8* in, uint8* out, int32 inRowBytes) 386d8e2fb50SAxel Dörfler { 3879e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i++) { 3889e34f742SAxel Dörfler out[1] = in[0]; 3899e34f742SAxel Dörfler out[2] = in[1]; 3909e34f742SAxel Dörfler out[3] = in[2]; 3919e34f742SAxel Dörfler 3929e34f742SAxel Dörfler in += 4; 3939e34f742SAxel Dörfler out += 3; 394d8e2fb50SAxel Dörfler } 395d8e2fb50SAxel Dörfler } 396d8e2fb50SAxel Dörfler 397d8e2fb50SAxel Dörfler 3989e34f742SAxel Dörfler // #pragma mark - conversion for decompression 3999e34f742SAxel Dörfler 4009e34f742SAxel Dörfler 401d8e2fb50SAxel Dörfler inline void 4029e34f742SAxel Dörfler convert_from_CMYK_to_32_photoshop(uint8* in, uint8* out, int32 inRowBytes, int32 xStep) 403d8e2fb50SAxel Dörfler { 4049e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i += 4) { 4059e34f742SAxel Dörfler int32 black = in[3]; 4069e34f742SAxel Dörfler out[0] = in[2] * black / 255; 4079e34f742SAxel Dörfler out[1] = in[1] * black / 255; 4089e34f742SAxel Dörfler out[2] = in[0] * black / 255; 4099e34f742SAxel Dörfler out[3] = 255; 4109e34f742SAxel Dörfler 4119e34f742SAxel Dörfler in += 4; 4129e34f742SAxel Dörfler out += xStep; 413d8e2fb50SAxel Dörfler } 414d8e2fb50SAxel Dörfler } 415d8e2fb50SAxel Dörfler 416d8e2fb50SAxel Dörfler 417d8e2fb50SAxel Dörfler //! !!! UNTESTED !!! 418d8e2fb50SAxel Dörfler inline void 4199e34f742SAxel Dörfler convert_from_CMYK_to_32(uint8* in, uint8* out, int32 inRowBytes, int32 xStep) 420d8e2fb50SAxel Dörfler { 4219e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i += 4) { 4229e34f742SAxel Dörfler int32 black = 255 - in[3]; 4239e34f742SAxel Dörfler out[0] = ((255 - in[2]) * black) / 255; 4249e34f742SAxel Dörfler out[1] = ((255 - in[1]) * black) / 255; 4259e34f742SAxel Dörfler out[2] = ((255 - in[0]) * black) / 255; 4269e34f742SAxel Dörfler out[3] = 255; 4279e34f742SAxel Dörfler 4289e34f742SAxel Dörfler in += 4; 4299e34f742SAxel Dörfler out += xStep; 430d8e2fb50SAxel Dörfler } 431d8e2fb50SAxel Dörfler } 432d8e2fb50SAxel Dörfler 433d8e2fb50SAxel Dörfler 434d8e2fb50SAxel Dörfler //! RGB24 8:8:8 to xRGB 8:8:8:8 435d8e2fb50SAxel Dörfler inline void 4369e34f742SAxel Dörfler convert_from_24_to_32(uint8* in, uint8* out, int32 inRowBytes, int32 xStep) 437d8e2fb50SAxel Dörfler { 4389e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i += 3) { 4399e34f742SAxel Dörfler out[0] = in[2]; 4409e34f742SAxel Dörfler out[1] = in[1]; 4419e34f742SAxel Dörfler out[2] = in[0]; 4429e34f742SAxel Dörfler out[3] = 255; 4439e34f742SAxel Dörfler 4449e34f742SAxel Dörfler in += 3; 4459e34f742SAxel Dörfler out += xStep; 4469e34f742SAxel Dörfler } 4479e34f742SAxel Dörfler } 4489e34f742SAxel Dörfler 4499e34f742SAxel Dörfler 4509e34f742SAxel Dörfler //! 8-bit to 8-bit, only need when rotating the image 4519e34f742SAxel Dörfler void 4529e34f742SAxel Dörfler translate_8(uint8* in, uint8* out, int32 inRowBytes, int32 xStep) 4539e34f742SAxel Dörfler { 4549e34f742SAxel Dörfler for (int32 i = 0; i < inRowBytes; i++) { 4559e34f742SAxel Dörfler out[0] = in[0]; 4569e34f742SAxel Dörfler 4579e34f742SAxel Dörfler in++; 4589e34f742SAxel Dörfler out += xStep; 459d8e2fb50SAxel Dörfler } 460d8e2fb50SAxel Dörfler } 461d8e2fb50SAxel Dörfler 462d8e2fb50SAxel Dörfler 4638687ff64SAxel Dörfler // #pragma mark - SView 4648687ff64SAxel Dörfler 4658687ff64SAxel Dörfler 4668687ff64SAxel Dörfler SView::SView(const char *name, float x, float y) 4678687ff64SAxel Dörfler : BView(BRect(x, y, x, y), name, B_FOLLOW_NONE, B_WILL_DRAW) 4688687ff64SAxel Dörfler { 4698687ff64SAxel Dörfler fPreferredWidth = 0; 4708687ff64SAxel Dörfler fPreferredHeight = 0; 4718687ff64SAxel Dörfler 4728687ff64SAxel Dörfler SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 4738687ff64SAxel Dörfler SetLowColor(ViewColor()); 4748687ff64SAxel Dörfler 4758687ff64SAxel Dörfler SetFont(be_plain_font); 4768687ff64SAxel Dörfler } 4778687ff64SAxel Dörfler 4788687ff64SAxel Dörfler 4798687ff64SAxel Dörfler void 4808687ff64SAxel Dörfler SView::GetPreferredSize(float* _width, float* _height) 4818687ff64SAxel Dörfler { 4828687ff64SAxel Dörfler if (_width) 4838687ff64SAxel Dörfler *_width = fPreferredWidth; 4848687ff64SAxel Dörfler if (_height) 4858687ff64SAxel Dörfler *_height = fPreferredHeight; 4868687ff64SAxel Dörfler } 4878687ff64SAxel Dörfler 4888687ff64SAxel Dörfler 4898687ff64SAxel Dörfler void 4908687ff64SAxel Dörfler SView::ResizeToPreferred() 4918687ff64SAxel Dörfler { 4928687ff64SAxel Dörfler ResizeTo(fPreferredWidth, fPreferredHeight); 4938687ff64SAxel Dörfler } 4948687ff64SAxel Dörfler 4958687ff64SAxel Dörfler 4968687ff64SAxel Dörfler void 4978687ff64SAxel Dörfler SView::ResizePreferredBy(float width, float height) 4988687ff64SAxel Dörfler { 4998687ff64SAxel Dörfler fPreferredWidth += width; 5008687ff64SAxel Dörfler fPreferredHeight += height; 5018687ff64SAxel Dörfler } 5028687ff64SAxel Dörfler 5038687ff64SAxel Dörfler 5048687ff64SAxel Dörfler void 505f9810471SAxel Dörfler SView::AddChild(BView *child, BView *before) 5068687ff64SAxel Dörfler { 5078687ff64SAxel Dörfler BView::AddChild(child, before); 5088687ff64SAxel Dörfler child->ResizeToPreferred(); 5098687ff64SAxel Dörfler BRect frame = child->Frame(); 5108687ff64SAxel Dörfler 5118687ff64SAxel Dörfler if (frame.right > fPreferredWidth) 5128687ff64SAxel Dörfler fPreferredWidth = frame.right; 5138687ff64SAxel Dörfler if (frame.bottom > fPreferredHeight) 5148687ff64SAxel Dörfler fPreferredHeight = frame.bottom; 5158687ff64SAxel Dörfler } 5168687ff64SAxel Dörfler 5178687ff64SAxel Dörfler 518d8e2fb50SAxel Dörfler // #pragma mark - 519d8e2fb50SAxel Dörfler 520d8e2fb50SAxel Dörfler 521d8e2fb50SAxel Dörfler SSlider::SSlider(BRect frame, const char *name, const char *label, 522d8e2fb50SAxel Dörfler BMessage *message, int32 minValue, int32 maxValue, orientation posture, 523d8e2fb50SAxel Dörfler thumb_style thumbType, uint32 resizingMode, uint32 flags) 524d8e2fb50SAxel Dörfler : BSlider(frame, name, label, message, minValue, maxValue, 525d8e2fb50SAxel Dörfler posture, thumbType, resizingMode, flags) 5269949213aSStephan Aßmus { 5278687ff64SAxel Dörfler rgb_color barColor = { 0, 0, 229, 255 }; 5288687ff64SAxel Dörfler UseFillColor(true, &barColor); 5299949213aSStephan Aßmus } 5309949213aSStephan Aßmus 5318687ff64SAxel Dörfler 5328687ff64SAxel Dörfler //! Update status string - show actual value 5339949213aSStephan Aßmus char* 5349949213aSStephan Aßmus SSlider::UpdateText() const 5359949213aSStephan Aßmus { 5368687ff64SAxel Dörfler snprintf(fStatusLabel, sizeof(fStatusLabel), "%ld", Value()); 5378687ff64SAxel Dörfler return fStatusLabel; 5389949213aSStephan Aßmus } 5399949213aSStephan Aßmus 5408687ff64SAxel Dörfler 5418687ff64SAxel Dörfler //! BSlider::ResizeToPreferred + Resize width if it's too small to show label and status 5429949213aSStephan Aßmus void 5439949213aSStephan Aßmus SSlider::ResizeToPreferred() 5449949213aSStephan Aßmus { 5459949213aSStephan Aßmus int32 width = (int32)ceil(StringWidth(Label()) + StringWidth("9999")); 5468687ff64SAxel Dörfler if (width < 230) 5478687ff64SAxel Dörfler width = 230; 5488687ff64SAxel Dörfler 5499949213aSStephan Aßmus float w, h; 5509949213aSStephan Aßmus GetPreferredSize(&w, &h); 5519949213aSStephan Aßmus ResizeTo(width, h); 5529949213aSStephan Aßmus } 5539949213aSStephan Aßmus 5549949213aSStephan Aßmus 555d8e2fb50SAxel Dörfler // #pragma mark - 5569949213aSStephan Aßmus 557d8e2fb50SAxel Dörfler 558d8e2fb50SAxel Dörfler TranslatorReadView::TranslatorReadView(const char *name, jpeg_settings *settings, 559d8e2fb50SAxel Dörfler float x, float y) 5609949213aSStephan Aßmus : SView(name, x, y), 561d8e2fb50SAxel Dörfler fSettings(settings) 5629949213aSStephan Aßmus { 5638687ff64SAxel Dörfler fAlwaysRGB32 = new BCheckBox(BRect(10, GetPreferredHeight(), 10, 564d8e2fb50SAxel Dörfler GetPreferredHeight()), "alwaysrgb32", VIEW_LABEL_ALWAYSRGB32, 565d8e2fb50SAxel Dörfler new BMessage(VIEW_MSG_SET_ALWAYSRGB32)); 5668687ff64SAxel Dörfler fAlwaysRGB32->SetFont(be_plain_font); 567d8e2fb50SAxel Dörfler if (fSettings->Always_B_RGB32) 5688687ff64SAxel Dörfler fAlwaysRGB32->SetValue(1); 5699949213aSStephan Aßmus 5708687ff64SAxel Dörfler AddChild(fAlwaysRGB32); 5719949213aSStephan Aßmus 5728687ff64SAxel Dörfler fPhotoshopCMYK = new BCheckBox(BRect(10, GetPreferredHeight(), 10, 5738687ff64SAxel Dörfler GetPreferredHeight()), "photoshopCMYK", VIEW_LABEL_PHOTOSHOPCMYK, 5748687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_PHOTOSHOPCMYK)); 5758687ff64SAxel Dörfler fPhotoshopCMYK->SetFont(be_plain_font); 576d8e2fb50SAxel Dörfler if (fSettings->PhotoshopCMYK) 5778687ff64SAxel Dörfler fPhotoshopCMYK->SetValue(1); 5789949213aSStephan Aßmus 5798687ff64SAxel Dörfler AddChild(fPhotoshopCMYK); 5809949213aSStephan Aßmus 5818687ff64SAxel Dörfler fShowErrorBox = new BCheckBox(BRect(10, GetPreferredHeight(), 10, 5828687ff64SAxel Dörfler GetPreferredHeight()), "error", VIEW_LABEL_SHOWREADERRORBOX, 5838687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_SHOWREADERRORBOX)); 5848687ff64SAxel Dörfler fShowErrorBox->SetFont(be_plain_font); 585d8e2fb50SAxel Dörfler if (fSettings->ShowReadWarningBox) 5868687ff64SAxel Dörfler fShowErrorBox->SetValue(1); 5879949213aSStephan Aßmus 5888687ff64SAxel Dörfler AddChild(fShowErrorBox); 5899949213aSStephan Aßmus 5909949213aSStephan Aßmus ResizeToPreferred(); 5919949213aSStephan Aßmus } 5929949213aSStephan Aßmus 5938687ff64SAxel Dörfler 5949949213aSStephan Aßmus void 5959949213aSStephan Aßmus TranslatorReadView::AttachedToWindow() 5969949213aSStephan Aßmus { 5978687ff64SAxel Dörfler fAlwaysRGB32->SetTarget(this); 5988687ff64SAxel Dörfler fPhotoshopCMYK->SetTarget(this); 5998687ff64SAxel Dörfler fShowErrorBox->SetTarget(this); 6009949213aSStephan Aßmus } 6019949213aSStephan Aßmus 6028687ff64SAxel Dörfler 6039949213aSStephan Aßmus void 6049949213aSStephan Aßmus TranslatorReadView::MessageReceived(BMessage* message) 6059949213aSStephan Aßmus { 6068687ff64SAxel Dörfler switch (message->what) { 6079949213aSStephan Aßmus case VIEW_MSG_SET_ALWAYSRGB32: 6089949213aSStephan Aßmus { 6099949213aSStephan Aßmus int32 value; 6109949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 611d8e2fb50SAxel Dörfler fSettings->Always_B_RGB32 = value; 612d8e2fb50SAxel Dörfler SaveSettings(fSettings); 6139949213aSStephan Aßmus } 6149949213aSStephan Aßmus break; 6159949213aSStephan Aßmus } 6169949213aSStephan Aßmus case VIEW_MSG_SET_PHOTOSHOPCMYK: 6179949213aSStephan Aßmus { 6189949213aSStephan Aßmus int32 value; 6199949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 620d8e2fb50SAxel Dörfler fSettings->PhotoshopCMYK = value; 621d8e2fb50SAxel Dörfler SaveSettings(fSettings); 6229949213aSStephan Aßmus } 6239949213aSStephan Aßmus break; 6249949213aSStephan Aßmus } 6259949213aSStephan Aßmus case VIEW_MSG_SET_SHOWREADERRORBOX: 6269949213aSStephan Aßmus { 6279949213aSStephan Aßmus int32 value; 6289949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 629d8e2fb50SAxel Dörfler fSettings->ShowReadWarningBox = value; 630d8e2fb50SAxel Dörfler SaveSettings(fSettings); 6319949213aSStephan Aßmus } 6329949213aSStephan Aßmus break; 6339949213aSStephan Aßmus } 6349949213aSStephan Aßmus default: 6359949213aSStephan Aßmus BView::MessageReceived(message); 6369949213aSStephan Aßmus break; 6379949213aSStephan Aßmus } 6389949213aSStephan Aßmus } 6399949213aSStephan Aßmus 6409949213aSStephan Aßmus 6418687ff64SAxel Dörfler // #pragma mark - TranslatorWriteView 6429949213aSStephan Aßmus 6438687ff64SAxel Dörfler 6448687ff64SAxel Dörfler TranslatorWriteView::TranslatorWriteView(const char *name, jpeg_settings *settings, 6458687ff64SAxel Dörfler float x, float y) 6469949213aSStephan Aßmus : SView(name, x, y), 647d8e2fb50SAxel Dörfler fSettings(settings) 6489949213aSStephan Aßmus { 6498687ff64SAxel Dörfler fQualitySlider = new SSlider(BRect(10, GetPreferredHeight(), 10, 6508687ff64SAxel Dörfler GetPreferredHeight()), "quality", VIEW_LABEL_QUALITY, 6518687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_QUALITY), 0, 100); 6528687ff64SAxel Dörfler fQualitySlider->SetHashMarks(B_HASH_MARKS_BOTTOM); 6538687ff64SAxel Dörfler fQualitySlider->SetHashMarkCount(10); 6548687ff64SAxel Dörfler fQualitySlider->SetLimitLabels("Low", "High"); 6558687ff64SAxel Dörfler fQualitySlider->SetFont(be_plain_font); 6568687ff64SAxel Dörfler fQualitySlider->SetValue(fSettings->Quality); 6578687ff64SAxel Dörfler AddChild(fQualitySlider); 6589949213aSStephan Aßmus 6598687ff64SAxel Dörfler fSmoothingSlider = new SSlider(BRect(10, GetPreferredHeight()+10, 10, 6608687ff64SAxel Dörfler GetPreferredHeight()), "smoothing", VIEW_LABEL_SMOOTHING, 6618687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_SMOOTHING), 0, 100); 6628687ff64SAxel Dörfler fSmoothingSlider->SetHashMarks(B_HASH_MARKS_BOTTOM); 6638687ff64SAxel Dörfler fSmoothingSlider->SetHashMarkCount(10); 6648687ff64SAxel Dörfler fSmoothingSlider->SetLimitLabels("None", "High"); 6658687ff64SAxel Dörfler fSmoothingSlider->SetFont(be_plain_font); 6668687ff64SAxel Dörfler fSmoothingSlider->SetValue(fSettings->Smoothing); 6678687ff64SAxel Dörfler AddChild(fSmoothingSlider); 6689949213aSStephan Aßmus 6698687ff64SAxel Dörfler fProgress = new BCheckBox(BRect(10, GetPreferredHeight()+10, 10, 6708687ff64SAxel Dörfler GetPreferredHeight()), "progress", VIEW_LABEL_PROGRESSIVE, 6718687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_PROGRESSIVE)); 6728687ff64SAxel Dörfler fProgress->SetFont(be_plain_font); 673d8e2fb50SAxel Dörfler if (fSettings->Progressive) 6748687ff64SAxel Dörfler fProgress->SetValue(1); 6759949213aSStephan Aßmus 6768687ff64SAxel Dörfler AddChild(fProgress); 6779949213aSStephan Aßmus 6788687ff64SAxel Dörfler fOptimizeColors = new BCheckBox(BRect(10, GetPreferredHeight()+5, 10, 6798687ff64SAxel Dörfler GetPreferredHeight() + 5), "optimizecolors", VIEW_LABEL_OPTIMIZECOLORS, 6808687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_OPTIMIZECOLORS)); 6818687ff64SAxel Dörfler fOptimizeColors->SetFont(be_plain_font); 682d8e2fb50SAxel Dörfler if (fSettings->OptimizeColors) 6838687ff64SAxel Dörfler fOptimizeColors->SetValue(1); 6849949213aSStephan Aßmus 6858687ff64SAxel Dörfler AddChild(fOptimizeColors); 6869949213aSStephan Aßmus 6878687ff64SAxel Dörfler fSmallerFile = new BCheckBox(BRect(25, GetPreferredHeight()+5, 25, 6888687ff64SAxel Dörfler GetPreferredHeight() + 5), "smallerfile", VIEW_LABEL_SMALLERFILE, 6898687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_SMALLERFILE)); 6908687ff64SAxel Dörfler fSmallerFile->SetFont(be_plain_font); 691d8e2fb50SAxel Dörfler if (fSettings->SmallerFile) 6928687ff64SAxel Dörfler fSmallerFile->SetValue(1); 693d8e2fb50SAxel Dörfler if (!fSettings->OptimizeColors) 6948687ff64SAxel Dörfler fSmallerFile->SetEnabled(false); 6959949213aSStephan Aßmus 6968687ff64SAxel Dörfler AddChild(fSmallerFile); 6979949213aSStephan Aßmus 6988687ff64SAxel Dörfler fGrayAsRGB24 = new BCheckBox(BRect(10, GetPreferredHeight()+5, 25, 6998687ff64SAxel Dörfler GetPreferredHeight()+5), "gray1asrgb24", VIEW_LABEL_GRAY1ASRGB24, 7008687ff64SAxel Dörfler new BMessage(VIEW_MSG_SET_GRAY1ASRGB24)); 7018687ff64SAxel Dörfler fGrayAsRGB24->SetFont(be_plain_font); 702d8e2fb50SAxel Dörfler if (fSettings->B_GRAY1_as_B_RGB24) 7038687ff64SAxel Dörfler fGrayAsRGB24->SetValue(1); 7049949213aSStephan Aßmus 7058687ff64SAxel Dörfler AddChild(fGrayAsRGB24); 7069949213aSStephan Aßmus 7079949213aSStephan Aßmus ResizeToPreferred(); 7089949213aSStephan Aßmus } 7099949213aSStephan Aßmus 7108687ff64SAxel Dörfler 7119949213aSStephan Aßmus void 7129949213aSStephan Aßmus TranslatorWriteView::AttachedToWindow() 7139949213aSStephan Aßmus { 7148687ff64SAxel Dörfler fQualitySlider->SetTarget(this); 7158687ff64SAxel Dörfler fSmoothingSlider->SetTarget(this); 7168687ff64SAxel Dörfler fProgress->SetTarget(this); 7178687ff64SAxel Dörfler fOptimizeColors->SetTarget(this); 7188687ff64SAxel Dörfler fSmallerFile->SetTarget(this); 7198687ff64SAxel Dörfler fGrayAsRGB24->SetTarget(this); 7209949213aSStephan Aßmus } 7219949213aSStephan Aßmus 7228687ff64SAxel Dörfler 7239949213aSStephan Aßmus void 7249949213aSStephan Aßmus TranslatorWriteView::MessageReceived(BMessage *message) 7259949213aSStephan Aßmus { 7268687ff64SAxel Dörfler switch (message->what) { 7279949213aSStephan Aßmus case VIEW_MSG_SET_QUALITY: 7289949213aSStephan Aßmus { 7299949213aSStephan Aßmus int32 value; 7309949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 731d8e2fb50SAxel Dörfler fSettings->Quality = value; 732d8e2fb50SAxel Dörfler SaveSettings(fSettings); 7339949213aSStephan Aßmus } 7349949213aSStephan Aßmus break; 7359949213aSStephan Aßmus } 7369949213aSStephan Aßmus case VIEW_MSG_SET_SMOOTHING: 7379949213aSStephan Aßmus { 7389949213aSStephan Aßmus int32 value; 7399949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 740d8e2fb50SAxel Dörfler fSettings->Smoothing = value; 741d8e2fb50SAxel Dörfler SaveSettings(fSettings); 7429949213aSStephan Aßmus } 7439949213aSStephan Aßmus break; 7449949213aSStephan Aßmus } 7459949213aSStephan Aßmus case VIEW_MSG_SET_PROGRESSIVE: 7469949213aSStephan Aßmus { 7479949213aSStephan Aßmus int32 value; 7489949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 749d8e2fb50SAxel Dörfler fSettings->Progressive = value; 750d8e2fb50SAxel Dörfler SaveSettings(fSettings); 7519949213aSStephan Aßmus } 7529949213aSStephan Aßmus break; 7539949213aSStephan Aßmus } 7549949213aSStephan Aßmus case VIEW_MSG_SET_OPTIMIZECOLORS: 7559949213aSStephan Aßmus { 7569949213aSStephan Aßmus int32 value; 7579949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 758d8e2fb50SAxel Dörfler fSettings->OptimizeColors = value; 759d8e2fb50SAxel Dörfler SaveSettings(fSettings); 7609949213aSStephan Aßmus } 7618687ff64SAxel Dörfler fSmallerFile->SetEnabled(fSettings->OptimizeColors); 7629949213aSStephan Aßmus break; 7639949213aSStephan Aßmus } 7649949213aSStephan Aßmus case VIEW_MSG_SET_SMALLERFILE: 7659949213aSStephan Aßmus { 7669949213aSStephan Aßmus int32 value; 7679949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 768d8e2fb50SAxel Dörfler fSettings->SmallerFile = value; 769d8e2fb50SAxel Dörfler SaveSettings(fSettings); 7709949213aSStephan Aßmus } 7719949213aSStephan Aßmus break; 7729949213aSStephan Aßmus } 7739949213aSStephan Aßmus case VIEW_MSG_SET_GRAY1ASRGB24: 7749949213aSStephan Aßmus { 7759949213aSStephan Aßmus int32 value; 7769949213aSStephan Aßmus if (message->FindInt32("be:value", &value) == B_OK) { 777d8e2fb50SAxel Dörfler fSettings->B_GRAY1_as_B_RGB24 = value; 778d8e2fb50SAxel Dörfler SaveSettings(fSettings); 7799949213aSStephan Aßmus } 7809949213aSStephan Aßmus break; 7819949213aSStephan Aßmus } 7829949213aSStephan Aßmus default: 7839949213aSStephan Aßmus BView::MessageReceived(message); 7849949213aSStephan Aßmus break; 7859949213aSStephan Aßmus } 7869949213aSStephan Aßmus } 7879949213aSStephan Aßmus 7889949213aSStephan Aßmus 789d8e2fb50SAxel Dörfler // #pragma mark - 7909949213aSStephan Aßmus 791d8e2fb50SAxel Dörfler 7929949213aSStephan Aßmus TranslatorAboutView::TranslatorAboutView(const char *name, float x, float y) 7939949213aSStephan Aßmus : SView(name, x, y) 7949949213aSStephan Aßmus { 7958687ff64SAxel Dörfler BStringView *title = new BStringView(BRect(10, 0, 10, 0), "Title", 7968687ff64SAxel Dörfler translatorName); 7979949213aSStephan Aßmus title->SetFont(be_bold_font); 7989949213aSStephan Aßmus 7999949213aSStephan Aßmus AddChild(title); 8009949213aSStephan Aßmus 8019949213aSStephan Aßmus BRect rect = title->Bounds(); 8029949213aSStephan Aßmus float space = title->StringWidth(" "); 8039949213aSStephan Aßmus 8049949213aSStephan Aßmus char versionString[16]; 805d8e2fb50SAxel Dörfler sprintf(versionString, "v%d.%d.%d", (int)(translatorVersion >> 8), 806d8e2fb50SAxel Dörfler (int)((translatorVersion >> 4) & 0xf), (int)(translatorVersion & 0xf)); 8079949213aSStephan Aßmus 808d8e2fb50SAxel Dörfler BStringView *version = new BStringView(BRect(rect.right+space, rect.top, 809d8e2fb50SAxel Dörfler rect.right+space, rect.top), "Version", versionString); 8109949213aSStephan Aßmus version->SetFont(be_plain_font); 8119949213aSStephan Aßmus version->SetFontSize(9); 8129949213aSStephan Aßmus // Make version be in the same line as title 8139949213aSStephan Aßmus version->ResizeToPreferred(); 8149949213aSStephan Aßmus version->MoveBy(0, rect.bottom-version->Frame().bottom); 8159949213aSStephan Aßmus 8169949213aSStephan Aßmus AddChild(version); 8179949213aSStephan Aßmus 8188687ff64SAxel Dörfler // Now for each line in translatorInfo add a BStringView 8198687ff64SAxel Dörfler char* current = translatorInfo; 8208687ff64SAxel Dörfler int32 index = 1; 8218687ff64SAxel Dörfler while (current != NULL && current[0]) { 8228687ff64SAxel Dörfler char text[128]; 8238687ff64SAxel Dörfler char* newLine = strchr(current, '\n'); 8248687ff64SAxel Dörfler if (newLine == NULL) { 8258687ff64SAxel Dörfler strlcpy(text, current, sizeof(text)); 8268687ff64SAxel Dörfler current = NULL; 8278687ff64SAxel Dörfler } else { 8288687ff64SAxel Dörfler strlcpy(text, current, min_c((int32)sizeof(text), newLine + 1 - current)); 8298687ff64SAxel Dörfler current = newLine + 1; 8308687ff64SAxel Dörfler } 8319949213aSStephan Aßmus 8328687ff64SAxel Dörfler BStringView* string = new BStringView(BRect(10, GetPreferredHeight(), 8338687ff64SAxel Dörfler 10, GetPreferredHeight()), "copyright", text); 8348687ff64SAxel Dörfler if (index > 3) 8358687ff64SAxel Dörfler string->SetFontSize(9); 8368687ff64SAxel Dörfler AddChild(string); 8378687ff64SAxel Dörfler 8388687ff64SAxel Dörfler index++; 8399949213aSStephan Aßmus } 8409949213aSStephan Aßmus 8419949213aSStephan Aßmus ResizeToPreferred(); 8429949213aSStephan Aßmus } 8439949213aSStephan Aßmus 8449949213aSStephan Aßmus 845d8e2fb50SAxel Dörfler // #pragma mark - 8469949213aSStephan Aßmus 847d8e2fb50SAxel Dörfler 8489949213aSStephan Aßmus TranslatorView::TranslatorView(const char *name) 849d8e2fb50SAxel Dörfler : SView(name), 850d8e2fb50SAxel Dörfler fTabWidth(30), 851d8e2fb50SAxel Dörfler fActiveChild(0) 8529949213aSStephan Aßmus { 8539949213aSStephan Aßmus // Set global var to true 854d8e2fb50SAxel Dörfler gAreSettingsRunning = true; 8559949213aSStephan Aßmus 856d8e2fb50SAxel Dörfler // Load settings to global settings struct 857d8e2fb50SAxel Dörfler LoadSettings(&fSettings); 8589949213aSStephan Aßmus 8598687ff64SAxel Dörfler font_height fontHeight; 8608687ff64SAxel Dörfler GetFontHeight(&fontHeight); 8618687ff64SAxel Dörfler fTabHeight = (int32)ceilf(fontHeight.ascent + fontHeight.descent + fontHeight.leading) + 7; 8629949213aSStephan Aßmus // Add left and top margins 8638687ff64SAxel Dörfler float top = fTabHeight + 20; 8649949213aSStephan Aßmus float left = 0; 8659949213aSStephan Aßmus 8669949213aSStephan Aßmus // This will remember longest string width 8679949213aSStephan Aßmus int32 nameWidth = 0; 8689949213aSStephan Aßmus 869d8e2fb50SAxel Dörfler SView *view = new TranslatorWriteView("Write", &fSettings, left, top); 8709949213aSStephan Aßmus AddChild(view); 871d8e2fb50SAxel Dörfler nameWidth = (int32)StringWidth(view->Name()); 8728687ff64SAxel Dörfler fTabs.AddItem(new BTab(view)); 8739949213aSStephan Aßmus 874d8e2fb50SAxel Dörfler view = new TranslatorReadView("Read", &fSettings, left, top); 8759949213aSStephan Aßmus AddChild(view); 8769949213aSStephan Aßmus if (nameWidth < StringWidth(view->Name())) 877d8e2fb50SAxel Dörfler nameWidth = (int32)StringWidth(view->Name()); 8788687ff64SAxel Dörfler fTabs.AddItem(new BTab(view)); 8799949213aSStephan Aßmus 8809949213aSStephan Aßmus view = new TranslatorAboutView("About", left, top); 8819949213aSStephan Aßmus AddChild(view); 8829949213aSStephan Aßmus if (nameWidth < StringWidth(view->Name())) 883d8e2fb50SAxel Dörfler nameWidth = (int32)StringWidth(view->Name()); 8848687ff64SAxel Dörfler fTabs.AddItem(new BTab(view)); 8859949213aSStephan Aßmus 886d8e2fb50SAxel Dörfler fTabWidth += nameWidth; 887d8e2fb50SAxel Dörfler if (fTabWidth * CountChildren() > GetPreferredWidth()) 888d8e2fb50SAxel Dörfler ResizePreferredBy((fTabWidth * CountChildren()) - GetPreferredWidth(), 0); 8899949213aSStephan Aßmus 8909949213aSStephan Aßmus // Add right and bottom margins 8919949213aSStephan Aßmus ResizePreferredBy(10, 15); 8929949213aSStephan Aßmus 8939949213aSStephan Aßmus ResizeToPreferred(); 8949949213aSStephan Aßmus 8959949213aSStephan Aßmus // Make TranslatorView resize itself with parent 8969949213aSStephan Aßmus SetFlags(Flags() | B_FOLLOW_ALL); 8979949213aSStephan Aßmus } 8989949213aSStephan Aßmus 899d8e2fb50SAxel Dörfler 900d8e2fb50SAxel Dörfler TranslatorView::~TranslatorView() 901d8e2fb50SAxel Dörfler { 902d8e2fb50SAxel Dörfler gAreSettingsRunning = false; 9038687ff64SAxel Dörfler 9048687ff64SAxel Dörfler BTab* tab; 9058687ff64SAxel Dörfler while ((tab = (BTab*)fTabs.RemoveItem((int32)0)) != NULL) { 9068687ff64SAxel Dörfler delete tab; 9078687ff64SAxel Dörfler } 908d8e2fb50SAxel Dörfler } 909d8e2fb50SAxel Dörfler 910d8e2fb50SAxel Dörfler 911d8e2fb50SAxel Dörfler //! Attached to window - resize parent to preferred 9129949213aSStephan Aßmus void 9139949213aSStephan Aßmus TranslatorView::AttachedToWindow() 9149949213aSStephan Aßmus { 9159949213aSStephan Aßmus // Hide all children except first one 916d8e2fb50SAxel Dörfler BView *child; 9179949213aSStephan Aßmus int32 index = 1; 918d8e2fb50SAxel Dörfler while ((child = ChildAt(index++)) != NULL) 9199949213aSStephan Aßmus child->Hide(); 9209949213aSStephan Aßmus 9218687ff64SAxel Dörfler } 9228687ff64SAxel Dörfler 9238687ff64SAxel Dörfler 9248687ff64SAxel Dörfler BRect 9258687ff64SAxel Dörfler TranslatorView::_TabFrame(int32 index) const 9268687ff64SAxel Dörfler { 9278687ff64SAxel Dörfler return BRect(index * fTabWidth, 10, (index + 1) * fTabWidth, 10 + fTabHeight); 9289949213aSStephan Aßmus } 9299949213aSStephan Aßmus 930d8e2fb50SAxel Dörfler 9319949213aSStephan Aßmus void 9329949213aSStephan Aßmus TranslatorView::Draw(BRect updateRect) 9339949213aSStephan Aßmus { 9349949213aSStephan Aßmus // This is needed because DataTranslations app hides children 9359949213aSStephan Aßmus // after user changes translator 936d8e2fb50SAxel Dörfler if (ChildAt(fActiveChild)->IsHidden()) 937d8e2fb50SAxel Dörfler ChildAt(fActiveChild)->Show(); 9389949213aSStephan Aßmus 9399949213aSStephan Aßmus // Clear 9409949213aSStephan Aßmus SetHighColor(ViewColor()); 9418687ff64SAxel Dörfler BRect frame = _TabFrame(0); 9428687ff64SAxel Dörfler FillRect(BRect(frame.left, frame.top, Bounds().right, frame.bottom - 1)); 9439949213aSStephan Aßmus 944d8e2fb50SAxel Dörfler int32 index = 0; 9458687ff64SAxel Dörfler BTab* tab; 9468687ff64SAxel Dörfler while ((tab = (BTab*)fTabs.ItemAt(index)) != NULL) { 9478687ff64SAxel Dörfler tab_position position; 9488687ff64SAxel Dörfler if (fActiveChild == index) 9498687ff64SAxel Dörfler position = B_TAB_FRONT; 9508687ff64SAxel Dörfler else if (index == 0) 9518687ff64SAxel Dörfler position = B_TAB_FIRST; 9529949213aSStephan Aßmus else 9538687ff64SAxel Dörfler position = B_TAB_ANY; 9549949213aSStephan Aßmus 9558687ff64SAxel Dörfler tab->DrawTab(this, _TabFrame(index), position, index + 1 != fActiveChild); 9569949213aSStephan Aßmus index++; 9579949213aSStephan Aßmus } 958d8e2fb50SAxel Dörfler 9598687ff64SAxel Dörfler // Draw bottom edge 9608687ff64SAxel Dörfler SetHighColor(tint_color(ViewColor(), B_LIGHTEN_MAX_TINT)); 9618687ff64SAxel Dörfler 9628687ff64SAxel Dörfler BRect selectedFrame = _TabFrame(fActiveChild); 9638687ff64SAxel Dörfler float offset = ceilf(frame.Height() / 2.0); 9648687ff64SAxel Dörfler 9658687ff64SAxel Dörfler if (selectedFrame.left > frame.left) { 9668687ff64SAxel Dörfler StrokeLine(BPoint(frame.left, frame.bottom), 9678687ff64SAxel Dörfler BPoint(selectedFrame.left, frame.bottom)); 9688687ff64SAxel Dörfler } 9698687ff64SAxel Dörfler if (selectedFrame.right + offset < Bounds().right) { 9708687ff64SAxel Dörfler StrokeLine(BPoint(selectedFrame.right + offset, frame.bottom), 9718687ff64SAxel Dörfler BPoint(Bounds().right, frame.bottom)); 9728687ff64SAxel Dörfler } 9739949213aSStephan Aßmus } 9749949213aSStephan Aßmus 975d8e2fb50SAxel Dörfler 976d8e2fb50SAxel Dörfler //! MouseDown, check if on tab, if so change tab if needed 9779949213aSStephan Aßmus void 9789949213aSStephan Aßmus TranslatorView::MouseDown(BPoint where) 9799949213aSStephan Aßmus { 9808687ff64SAxel Dörfler BRect frame = _TabFrame(fTabs.CountItems() - 1); 9818687ff64SAxel Dörfler frame.left = 0; 9828687ff64SAxel Dörfler if (!frame.Contains(where)) 9838687ff64SAxel Dörfler return; 9848687ff64SAxel Dörfler 9858687ff64SAxel Dörfler for (int32 index = fTabs.CountItems(); index-- > 0;) { 9868687ff64SAxel Dörfler if (!_TabFrame(index).Contains(where)) 9878687ff64SAxel Dörfler continue; 9888687ff64SAxel Dörfler 989d8e2fb50SAxel Dörfler if (fActiveChild != index) { 9909949213aSStephan Aßmus // Hide current visible child 991d8e2fb50SAxel Dörfler ChildAt(fActiveChild)->Hide(); 9928687ff64SAxel Dörfler 9939949213aSStephan Aßmus // This loop is needed because it looks like in DataTranslations 9949949213aSStephan Aßmus // view gets hidden more than one time when user changes translator 9958687ff64SAxel Dörfler while (ChildAt(index)->IsHidden()) { 9969949213aSStephan Aßmus ChildAt(index)->Show(); 9978687ff64SAxel Dörfler } 9988687ff64SAxel Dörfler 9999949213aSStephan Aßmus // Remember which one is currently visible 1000d8e2fb50SAxel Dörfler fActiveChild = index; 10018687ff64SAxel Dörfler Invalidate(frame); 10028687ff64SAxel Dörfler break; 10039949213aSStephan Aßmus } 10049949213aSStephan Aßmus } 1005d8e2fb50SAxel Dörfler } 10069949213aSStephan Aßmus 10079949213aSStephan Aßmus 1008d8e2fb50SAxel Dörfler // #pragma mark - 10099949213aSStephan Aßmus 1010d8e2fb50SAxel Dörfler 1011d8e2fb50SAxel Dörfler TranslatorWindow::TranslatorWindow(bool quitOnClose) 1012117da2d7SAxel Dörfler : BWindow(BRect(100, 100, 100, 100), "JPEG Settings", B_TITLED_WINDOW, 1013117da2d7SAxel Dörfler B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS) 10149949213aSStephan Aßmus { 10159949213aSStephan Aßmus BRect extent(0, 0, 0, 0); 10169949213aSStephan Aßmus BView *config = NULL; 10179949213aSStephan Aßmus MakeConfig(NULL, &config, &extent); 10189949213aSStephan Aßmus 10199949213aSStephan Aßmus AddChild(config); 10209949213aSStephan Aßmus ResizeTo(extent.Width(), extent.Height()); 10219949213aSStephan Aßmus 10229949213aSStephan Aßmus // Make application quit after this window close 1023d8e2fb50SAxel Dörfler if (quitOnClose) 10249949213aSStephan Aßmus SetFlags(Flags() | B_QUIT_ON_WINDOW_CLOSE); 10259949213aSStephan Aßmus } 10269949213aSStephan Aßmus 10279949213aSStephan Aßmus 1028d8e2fb50SAxel Dörfler // #pragma mark - Translator Add-On 10299949213aSStephan Aßmus 10309949213aSStephan Aßmus 10319949213aSStephan Aßmus 1032d8e2fb50SAxel Dörfler /*! Hook to create and return our configuration view */ 10339949213aSStephan Aßmus status_t 10349949213aSStephan Aßmus MakeConfig(BMessage *ioExtension, BView **outView, BRect *outExtent) 10359949213aSStephan Aßmus { 10369949213aSStephan Aßmus *outView = new TranslatorView("TranslatorView"); 10379949213aSStephan Aßmus *outExtent = (*outView)->Frame(); 10389949213aSStephan Aßmus return B_OK; 10399949213aSStephan Aßmus } 10409949213aSStephan Aßmus 1041d8e2fb50SAxel Dörfler /*! Determine whether or not we can handle this data */ 10429949213aSStephan Aßmus status_t 1043d8e2fb50SAxel Dörfler Identify(BPositionIO *inSource, const translation_format *inFormat, 1044d8e2fb50SAxel Dörfler BMessage *ioExtension, translator_info *outInfo, uint32 outType) 10459949213aSStephan Aßmus { 1046d8e2fb50SAxel Dörfler if (outType != 0 && outType != B_TRANSLATOR_BITMAP && outType != JPEG_FORMAT) 10479949213aSStephan Aßmus return B_NO_TRANSLATOR; 10489949213aSStephan Aßmus 10499949213aSStephan Aßmus // !!! You might need to make this buffer bigger to test for your native format 10509949213aSStephan Aßmus off_t position = inSource->Position(); 10519949213aSStephan Aßmus char header[sizeof(TranslatorBitmap)]; 10529949213aSStephan Aßmus status_t err = inSource->Read(header, sizeof(TranslatorBitmap)); 10539949213aSStephan Aßmus inSource->Seek(position, SEEK_SET); 1054d8e2fb50SAxel Dörfler if (err < B_OK) 1055d8e2fb50SAxel Dörfler return err; 10569949213aSStephan Aßmus 10579949213aSStephan Aßmus if (B_BENDIAN_TO_HOST_INT32(((TranslatorBitmap *)header)->magic) == B_TRANSLATOR_BITMAP) { 10589949213aSStephan Aßmus outInfo->type = inputFormats[1].type; 10599949213aSStephan Aßmus outInfo->translator = 0; 10609949213aSStephan Aßmus outInfo->group = inputFormats[1].group; 10619949213aSStephan Aßmus outInfo->quality = inputFormats[1].quality; 10629949213aSStephan Aßmus outInfo->capability = inputFormats[1].capability; 10639949213aSStephan Aßmus strcpy(outInfo->name, inputFormats[1].name); 10649949213aSStephan Aßmus strcpy(outInfo->MIME, inputFormats[1].MIME); 10659949213aSStephan Aßmus } else { 10669949213aSStephan Aßmus // First 3 bytes in jpg files are always the same from what i've seen so far 10679949213aSStephan Aßmus // check them 10689949213aSStephan Aßmus if (header[0] == (char)0xff && header[1] == (char)0xd8 && header[2] == (char)0xff) { 10699949213aSStephan Aßmus /* this below would be safer but it slows down whole thing 10709949213aSStephan Aßmus 10719949213aSStephan Aßmus struct jpeg_decompress_struct cinfo; 10729949213aSStephan Aßmus struct jpeg_error_mgr jerr; 10739949213aSStephan Aßmus cinfo.err = jpeg_std_error(&jerr); 10749949213aSStephan Aßmus jpeg_create_decompress(&cinfo); 10759949213aSStephan Aßmus be_jpeg_stdio_src(&cinfo, inSource); 10769949213aSStephan Aßmus // now try to read header 10779949213aSStephan Aßmus // it can't be read before checking first 3 bytes 10789949213aSStephan Aßmus // because it will hang up if there is no header (not jpeg file) 10799949213aSStephan Aßmus int result = jpeg_read_header(&cinfo, FALSE); 10809949213aSStephan Aßmus jpeg_destroy_decompress(&cinfo); 10819949213aSStephan Aßmus if (result == JPEG_HEADER_OK) { 10829949213aSStephan Aßmus */ outInfo->type = inputFormats[0].type; 10839949213aSStephan Aßmus outInfo->translator = 0; 10849949213aSStephan Aßmus outInfo->group = inputFormats[0].group; 10859949213aSStephan Aßmus outInfo->quality = inputFormats[0].quality; 10869949213aSStephan Aßmus outInfo->capability = inputFormats[0].capability; 10879949213aSStephan Aßmus strcpy(outInfo->name, inputFormats[0].name); 10889949213aSStephan Aßmus strcpy(outInfo->MIME, inputFormats[0].MIME); 10899949213aSStephan Aßmus return B_OK; 10909949213aSStephan Aßmus /* } else 10919949213aSStephan Aßmus return B_NO_TRANSLATOR; 10929949213aSStephan Aßmus */ 10939949213aSStephan Aßmus } else 10949949213aSStephan Aßmus return B_NO_TRANSLATOR; 10959949213aSStephan Aßmus } 10969949213aSStephan Aßmus 10979949213aSStephan Aßmus return B_OK; 10989949213aSStephan Aßmus } 10999949213aSStephan Aßmus 1100d8e2fb50SAxel Dörfler /*! Arguably the most important method in the add-on */ 11019949213aSStephan Aßmus status_t 1102d8e2fb50SAxel Dörfler Translate(BPositionIO *inSource, const translator_info *inInfo, 1103d8e2fb50SAxel Dörfler BMessage *ioExtension, uint32 outType, BPositionIO *outDestination) 11049949213aSStephan Aßmus { 11059949213aSStephan Aßmus // If no specific type was requested, convert to the interchange format 11069949213aSStephan Aßmus if (outType == 0) outType = B_TRANSLATOR_BITMAP; 11079949213aSStephan Aßmus 11089949213aSStephan Aßmus // What action to take, based on the findings of Identify() 11099949213aSStephan Aßmus if (outType == inInfo->type) { 11109949213aSStephan Aßmus return Copy(inSource, outDestination); 11119949213aSStephan Aßmus } else if (inInfo->type == B_TRANSLATOR_BITMAP && outType == JPEG_FORMAT) { 11129949213aSStephan Aßmus return Compress(inSource, outDestination); 11139949213aSStephan Aßmus } else if (inInfo->type == JPEG_FORMAT && outType == B_TRANSLATOR_BITMAP) { 111452e8f46aSAxel Dörfler return Decompress(inSource, outDestination, ioExtension); 11159949213aSStephan Aßmus } 11169949213aSStephan Aßmus 11179949213aSStephan Aßmus return B_NO_TRANSLATOR; 11189949213aSStephan Aßmus } 11199949213aSStephan Aßmus 1120d8e2fb50SAxel Dörfler /*! The user has requested the same format for input and output, so just copy */ 112152e8f46aSAxel Dörfler static status_t 11229949213aSStephan Aßmus Copy(BPositionIO *in, BPositionIO *out) 11239949213aSStephan Aßmus { 11249949213aSStephan Aßmus int block_size = 65536; 11259949213aSStephan Aßmus void *buffer = malloc(block_size); 11269949213aSStephan Aßmus char temp[1024]; 11279949213aSStephan Aßmus if (buffer == NULL) { 11289949213aSStephan Aßmus buffer = temp; 11299949213aSStephan Aßmus block_size = 1024; 11309949213aSStephan Aßmus } 11319949213aSStephan Aßmus status_t err = B_OK; 11329949213aSStephan Aßmus 11339949213aSStephan Aßmus // Read until end of file or error 11349949213aSStephan Aßmus while (1) { 11359949213aSStephan Aßmus ssize_t to_read = block_size; 11369949213aSStephan Aßmus err = in->Read(buffer, to_read); 11379949213aSStephan Aßmus // Explicit check for EOF 11389949213aSStephan Aßmus if (err == -1) { 11399949213aSStephan Aßmus if (buffer != temp) free(buffer); 11409949213aSStephan Aßmus return B_OK; 11419949213aSStephan Aßmus } 11429949213aSStephan Aßmus if (err <= B_OK) break; 11439949213aSStephan Aßmus to_read = err; 11449949213aSStephan Aßmus err = out->Write(buffer, to_read); 11459949213aSStephan Aßmus if (err != to_read) if (err >= 0) err = B_DEVICE_FULL; 11469949213aSStephan Aßmus if (err < B_OK) break; 11479949213aSStephan Aßmus } 11489949213aSStephan Aßmus 11499949213aSStephan Aßmus if (buffer != temp) free(buffer); 11509949213aSStephan Aßmus return (err >= 0) ? B_OK : err; 11519949213aSStephan Aßmus } 11529949213aSStephan Aßmus 1153d8e2fb50SAxel Dörfler 1154d8e2fb50SAxel Dörfler /*! Encode into the native format */ 115552e8f46aSAxel Dörfler static status_t 11569949213aSStephan Aßmus Compress(BPositionIO *in, BPositionIO *out) 11579949213aSStephan Aßmus { 11589949213aSStephan Aßmus // Load Settings 1159d8e2fb50SAxel Dörfler jpeg_settings settings; 1160d8e2fb50SAxel Dörfler LoadSettings(&settings); 11619949213aSStephan Aßmus 11629949213aSStephan Aßmus // Read info about bitmap 11639949213aSStephan Aßmus TranslatorBitmap header; 11649949213aSStephan Aßmus status_t err = in->Read(&header, sizeof(TranslatorBitmap)); 1165d8e2fb50SAxel Dörfler if (err < B_OK) 1166d8e2fb50SAxel Dörfler return err; 1167d8e2fb50SAxel Dörfler else if (err < (int)sizeof(TranslatorBitmap)) 1168d8e2fb50SAxel Dörfler return B_ERROR; 11699949213aSStephan Aßmus 11709949213aSStephan Aßmus // Grab dimension, color space, and size information from the stream 11719949213aSStephan Aßmus BRect bounds; 11729949213aSStephan Aßmus bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left); 11739949213aSStephan Aßmus bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top); 11749949213aSStephan Aßmus bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right); 11759949213aSStephan Aßmus bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom); 11769949213aSStephan Aßmus 11779949213aSStephan Aßmus int32 in_row_bytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes); 11789949213aSStephan Aßmus 11799949213aSStephan Aßmus int width = bounds.IntegerWidth() + 1; 11809949213aSStephan Aßmus int height = bounds.IntegerHeight() + 1; 11819949213aSStephan Aßmus 11829949213aSStephan Aßmus // Function pointer to convert function 11839949213aSStephan Aßmus // It will point to proper function if needed 11849e34f742SAxel Dörfler void (*converter)(uchar *inscanline, uchar *outscanline, 11859e34f742SAxel Dörfler int32 inRowBytes) = NULL; 11869949213aSStephan Aßmus 11879949213aSStephan Aßmus // Default color info 11889949213aSStephan Aßmus J_COLOR_SPACE jpg_color_space = JCS_RGB; 11899949213aSStephan Aßmus int jpg_input_components = 3; 11909949213aSStephan Aßmus int32 out_row_bytes; 11919949213aSStephan Aßmus int padding = 0; 11929949213aSStephan Aßmus 1193d8e2fb50SAxel Dörfler switch ((color_space)B_BENDIAN_TO_HOST_INT32(header.colors)) { 11949949213aSStephan Aßmus case B_CMAP8: 11959949213aSStephan Aßmus converter = convert_from_cmap8_to_24; 11969949213aSStephan Aßmus padding = in_row_bytes - width; 11979949213aSStephan Aßmus break; 1198d8e2fb50SAxel Dörfler 11999949213aSStephan Aßmus case B_GRAY1: 1200d8e2fb50SAxel Dörfler if (settings.B_GRAY1_as_B_RGB24) { 12019949213aSStephan Aßmus converter = convert_from_gray1_to_24; 12029949213aSStephan Aßmus } else { 12039949213aSStephan Aßmus jpg_input_components = 1; 12049949213aSStephan Aßmus jpg_color_space = JCS_GRAYSCALE; 12059949213aSStephan Aßmus converter = convert_from_gray1_to_gray8; 12069949213aSStephan Aßmus } 12079949213aSStephan Aßmus padding = in_row_bytes - (width/8); 12089949213aSStephan Aßmus break; 1209d8e2fb50SAxel Dörfler 12109949213aSStephan Aßmus case B_GRAY8: 12119949213aSStephan Aßmus jpg_input_components = 1; 12129949213aSStephan Aßmus jpg_color_space = JCS_GRAYSCALE; 12139949213aSStephan Aßmus padding = in_row_bytes - width; 12149949213aSStephan Aßmus break; 1215d8e2fb50SAxel Dörfler 12169949213aSStephan Aßmus case B_RGB15: 12179949213aSStephan Aßmus case B_RGBA15: 12189949213aSStephan Aßmus converter = convert_from_15_to_24; 12199949213aSStephan Aßmus padding = in_row_bytes - (width * 2); 12209949213aSStephan Aßmus break; 1221d8e2fb50SAxel Dörfler 12229949213aSStephan Aßmus case B_RGB15_BIG: 12239949213aSStephan Aßmus case B_RGBA15_BIG: 12249949213aSStephan Aßmus converter = convert_from_15b_to_24; 12259949213aSStephan Aßmus padding = in_row_bytes - (width * 2); 12269949213aSStephan Aßmus break; 1227d8e2fb50SAxel Dörfler 12289949213aSStephan Aßmus case B_RGB16: 12299949213aSStephan Aßmus converter = convert_from_16_to_24; 12309949213aSStephan Aßmus padding = in_row_bytes - (width * 2); 12319949213aSStephan Aßmus break; 1232d8e2fb50SAxel Dörfler 12339949213aSStephan Aßmus case B_RGB16_BIG: 12349949213aSStephan Aßmus converter = convert_from_16b_to_24; 12359949213aSStephan Aßmus padding = in_row_bytes - (width * 2); 12369949213aSStephan Aßmus break; 1237d8e2fb50SAxel Dörfler 12389949213aSStephan Aßmus case B_RGB24: 12399949213aSStephan Aßmus converter = convert_from_24_to_24; 12409949213aSStephan Aßmus padding = in_row_bytes - (width * 3); 12419949213aSStephan Aßmus break; 1242d8e2fb50SAxel Dörfler 12439949213aSStephan Aßmus case B_RGB24_BIG: 12449949213aSStephan Aßmus padding = in_row_bytes - (width * 3); 12459949213aSStephan Aßmus break; 1246d8e2fb50SAxel Dörfler 12479949213aSStephan Aßmus case B_RGB32: 12489949213aSStephan Aßmus case B_RGBA32: 12499949213aSStephan Aßmus converter = convert_from_32_to_24; 12509949213aSStephan Aßmus padding = in_row_bytes - (width * 4); 12519949213aSStephan Aßmus break; 1252d8e2fb50SAxel Dörfler 12539949213aSStephan Aßmus case B_RGB32_BIG: 12549949213aSStephan Aßmus case B_RGBA32_BIG: 12559949213aSStephan Aßmus converter = convert_from_32b_to_24; 12569949213aSStephan Aßmus padding = in_row_bytes - (width * 4); 12579949213aSStephan Aßmus break; 1258d8e2fb50SAxel Dörfler 12599949213aSStephan Aßmus case B_CMYK32: 12609949213aSStephan Aßmus jpg_color_space = JCS_CMYK; 12619949213aSStephan Aßmus jpg_input_components = 4; 12629949213aSStephan Aßmus padding = in_row_bytes - (width * 4); 12639949213aSStephan Aßmus break; 1264d8e2fb50SAxel Dörfler 12659949213aSStephan Aßmus default: 12669949213aSStephan Aßmus fprintf(stderr, "Wrong type: Color space not implemented.\n"); 12679949213aSStephan Aßmus return B_ERROR; 12689949213aSStephan Aßmus } 12699949213aSStephan Aßmus out_row_bytes = jpg_input_components * width; 12709949213aSStephan Aßmus 12719949213aSStephan Aßmus // Set basic things needed for jpeg writing 12729949213aSStephan Aßmus struct jpeg_compress_struct cinfo; 12739949213aSStephan Aßmus struct jpeg_error_mgr jerr; 1274d8e2fb50SAxel Dörfler cinfo.err = be_jpeg_std_error(&jerr, &settings); 12759949213aSStephan Aßmus jpeg_create_compress(&cinfo); 12769949213aSStephan Aßmus be_jpeg_stdio_dest(&cinfo, out); 12779949213aSStephan Aßmus 12789949213aSStephan Aßmus // Set basic values 12799949213aSStephan Aßmus cinfo.image_width = width; 12809949213aSStephan Aßmus cinfo.image_height = height; 12819949213aSStephan Aßmus cinfo.input_components = jpg_input_components; 12829949213aSStephan Aßmus cinfo.in_color_space = jpg_color_space; 12839949213aSStephan Aßmus jpeg_set_defaults(&cinfo); 12849949213aSStephan Aßmus 12859949213aSStephan Aßmus // Set better accuracy 12869949213aSStephan Aßmus cinfo.dct_method = JDCT_ISLOW; 12879949213aSStephan Aßmus 12889949213aSStephan Aßmus // This is needed to prevent some colors loss 12899949213aSStephan Aßmus // With it generated jpegs are as good as from Fireworks (at last! :D) 1290d8e2fb50SAxel Dörfler if (settings.OptimizeColors) { 12919949213aSStephan Aßmus int index = 0; 12929949213aSStephan Aßmus while (index < cinfo.num_components) { 12939949213aSStephan Aßmus cinfo.comp_info[index].h_samp_factor = 1; 12949949213aSStephan Aßmus cinfo.comp_info[index].v_samp_factor = 1; 12959949213aSStephan Aßmus // This will make file smaller, but with worse quality more or less 12969949213aSStephan Aßmus // like with 93%-94% (but it's subjective opinion) on tested images 12979949213aSStephan Aßmus // but with smaller size (between 92% and 93% on tested images) 1298d8e2fb50SAxel Dörfler if (settings.SmallerFile) 12999949213aSStephan Aßmus cinfo.comp_info[index].quant_tbl_no = 1; 13009949213aSStephan Aßmus // This will make bigger file, but also better quality ;] 13019949213aSStephan Aßmus // from my tests it seems like useless - better quality with smaller 13029949213aSStephan Aßmus // can be acheived without this 13039949213aSStephan Aßmus // cinfo.comp_info[index].dc_tbl_no = 1; 13049949213aSStephan Aßmus // cinfo.comp_info[index].ac_tbl_no = 1; 13059949213aSStephan Aßmus index++; 13069949213aSStephan Aßmus } 13079949213aSStephan Aßmus } 13089949213aSStephan Aßmus 13099949213aSStephan Aßmus // Set quality 1310d8e2fb50SAxel Dörfler jpeg_set_quality(&cinfo, settings.Quality, true); 13119949213aSStephan Aßmus 13129949213aSStephan Aßmus // Set progressive compression if needed 13139949213aSStephan Aßmus // if not, turn on optimizing in libjpeg 1314d8e2fb50SAxel Dörfler if (settings.Progressive) 13159949213aSStephan Aßmus jpeg_simple_progression(&cinfo); 13169949213aSStephan Aßmus else 13179949213aSStephan Aßmus cinfo.optimize_coding = TRUE; 13189949213aSStephan Aßmus 13199949213aSStephan Aßmus // Set smoothing (effect like Blur) 1320d8e2fb50SAxel Dörfler cinfo.smoothing_factor = settings.Smoothing; 13219949213aSStephan Aßmus 13229949213aSStephan Aßmus // Initialize compression 13239949213aSStephan Aßmus jpeg_start_compress(&cinfo, TRUE); 13249949213aSStephan Aßmus 13259949213aSStephan Aßmus // Declare scanlines 13269949213aSStephan Aßmus JSAMPROW in_scanline = NULL; 13279949213aSStephan Aßmus JSAMPROW out_scanline = NULL; 13289949213aSStephan Aßmus JSAMPROW writeline; // Pointer to in_scanline (default) or out_scanline (if there will be conversion) 13299949213aSStephan Aßmus 13309949213aSStephan Aßmus // Allocate scanline 13319949213aSStephan Aßmus // Use libjpeg memory allocation functions, so in case of error it will free them itself 1332d8e2fb50SAxel Dörfler in_scanline = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo, 1333d8e2fb50SAxel Dörfler JPOOL_PERMANENT, in_row_bytes); 13349949213aSStephan Aßmus 13359949213aSStephan Aßmus // We need 2nd scanline storage ony for conversion 13369949213aSStephan Aßmus if (converter != NULL) { 13379949213aSStephan Aßmus // There will be conversion, allocate second scanline... 13389949213aSStephan Aßmus // Use libjpeg memory allocation functions, so in case of error it will free them itself 1339d8e2fb50SAxel Dörfler out_scanline = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo, 1340d8e2fb50SAxel Dörfler JPOOL_PERMANENT, out_row_bytes); 13419949213aSStephan Aßmus // ... and make it the one to write to file 13429949213aSStephan Aßmus writeline = out_scanline; 13439949213aSStephan Aßmus } else 13449949213aSStephan Aßmus writeline = in_scanline; 13459949213aSStephan Aßmus 13469949213aSStephan Aßmus while (cinfo.next_scanline < cinfo.image_height) { 13479949213aSStephan Aßmus // Read scanline 13489949213aSStephan Aßmus err = in->Read(in_scanline, in_row_bytes); 13499949213aSStephan Aßmus if (err < in_row_bytes) 1350d8e2fb50SAxel Dörfler return err < B_OK ? Error((j_common_ptr)&cinfo, err) 1351d8e2fb50SAxel Dörfler : Error((j_common_ptr)&cinfo, B_ERROR); 13529949213aSStephan Aßmus 13539949213aSStephan Aßmus // Convert if needed 13549949213aSStephan Aßmus if (converter != NULL) 13559949213aSStephan Aßmus converter(in_scanline, out_scanline, in_row_bytes - padding); 13569949213aSStephan Aßmus 13579949213aSStephan Aßmus // Write scanline 13589949213aSStephan Aßmus jpeg_write_scanlines(&cinfo, &writeline, 1); 13599949213aSStephan Aßmus } 13609949213aSStephan Aßmus 13619949213aSStephan Aßmus jpeg_finish_compress(&cinfo); 13629949213aSStephan Aßmus jpeg_destroy_compress(&cinfo); 13639949213aSStephan Aßmus return B_OK; 13649949213aSStephan Aßmus } 13659949213aSStephan Aßmus 1366d8e2fb50SAxel Dörfler 1367d8e2fb50SAxel Dörfler /*! Decode the native format */ 136852e8f46aSAxel Dörfler static status_t 136952e8f46aSAxel Dörfler Decompress(BPositionIO *in, BPositionIO *out, BMessage* ioExtension) 13709949213aSStephan Aßmus { 13719949213aSStephan Aßmus // Load Settings 1372d8e2fb50SAxel Dörfler jpeg_settings settings; 1373d8e2fb50SAxel Dörfler LoadSettings(&settings); 13749949213aSStephan Aßmus 13759949213aSStephan Aßmus // Set basic things needed for jpeg reading 13769949213aSStephan Aßmus struct jpeg_decompress_struct cinfo; 13779949213aSStephan Aßmus struct jpeg_error_mgr jerr; 1378d8e2fb50SAxel Dörfler cinfo.err = be_jpeg_std_error(&jerr, &settings); 13799949213aSStephan Aßmus jpeg_create_decompress(&cinfo); 13809949213aSStephan Aßmus be_jpeg_stdio_src(&cinfo, in); 13819949213aSStephan Aßmus 138252e8f46aSAxel Dörfler jpeg_save_markers(&cinfo, MARKER_EXIF, 131072); 138352e8f46aSAxel Dörfler // make sure the EXIF tag is stored 138452e8f46aSAxel Dörfler 13859949213aSStephan Aßmus // Read info about image 13869949213aSStephan Aßmus jpeg_read_header(&cinfo, TRUE); 13879949213aSStephan Aßmus 138852e8f46aSAxel Dörfler BMessage exif; 138952e8f46aSAxel Dörfler 1390*f13b5de6SAxel Dörfler // parse EXIF data and add it ioExtension, if any 139152e8f46aSAxel Dörfler jpeg_marker_struct* marker = cinfo.marker_list; 139252e8f46aSAxel Dörfler while (marker != NULL) { 139352e8f46aSAxel Dörfler if (marker->marker == MARKER_EXIF 139452e8f46aSAxel Dörfler && !strncmp((char*)marker->data, "Exif", 4)) { 1395*f13b5de6SAxel Dörfler if (ioExtension != NULL) { 139652e8f46aSAxel Dörfler // Strip EXIF header from TIFF data 139752e8f46aSAxel Dörfler ioExtension->AddData("exif", B_RAW_TYPE, 139852e8f46aSAxel Dörfler (uint8 *)marker->data + 6, marker->data_length - 6); 1399*f13b5de6SAxel Dörfler } 140052e8f46aSAxel Dörfler 140152e8f46aSAxel Dörfler BMemoryIO io(marker->data + 6, marker->data_length - 6); 140252e8f46aSAxel Dörfler convert_exif_to_message(io, exif); 140352e8f46aSAxel Dörfler } 140452e8f46aSAxel Dörfler marker = marker->next; 140552e8f46aSAxel Dörfler } 140652e8f46aSAxel Dörfler 14079949213aSStephan Aßmus // Default color info 140852e8f46aSAxel Dörfler color_space outColorSpace = B_RGB32; 140952e8f46aSAxel Dörfler int outColorComponents = 4; 14109949213aSStephan Aßmus 14119949213aSStephan Aßmus // Function pointer to convert function 14129949213aSStephan Aßmus // It will point to proper function if needed 141352e8f46aSAxel Dörfler void (*converter)(uchar *inScanLine, uchar *outScanLine, 14149e34f742SAxel Dörfler int32 inRowBytes, int32 xStep) = convert_from_24_to_32; 14159949213aSStephan Aßmus 14169949213aSStephan Aßmus // If color space isn't rgb 14179949213aSStephan Aßmus if (cinfo.out_color_space != JCS_RGB) { 1418d8e2fb50SAxel Dörfler switch (cinfo.out_color_space) { 14199949213aSStephan Aßmus case JCS_UNKNOWN: /* error/unspecified */ 14209949213aSStephan Aßmus fprintf(stderr, "From Type: Jpeg uses unknown color type\n"); 14219949213aSStephan Aßmus break; 14229949213aSStephan Aßmus case JCS_GRAYSCALE: /* monochrome */ 14239949213aSStephan Aßmus // Check if user wants to read only as RGB32 or not 1424d8e2fb50SAxel Dörfler if (!settings.Always_B_RGB32) { 14259949213aSStephan Aßmus // Grayscale 142652e8f46aSAxel Dörfler outColorSpace = B_GRAY8; 142752e8f46aSAxel Dörfler outColorComponents = 1; 14289e34f742SAxel Dörfler converter = translate_8; 14299949213aSStephan Aßmus } else { 14309949213aSStephan Aßmus // RGB 14319949213aSStephan Aßmus cinfo.out_color_space = JCS_RGB; 14329949213aSStephan Aßmus cinfo.output_components = 3; 14339949213aSStephan Aßmus converter = convert_from_24_to_32; 14349949213aSStephan Aßmus } 14359949213aSStephan Aßmus break; 14369949213aSStephan Aßmus case JCS_YCbCr: /* Y/Cb/Cr (also known as YUV) */ 14379949213aSStephan Aßmus cinfo.out_color_space = JCS_RGB; 14389949213aSStephan Aßmus converter = convert_from_24_to_32; 14399949213aSStephan Aßmus break; 14409949213aSStephan Aßmus case JCS_YCCK: /* Y/Cb/Cr/K */ 14419949213aSStephan Aßmus // Let libjpeg convert it to CMYK 14429949213aSStephan Aßmus cinfo.out_color_space = JCS_CMYK; 14439949213aSStephan Aßmus // Fall through to CMYK since we need the same settings 14449949213aSStephan Aßmus case JCS_CMYK: /* C/M/Y/K */ 14459949213aSStephan Aßmus // Use proper converter 1446d8e2fb50SAxel Dörfler if (settings.PhotoshopCMYK) 14479949213aSStephan Aßmus converter = convert_from_CMYK_to_32_photoshop; 14489949213aSStephan Aßmus else 14499949213aSStephan Aßmus converter = convert_from_CMYK_to_32; 14509949213aSStephan Aßmus break; 14519949213aSStephan Aßmus default: 14529949213aSStephan Aßmus fprintf(stderr, "From Type: Jpeg uses hmm... i don't know really :(\n"); 14539949213aSStephan Aßmus break; 14549949213aSStephan Aßmus } 14559949213aSStephan Aßmus } 14569949213aSStephan Aßmus 14579949213aSStephan Aßmus // Initialize decompression 14589949213aSStephan Aßmus jpeg_start_decompress(&cinfo); 14599949213aSStephan Aßmus 14609e34f742SAxel Dörfler // retrieve orientation from settings/EXIF 146152e8f46aSAxel Dörfler int32 orientation; 14629e34f742SAxel Dörfler if (ioExtension == NULL 14639e34f742SAxel Dörfler || ioExtension->FindInt32("exif:orientation", &orientation) != B_OK) { 146452e8f46aSAxel Dörfler if (exif.FindInt32("Orientation", &orientation) != B_OK) 146552e8f46aSAxel Dörfler orientation = 1; 146652e8f46aSAxel Dörfler } 14679949213aSStephan Aßmus 14689e34f742SAxel Dörfler if (orientation != 1 && converter == NULL) 14699e34f742SAxel Dörfler converter = translate_8; 14709e34f742SAxel Dörfler 14719e34f742SAxel Dörfler int32 outputWidth = orientation > 4 ? cinfo.output_height : cinfo.output_width; 14729e34f742SAxel Dörfler int32 outputHeight = orientation > 4 ? cinfo.output_width : cinfo.output_height; 14739e34f742SAxel Dörfler 14749e34f742SAxel Dörfler int32 destOffset = dest_index(outputWidth, outputHeight, 14759e34f742SAxel Dörfler 0, 0, orientation) * outColorComponents; 14769e34f742SAxel Dörfler int32 xStep = dest_index(outputWidth, outputHeight, 14779e34f742SAxel Dörfler 1, 0, orientation) * outColorComponents - destOffset; 14789e34f742SAxel Dörfler int32 yStep = dest_index(outputWidth, outputHeight, 14799e34f742SAxel Dörfler 0, 1, orientation) * outColorComponents - destOffset; 14809e34f742SAxel Dörfler bool needAll = orientation != 1; 14819e34f742SAxel Dörfler 14829e34f742SAxel Dörfler // Initialize this bounds rect to the size of your image 14839e34f742SAxel Dörfler BRect bounds(0, 0, outputWidth - 1, outputHeight - 1); 14849e34f742SAxel Dörfler 14859e34f742SAxel Dörfler #if 0 14869e34f742SAxel Dörfler printf("destOffset = %ld, xStep = %ld, yStep = %ld, input: %ld x %ld, output: %ld x %ld, orientation %ld\n", 14879e34f742SAxel Dörfler destOffset, xStep, yStep, (int32)cinfo.output_width, (int32)cinfo.output_height, 14889e34f742SAxel Dörfler bounds.IntegerWidth() + 1, bounds.IntegerHeight() + 1, orientation); 14899e34f742SAxel Dörfler #endif 14909e34f742SAxel Dörfler 14919949213aSStephan Aßmus // Bytes count in one line of image (scanline) 14929e34f742SAxel Dörfler int32 inRowBytes = cinfo.output_width * cinfo.output_components; 14939e34f742SAxel Dörfler int32 rowBytes = (bounds.IntegerWidth() + 1) * outColorComponents; 14949e34f742SAxel Dörfler int32 dataSize = cinfo.output_width * cinfo.output_height 14959e34f742SAxel Dörfler * outColorComponents; 14969949213aSStephan Aßmus 14979949213aSStephan Aßmus // Fill out the B_TRANSLATOR_BITMAP's header 14989949213aSStephan Aßmus TranslatorBitmap header; 14999949213aSStephan Aßmus header.magic = B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP); 15009949213aSStephan Aßmus header.bounds.left = B_HOST_TO_BENDIAN_FLOAT(bounds.left); 15019949213aSStephan Aßmus header.bounds.top = B_HOST_TO_BENDIAN_FLOAT(bounds.top); 15029949213aSStephan Aßmus header.bounds.right = B_HOST_TO_BENDIAN_FLOAT(bounds.right); 15039949213aSStephan Aßmus header.bounds.bottom = B_HOST_TO_BENDIAN_FLOAT(bounds.bottom); 150452e8f46aSAxel Dörfler header.colors = (color_space)B_HOST_TO_BENDIAN_INT32(outColorSpace); 150552e8f46aSAxel Dörfler header.rowBytes = B_HOST_TO_BENDIAN_INT32(rowBytes); 15069e34f742SAxel Dörfler header.dataSize = B_HOST_TO_BENDIAN_INT32(dataSize); 15079949213aSStephan Aßmus 15089949213aSStephan Aßmus // Write out the header 15099949213aSStephan Aßmus status_t err = out->Write(&header, sizeof(TranslatorBitmap)); 1510d8e2fb50SAxel Dörfler if (err < B_OK) 1511d8e2fb50SAxel Dörfler return Error((j_common_ptr)&cinfo, err); 1512d8e2fb50SAxel Dörfler else if (err < (int)sizeof(TranslatorBitmap)) 1513d8e2fb50SAxel Dörfler return Error((j_common_ptr)&cinfo, B_ERROR); 15149949213aSStephan Aßmus 15159949213aSStephan Aßmus // Declare scanlines 15169e34f742SAxel Dörfler JSAMPROW inScanLine = NULL; 15179e34f742SAxel Dörfler uint8* dest = NULL; 15189e34f742SAxel Dörfler uint8* destLine = NULL; 15199949213aSStephan Aßmus 15209949213aSStephan Aßmus // Allocate scanline 15219949213aSStephan Aßmus // Use libjpeg memory allocation functions, so in case of error it will free them itself 15229e34f742SAxel Dörfler inScanLine = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo, 15239e34f742SAxel Dörfler JPOOL_PERMANENT, inRowBytes); 15249949213aSStephan Aßmus 15259949213aSStephan Aßmus // We need 2nd scanline storage only for conversion 15269949213aSStephan Aßmus if (converter != NULL) { 15279949213aSStephan Aßmus // There will be conversion, allocate second scanline... 15289e34f742SAxel Dörfler // Use libjpeg memory allocation functions, so in case of error it will free 15299e34f742SAxel Dörfler // them itself 15309e34f742SAxel Dörfler dest = (uint8*)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo, 15319e34f742SAxel Dörfler JPOOL_PERMANENT, needAll ? dataSize : rowBytes); 15329e34f742SAxel Dörfler destLine = dest + destOffset; 15339949213aSStephan Aßmus } else 15349e34f742SAxel Dörfler destLine = inScanLine; 15359949213aSStephan Aßmus 15369949213aSStephan Aßmus while (cinfo.output_scanline < cinfo.output_height) { 15379949213aSStephan Aßmus // Read scanline 15389e34f742SAxel Dörfler jpeg_read_scanlines(&cinfo, &inScanLine, 1); 15399949213aSStephan Aßmus 15409949213aSStephan Aßmus // Convert if needed 15419949213aSStephan Aßmus if (converter != NULL) 15429e34f742SAxel Dörfler converter(inScanLine, destLine, inRowBytes, xStep); 15439949213aSStephan Aßmus 15449e34f742SAxel Dörfler if (!needAll) { 15459949213aSStephan Aßmus // Write the scanline buffer to the output stream 15469e34f742SAxel Dörfler ssize_t bytesWritten = out->Write(destLine, rowBytes); 15479e34f742SAxel Dörfler if (bytesWritten < rowBytes) { 15489e34f742SAxel Dörfler return bytesWritten < B_OK 15499e34f742SAxel Dörfler ? Error((j_common_ptr)&cinfo, bytesWritten) 1550d8e2fb50SAxel Dörfler : Error((j_common_ptr)&cinfo, B_ERROR); 15519949213aSStephan Aßmus } 15529e34f742SAxel Dörfler } else 15539e34f742SAxel Dörfler destLine += yStep; 15549e34f742SAxel Dörfler } 15559e34f742SAxel Dörfler 15569e34f742SAxel Dörfler if (needAll) { 15579e34f742SAxel Dörfler ssize_t bytesWritten = out->Write(dest, dataSize); 15589e34f742SAxel Dörfler if (bytesWritten < dataSize) { 15599e34f742SAxel Dörfler return bytesWritten < B_OK 15609e34f742SAxel Dörfler ? Error((j_common_ptr)&cinfo, bytesWritten) 15619e34f742SAxel Dörfler : Error((j_common_ptr)&cinfo, B_ERROR); 15629e34f742SAxel Dörfler } 15639e34f742SAxel Dörfler } 15649949213aSStephan Aßmus 15659949213aSStephan Aßmus jpeg_finish_decompress(&cinfo); 15669949213aSStephan Aßmus jpeg_destroy_decompress(&cinfo); 15679949213aSStephan Aßmus return B_OK; 15689949213aSStephan Aßmus } 15699949213aSStephan Aßmus 1570d8e2fb50SAxel Dörfler /*! 1571d8e2fb50SAxel Dörfler Frees jpeg alocated memory 1572d8e2fb50SAxel Dörfler Returns given error (B_ERROR by default) 1573d8e2fb50SAxel Dörfler */ 157452e8f46aSAxel Dörfler static status_t 15759949213aSStephan Aßmus Error(j_common_ptr cinfo, status_t error) 15769949213aSStephan Aßmus { 15779949213aSStephan Aßmus jpeg_destroy(cinfo); 15789949213aSStephan Aßmus return error; 15799949213aSStephan Aßmus } 1580d8e2fb50SAxel Dörfler 1581d8e2fb50SAxel Dörfler 1582d8e2fb50SAxel Dörfler // #pragma mark - 1583d8e2fb50SAxel Dörfler 1584d8e2fb50SAxel Dörfler 1585d8e2fb50SAxel Dörfler int 1586117da2d7SAxel Dörfler main(int, char**) 1587117da2d7SAxel Dörfler { 1588117da2d7SAxel Dörfler BApplication app("application/x-vnd.Haiku-JPEGTranslator"); 1589d8e2fb50SAxel Dörfler 1590d8e2fb50SAxel Dörfler TranslatorWindow *window = new TranslatorWindow(); 1591d8e2fb50SAxel Dörfler window->Show(); 1592d8e2fb50SAxel Dörfler 1593d8e2fb50SAxel Dörfler app.Run(); 1594d8e2fb50SAxel Dörfler return 0; 1595d8e2fb50SAxel Dörfler } 1596d8e2fb50SAxel Dörfler 1597