1 /* 2 3 Copyright (c) 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 "JPEG2000Translator.h" 34 #include "TranslatorWindow.h" 35 36 #include <syslog.h> 37 38 #include <LayoutBuilder.h> 39 #include <TabView.h> 40 #include <TextView.h> 41 42 43 #undef B_TRANSLATION_CONTEXT 44 #define B_TRANSLATION_CONTEXT "JPEG2000Translator" 45 46 // Set these accordingly 47 #define JP2_ACRONYM "JP2" 48 #define JP2_FORMAT 'JP2 ' 49 #define JP2_MIME_STRING "image/jp2" 50 #define JP2_DESCRIPTION "JPEG2000 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 (JPEG2000Translator)" 55 56 static int32 sTranslatorVersion = B_TRANSLATION_MAKE_VERSION(1, 0, 0); 57 58 static const char* sTranslatorName = B_TRANSLATE("JPEG2000 images"); 59 static const char* sTranslatorInfo = B_TRANSLATE("©2002-2003, Shard\n" 60 "©2005-2006, Haiku\n" 61 "\n" 62 "Based on JasPer library:\n" 63 "© 1999-2000, Image Power, Inc. and\n" 64 "the University of British Columbia, Canada.\n" 65 "© 2001-2003 Michael David Adams.\n" 66 "\thttp://www.ece.uvic.ca/~mdadams/jasper/\n" 67 "\n" 68 "ImageMagick's jp2 codec was used as \"tutorial\".\n" 69 "\thttp://www.imagemagick.org/\n"); 70 71 static const translation_format sInputFormats[] = { 72 { JP2_FORMAT, B_TRANSLATOR_BITMAP, 0.5, 0.5, 73 JP2_MIME_STRING, JP2_DESCRIPTION }, 74 { B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.5, 0.5, 75 B_TRANSLATOR_BITMAP_MIME_STRING, B_TRANSLATOR_BITMAP_DESCRIPTION }, 76 }; 77 78 static const translation_format sOutputFormats[] = { 79 { JP2_FORMAT, B_TRANSLATOR_BITMAP, 0.5, 0.5, 80 JP2_MIME_STRING, JP2_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 86 static const TranSetting sDefaultSettings[] = { 87 {JP2_SET_QUALITY, TRAN_SETTING_INT32, 25}, 88 {JP2_SET_JPC, TRAN_SETTING_BOOL, false}, 89 {JP2_SET_GRAY1_AS_B_RGB24, TRAN_SETTING_BOOL, false}, 90 {JP2_SET_GRAY8_AS_B_RGB32, TRAN_SETTING_BOOL, true} 91 }; 92 93 const uint32 kNumInputFormats = sizeof(sInputFormats) / sizeof(translation_format); 94 const uint32 kNumOutputFormats = sizeof(sOutputFormats) / sizeof(translation_format); 95 const uint32 kNumDefaultSettings = sizeof(sDefaultSettings) / sizeof(TranSetting); 96 97 98 #define JP2_BOX_JP 0x6a502020 99 #define JPC_MS_SOC 0xff4f 100 101 102 namespace conversion{ 103 //! Make RGB32 scanline from *pixels[3] 104 inline void 105 read_rgb24_to_rgb32(jas_matrix_t** pixels, uchar* scanline, int width) 106 { 107 int32 index = 0; 108 int32 x = 0; 109 while (x < width) { 110 scanline[index++] = (uchar)jas_matrix_getv(pixels[2], x); 111 scanline[index++] = (uchar)jas_matrix_getv(pixels[1], x); 112 scanline[index++] = (uchar)jas_matrix_getv(pixels[0], x); 113 scanline[index++] = 255; 114 x++; 115 } 116 } 117 118 119 //! Make gray scanline from *pixels[1] 120 inline void 121 read_gray_to_rgb32(jas_matrix_t** pixels, uchar* scanline, int width) 122 { 123 int32 index = 0; 124 int32 x = 0; 125 uchar color = 0; 126 while (x < width) { 127 color = (uchar)jas_matrix_getv(pixels[0], x++); 128 scanline[index++] = color; 129 scanline[index++] = color; 130 scanline[index++] = color; 131 scanline[index++] = 255; 132 } 133 } 134 135 136 /*! 137 Make RGBA32 scanline from *pixels[4] 138 (just read data to scanline) 139 */ 140 inline void 141 read_rgba32(jas_matrix_t** pixels, uchar *scanline, int width) 142 { 143 int32 index = 0; 144 int32 x = 0; 145 while (x < width) { 146 scanline[index++] = (uchar)jas_matrix_getv(pixels[2], x); 147 scanline[index++] = (uchar)jas_matrix_getv(pixels[1], x); 148 scanline[index++] = (uchar)jas_matrix_getv(pixels[0], x); 149 scanline[index++] = (uchar)jas_matrix_getv(pixels[3], x); 150 x++; 151 } 152 } 153 154 155 /*! 156 Make gray scanline from *pixels[1] 157 (just read data to scanline) 158 */ 159 inline void 160 read_gray(jas_matrix_t** pixels, uchar* scanline, int width) 161 { 162 int32 x = 0; 163 while (x < width) { 164 scanline[x] = (uchar)jas_matrix_getv(pixels[0], x); 165 x++; 166 } 167 } 168 169 170 //! Make *pixels[1] from gray1 scanline 171 inline void 172 write_gray1_to_gray(jas_matrix_t** pixels, uchar* scanline, int width) 173 { 174 int32 x = 0; 175 int32 index = 0; 176 while (x < (width/8)) { 177 unsigned char c = scanline[x++]; 178 for (int b = 128; b; b = b >> 1) { 179 if (c & b) 180 jas_matrix_setv(pixels[0], index++, 0); 181 else 182 jas_matrix_setv(pixels[0], index++, 255); 183 } 184 } 185 } 186 187 188 //! Make *pixels[3] from gray1 scanline 189 inline void 190 write_gray1_to_rgb24(jas_matrix_t** pixels, uchar* scanline, int width) 191 { 192 int32 x = 0; 193 int32 index = 0; 194 while (x < (width / 8)) { 195 unsigned char c = scanline[x++]; 196 for (int b = 128; b; b = b >> 1) { 197 if (c & b) { 198 jas_matrix_setv(pixels[0], index, 0); 199 jas_matrix_setv(pixels[1], index, 0); 200 jas_matrix_setv(pixels[2], index, 0); 201 } else { 202 jas_matrix_setv(pixels[0], index, 255); 203 jas_matrix_setv(pixels[1], index, 255); 204 jas_matrix_setv(pixels[2], index, 255); 205 } 206 index++; 207 } 208 } 209 } 210 211 212 //! Make *pixels[3] from cmap8 scanline 213 inline void 214 write_cmap8_to_rgb24(jas_matrix_t** pixels, uchar* scanline, int width) 215 { 216 const color_map* map = system_colors(); 217 int32 x = 0; 218 while (x < width) { 219 rgb_color color = map->color_list[scanline[x]]; 220 221 jas_matrix_setv(pixels[0], x, color.red); 222 jas_matrix_setv(pixels[1], x, color.green); 223 jas_matrix_setv(pixels[2], x, color.blue); 224 x++; 225 } 226 } 227 228 229 /*! 230 Make *pixels[1] from gray scanline 231 (just write data to pixels) 232 */ 233 inline void 234 write_gray(jas_matrix_t** pixels, uchar* scanline, int width) 235 { 236 int32 x = 0; 237 while (x < width) { 238 jas_matrix_setv(pixels[0], x, scanline[x]); 239 x++; 240 } 241 } 242 243 244 /*! 245 Make *pixels[3] from RGB15/RGBA15 scanline 246 (just write data to pixels) 247 */ 248 inline void 249 write_rgb15_to_rgb24(jas_matrix_t** pixels, uchar* scanline, int width) 250 { 251 int32 x = 0; 252 int32 index = 0; 253 int16 in_pixel; 254 while (x < width) { 255 in_pixel = scanline[index] | (scanline[index+1] << 8); 256 index += 2; 257 258 jas_matrix_setv(pixels[0], x, (char)(((in_pixel & 0x7c00)) >> 7) 259 | (((in_pixel & 0x7c00)) >> 12)); 260 jas_matrix_setv(pixels[1], x, (char)(((in_pixel & 0x3e0)) >> 2) 261 | (((in_pixel & 0x3e0)) >> 7)); 262 jas_matrix_setv(pixels[2], x, (char)(((in_pixel & 0x1f)) << 3) 263 | (((in_pixel & 0x1f)) >> 2)); 264 x++; 265 } 266 } 267 268 269 /*! 270 Make *pixels[3] from RGB15/RGBA15 bigendian scanline 271 (just write data to pixels) 272 */ 273 inline void 274 write_rgb15b_to_rgb24(jas_matrix_t** pixels, uchar* scanline, int width) 275 { 276 int32 x = 0; 277 int32 index = 0; 278 int16 in_pixel; 279 while (x < width) { 280 in_pixel = scanline[index + 1] | (scanline[index] << 8); 281 index += 2; 282 283 jas_matrix_setv(pixels[0], x, (char)(((in_pixel & 0x7c00)) >> 7) 284 | (((in_pixel & 0x7c00)) >> 12)); 285 jas_matrix_setv(pixels[1], x, (char)(((in_pixel & 0x3e0)) >> 2) 286 | (((in_pixel & 0x3e0)) >> 7)); 287 jas_matrix_setv(pixels[2], x, (char)(((in_pixel & 0x1f)) << 3) 288 | (((in_pixel & 0x1f)) >> 2)); 289 x++; 290 } 291 } 292 293 294 /*! 295 Make *pixels[3] from RGB16/RGBA16 scanline 296 (just write data to pixels) 297 */ 298 inline void 299 write_rgb16_to_rgb24(jas_matrix_t** pixels, uchar* scanline, int width) 300 { 301 int32 x = 0; 302 int32 index = 0; 303 int16 in_pixel; 304 while (x < width) { 305 in_pixel = scanline[index] | (scanline[index+1] << 8); 306 index += 2; 307 308 jas_matrix_setv(pixels[0], x, (char)(((in_pixel & 0xf800)) >> 8) 309 | (((in_pixel & 0x7c00)) >> 12)); 310 jas_matrix_setv(pixels[1], x, (char)(((in_pixel & 0x7e0)) >> 3) 311 | (((in_pixel & 0x7e0)) >> 9)); 312 jas_matrix_setv(pixels[2], x, (char)(((in_pixel & 0x1f)) << 3) 313 | (((in_pixel & 0x1f)) >> 2)); 314 x++; 315 } 316 } 317 318 319 /*! 320 Make *pixels[3] from RGB16/RGBA16 bigendian scanline 321 (just write data to pixels) 322 */ 323 inline void 324 write_rgb16b_to_rgb24(jas_matrix_t** pixels, uchar* scanline, int width) 325 { 326 int32 x = 0; 327 int32 index = 0; 328 int16 in_pixel; 329 while (x < width) { 330 in_pixel = scanline[index + 1] | (scanline[index] << 8); 331 index += 2; 332 333 jas_matrix_setv(pixels[0], x, (char)(((in_pixel & 0xf800)) >> 8) 334 | (((in_pixel & 0xf800)) >> 13)); 335 jas_matrix_setv(pixels[1], x, (char)(((in_pixel & 0x7e0)) >> 3) 336 | (((in_pixel & 0x7e0)) >> 9)); 337 jas_matrix_setv(pixels[2], x, (char)(((in_pixel & 0x1f)) << 3) 338 | (((in_pixel & 0x1f)) >> 2)); 339 x++; 340 } 341 } 342 343 344 /*! 345 Make *pixels[3] from RGB24 scanline 346 (just write data to pixels) 347 */ 348 inline void 349 write_rgb24(jas_matrix_t** pixels, uchar* scanline, int width) 350 { 351 int32 index = 0; 352 int32 x = 0; 353 while (x < width) { 354 jas_matrix_setv(pixels[2], x, scanline[index++]); 355 jas_matrix_setv(pixels[1], x, scanline[index++]); 356 jas_matrix_setv(pixels[0], x, scanline[index++]); 357 x++; 358 } 359 } 360 361 362 /*! 363 Make *pixels[3] from RGB24 bigendian scanline 364 (just write data to pixels) 365 */ 366 inline void 367 write_rgb24b(jas_matrix_t** pixels, uchar* scanline, int width) 368 { 369 int32 index = 0; 370 int32 x = 0; 371 while (x < width) { 372 jas_matrix_setv(pixels[0], x, scanline[index++]); 373 jas_matrix_setv(pixels[1], x, scanline[index++]); 374 jas_matrix_setv(pixels[2], x, scanline[index++]); 375 x++; 376 } 377 } 378 379 380 /*! 381 Make *pixels[3] from RGB32 scanline 382 (just write data to pixels) 383 */ 384 inline void 385 write_rgb32_to_rgb24(jas_matrix_t** pixels, uchar* scanline, int width) 386 { 387 int32 index = 0; 388 int32 x = 0; 389 while (x < width) { 390 jas_matrix_setv(pixels[2], x, scanline[index++]); 391 jas_matrix_setv(pixels[1], x, scanline[index++]); 392 jas_matrix_setv(pixels[0], x, scanline[index++]); 393 index++; 394 x++; 395 } 396 } 397 398 399 /*! 400 Make *pixels[3] from RGB32 bigendian scanline 401 (just write data to pixels) 402 */ 403 inline void 404 write_rgb32b_to_rgb24(jas_matrix_t** pixels, uchar* scanline, int width) 405 { 406 int32 index = 0; 407 int32 x = 0; 408 while (x < width) { 409 index++; 410 jas_matrix_setv(pixels[0], x, scanline[index++]); 411 jas_matrix_setv(pixels[1], x, scanline[index++]); 412 jas_matrix_setv(pixels[2], x, scanline[index++]); 413 x++; 414 } 415 } 416 417 418 /*! 419 Make *pixels[4] from RGBA32 scanline 420 (just write data to pixels) 421 !!! UNTESTED !!! 422 */ 423 inline void 424 write_rgba32(jas_matrix_t** pixels, uchar* scanline, int width) 425 { 426 int32 index = 0; 427 int32 x = 0; 428 while (x < width) { 429 jas_matrix_setv(pixels[3], x, scanline[index++]); 430 jas_matrix_setv(pixels[2], x, scanline[index++]); 431 jas_matrix_setv(pixels[1], x, scanline[index++]); 432 jas_matrix_setv(pixels[0], x, scanline[index++]); 433 x++; 434 } 435 } 436 437 438 /*! 439 Make *pixels[4] from RGBA32 bigendian scanline 440 (just write data to pixels) 441 !!! UNTESTED !!! 442 */ 443 inline void 444 write_rgba32b(jas_matrix_t** pixels, uchar* scanline, int width) 445 { 446 int32 index = 0; 447 int32 x = 0; 448 while (x < width) { 449 jas_matrix_setv(pixels[0], x, scanline[index++]); 450 jas_matrix_setv(pixels[1], x, scanline[index++]); 451 jas_matrix_setv(pixels[2], x, scanline[index++]); 452 jas_matrix_setv(pixels[3], x, scanline[index++]); 453 x++; 454 } 455 } 456 457 458 }// end namespace conversion 459 460 461 // #pragma mark - jasper I/O 462 463 464 static int 465 Read(jas_stream_obj_t* object, char* buffer, const int length) 466 { 467 return (*(BPositionIO**)object)->Read(buffer, length); 468 } 469 470 471 static int 472 Write(jas_stream_obj_t* object, char* buffer, const int length) 473 { 474 return (*(BPositionIO**)object)->Write(buffer, length); 475 } 476 477 478 static long 479 Seek(jas_stream_obj_t* object, long offset, int origin) 480 { 481 return (*(BPositionIO**)object)->Seek(offset, origin); 482 } 483 484 485 static int 486 Close(jas_stream_obj_t* object) 487 { 488 return 0; 489 } 490 491 492 static jas_stream_ops_t positionIOops = { 493 Read, 494 Write, 495 Seek, 496 Close 497 }; 498 499 500 static jas_stream_t* 501 jas_stream_positionIOopen(BPositionIO *positionIO) 502 { 503 jas_stream_t* stream; 504 505 stream = (jas_stream_t *)malloc(sizeof(jas_stream_t)); 506 if (stream == (jas_stream_t *)NULL) 507 return (jas_stream_t *)NULL; 508 509 memset(stream, 0, sizeof(jas_stream_t)); 510 stream->rwlimit_ = -1; 511 stream->obj_=(jas_stream_obj_t *)malloc(sizeof(BPositionIO*)); 512 if (stream->obj_ == (jas_stream_obj_t *)NULL) { 513 free(stream); 514 return (jas_stream_t *)NULL; 515 } 516 517 *((BPositionIO**)stream->obj_) = positionIO; 518 stream->ops_ = (&positionIOops); 519 stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY; 520 stream->bufbase_ = stream->tinybuf_; 521 stream->bufsize_ = 1; 522 stream->bufstart_ = (&stream->bufbase_[JAS_STREAM_MAXPUTBACK]); 523 stream->ptr_ = stream->bufstart_; 524 stream->bufmode_ |= JAS_STREAM_UNBUF & JAS_STREAM_BUFMODEMASK; 525 526 return stream; 527 } 528 529 530 // #pragma mark - 531 532 533 SSlider::SSlider(const char* name, const char* label, 534 BMessage* message, int32 minValue, int32 maxValue, orientation posture, 535 thumb_style thumbType, uint32 flags) 536 : 537 BSlider(name, label, message, minValue, maxValue, 538 posture, thumbType, flags) 539 { 540 rgb_color barColor = { 0, 0, 229, 255 }; 541 UseFillColor(true, &barColor); 542 } 543 544 545 //! Update status string - show actual value 546 const char* 547 SSlider::UpdateText() const 548 { 549 snprintf(fStatusLabel, sizeof(fStatusLabel), "%" B_PRId32, Value()); 550 return fStatusLabel; 551 } 552 553 554 // #pragma mark - 555 556 557 TranslatorReadView::TranslatorReadView(const char* name, 558 TranslatorSettings* settings) 559 : 560 BView(name, 0, new BGroupLayout(B_VERTICAL)), 561 fSettings(settings) 562 { 563 fGrayAsRGB32 = new BCheckBox("grayasrgb32", 564 B_TRANSLATE("Read greyscale images as RGB32"), 565 new BMessage(VIEW_MSG_SET_GRAYASRGB32)); 566 if (fSettings->SetGetBool(JP2_SET_GRAY8_AS_B_RGB32)) 567 fGrayAsRGB32->SetValue(B_CONTROL_ON); 568 569 float padding = 10.0f; 570 BLayoutBuilder::Group<>(this, B_VERTICAL) 571 .SetInsets(padding) 572 .Add(fGrayAsRGB32) 573 .AddGlue(); 574 } 575 576 577 TranslatorReadView::~TranslatorReadView() 578 { 579 fSettings->Release(); 580 } 581 582 583 void 584 TranslatorReadView::AttachedToWindow() 585 { 586 fGrayAsRGB32->SetTarget(this); 587 } 588 589 590 void 591 TranslatorReadView::MessageReceived(BMessage* message) 592 { 593 switch (message->what) { 594 case VIEW_MSG_SET_GRAYASRGB32: 595 { 596 int32 value; 597 if (message->FindInt32("be:value", &value) == B_OK) { 598 bool boolValue = value; 599 fSettings->SetGetBool(JP2_SET_GRAY8_AS_B_RGB32, &boolValue); 600 fSettings->SaveSettings(); 601 } 602 break; 603 } 604 default: 605 BView::MessageReceived(message); 606 break; 607 } 608 } 609 610 611 // #pragma mark - TranslatorWriteView 612 613 614 TranslatorWriteView::TranslatorWriteView(const char* name, 615 TranslatorSettings* settings) 616 : 617 BView(name, 0, new BGroupLayout(B_VERTICAL)), 618 fSettings(settings) 619 { 620 fQualitySlider = new SSlider("quality", B_TRANSLATE("Output quality"), 621 new BMessage(VIEW_MSG_SET_QUALITY), 0, 100); 622 fQualitySlider->SetHashMarks(B_HASH_MARKS_BOTTOM); 623 fQualitySlider->SetHashMarkCount(10); 624 fQualitySlider->SetLimitLabels(B_TRANSLATE("Low"), B_TRANSLATE("High")); 625 fQualitySlider->SetValue(fSettings->SetGetInt32(JP2_SET_QUALITY)); 626 627 fGrayAsRGB24 = new BCheckBox("gray1asrgb24", 628 B_TRANSLATE("Write black-and-white images as RGB24"), 629 new BMessage(VIEW_MSG_SET_GRAY1ASRGB24)); 630 if (fSettings->SetGetBool(JP2_SET_GRAY1_AS_B_RGB24)) 631 fGrayAsRGB24->SetValue(B_CONTROL_ON); 632 633 fCodeStreamOnly = new BCheckBox("codestreamonly", 634 B_TRANSLATE("Output only codestream (.jpc)"), 635 new BMessage(VIEW_MSG_SET_JPC)); 636 if (fSettings->SetGetBool(JP2_SET_JPC)) 637 fCodeStreamOnly->SetValue(B_CONTROL_ON); 638 639 BLayoutBuilder::Group<>(this, B_VERTICAL) 640 .SetInsets(B_USE_DEFAULT_SPACING) 641 .Add(fQualitySlider) 642 .Add(fGrayAsRGB24) 643 .Add(fCodeStreamOnly) 644 .AddGlue(); 645 } 646 647 648 TranslatorWriteView::~TranslatorWriteView() 649 { 650 fSettings->Release(); 651 } 652 653 654 void 655 TranslatorWriteView::AttachedToWindow() 656 { 657 fQualitySlider->SetTarget(this); 658 fGrayAsRGB24->SetTarget(this); 659 fCodeStreamOnly->SetTarget(this); 660 } 661 662 663 void 664 TranslatorWriteView::MessageReceived(BMessage* message) 665 { 666 switch (message->what) { 667 case VIEW_MSG_SET_QUALITY: 668 { 669 int32 value; 670 if (message->FindInt32("be:value", &value) == B_OK) { 671 fSettings->SetGetInt32(JP2_SET_QUALITY, &value); 672 fSettings->SaveSettings(); 673 } 674 break; 675 } 676 case VIEW_MSG_SET_GRAY1ASRGB24: 677 { 678 int32 value; 679 if (message->FindInt32("be:value", &value) == B_OK) { 680 bool boolValue = value; 681 fSettings->SetGetBool(JP2_SET_GRAY1_AS_B_RGB24, &boolValue); 682 fSettings->SaveSettings(); 683 } 684 break; 685 } 686 case VIEW_MSG_SET_JPC: 687 { 688 int32 value; 689 if (message->FindInt32("be:value", &value) == B_OK) { 690 bool boolValue = value; 691 fSettings->SetGetBool(JP2_SET_JPC, &boolValue); 692 fSettings->SaveSettings(); 693 } 694 break; 695 } 696 default: 697 BView::MessageReceived(message); 698 break; 699 } 700 } 701 702 703 // #pragma mark - 704 705 706 TranslatorAboutView::TranslatorAboutView(const char* name) 707 : 708 BView(name, 0, new BGroupLayout(B_VERTICAL)) 709 { 710 BAlignment labelAlignment = BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP); 711 BStringView* title = new BStringView("Title", sTranslatorName); 712 title->SetFont(be_bold_font); 713 title->SetExplicitAlignment(labelAlignment); 714 715 char versionString[100]; 716 snprintf(versionString, sizeof(versionString), 717 B_TRANSLATE("Version %d.%d.%d"), 718 static_cast<int>(sTranslatorVersion >> 8), 719 static_cast<int>((sTranslatorVersion >> 4) & 0xf), 720 static_cast<int>(sTranslatorVersion & 0xf)); 721 722 BStringView* version = new BStringView("Version", versionString); 723 version->SetExplicitAlignment(labelAlignment); 724 725 BTextView* infoView = new BTextView("info"); 726 infoView->SetText(sTranslatorInfo); 727 infoView->SetViewUIColor(B_PANEL_BACKGROUND_COLOR); 728 rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR); 729 infoView->SetFontAndColor(be_plain_font, B_FONT_ALL, &textColor); 730 infoView->MakeEditable(false); 731 732 BLayoutBuilder::Group<>(this, B_VERTICAL, 0) 733 .SetInsets(B_USE_DEFAULT_SPACING) 734 .Add(title) 735 .Add(version) 736 .Add(infoView); 737 } 738 739 740 // #pragma mark - 741 742 743 TranslatorView::TranslatorView(const char* name, TranslatorSettings* settings) 744 : 745 BTabView(name, B_WIDTH_FROM_LABEL) 746 { 747 SetBorder(B_NO_BORDER); 748 749 AddTab(new TranslatorWriteView(B_TRANSLATE("Write"), 750 settings->Acquire())); 751 AddTab(new TranslatorReadView(B_TRANSLATE("Read"), 752 settings->Acquire())); 753 AddTab(new TranslatorAboutView(B_TRANSLATE("About"))); 754 755 settings->Release(); 756 757 BFont font; 758 GetFont(&font); 759 SetExplicitPreferredSize( 760 BSize((font.Size() * 380) / 12, (font.Size() * 250) / 12)); 761 } 762 763 764 // #pragma mark - 765 766 BView* 767 JP2Translator::NewConfigView(TranslatorSettings* settings) 768 { 769 BView* outView = new TranslatorView("TranslatorView", settings); 770 return outView; 771 } 772 773 774 JP2Translator::JP2Translator() 775 : BaseTranslator(sTranslatorName, sTranslatorInfo, sTranslatorVersion, 776 sInputFormats, kNumInputFormats, 777 sOutputFormats, kNumOutputFormats, 778 JP2_SETTINGS_FILE, 779 sDefaultSettings, kNumDefaultSettings, 780 B_TRANSLATOR_BITMAP, JP2_FORMAT) 781 { 782 } 783 784 785 //! Determine whether or not we can handle this data 786 status_t 787 JP2Translator::DerivedIdentify(BPositionIO* inSource, 788 const translation_format* inFormat, BMessage* ioExtension, 789 translator_info* outInfo, uint32 outType) 790 { 791 if ((outType != 0) && (outType != B_TRANSLATOR_BITMAP) 792 && outType != JP2_FORMAT) 793 return B_NO_TRANSLATOR; 794 795 // !!! You might need to make this buffer bigger to test for your 796 // native format 797 off_t position = inSource->Position(); 798 uint8 header[sizeof(TranslatorBitmap)]; 799 status_t err = inSource->Read(header, sizeof(TranslatorBitmap)); 800 inSource->Seek(position, SEEK_SET); 801 if (err < B_OK) 802 return err; 803 804 if (B_BENDIAN_TO_HOST_INT32(((TranslatorBitmap *)header)->magic) 805 == B_TRANSLATOR_BITMAP) { 806 if (PopulateInfoFromFormat(outInfo, B_TRANSLATOR_BITMAP) != B_OK) 807 return B_NO_TRANSLATOR; 808 } else { 809 if ((((header[4] << 24) | (header[5] << 16) | (header[6] << 8) 810 | header[7]) == JP2_BOX_JP) // JP2 811 || (header[0] == (JPC_MS_SOC >> 8) && header[1] 812 == (JPC_MS_SOC & 0xff))) // JPC 813 { 814 if (PopulateInfoFromFormat(outInfo, JP2_FORMAT) != B_OK) 815 return B_NO_TRANSLATOR; 816 } else 817 return B_NO_TRANSLATOR; 818 } 819 820 return B_OK; 821 } 822 823 824 status_t 825 JP2Translator::DerivedTranslate(BPositionIO* inSource, 826 const translator_info* inInfo, BMessage* ioExtension, uint32 outType, 827 BPositionIO* outDestination, int32 baseType) 828 { 829 // If no specific type was requested, convert to the interchange format 830 if (outType == 0) 831 outType = B_TRANSLATOR_BITMAP; 832 833 // What action to take, based on the findings of Identify() 834 if (outType == inInfo->type) 835 return Copy(inSource, outDestination); 836 if (inInfo->type == B_TRANSLATOR_BITMAP && outType == JP2_FORMAT) 837 return Compress(inSource, outDestination); 838 if (inInfo->type == JP2_FORMAT && outType == B_TRANSLATOR_BITMAP) 839 return Decompress(inSource, outDestination); 840 841 return B_NO_TRANSLATOR; 842 } 843 844 845 //! The user has requested the same format for input and output, so just copy 846 status_t 847 JP2Translator::Copy(BPositionIO* in, BPositionIO* out) 848 { 849 int block_size = 65536; 850 void* buffer = malloc(block_size); 851 char temp[1024]; 852 if (buffer == NULL) { 853 buffer = temp; 854 block_size = 1024; 855 } 856 status_t err = B_OK; 857 858 // Read until end of file or error 859 while (1) { 860 ssize_t to_read = block_size; 861 err = in->Read(buffer, to_read); 862 // Explicit check for EOF 863 if (err == -1) { 864 if (buffer != temp) 865 free(buffer); 866 return B_OK; 867 } 868 if (err <= B_OK) break; 869 to_read = err; 870 err = out->Write(buffer, to_read); 871 if (err != to_read) if (err >= 0) err = B_DEVICE_FULL; 872 if (err < B_OK) break; 873 } 874 875 if (buffer != temp) 876 free(buffer); 877 return (err >= 0) ? B_OK : err; 878 } 879 880 881 //! Encode into the native format 882 status_t 883 JP2Translator::Compress(BPositionIO* in, BPositionIO* out) 884 { 885 using namespace conversion; 886 887 // Read info about bitmap 888 TranslatorBitmap header; 889 status_t err = in->Read(&header, sizeof(TranslatorBitmap)); 890 if (err < B_OK) 891 return err; 892 if (err < (int)sizeof(TranslatorBitmap)) 893 return B_ERROR; 894 895 // Grab dimension, color space, and size information from the stream 896 BRect bounds; 897 bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left); 898 bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top); 899 bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right); 900 bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom); 901 902 int32 in_row_bytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes); 903 904 int width = bounds.IntegerWidth() + 1; 905 int height = bounds.IntegerHeight() + 1; 906 907 // Function pointer to write function 908 // It MUST point to proper function 909 void (*converter)(jas_matrix_t** pixels, uchar* inscanline, 910 int width) = write_rgba32; 911 912 // Default color info 913 int out_color_space = JAS_CLRSPC_SRGB; 914 int out_color_components = 3; 915 916 switch ((color_space)B_BENDIAN_TO_HOST_INT32(header.colors)) { 917 case B_GRAY1: 918 if (fSettings->SetGetBool(JP2_SET_GRAY1_AS_B_RGB24)) { 919 converter = write_gray1_to_rgb24; 920 } else { 921 out_color_components = 1; 922 out_color_space = JAS_CLRSPC_SGRAY; 923 converter = write_gray1_to_gray; 924 } 925 break; 926 927 case B_CMAP8: 928 converter = write_cmap8_to_rgb24; 929 break; 930 931 case B_GRAY8: 932 out_color_components = 1; 933 out_color_space = JAS_CLRSPC_SGRAY; 934 converter = write_gray; 935 break; 936 937 case B_RGB15: 938 case B_RGBA15: 939 converter = write_rgb15_to_rgb24; 940 break; 941 942 case B_RGB15_BIG: 943 case B_RGBA15_BIG: 944 converter = write_rgb15b_to_rgb24; 945 break; 946 947 case B_RGB16: 948 converter = write_rgb16_to_rgb24; 949 break; 950 951 case B_RGB16_BIG: 952 converter = write_rgb16b_to_rgb24; 953 break; 954 955 case B_RGB24: 956 converter = write_rgb24; 957 break; 958 959 case B_RGB24_BIG: 960 converter = write_rgb24b; 961 break; 962 963 case B_RGB32: 964 converter = write_rgb32_to_rgb24; 965 break; 966 967 case B_RGB32_BIG: 968 converter = write_rgb32b_to_rgb24; 969 break; 970 971 case B_RGBA32: 972 /* 973 // In theory it should be possible to write 4 color components 974 // to jp2, so it should be possible to have transparency. 975 // Unfortunetly libjasper does not agree with that 976 // For now i don't know how to modify it :( 977 978 out_color_components = 4; 979 converter = write_rgba32; 980 */ 981 converter = write_rgb32_to_rgb24; 982 break; 983 984 case B_RGBA32_BIG: 985 /* 986 // In theory it should be possible to write 4 color components 987 // to jp2, so it should be possible to have transparency. 988 // Unfortunetly libjasper does not agree with that 989 // For now i don't know how to modify it :( 990 991 out_color_components = 4; 992 converter = write_rgba32b; 993 */ 994 converter = write_rgb32b_to_rgb24; 995 break; 996 997 default: 998 syslog(LOG_ERR, "Unknown color space.\n"); 999 return B_ERROR; 1000 } 1001 1002 jas_image_t* image; 1003 jas_stream_t* outs; 1004 jas_matrix_t* pixels[4]; 1005 jas_image_cmptparm_t component_info[4]; 1006 1007 if (jas_init()) 1008 return B_ERROR; 1009 1010 if (!(outs = jas_stream_positionIOopen(out))) 1011 return B_ERROR; 1012 1013 int32 i = 0; 1014 for (i = 0; i < (long)out_color_components; i++) { 1015 (void) memset(component_info + i, 0, sizeof(jas_image_cmptparm_t)); 1016 component_info[i].hstep = 1; 1017 component_info[i].vstep = 1; 1018 component_info[i].width = (unsigned int)width; 1019 component_info[i].height = (unsigned int)height; 1020 component_info[i].prec = (unsigned int)8; 1021 } 1022 1023 image = jas_image_create((short)out_color_components, component_info, 1024 out_color_space); 1025 if (image == (jas_image_t *)NULL) 1026 return Error(outs, NULL, NULL, 0, NULL, B_ERROR); 1027 1028 uchar *in_scanline = (uchar*) malloc(in_row_bytes); 1029 if (in_scanline == NULL) 1030 return Error(outs, image, NULL, 0, NULL, B_ERROR); 1031 1032 for (i = 0; i < (long)out_color_components; i++) { 1033 pixels[i] = jas_matrix_create(1, (unsigned int)width); 1034 if (pixels[i] == (jas_matrix_t *)NULL) 1035 return Error(outs, image, pixels, i+1, in_scanline, B_ERROR); 1036 } 1037 1038 int32 y = 0; 1039 for (y = 0; y < (long)height; y++) { 1040 err = in->Read(in_scanline, in_row_bytes); 1041 if (err < in_row_bytes) { 1042 return (err < B_OK) ? Error(outs, image, pixels, 1043 out_color_components, in_scanline, err) 1044 : Error(outs, image, pixels, out_color_components, in_scanline, 1045 B_ERROR); 1046 } 1047 1048 converter(pixels, in_scanline, width); 1049 1050 for (i = 0; i < (long)out_color_components; i++) { 1051 (void)jas_image_writecmpt(image, (short)i, 0, (unsigned int)y, 1052 (unsigned int)width, 1, pixels[i]); 1053 } 1054 } 1055 1056 char opts[16]; 1057 sprintf(opts, "rate=%1f", 1058 (float)fSettings->SetGetInt32(JP2_SET_QUALITY) / 100.0); 1059 1060 if (jas_image_encode(image, outs, jas_image_strtofmt( 1061 fSettings->SetGetBool(JP2_SET_JPC) ? 1062 (char*)"jpc" : (char*)"jp2"), opts)) { 1063 return Error(outs, image, pixels, 1064 out_color_components, in_scanline, err); 1065 } 1066 1067 free(in_scanline); 1068 1069 for (i = 0; i < (long)out_color_components; i++) 1070 jas_matrix_destroy(pixels[i]); 1071 1072 jas_stream_close(outs); 1073 jas_image_destroy(image); 1074 jas_image_clearfmts(); 1075 1076 return B_OK; 1077 } 1078 1079 1080 //! Decode the native format 1081 status_t 1082 JP2Translator::Decompress(BPositionIO* in, BPositionIO* out) 1083 { 1084 using namespace conversion; 1085 1086 jas_image_t* image; 1087 jas_stream_t* ins; 1088 jas_matrix_t* pixels[4]; 1089 1090 if (jas_init()) 1091 return B_ERROR; 1092 1093 if (!(ins = jas_stream_positionIOopen(in))) 1094 return B_ERROR; 1095 1096 if (!(image = jas_image_decode(ins, -1, 0))) 1097 return Error(ins, NULL, NULL, 0, NULL, B_ERROR); 1098 1099 // Default color info 1100 color_space out_color_space; 1101 int out_color_components; 1102 int in_color_components = jas_image_numcmpts(image); 1103 1104 // Function pointer to read function 1105 // It MUST point to proper function 1106 void (*converter)(jas_matrix_t** pixels, uchar* outscanline, 1107 int width) = NULL; 1108 1109 switch (jas_clrspc_fam(jas_image_clrspc(image))) { 1110 case JAS_CLRSPC_FAM_RGB: 1111 out_color_components = 4; 1112 if (in_color_components == 3) { 1113 out_color_space = B_RGB32; 1114 converter = read_rgb24_to_rgb32; 1115 } else if (in_color_components == 4) { 1116 out_color_space = B_RGBA32; 1117 converter = read_rgba32; 1118 } else { 1119 syslog(LOG_ERR, "Other than RGB with 3 or 4 color " 1120 "components not implemented.\n"); 1121 return Error(ins, image, NULL, 0, NULL, B_ERROR); 1122 } 1123 break; 1124 case JAS_CLRSPC_FAM_GRAY: 1125 if (fSettings->SetGetBool(JP2_SET_GRAY8_AS_B_RGB32)) { 1126 out_color_space = B_RGB32; 1127 out_color_components = 4; 1128 converter = read_gray_to_rgb32; 1129 } else { 1130 out_color_space = B_GRAY8; 1131 out_color_components = 1; 1132 converter = read_gray; 1133 } 1134 break; 1135 case JAS_CLRSPC_FAM_YCBCR: 1136 syslog(LOG_ERR, "Color space YCBCR not implemented yet.\n"); 1137 return Error(ins, image, NULL, 0, NULL, B_ERROR); 1138 break; 1139 case JAS_CLRSPC_UNKNOWN: 1140 default: 1141 syslog(LOG_ERR, "Color space unknown. \n"); 1142 return Error(ins, image, NULL, 0, NULL, B_ERROR); 1143 break; 1144 } 1145 1146 float width = (float)jas_image_width(image); 1147 float height = (float)jas_image_height(image); 1148 1149 // Bytes count in one line of image (scanline) 1150 int64 out_row_bytes = (int32)width * out_color_components; 1151 // NOTE: things will go wrong if "out_row_bytes" wouldn't fit into 32 bits 1152 1153 // !!! Initialize this bounds rect to the size of your image 1154 BRect bounds(0, 0, width - 1, height - 1); 1155 1156 1157 // Fill out the B_TRANSLATOR_BITMAP's header 1158 TranslatorBitmap header; 1159 header.magic = B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP); 1160 header.bounds.left = B_HOST_TO_BENDIAN_FLOAT(bounds.left); 1161 header.bounds.top = B_HOST_TO_BENDIAN_FLOAT(bounds.top); 1162 header.bounds.right = B_HOST_TO_BENDIAN_FLOAT(bounds.right); 1163 header.bounds.bottom = B_HOST_TO_BENDIAN_FLOAT(bounds.bottom); 1164 header.colors = (color_space)B_HOST_TO_BENDIAN_INT32(out_color_space); 1165 header.rowBytes = B_HOST_TO_BENDIAN_INT32(out_row_bytes); 1166 header.dataSize = B_HOST_TO_BENDIAN_INT32((int32)(out_row_bytes * height)); 1167 1168 // Write out the header 1169 status_t err = out->Write(&header, sizeof(TranslatorBitmap)); 1170 if (err < B_OK) 1171 return Error(ins, image, NULL, 0, NULL, err); 1172 if (err < (int)sizeof(TranslatorBitmap)) 1173 return Error(ins, image, NULL, 0, NULL, B_ERROR); 1174 1175 uchar *out_scanline = (uchar*) malloc(out_row_bytes); 1176 if (out_scanline == NULL) 1177 return Error(ins, image, NULL, 0, NULL, B_ERROR); 1178 1179 int32 i = 0; 1180 for (i = 0; i < (long)in_color_components; i++) { 1181 pixels[i] = jas_matrix_create(1, (unsigned int)width); 1182 if (pixels[i] == (jas_matrix_t *)NULL) 1183 return Error(ins, image, pixels, i + 1, out_scanline, B_ERROR); 1184 } 1185 1186 int32 y = 0; 1187 for (y = 0; y < (long)height; y++) { 1188 for (i = 0; i < (long)in_color_components; i++) { 1189 (void)jas_image_readcmpt(image, (short)i, 0, (unsigned int)y, 1190 (unsigned int)width, 1, pixels[i]); 1191 } 1192 1193 converter(pixels, out_scanline, (int32)width); 1194 1195 err = out->Write(out_scanline, out_row_bytes); 1196 if (err < out_row_bytes) { 1197 return (err < B_OK) ? Error(ins, image, pixels, in_color_components, 1198 out_scanline, err) 1199 : Error(ins, image, pixels, in_color_components, out_scanline, 1200 B_ERROR); 1201 } 1202 } 1203 1204 free(out_scanline); 1205 1206 for (i = 0; i < (long)in_color_components; i++) 1207 jas_matrix_destroy(pixels[i]); 1208 1209 jas_stream_close(ins); 1210 jas_image_destroy(image); 1211 jas_image_clearfmts(); 1212 1213 return B_OK; 1214 } 1215 1216 1217 /*! searches in both inputFormats & outputFormats */ 1218 status_t 1219 JP2Translator::PopulateInfoFromFormat(translator_info* info, 1220 uint32 formatType, translator_id id) 1221 { 1222 int32 formatCount; 1223 const translation_format* formats = OutputFormats(&formatCount); 1224 1225 for (int i = 0; i <= 1; formats = InputFormats(&formatCount), i++) { 1226 if (PopulateInfoFromFormat(info, formatType, 1227 formats, formatCount) == B_OK) { 1228 info->translator = id; 1229 return B_OK; 1230 } 1231 } 1232 1233 return B_ERROR; 1234 } 1235 1236 1237 status_t 1238 JP2Translator::PopulateInfoFromFormat(translator_info* info, 1239 uint32 formatType, const translation_format* formats, int32 formatCount) 1240 { 1241 for (int i = 0; i < formatCount; i++) { 1242 if (formats[i].type == formatType) { 1243 info->type = formatType; 1244 info->group = formats[i].group; 1245 info->quality = formats[i].quality; 1246 info->capability = formats[i].capability; 1247 if (strcmp(formats[i].name, B_TRANSLATOR_BITMAP_DESCRIPTION) 1248 == 0) { 1249 strlcpy(info->name, 1250 B_TRANSLATE(B_TRANSLATOR_BITMAP_DESCRIPTION), 1251 sizeof(info->name)); 1252 } else { 1253 strlcpy(info->name, formats[i].name, sizeof(info->name)); 1254 } 1255 strlcpy(info->MIME, formats[i].MIME, sizeof(info->MIME)); 1256 return B_OK; 1257 } 1258 } 1259 1260 return B_ERROR; 1261 } 1262 1263 1264 /*! 1265 Frees jpeg alocated memory 1266 Returns given error (B_ERROR by default) 1267 */ 1268 status_t 1269 Error(jas_stream_t* stream, jas_image_t* image, jas_matrix_t** pixels, 1270 int32 pixels_count, uchar* scanline, status_t error) 1271 { 1272 if (pixels) { 1273 int32 i; 1274 for (i = 0; i < (long)pixels_count; i++) { 1275 if (pixels[i] != NULL) 1276 jas_matrix_destroy(pixels[i]); 1277 } 1278 } 1279 if (stream) 1280 jas_stream_close(stream); 1281 if (image) 1282 jas_image_destroy(image); 1283 1284 jas_image_clearfmts(); 1285 free(scanline); 1286 1287 return error; 1288 } 1289 1290 1291 // #pragma mark - 1292 1293 BTranslator* 1294 make_nth_translator(int32 n, image_id you, uint32 flags, ...) 1295 { 1296 if (!n) 1297 return new JP2Translator(); 1298 1299 return NULL; 1300 } 1301 1302 1303 int 1304 main() 1305 { 1306 BApplication app("application/x-vnd.Haiku-JPEG2000Translator"); 1307 JP2Translator* translator = new JP2Translator(); 1308 if (LaunchTranslatorWindow(translator, sTranslatorName) == B_OK) 1309 app.Run(); 1310 1311 return 0; 1312 } 1313 1314