1 /* 2 3 Copyright (c) 2002-2003, Marcin 'Shard' Konicki 4 All rights reserved. 5 6 Redistribution and use in source and binary forms, with or without 7 modification, are permitted provided that the following conditions are met: 8 9 * Redistributions of source code must retain the above copyright notice, 10 this list of conditions and the following disclaimer. 11 * Redistributions in binary form must reproduce the above copyright notice, 12 this list of conditions and the following disclaimer in the documentation and/or 13 other materials provided with the distribution. 14 * Name "Marcin Konicki", "Shard" or any combination of them, 15 must not be used to endorse or promote products derived from this 16 software without specific prior written permission from Marcin Konicki. 17 18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 20 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 22 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 28 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30 */ 31 32 33 #include "JPEGTranslator.h" 34 #include "TranslatorWindow.h" 35 #include "exif_parser.h" 36 37 #include <Alignment.h> 38 #include <GridLayoutBuilder.h> 39 #include <GroupLayoutBuilder.h> 40 #include <TabView.h> 41 #include <TextView.h> 42 43 44 #define MARKER_EXIF 0xe1 45 46 // Set these accordingly 47 #define JPEG_ACRONYM "JPEG" 48 #define JPEG_FORMAT 'JPEG' 49 #define JPEG_MIME_STRING "image/jpeg" 50 #define JPEG_DESCRIPTION "JPEG image" 51 52 // The translation kit's native file type 53 #define B_TRANSLATOR_BITMAP_MIME_STRING "image/x-be-bitmap" 54 #define B_TRANSLATOR_BITMAP_DESCRIPTION "Be Bitmap Format (JPEGTranslator)" 55 56 57 // Translation Kit required globals 58 char gTranslatorName[] = "JPEG images"; 59 char gTranslatorInfo[] = 60 "©2002-2003, Marcin Konicki\n" 61 "©2005-2007, Haiku\n" 62 "\n" 63 "Based on IJG library © 1994-2009, Thomas G. Lane, Guido Vollbeding.\n" 64 " http://www.ijg.org/files/\n" 65 "\n" 66 "with \"lossless\" encoding support patch by Ken Murchison\n" 67 " http://www.oceana.com/ftp/ljpeg/\n" 68 "\n" 69 "With some colorspace conversion routines by Magnus Hellman\n" 70 " http://www.bebits.com/app/802\n"; 71 72 int32 gTranslatorVersion = B_TRANSLATION_MAKE_VERSION(1, 2, 0); 73 74 // Define the formats we know how to read 75 const translation_format gInputFormats[] = { 76 { JPEG_FORMAT, B_TRANSLATOR_BITMAP, 0.5, 0.5, 77 JPEG_MIME_STRING, JPEG_DESCRIPTION }, 78 { B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.5, 0.5, 79 B_TRANSLATOR_BITMAP_MIME_STRING, B_TRANSLATOR_BITMAP_DESCRIPTION } 80 }; 81 const int gInputFormatCount = sizeof(gInputFormats) / sizeof(translation_format); 82 83 // Define the formats we know how to write 84 const translation_format gOutputFormats[] = { 85 { JPEG_FORMAT, B_TRANSLATOR_BITMAP, 0.5, 0.5, 86 JPEG_MIME_STRING, JPEG_DESCRIPTION }, 87 { B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.5, 0.5, 88 B_TRANSLATOR_BITMAP_MIME_STRING, B_TRANSLATOR_BITMAP_DESCRIPTION } 89 }; 90 const int gOutputFormatCount = sizeof(gOutputFormats) / sizeof(translation_format); 91 92 93 TranSetting gSettings[] = { 94 {JPEG_SET_SMOOTHING, TRAN_SETTING_INT32, 0}, 95 {JPEG_SET_QUALITY, TRAN_SETTING_INT32, 95}, 96 {JPEG_SET_PROGRESSIVE, TRAN_SETTING_BOOL, true}, 97 {JPEG_SET_OPT_COLORS, TRAN_SETTING_BOOL, true}, 98 {JPEG_SET_SMALL_FILES, TRAN_SETTING_BOOL, false}, 99 {JPEG_SET_GRAY1_AS_RGB24, TRAN_SETTING_BOOL, false}, 100 {JPEG_SET_ALWAYS_RGB32, TRAN_SETTING_BOOL, true}, 101 {JPEG_SET_PHOTOSHOP_CMYK, TRAN_SETTING_BOOL, true}, 102 {JPEG_SET_SHOWREADWARNING, TRAN_SETTING_BOOL, true} 103 }; 104 const int gSettingsCount = sizeof(gSettings) / sizeof(TranSetting); 105 106 107 namespace conversion { 108 109 110 static bool 111 x_flipped(int32 orientation) 112 { 113 return orientation == 2 || orientation == 3 114 || orientation == 6 || orientation == 7; 115 } 116 117 118 static bool 119 y_flipped(int32 orientation) 120 { 121 return orientation == 3 || orientation == 4 122 || orientation == 7 || orientation == 8; 123 } 124 125 126 static int32 127 dest_index(uint32 width, uint32 height, uint32 x, uint32 y, int32 orientation) 128 { 129 if (orientation > 4) { 130 uint32 temp = x; 131 x = y; 132 y = temp; 133 } 134 if (y_flipped(orientation)) 135 y = height - 1 - y; 136 if (x_flipped(orientation)) 137 x = width - 1 - x; 138 139 return y * width + x; 140 } 141 142 143 // #pragma mark - conversion for compression 144 145 146 inline void 147 convert_from_gray1_to_gray8(uint8* in, uint8* out, int32 inRowBytes) 148 { 149 int32 index = 0; 150 int32 index2 = 0; 151 while (index < inRowBytes) { 152 unsigned char c = in[index++]; 153 for (int b = 128; b; b = b>>1) { 154 unsigned char color; 155 if (c & b) 156 color = 0; 157 else 158 color = 255; 159 out[index2++] = color; 160 } 161 } 162 } 163 164 165 inline void 166 convert_from_gray1_to_24(uint8* in, uint8* out, int32 inRowBytes) 167 { 168 int32 index = 0; 169 int32 index2 = 0; 170 while (index < inRowBytes) { 171 unsigned char c = in[index++]; 172 for (int b = 128; b; b = b>>1) { 173 unsigned char color; 174 if (c & b) 175 color = 0; 176 else 177 color = 255; 178 out[index2++] = color; 179 out[index2++] = color; 180 out[index2++] = color; 181 } 182 } 183 } 184 185 186 inline void 187 convert_from_cmap8_to_24(uint8* in, uint8* out, int32 inRowBytes) 188 { 189 const color_map * map = system_colors(); 190 int32 index = 0; 191 int32 index2 = 0; 192 while (index < inRowBytes) { 193 rgb_color color = map->color_list[in[index++]]; 194 195 out[index2++] = color.red; 196 out[index2++] = color.green; 197 out[index2++] = color.blue; 198 } 199 } 200 201 202 inline void 203 convert_from_15_to_24(uint8* in, uint8* out, int32 inRowBytes) 204 { 205 int32 index = 0; 206 int32 index2 = 0; 207 int16 in_pixel; 208 while (index < inRowBytes) { 209 in_pixel = in[index] | (in[index + 1] << 8); 210 index += 2; 211 212 out[index2++] = (((in_pixel & 0x7c00)) >> 7) | (((in_pixel & 0x7c00)) >> 12); 213 out[index2++] = (((in_pixel & 0x3e0)) >> 2) | (((in_pixel & 0x3e0)) >> 7); 214 out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2); 215 } 216 } 217 218 219 inline void 220 convert_from_15b_to_24(uint8* in, uint8* out, int32 inRowBytes) 221 { 222 int32 index = 0; 223 int32 index2 = 0; 224 int16 in_pixel; 225 while (index < inRowBytes) { 226 in_pixel = in[index + 1] | (in[index] << 8); 227 index += 2; 228 229 out[index2++] = (((in_pixel & 0x7c00)) >> 7) | (((in_pixel & 0x7c00)) >> 12); 230 out[index2++] = (((in_pixel & 0x3e0)) >> 2) | (((in_pixel & 0x3e0)) >> 7); 231 out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2); 232 } 233 } 234 235 236 inline void 237 convert_from_16_to_24(uint8* in, uint8* out, int32 inRowBytes) 238 { 239 int32 index = 0; 240 int32 index2 = 0; 241 int16 in_pixel; 242 while (index < inRowBytes) { 243 in_pixel = in[index] | (in[index + 1] << 8); 244 index += 2; 245 246 out[index2++] = (((in_pixel & 0xf800)) >> 8) | (((in_pixel & 0xf800)) >> 13); 247 out[index2++] = (((in_pixel & 0x7e0)) >> 3) | (((in_pixel & 0x7e0)) >> 9); 248 out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2); 249 } 250 } 251 252 253 inline void 254 convert_from_16b_to_24(uint8* in, uint8* out, int32 inRowBytes) 255 { 256 int32 index = 0; 257 int32 index2 = 0; 258 int16 in_pixel; 259 while (index < inRowBytes) { 260 in_pixel = in[index + 1] | (in[index] << 8); 261 index += 2; 262 263 out[index2++] = (((in_pixel & 0xf800)) >> 8) | (((in_pixel & 0xf800)) >> 13); 264 out[index2++] = (((in_pixel & 0x7e0)) >> 3) | (((in_pixel & 0x7e0)) >> 9); 265 out[index2++] = (((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2); 266 } 267 } 268 269 270 inline void 271 convert_from_24_to_24(uint8* in, uint8* out, int32 inRowBytes) 272 { 273 int32 index = 0; 274 int32 index2 = 0; 275 while (index < inRowBytes) { 276 out[index2++] = in[index + 2]; 277 out[index2++] = in[index + 1]; 278 out[index2++] = in[index]; 279 index+=3; 280 } 281 } 282 283 284 inline void 285 convert_from_32_to_24(uint8* in, uint8* out, int32 inRowBytes) 286 { 287 inRowBytes /= 4; 288 289 for (int32 i = 0; i < inRowBytes; i++) { 290 out[0] = in[2]; 291 out[1] = in[1]; 292 out[2] = in[0]; 293 294 in += 4; 295 out += 3; 296 } 297 } 298 299 300 inline void 301 convert_from_32b_to_24(uint8* in, uint8* out, int32 inRowBytes) 302 { 303 inRowBytes /= 4; 304 305 for (int32 i = 0; i < inRowBytes; i++) { 306 out[0] = in[1]; 307 out[1] = in[2]; 308 out[2] = in[3]; 309 310 in += 4; 311 out += 3; 312 } 313 } 314 315 316 // #pragma mark - conversion for decompression 317 318 319 inline void 320 convert_from_CMYK_to_32_photoshop(uint8* in, uint8* out, int32 inRowBytes, int32 xStep) 321 { 322 for (int32 i = 0; i < inRowBytes; i += 4) { 323 int32 black = in[3]; 324 out[0] = in[2] * black / 255; 325 out[1] = in[1] * black / 255; 326 out[2] = in[0] * black / 255; 327 out[3] = 255; 328 329 in += 4; 330 out += xStep; 331 } 332 } 333 334 335 //! !!! UNTESTED !!! 336 inline void 337 convert_from_CMYK_to_32(uint8* in, uint8* out, int32 inRowBytes, int32 xStep) 338 { 339 for (int32 i = 0; i < inRowBytes; i += 4) { 340 int32 black = 255 - in[3]; 341 out[0] = ((255 - in[2]) * black) / 255; 342 out[1] = ((255 - in[1]) * black) / 255; 343 out[2] = ((255 - in[0]) * black) / 255; 344 out[3] = 255; 345 346 in += 4; 347 out += xStep; 348 } 349 } 350 351 352 //! RGB24 8:8:8 to xRGB 8:8:8:8 353 inline void 354 convert_from_24_to_32(uint8* in, uint8* out, int32 inRowBytes, int32 xStep) 355 { 356 for (int32 i = 0; i < inRowBytes; i += 3) { 357 out[0] = in[2]; 358 out[1] = in[1]; 359 out[2] = in[0]; 360 out[3] = 255; 361 362 in += 3; 363 out += xStep; 364 } 365 } 366 367 368 //! 8-bit to 8-bit, only need when rotating the image 369 void 370 translate_8(uint8* in, uint8* out, int32 inRowBytes, int32 xStep) 371 { 372 for (int32 i = 0; i < inRowBytes; i++) { 373 out[0] = in[0]; 374 375 in++; 376 out += xStep; 377 } 378 } 379 380 381 } // namespace conversion 382 383 384 // #pragma mark - 385 386 387 SSlider::SSlider(const char* name, const char* label, 388 BMessage* message, int32 minValue, int32 maxValue, orientation posture, 389 thumb_style thumbType, uint32 flags) 390 : BSlider(name, label, message, minValue, maxValue, 391 posture, thumbType, flags) 392 { 393 rgb_color barColor = { 0, 0, 229, 255 }; 394 UseFillColor(true, &barColor); 395 } 396 397 398 //! Update status string - show actual value 399 const char* 400 SSlider::UpdateText() const 401 { 402 snprintf(fStatusLabel, sizeof(fStatusLabel), "%ld", Value()); 403 return fStatusLabel; 404 } 405 406 407 // #pragma mark - 408 409 410 TranslatorReadView::TranslatorReadView(const char* name, 411 TranslatorSettings* settings) 412 : 413 BView(name, 0, new BGroupLayout(B_HORIZONTAL)), 414 fSettings(settings) 415 // settings should already be Acquired() 416 { 417 fAlwaysRGB32 = new BCheckBox("alwaysrgb32", VIEW_LABEL_ALWAYSRGB32, 418 new BMessage(VIEW_MSG_SET_ALWAYSRGB32)); 419 if (fSettings->SetGetBool(JPEG_SET_ALWAYS_RGB32, NULL)) 420 fAlwaysRGB32->SetValue(B_CONTROL_ON); 421 422 fPhotoshopCMYK = new BCheckBox("photoshopCMYK", VIEW_LABEL_PHOTOSHOPCMYK, 423 new BMessage(VIEW_MSG_SET_PHOTOSHOPCMYK)); 424 if (fSettings->SetGetBool(JPEG_SET_PHOTOSHOP_CMYK, NULL)) 425 fPhotoshopCMYK->SetValue(B_CONTROL_ON); 426 427 fShowErrorBox = new BCheckBox("error", VIEW_LABEL_SHOWREADERRORBOX, 428 new BMessage(VIEW_MSG_SET_SHOWREADERRORBOX)); 429 if (fSettings->SetGetBool(JPEG_SET_SHOWREADWARNING, NULL)) 430 fShowErrorBox->SetValue(B_CONTROL_ON); 431 432 float padding = 5.0f; 433 AddChild(BGroupLayoutBuilder(B_VERTICAL, padding) 434 .Add(fAlwaysRGB32) 435 .Add(fPhotoshopCMYK) 436 .Add(fShowErrorBox) 437 .AddGlue() 438 .SetInsets(padding, padding, padding, padding) 439 ); 440 441 } 442 443 444 TranslatorReadView::~TranslatorReadView() 445 { 446 fSettings->Release(); 447 } 448 449 450 void 451 TranslatorReadView::AttachedToWindow() 452 { 453 BView::AttachedToWindow(); 454 455 fAlwaysRGB32->SetTarget(this); 456 fPhotoshopCMYK->SetTarget(this); 457 fShowErrorBox->SetTarget(this); 458 } 459 460 461 void 462 TranslatorReadView::MessageReceived(BMessage* message) 463 { 464 switch (message->what) { 465 case VIEW_MSG_SET_ALWAYSRGB32: 466 { 467 int32 value; 468 if (message->FindInt32("be:value", &value) == B_OK) { 469 bool boolValue = value; 470 fSettings->SetGetBool(JPEG_SET_ALWAYS_RGB32, &boolValue); 471 fSettings->SaveSettings(); 472 } 473 break; 474 } 475 case VIEW_MSG_SET_PHOTOSHOPCMYK: 476 { 477 int32 value; 478 if (message->FindInt32("be:value", &value) == B_OK) { 479 bool boolValue = value; 480 fSettings->SetGetBool(JPEG_SET_PHOTOSHOP_CMYK, &boolValue); 481 fSettings->SaveSettings(); 482 } 483 break; 484 } 485 case VIEW_MSG_SET_SHOWREADERRORBOX: 486 { 487 int32 value; 488 if (message->FindInt32("be:value", &value) == B_OK) { 489 bool boolValue = value; 490 fSettings->SetGetBool(JPEG_SET_SHOWREADWARNING, &boolValue); 491 fSettings->SaveSettings(); 492 } 493 break; 494 } 495 default: 496 BView::MessageReceived(message); 497 break; 498 } 499 } 500 501 502 // #pragma mark - TranslatorWriteView 503 504 505 TranslatorWriteView::TranslatorWriteView(const char* name, 506 TranslatorSettings* settings) 507 : 508 BView(name, 0, new BGroupLayout(B_VERTICAL)), 509 fSettings(settings) 510 // settings should already be Acquired() 511 { 512 fQualitySlider = new SSlider("quality", VIEW_LABEL_QUALITY, 513 new BMessage(VIEW_MSG_SET_QUALITY), 0, 100); 514 fQualitySlider->SetHashMarks(B_HASH_MARKS_BOTTOM); 515 fQualitySlider->SetHashMarkCount(10); 516 fQualitySlider->SetLimitLabels("Low", "High"); 517 fQualitySlider->SetValue(fSettings->SetGetInt32(JPEG_SET_QUALITY, NULL)); 518 519 fSmoothingSlider = new SSlider("smoothing", VIEW_LABEL_SMOOTHING, 520 new BMessage(VIEW_MSG_SET_SMOOTHING), 0, 100); 521 fSmoothingSlider->SetHashMarks(B_HASH_MARKS_BOTTOM); 522 fSmoothingSlider->SetHashMarkCount(10); 523 fSmoothingSlider->SetLimitLabels("None", "High"); 524 fSmoothingSlider->SetValue( 525 fSettings->SetGetInt32(JPEG_SET_SMOOTHING, NULL)); 526 527 fProgress = new BCheckBox("progress", VIEW_LABEL_PROGRESSIVE, 528 new BMessage(VIEW_MSG_SET_PROGRESSIVE)); 529 if (fSettings->SetGetBool(JPEG_SET_PROGRESSIVE, NULL)) 530 fProgress->SetValue(B_CONTROL_ON); 531 532 fSmallerFile = new BCheckBox("smallerfile", VIEW_LABEL_SMALLERFILE, 533 new BMessage(VIEW_MSG_SET_SMALLERFILE)); 534 if (fSettings->SetGetBool(JPEG_SET_SMALL_FILES)) 535 fSmallerFile->SetValue(B_CONTROL_ON); 536 537 fOptimizeColors = new BCheckBox("optimizecolors", VIEW_LABEL_OPTIMIZECOLORS, 538 new BMessage(VIEW_MSG_SET_OPTIMIZECOLORS)); 539 if (fSettings->SetGetBool(JPEG_SET_OPT_COLORS, NULL)) 540 fOptimizeColors->SetValue(B_CONTROL_ON); 541 else 542 fSmallerFile->SetEnabled(false); 543 544 fGrayAsRGB24 = new BCheckBox("gray1asrgb24", VIEW_LABEL_GRAY1ASRGB24, 545 new BMessage(VIEW_MSG_SET_GRAY1ASRGB24)); 546 if (fSettings->SetGetBool(JPEG_SET_GRAY1_AS_RGB24)) 547 fGrayAsRGB24->SetValue(B_CONTROL_ON); 548 549 float padding = 5.0f; 550 AddChild(BGroupLayoutBuilder(B_VERTICAL, padding) 551 .Add(fQualitySlider) 552 .Add(fSmoothingSlider) 553 .Add(fProgress) 554 .Add(fOptimizeColors) 555 .Add(fSmallerFile) 556 .Add(fGrayAsRGB24) 557 .AddGlue() 558 .SetInsets(padding, padding, padding, padding) 559 ); 560 } 561 562 563 TranslatorWriteView::~TranslatorWriteView() 564 { 565 fSettings->Release(); 566 } 567 568 569 void 570 TranslatorWriteView::AttachedToWindow() 571 { 572 BView::AttachedToWindow(); 573 574 fQualitySlider->SetTarget(this); 575 fSmoothingSlider->SetTarget(this); 576 fProgress->SetTarget(this); 577 fOptimizeColors->SetTarget(this); 578 fSmallerFile->SetTarget(this); 579 fGrayAsRGB24->SetTarget(this); 580 } 581 582 583 void 584 TranslatorWriteView::MessageReceived(BMessage* message) 585 { 586 switch (message->what) { 587 case VIEW_MSG_SET_QUALITY: 588 { 589 int32 value; 590 if (message->FindInt32("be:value", &value) == B_OK) { 591 fSettings->SetGetInt32(JPEG_SET_QUALITY, &value); 592 fSettings->SaveSettings(); 593 } 594 break; 595 } 596 case VIEW_MSG_SET_SMOOTHING: 597 { 598 int32 value; 599 if (message->FindInt32("be:value", &value) == B_OK) { 600 fSettings->SetGetInt32(JPEG_SET_SMOOTHING, &value); 601 fSettings->SaveSettings(); 602 } 603 break; 604 } 605 case VIEW_MSG_SET_PROGRESSIVE: 606 { 607 int32 value; 608 if (message->FindInt32("be:value", &value) == B_OK) { 609 bool boolValue = value; 610 fSettings->SetGetBool(JPEG_SET_PROGRESSIVE, &boolValue); 611 fSettings->SaveSettings(); 612 } 613 break; 614 } 615 case VIEW_MSG_SET_OPTIMIZECOLORS: 616 { 617 int32 value; 618 if (message->FindInt32("be:value", &value) == B_OK) { 619 bool boolValue = value; 620 fSettings->SetGetBool(JPEG_SET_OPT_COLORS, &boolValue); 621 fSmallerFile->SetEnabled(value); 622 fSettings->SaveSettings(); 623 } 624 break; 625 } 626 case VIEW_MSG_SET_SMALLERFILE: 627 { 628 int32 value; 629 if (message->FindInt32("be:value", &value) == B_OK) { 630 bool boolValue = value; 631 fSettings->SetGetBool(JPEG_SET_SMALL_FILES, &boolValue); 632 fSettings->SaveSettings(); 633 } 634 break; 635 } 636 case VIEW_MSG_SET_GRAY1ASRGB24: 637 { 638 int32 value; 639 if (message->FindInt32("be:value", &value) == B_OK) { 640 bool boolValue = value; 641 fSettings->SetGetBool(JPEG_SET_GRAY1_AS_RGB24, &boolValue); 642 fSettings->SaveSettings(); 643 } 644 break; 645 } 646 default: 647 BView::MessageReceived(message); 648 break; 649 } 650 } 651 652 653 // #pragma mark - 654 655 656 TranslatorAboutView::TranslatorAboutView(const char* name) 657 : 658 BView(name, 0, new BGroupLayout(B_VERTICAL)) 659 { 660 BAlignment labelAlignment = BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP); 661 BStringView* title = new BStringView("Title", gTranslatorName); 662 title->SetFont(be_bold_font); 663 title->SetExplicitAlignment(labelAlignment); 664 665 char versionString[16]; 666 sprintf(versionString, "v%d.%d.%d", (int)(gTranslatorVersion >> 8), 667 (int)((gTranslatorVersion >> 4) & 0xf), (int)(gTranslatorVersion & 0xf)); 668 669 BStringView* version = new BStringView("Version", versionString); 670 version->SetExplicitAlignment(labelAlignment); 671 672 BTextView* infoView = new BTextView("info"); 673 infoView->SetText(gTranslatorInfo); 674 infoView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 675 infoView->MakeEditable(false); 676 677 float padding = 5.0f; 678 AddChild(BGroupLayoutBuilder(B_VERTICAL, padding) 679 .Add(BGroupLayoutBuilder(B_HORIZONTAL, padding) 680 .Add(title) 681 .Add(version) 682 .AddGlue() 683 ) 684 .Add(infoView) 685 .SetInsets(padding, padding, padding, padding) 686 ); 687 } 688 689 690 TranslatorView::TranslatorView(const char* name, TranslatorSettings* settings) 691 : 692 BTabView(name) 693 { 694 AddTab(new TranslatorWriteView("Write", settings->Acquire())); 695 AddTab(new TranslatorReadView("Read", settings->Acquire())); 696 AddTab(new TranslatorAboutView("About")); 697 698 settings->Release(); 699 700 BFont font; 701 GetFont(&font); 702 SetExplicitPreferredSize( 703 BSize((font.Size() * 380) / 12, (font.Size() * 250) / 12)); 704 } 705 706 707 // #pragma mark - Translator Add-On 708 709 710 BView* 711 JPEGTranslator::NewConfigView(TranslatorSettings* settings) 712 { 713 BView* configView = new TranslatorView("TranslatorView", settings); 714 return configView; 715 } 716 717 718 /*! Determine whether or not we can handle this data */ 719 status_t 720 JPEGTranslator::DerivedIdentify(BPositionIO* inSource, 721 const translation_format* inFormat, BMessage* ioExtension, 722 translator_info* outInfo, uint32 outType) 723 { 724 if (outType != 0 && outType != B_TRANSLATOR_BITMAP && outType != JPEG_FORMAT) 725 return B_NO_TRANSLATOR; 726 727 // !!! You might need to make this buffer bigger to test for your native format 728 off_t position = inSource->Position(); 729 char header[sizeof(TranslatorBitmap)]; 730 status_t err = inSource->Read(header, sizeof(TranslatorBitmap)); 731 inSource->Seek(position, SEEK_SET); 732 if (err < B_OK) 733 return err; 734 735 if (B_BENDIAN_TO_HOST_INT32(((TranslatorBitmap *)header)->magic) == B_TRANSLATOR_BITMAP) { 736 if (PopulateInfoFromFormat(outInfo, B_TRANSLATOR_BITMAP) != B_OK) 737 return B_NO_TRANSLATOR; 738 } else { 739 // First 3 bytes in jpg files are always the same from what i've seen so far 740 // check them 741 if (header[0] == (char)0xff && header[1] == (char)0xd8 && header[2] == (char)0xff) { 742 if (PopulateInfoFromFormat(outInfo, JPEG_FORMAT) != B_OK) 743 return B_NO_TRANSLATOR; 744 745 } else 746 return B_NO_TRANSLATOR; 747 } 748 749 return B_OK; 750 } 751 752 753 status_t 754 JPEGTranslator::DerivedTranslate(BPositionIO* inSource, 755 const translator_info* inInfo, BMessage* ioExtension, uint32 outType, 756 BPositionIO* outDestination, int32 baseType) 757 { 758 // If no specific type was requested, convert to the interchange format 759 if (outType == 0) 760 outType = B_TRANSLATOR_BITMAP; 761 762 // Setup a "breakpoint" since throwing exceptions does not seem to work 763 // at all in an add-on. (?) 764 // In the be_jerror.cpp we implement a handler for critical library errors 765 // (be_error_exit()) and there we use the longjmp() function to return to 766 // this place. If this happens, it is as if the setjmp() call is called 767 // a second time, but this time the return value will be 1. The first 768 // invokation will return 0. 769 jmp_buf longJumpBuffer; 770 int jmpRet = setjmp(longJumpBuffer); 771 if (jmpRet == 1) 772 return B_ERROR; 773 774 try { 775 // What action to take, based on the findings of Identify() 776 if (outType == inInfo->type) { 777 return Copy(inSource, outDestination); 778 } else if (inInfo->type == B_TRANSLATOR_BITMAP 779 && outType == JPEG_FORMAT) { 780 return Compress(inSource, outDestination, &longJumpBuffer); 781 } else if (inInfo->type == JPEG_FORMAT 782 && outType == B_TRANSLATOR_BITMAP) { 783 return Decompress(inSource, outDestination, ioExtension, 784 &longJumpBuffer); 785 } 786 } catch (...) { 787 fprintf(stderr, "libjpeg encoutered a critical error " 788 "(caught C++ exception).\n"); 789 return B_ERROR; 790 } 791 792 return B_NO_TRANSLATOR; 793 } 794 795 796 /*! The user has requested the same format for input and output, so just copy */ 797 status_t 798 JPEGTranslator::Copy(BPositionIO* in, BPositionIO* out) 799 { 800 int block_size = 65536; 801 void* buffer = malloc(block_size); 802 char temp[1024]; 803 if (buffer == NULL) { 804 buffer = temp; 805 block_size = 1024; 806 } 807 status_t err = B_OK; 808 809 // Read until end of file or error 810 while (1) { 811 ssize_t to_read = block_size; 812 err = in->Read(buffer, to_read); 813 // Explicit check for EOF 814 if (err == -1) { 815 if (buffer != temp) free(buffer); 816 return B_OK; 817 } 818 if (err <= B_OK) break; 819 to_read = err; 820 err = out->Write(buffer, to_read); 821 if (err != to_read) if (err >= 0) err = B_DEVICE_FULL; 822 if (err < B_OK) break; 823 } 824 825 if (buffer != temp) free(buffer); 826 return (err >= 0) ? B_OK : err; 827 } 828 829 830 /*! Encode into the native format */ 831 status_t 832 JPEGTranslator::Compress(BPositionIO* in, BPositionIO* out, 833 const jmp_buf* longJumpBuffer) 834 { 835 using namespace conversion; 836 837 // Read info about bitmap 838 TranslatorBitmap header; 839 status_t err = in->Read(&header, sizeof(TranslatorBitmap)); 840 if (err < B_OK) 841 return err; 842 else if (err < (int)sizeof(TranslatorBitmap)) 843 return B_ERROR; 844 845 // Grab dimension, color space, and size information from the stream 846 BRect bounds; 847 bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left); 848 bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top); 849 bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right); 850 bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom); 851 852 int32 in_row_bytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes); 853 854 int width = bounds.IntegerWidth() + 1; 855 int height = bounds.IntegerHeight() + 1; 856 857 // Function pointer to convert function 858 // It will point to proper function if needed 859 void (*converter)(uchar* inscanline, uchar* outscanline, 860 int32 inRowBytes) = NULL; 861 862 // Default color info 863 J_COLOR_SPACE jpg_color_space = JCS_RGB; 864 int jpg_input_components = 3; 865 int32 out_row_bytes; 866 int padding = 0; 867 868 switch ((color_space)B_BENDIAN_TO_HOST_INT32(header.colors)) { 869 case B_CMAP8: 870 converter = convert_from_cmap8_to_24; 871 padding = in_row_bytes - width; 872 break; 873 874 case B_GRAY1: 875 if (fSettings->SetGetBool(JPEG_SET_GRAY1_AS_RGB24, NULL)) { 876 converter = convert_from_gray1_to_24; 877 } else { 878 jpg_input_components = 1; 879 jpg_color_space = JCS_GRAYSCALE; 880 converter = convert_from_gray1_to_gray8; 881 } 882 padding = in_row_bytes - (width / 8); 883 break; 884 885 case B_GRAY8: 886 jpg_input_components = 1; 887 jpg_color_space = JCS_GRAYSCALE; 888 padding = in_row_bytes - width; 889 break; 890 891 case B_RGB15: 892 case B_RGBA15: 893 converter = convert_from_15_to_24; 894 padding = in_row_bytes - (width * 2); 895 break; 896 897 case B_RGB15_BIG: 898 case B_RGBA15_BIG: 899 converter = convert_from_15b_to_24; 900 padding = in_row_bytes - (width * 2); 901 break; 902 903 case B_RGB16: 904 converter = convert_from_16_to_24; 905 padding = in_row_bytes - (width * 2); 906 break; 907 908 case B_RGB16_BIG: 909 converter = convert_from_16b_to_24; 910 padding = in_row_bytes - (width * 2); 911 break; 912 913 case B_RGB24: 914 converter = convert_from_24_to_24; 915 padding = in_row_bytes - (width * 3); 916 break; 917 918 case B_RGB24_BIG: 919 padding = in_row_bytes - (width * 3); 920 break; 921 922 case B_RGB32: 923 case B_RGBA32: 924 converter = convert_from_32_to_24; 925 padding = in_row_bytes - (width * 4); 926 break; 927 928 case B_RGB32_BIG: 929 case B_RGBA32_BIG: 930 converter = convert_from_32b_to_24; 931 padding = in_row_bytes - (width * 4); 932 break; 933 934 case B_CMYK32: 935 jpg_color_space = JCS_CMYK; 936 jpg_input_components = 4; 937 padding = in_row_bytes - (width * 4); 938 break; 939 940 default: 941 fprintf(stderr, "Wrong type: Color space not implemented.\n"); 942 return B_ERROR; 943 } 944 out_row_bytes = jpg_input_components * width; 945 946 // Set basic things needed for jpeg writing 947 struct jpeg_compress_struct cinfo; 948 struct jpeg_error_mgr jerr; 949 cinfo.err = be_jpeg_std_error(&jerr, fSettings, longJumpBuffer); 950 jpeg_create_compress(&cinfo); 951 be_jpeg_stdio_dest(&cinfo, out); 952 953 // Set basic values 954 cinfo.image_width = width; 955 cinfo.image_height = height; 956 cinfo.input_components = jpg_input_components; 957 cinfo.in_color_space = jpg_color_space; 958 jpeg_set_defaults(&cinfo); 959 960 // Set better accuracy 961 cinfo.dct_method = JDCT_ISLOW; 962 963 // This is needed to prevent some colors loss 964 // With it generated jpegs are as good as from Fireworks (at last! :D) 965 if (fSettings->SetGetBool(JPEG_SET_OPT_COLORS, NULL)) { 966 int index = 0; 967 while (index < cinfo.num_components) { 968 cinfo.comp_info[index].h_samp_factor = 1; 969 cinfo.comp_info[index].v_samp_factor = 1; 970 // This will make file smaller, but with worse quality more or less 971 // like with 93%-94% (but it's subjective opinion) on tested images 972 // but with smaller size (between 92% and 93% on tested images) 973 if (fSettings->SetGetBool(JPEG_SET_SMALL_FILES)) 974 cinfo.comp_info[index].quant_tbl_no = 1; 975 // This will make bigger file, but also better quality ;] 976 // from my tests it seems like useless - better quality with smaller 977 // can be acheived without this 978 // cinfo.comp_info[index].dc_tbl_no = 1; 979 // cinfo.comp_info[index].ac_tbl_no = 1; 980 index++; 981 } 982 } 983 984 // Set quality 985 jpeg_set_quality(&cinfo, fSettings->SetGetInt32(JPEG_SET_QUALITY, NULL), true); 986 987 // Set progressive compression if needed 988 // if not, turn on optimizing in libjpeg 989 if (fSettings->SetGetBool(JPEG_SET_PROGRESSIVE, NULL)) 990 jpeg_simple_progression(&cinfo); 991 else 992 cinfo.optimize_coding = TRUE; 993 994 // Set smoothing (effect like Blur) 995 cinfo.smoothing_factor = fSettings->SetGetInt32(JPEG_SET_SMOOTHING, NULL); 996 997 // Initialize compression 998 jpeg_start_compress(&cinfo, TRUE); 999 1000 // Declare scanlines 1001 JSAMPROW in_scanline = NULL; 1002 JSAMPROW out_scanline = NULL; 1003 JSAMPROW writeline; 1004 // Pointer to in_scanline (default) or out_scanline (if there will be conversion) 1005 1006 // Allocate scanline 1007 // Use libjpeg memory allocation functions, so in case of error it will free them itself 1008 in_scanline = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo, 1009 JPOOL_PERMANENT, in_row_bytes); 1010 1011 // We need 2nd scanline storage ony for conversion 1012 if (converter != NULL) { 1013 // There will be conversion, allocate second scanline... 1014 // Use libjpeg memory allocation functions, so in case of error it will free them itself 1015 out_scanline = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo, 1016 JPOOL_PERMANENT, out_row_bytes); 1017 // ... and make it the one to write to file 1018 writeline = out_scanline; 1019 } else 1020 writeline = in_scanline; 1021 1022 while (cinfo.next_scanline < cinfo.image_height) { 1023 // Read scanline 1024 err = in->Read(in_scanline, in_row_bytes); 1025 if (err < in_row_bytes) 1026 return err < B_OK ? Error((j_common_ptr)&cinfo, err) 1027 : Error((j_common_ptr)&cinfo, B_ERROR); 1028 1029 // Convert if needed 1030 if (converter != NULL) 1031 converter(in_scanline, out_scanline, in_row_bytes - padding); 1032 1033 // Write scanline 1034 jpeg_write_scanlines(&cinfo, &writeline, 1); 1035 } 1036 1037 jpeg_finish_compress(&cinfo); 1038 jpeg_destroy_compress(&cinfo); 1039 return B_OK; 1040 } 1041 1042 1043 /*! Decode the native format */ 1044 status_t 1045 JPEGTranslator::Decompress(BPositionIO* in, BPositionIO* out, 1046 BMessage* ioExtension, const jmp_buf* longJumpBuffer) 1047 { 1048 using namespace conversion; 1049 1050 // Set basic things needed for jpeg reading 1051 struct jpeg_decompress_struct cinfo; 1052 struct jpeg_error_mgr jerr; 1053 cinfo.err = be_jpeg_std_error(&jerr, fSettings, longJumpBuffer); 1054 jpeg_create_decompress(&cinfo); 1055 be_jpeg_stdio_src(&cinfo, in); 1056 1057 jpeg_save_markers(&cinfo, MARKER_EXIF, 131072); 1058 // make sure the EXIF tag is stored 1059 1060 // Read info about image 1061 jpeg_read_header(&cinfo, TRUE); 1062 1063 BMessage exif; 1064 1065 // parse EXIF data and add it ioExtension, if any 1066 jpeg_marker_struct* marker = cinfo.marker_list; 1067 while (marker != NULL) { 1068 if (marker->marker == MARKER_EXIF 1069 && !strncmp((char*)marker->data, "Exif", 4)) { 1070 if (ioExtension != NULL) { 1071 // Strip EXIF header from TIFF data 1072 ioExtension->AddData("exif", B_RAW_TYPE, 1073 (uint8*)marker->data + 6, marker->data_length - 6); 1074 } 1075 1076 BMemoryIO io(marker->data + 6, marker->data_length - 6); 1077 convert_exif_to_message(io, exif); 1078 } 1079 marker = marker->next; 1080 } 1081 1082 // Default color info 1083 color_space outColorSpace = B_RGB32; 1084 int outColorComponents = 4; 1085 1086 // Function pointer to convert function 1087 // It will point to proper function if needed 1088 void (*converter)(uchar* inScanLine, uchar* outScanLine, 1089 int32 inRowBytes, int32 xStep) = convert_from_24_to_32; 1090 1091 // If color space isn't rgb 1092 if (cinfo.out_color_space != JCS_RGB) { 1093 switch (cinfo.out_color_space) { 1094 case JCS_UNKNOWN: /* error/unspecified */ 1095 fprintf(stderr, "From Type: Jpeg uses unknown color type\n"); 1096 break; 1097 case JCS_GRAYSCALE: /* monochrome */ 1098 // Check if user wants to read only as RGB32 or not 1099 if (!fSettings->SetGetBool(JPEG_SET_ALWAYS_RGB32, NULL)) { 1100 // Grayscale 1101 outColorSpace = B_GRAY8; 1102 outColorComponents = 1; 1103 converter = translate_8; 1104 } else { 1105 // RGB 1106 cinfo.out_color_space = JCS_RGB; 1107 cinfo.output_components = 3; 1108 converter = convert_from_24_to_32; 1109 } 1110 break; 1111 case JCS_YCbCr: /* Y/Cb/Cr (also known as YUV) */ 1112 cinfo.out_color_space = JCS_RGB; 1113 converter = convert_from_24_to_32; 1114 break; 1115 case JCS_YCCK: /* Y/Cb/Cr/K */ 1116 // Let libjpeg convert it to CMYK 1117 cinfo.out_color_space = JCS_CMYK; 1118 // Fall through to CMYK since we need the same settings 1119 case JCS_CMYK: /* C/M/Y/K */ 1120 // Use proper converter 1121 if (fSettings->SetGetBool(JPEG_SET_PHOTOSHOP_CMYK)) 1122 converter = convert_from_CMYK_to_32_photoshop; 1123 else 1124 converter = convert_from_CMYK_to_32; 1125 break; 1126 default: 1127 fprintf(stderr, "From Type: Jpeg uses hmm... i don't know really :(\n"); 1128 break; 1129 } 1130 } 1131 1132 // Initialize decompression 1133 jpeg_start_decompress(&cinfo); 1134 1135 // retrieve orientation from settings/EXIF 1136 int32 orientation; 1137 if (ioExtension == NULL 1138 || ioExtension->FindInt32("exif:orientation", &orientation) != B_OK) { 1139 if (exif.FindInt32("Orientation", &orientation) != B_OK) 1140 orientation = 1; 1141 } 1142 1143 if (orientation != 1 && converter == NULL) 1144 converter = translate_8; 1145 1146 int32 outputWidth = orientation > 4 ? cinfo.output_height : cinfo.output_width; 1147 int32 outputHeight = orientation > 4 ? cinfo.output_width : cinfo.output_height; 1148 1149 int32 destOffset = dest_index(outputWidth, outputHeight, 1150 0, 0, orientation) * outColorComponents; 1151 int32 xStep = dest_index(outputWidth, outputHeight, 1152 1, 0, orientation) * outColorComponents - destOffset; 1153 int32 yStep = dest_index(outputWidth, outputHeight, 1154 0, 1, orientation) * outColorComponents - destOffset; 1155 bool needAll = orientation != 1; 1156 1157 // Initialize this bounds rect to the size of your image 1158 BRect bounds(0, 0, outputWidth - 1, outputHeight - 1); 1159 1160 #if 0 1161 printf("destOffset = %ld, xStep = %ld, yStep = %ld, input: %ld x %ld, output: %ld x %ld, orientation %ld\n", 1162 destOffset, xStep, yStep, (int32)cinfo.output_width, (int32)cinfo.output_height, 1163 bounds.IntegerWidth() + 1, bounds.IntegerHeight() + 1, orientation); 1164 #endif 1165 1166 // Bytes count in one line of image (scanline) 1167 int32 inRowBytes = cinfo.output_width * cinfo.output_components; 1168 int32 rowBytes = (bounds.IntegerWidth() + 1) * outColorComponents; 1169 int32 dataSize = cinfo.output_width * cinfo.output_height 1170 * outColorComponents; 1171 1172 // Fill out the B_TRANSLATOR_BITMAP's header 1173 TranslatorBitmap header; 1174 header.magic = B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP); 1175 header.bounds.left = B_HOST_TO_BENDIAN_FLOAT(bounds.left); 1176 header.bounds.top = B_HOST_TO_BENDIAN_FLOAT(bounds.top); 1177 header.bounds.right = B_HOST_TO_BENDIAN_FLOAT(bounds.right); 1178 header.bounds.bottom = B_HOST_TO_BENDIAN_FLOAT(bounds.bottom); 1179 header.colors = (color_space)B_HOST_TO_BENDIAN_INT32(outColorSpace); 1180 header.rowBytes = B_HOST_TO_BENDIAN_INT32(rowBytes); 1181 header.dataSize = B_HOST_TO_BENDIAN_INT32(dataSize); 1182 1183 // Write out the header 1184 status_t err = out->Write(&header, sizeof(TranslatorBitmap)); 1185 if (err < B_OK) 1186 return Error((j_common_ptr)&cinfo, err); 1187 else if (err < (int)sizeof(TranslatorBitmap)) 1188 return Error((j_common_ptr)&cinfo, B_ERROR); 1189 1190 // Declare scanlines 1191 JSAMPROW inScanLine = NULL; 1192 uint8* dest = NULL; 1193 uint8* destLine = NULL; 1194 1195 // Allocate scanline 1196 // Use libjpeg memory allocation functions, so in case of error it will free them itself 1197 inScanLine = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo, 1198 JPOOL_PERMANENT, inRowBytes); 1199 1200 // We need 2nd scanline storage only for conversion 1201 if (converter != NULL) { 1202 // There will be conversion, allocate second scanline... 1203 // Use libjpeg memory allocation functions, so in case of error it will 1204 // free them itself 1205 dest = (uint8*)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo, 1206 JPOOL_PERMANENT, needAll ? dataSize : rowBytes); 1207 destLine = dest + destOffset; 1208 } else 1209 destLine = inScanLine; 1210 1211 while (cinfo.output_scanline < cinfo.output_height) { 1212 // Read scanline 1213 jpeg_read_scanlines(&cinfo, &inScanLine, 1); 1214 1215 // Convert if needed 1216 if (converter != NULL) 1217 converter(inScanLine, destLine, inRowBytes, xStep); 1218 1219 if (!needAll) { 1220 // Write the scanline buffer to the output stream 1221 ssize_t bytesWritten = out->Write(destLine, rowBytes); 1222 if (bytesWritten < rowBytes) { 1223 return bytesWritten < B_OK 1224 ? Error((j_common_ptr)&cinfo, bytesWritten) 1225 : Error((j_common_ptr)&cinfo, B_ERROR); 1226 } 1227 } else 1228 destLine += yStep; 1229 } 1230 1231 if (needAll) { 1232 ssize_t bytesWritten = out->Write(dest, dataSize); 1233 if (bytesWritten < dataSize) { 1234 return bytesWritten < B_OK 1235 ? Error((j_common_ptr)&cinfo, bytesWritten) 1236 : Error((j_common_ptr)&cinfo, B_ERROR); 1237 } 1238 } 1239 1240 jpeg_finish_decompress(&cinfo); 1241 jpeg_destroy_decompress(&cinfo); 1242 return B_OK; 1243 } 1244 1245 /*! have the other PopulateInfoFromFormat() check both inputFormats & outputFormats */ 1246 status_t 1247 JPEGTranslator::PopulateInfoFromFormat(translator_info* info, 1248 uint32 formatType, translator_id id) 1249 { 1250 int32 formatCount; 1251 const translation_format* formats = OutputFormats(&formatCount); 1252 for (int i = 0; i <= 1 ;formats = InputFormats(&formatCount), i++) { 1253 if (PopulateInfoFromFormat(info, formatType, 1254 formats, formatCount) == B_OK) { 1255 info->translator = id; 1256 return B_OK; 1257 } 1258 } 1259 1260 return B_ERROR; 1261 } 1262 1263 1264 status_t 1265 JPEGTranslator::PopulateInfoFromFormat(translator_info* info, 1266 uint32 formatType, const translation_format* formats, int32 formatCount) 1267 { 1268 for (int i = 0; i < formatCount; i++) { 1269 if (formats[i].type == formatType) { 1270 info->type = formatType; 1271 info->group = formats[i].group; 1272 info->quality = formats[i].quality; 1273 info->capability = formats[i].capability; 1274 strcpy(info->name, formats[i].name); 1275 strcpy(info->MIME, formats[i].MIME); 1276 return B_OK; 1277 } 1278 } 1279 1280 return B_ERROR; 1281 } 1282 1283 /*! 1284 Frees jpeg alocated memory 1285 Returns given error (B_ERROR by default) 1286 */ 1287 status_t 1288 JPEGTranslator::Error(j_common_ptr cinfo, status_t error) 1289 { 1290 jpeg_destroy(cinfo); 1291 return error; 1292 } 1293 1294 1295 JPEGTranslator::JPEGTranslator() 1296 : 1297 BaseTranslator(gTranslatorName, gTranslatorInfo, gTranslatorVersion, 1298 gInputFormats, gInputFormatCount, gOutputFormats, gOutputFormatCount, 1299 SETTINGS_FILE, gSettings, gSettingsCount, 1300 B_TRANSLATOR_BITMAP, JPEG_FORMAT) 1301 {} 1302 1303 1304 BTranslator* 1305 make_nth_translator(int32 n, image_id you, uint32 flags, ...) 1306 { 1307 if (n == 0) 1308 return new JPEGTranslator(); 1309 1310 return NULL; 1311 } 1312 1313 1314 int 1315 main(int, char**) 1316 { 1317 BApplication app("application/x-vnd.Haiku-JPEGTranslator"); 1318 JPEGTranslator* translator = new JPEGTranslator(); 1319 if (LaunchTranslatorWindow(translator, gTranslatorName) == B_OK) 1320 app.Run(); 1321 1322 return 0; 1323 } 1324 1325