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