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