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 758 759 // #pragma mark - 760 761 BView* 762 JP2Translator::NewConfigView(TranslatorSettings* settings) 763 { 764 BView* outView = new TranslatorView("TranslatorView", settings); 765 return outView; 766 } 767 768 769 JP2Translator::JP2Translator() 770 : BaseTranslator(sTranslatorName, sTranslatorInfo, sTranslatorVersion, 771 sInputFormats, kNumInputFormats, 772 sOutputFormats, kNumOutputFormats, 773 JP2_SETTINGS_FILE, 774 sDefaultSettings, kNumDefaultSettings, 775 B_TRANSLATOR_BITMAP, JP2_FORMAT) 776 { 777 } 778 779 780 //! Determine whether or not we can handle this data 781 status_t 782 JP2Translator::DerivedIdentify(BPositionIO* inSource, 783 const translation_format* inFormat, BMessage* ioExtension, 784 translator_info* outInfo, uint32 outType) 785 { 786 if ((outType != 0) && (outType != B_TRANSLATOR_BITMAP) 787 && outType != JP2_FORMAT) 788 return B_NO_TRANSLATOR; 789 790 // !!! You might need to make this buffer bigger to test for your 791 // native format 792 off_t position = inSource->Position(); 793 uint8 header[sizeof(TranslatorBitmap)]; 794 status_t err = inSource->Read(header, sizeof(TranslatorBitmap)); 795 inSource->Seek(position, SEEK_SET); 796 if (err < B_OK) 797 return err; 798 799 if (B_BENDIAN_TO_HOST_INT32(((TranslatorBitmap *)header)->magic) 800 == B_TRANSLATOR_BITMAP) { 801 if (PopulateInfoFromFormat(outInfo, B_TRANSLATOR_BITMAP) != B_OK) 802 return B_NO_TRANSLATOR; 803 } else { 804 if ((((header[4] << 24) | (header[5] << 16) | (header[6] << 8) 805 | header[7]) == JP2_BOX_JP) // JP2 806 || (header[0] == (JPC_MS_SOC >> 8) && header[1] 807 == (JPC_MS_SOC & 0xff))) // JPC 808 { 809 if (PopulateInfoFromFormat(outInfo, JP2_FORMAT) != B_OK) 810 return B_NO_TRANSLATOR; 811 } else 812 return B_NO_TRANSLATOR; 813 } 814 815 return B_OK; 816 } 817 818 819 status_t 820 JP2Translator::DerivedTranslate(BPositionIO* inSource, 821 const translator_info* inInfo, BMessage* ioExtension, uint32 outType, 822 BPositionIO* outDestination, int32 baseType) 823 { 824 // If no specific type was requested, convert to the interchange format 825 if (outType == 0) 826 outType = B_TRANSLATOR_BITMAP; 827 828 // What action to take, based on the findings of Identify() 829 if (outType == inInfo->type) 830 return Copy(inSource, outDestination); 831 if (inInfo->type == B_TRANSLATOR_BITMAP && outType == JP2_FORMAT) 832 return Compress(inSource, outDestination); 833 if (inInfo->type == JP2_FORMAT && outType == B_TRANSLATOR_BITMAP) 834 return Decompress(inSource, outDestination); 835 836 return B_NO_TRANSLATOR; 837 } 838 839 840 //! The user has requested the same format for input and output, so just copy 841 status_t 842 JP2Translator::Copy(BPositionIO* in, BPositionIO* out) 843 { 844 int block_size = 65536; 845 void* buffer = malloc(block_size); 846 char temp[1024]; 847 if (buffer == NULL) { 848 buffer = temp; 849 block_size = 1024; 850 } 851 status_t err = B_OK; 852 853 // Read until end of file or error 854 while (1) { 855 ssize_t to_read = block_size; 856 err = in->Read(buffer, to_read); 857 // Explicit check for EOF 858 if (err == -1) { 859 if (buffer != temp) 860 free(buffer); 861 return B_OK; 862 } 863 if (err <= B_OK) break; 864 to_read = err; 865 err = out->Write(buffer, to_read); 866 if (err != to_read) if (err >= 0) err = B_DEVICE_FULL; 867 if (err < B_OK) break; 868 } 869 870 if (buffer != temp) 871 free(buffer); 872 return (err >= 0) ? B_OK : err; 873 } 874 875 876 //! Encode into the native format 877 status_t 878 JP2Translator::Compress(BPositionIO* in, BPositionIO* out) 879 { 880 using namespace conversion; 881 882 // Read info about bitmap 883 TranslatorBitmap header; 884 status_t err = in->Read(&header, sizeof(TranslatorBitmap)); 885 if (err < B_OK) 886 return err; 887 if (err < (int)sizeof(TranslatorBitmap)) 888 return B_ERROR; 889 890 // Grab dimension, color space, and size information from the stream 891 BRect bounds; 892 bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left); 893 bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top); 894 bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right); 895 bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom); 896 897 int32 in_row_bytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes); 898 899 int width = bounds.IntegerWidth() + 1; 900 int height = bounds.IntegerHeight() + 1; 901 902 // Function pointer to write function 903 // It MUST point to proper function 904 void (*converter)(jas_matrix_t** pixels, uchar* inscanline, 905 int width) = write_rgba32; 906 907 // Default color info 908 int out_color_space = JAS_CLRSPC_SRGB; 909 int out_color_components = 3; 910 911 switch ((color_space)B_BENDIAN_TO_HOST_INT32(header.colors)) { 912 case B_GRAY1: 913 if (fSettings->SetGetBool(JP2_SET_GRAY1_AS_B_RGB24)) { 914 converter = write_gray1_to_rgb24; 915 } else { 916 out_color_components = 1; 917 out_color_space = JAS_CLRSPC_SGRAY; 918 converter = write_gray1_to_gray; 919 } 920 break; 921 922 case B_CMAP8: 923 converter = write_cmap8_to_rgb24; 924 break; 925 926 case B_GRAY8: 927 out_color_components = 1; 928 out_color_space = JAS_CLRSPC_SGRAY; 929 converter = write_gray; 930 break; 931 932 case B_RGB15: 933 case B_RGBA15: 934 converter = write_rgb15_to_rgb24; 935 break; 936 937 case B_RGB15_BIG: 938 case B_RGBA15_BIG: 939 converter = write_rgb15b_to_rgb24; 940 break; 941 942 case B_RGB16: 943 converter = write_rgb16_to_rgb24; 944 break; 945 946 case B_RGB16_BIG: 947 converter = write_rgb16b_to_rgb24; 948 break; 949 950 case B_RGB24: 951 converter = write_rgb24; 952 break; 953 954 case B_RGB24_BIG: 955 converter = write_rgb24b; 956 break; 957 958 case B_RGB32: 959 converter = write_rgb32_to_rgb24; 960 break; 961 962 case B_RGB32_BIG: 963 converter = write_rgb32b_to_rgb24; 964 break; 965 966 case B_RGBA32: 967 /* 968 // In theory it should be possible to write 4 color components 969 // to jp2, so it should be possible to have transparency. 970 // Unfortunetly libjasper does not agree with that 971 // For now i don't know how to modify it :( 972 973 out_color_components = 4; 974 converter = write_rgba32; 975 */ 976 converter = write_rgb32_to_rgb24; 977 break; 978 979 case B_RGBA32_BIG: 980 /* 981 // In theory it should be possible to write 4 color components 982 // to jp2, so it should be possible to have transparency. 983 // Unfortunetly libjasper does not agree with that 984 // For now i don't know how to modify it :( 985 986 out_color_components = 4; 987 converter = write_rgba32b; 988 */ 989 converter = write_rgb32b_to_rgb24; 990 break; 991 992 default: 993 syslog(LOG_ERR, "Unknown color space.\n"); 994 return B_ERROR; 995 } 996 997 jas_image_t* image; 998 jas_stream_t* outs; 999 jas_matrix_t* pixels[4]; 1000 jas_image_cmptparm_t component_info[4]; 1001 1002 if (jas_init()) 1003 return B_ERROR; 1004 1005 if (!(outs = jas_stream_positionIOopen(out))) 1006 return B_ERROR; 1007 1008 int32 i = 0; 1009 for (i = 0; i < (long)out_color_components; i++) { 1010 (void) memset(component_info + i, 0, sizeof(jas_image_cmptparm_t)); 1011 component_info[i].hstep = 1; 1012 component_info[i].vstep = 1; 1013 component_info[i].width = (unsigned int)width; 1014 component_info[i].height = (unsigned int)height; 1015 component_info[i].prec = (unsigned int)8; 1016 } 1017 1018 image = jas_image_create((short)out_color_components, component_info, 1019 out_color_space); 1020 if (image == (jas_image_t *)NULL) 1021 return Error(outs, NULL, NULL, 0, NULL, B_ERROR); 1022 1023 uchar *in_scanline = (uchar*) malloc(in_row_bytes); 1024 if (in_scanline == NULL) 1025 return Error(outs, image, NULL, 0, NULL, B_ERROR); 1026 1027 for (i = 0; i < (long)out_color_components; i++) { 1028 pixels[i] = jas_matrix_create(1, (unsigned int)width); 1029 if (pixels[i] == (jas_matrix_t *)NULL) 1030 return Error(outs, image, pixels, i+1, in_scanline, B_ERROR); 1031 } 1032 1033 int32 y = 0; 1034 for (y = 0; y < (long)height; y++) { 1035 err = in->Read(in_scanline, in_row_bytes); 1036 if (err < in_row_bytes) { 1037 return (err < B_OK) ? Error(outs, image, pixels, 1038 out_color_components, in_scanline, err) 1039 : Error(outs, image, pixels, out_color_components, in_scanline, 1040 B_ERROR); 1041 } 1042 1043 converter(pixels, in_scanline, width); 1044 1045 for (i = 0; i < (long)out_color_components; i++) { 1046 (void)jas_image_writecmpt(image, (short)i, 0, (unsigned int)y, 1047 (unsigned int)width, 1, pixels[i]); 1048 } 1049 } 1050 1051 char opts[16]; 1052 sprintf(opts, "rate=%1f", 1053 (float)fSettings->SetGetInt32(JP2_SET_QUALITY) / 100.0); 1054 1055 if (jas_image_encode(image, outs, jas_image_strtofmt( 1056 fSettings->SetGetBool(JP2_SET_JPC) ? 1057 (char*)"jpc" : (char*)"jp2"), opts)) { 1058 return Error(outs, image, pixels, 1059 out_color_components, in_scanline, err); 1060 } 1061 1062 free(in_scanline); 1063 1064 for (i = 0; i < (long)out_color_components; i++) 1065 jas_matrix_destroy(pixels[i]); 1066 1067 jas_stream_close(outs); 1068 jas_image_destroy(image); 1069 jas_image_clearfmts(); 1070 1071 return B_OK; 1072 } 1073 1074 1075 //! Decode the native format 1076 status_t 1077 JP2Translator::Decompress(BPositionIO* in, BPositionIO* out) 1078 { 1079 using namespace conversion; 1080 1081 jas_image_t* image; 1082 jas_stream_t* ins; 1083 jas_matrix_t* pixels[4]; 1084 1085 if (jas_init()) 1086 return B_ERROR; 1087 1088 if (!(ins = jas_stream_positionIOopen(in))) 1089 return B_ERROR; 1090 1091 if (!(image = jas_image_decode(ins, -1, 0))) 1092 return Error(ins, NULL, NULL, 0, NULL, B_ERROR); 1093 1094 // Default color info 1095 color_space out_color_space; 1096 int out_color_components; 1097 int in_color_components = jas_image_numcmpts(image); 1098 1099 // Function pointer to read function 1100 // It MUST point to proper function 1101 void (*converter)(jas_matrix_t** pixels, uchar* outscanline, 1102 int width) = NULL; 1103 1104 switch (jas_clrspc_fam(jas_image_clrspc(image))) { 1105 case JAS_CLRSPC_FAM_RGB: 1106 out_color_components = 4; 1107 if (in_color_components == 3) { 1108 out_color_space = B_RGB32; 1109 converter = read_rgb24_to_rgb32; 1110 } else if (in_color_components == 4) { 1111 out_color_space = B_RGBA32; 1112 converter = read_rgba32; 1113 } else { 1114 syslog(LOG_ERR, "Other than RGB with 3 or 4 color " 1115 "components not implemented.\n"); 1116 return Error(ins, image, NULL, 0, NULL, B_ERROR); 1117 } 1118 break; 1119 case JAS_CLRSPC_FAM_GRAY: 1120 if (fSettings->SetGetBool(JP2_SET_GRAY8_AS_B_RGB32)) { 1121 out_color_space = B_RGB32; 1122 out_color_components = 4; 1123 converter = read_gray_to_rgb32; 1124 } else { 1125 out_color_space = B_GRAY8; 1126 out_color_components = 1; 1127 converter = read_gray; 1128 } 1129 break; 1130 case JAS_CLRSPC_FAM_YCBCR: 1131 syslog(LOG_ERR, "Color space YCBCR not implemented yet.\n"); 1132 return Error(ins, image, NULL, 0, NULL, B_ERROR); 1133 break; 1134 case JAS_CLRSPC_UNKNOWN: 1135 default: 1136 syslog(LOG_ERR, "Color space unknown. \n"); 1137 return Error(ins, image, NULL, 0, NULL, B_ERROR); 1138 break; 1139 } 1140 1141 float width = (float)jas_image_width(image); 1142 float height = (float)jas_image_height(image); 1143 1144 // Bytes count in one line of image (scanline) 1145 int64 out_row_bytes = (int32)width * out_color_components; 1146 // NOTE: things will go wrong if "out_row_bytes" wouldn't fit into 32 bits 1147 1148 // !!! Initialize this bounds rect to the size of your image 1149 BRect bounds(0, 0, width - 1, height - 1); 1150 1151 1152 // Fill out the B_TRANSLATOR_BITMAP's header 1153 TranslatorBitmap header; 1154 header.magic = B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP); 1155 header.bounds.left = B_HOST_TO_BENDIAN_FLOAT(bounds.left); 1156 header.bounds.top = B_HOST_TO_BENDIAN_FLOAT(bounds.top); 1157 header.bounds.right = B_HOST_TO_BENDIAN_FLOAT(bounds.right); 1158 header.bounds.bottom = B_HOST_TO_BENDIAN_FLOAT(bounds.bottom); 1159 header.colors = (color_space)B_HOST_TO_BENDIAN_INT32(out_color_space); 1160 header.rowBytes = B_HOST_TO_BENDIAN_INT32(out_row_bytes); 1161 header.dataSize = B_HOST_TO_BENDIAN_INT32((int32)(out_row_bytes * height)); 1162 1163 // Write out the header 1164 status_t err = out->Write(&header, sizeof(TranslatorBitmap)); 1165 if (err < B_OK) 1166 return Error(ins, image, NULL, 0, NULL, err); 1167 if (err < (int)sizeof(TranslatorBitmap)) 1168 return Error(ins, image, NULL, 0, NULL, B_ERROR); 1169 1170 uchar *out_scanline = (uchar*) malloc(out_row_bytes); 1171 if (out_scanline == NULL) 1172 return Error(ins, image, NULL, 0, NULL, B_ERROR); 1173 1174 int32 i = 0; 1175 for (i = 0; i < (long)in_color_components; i++) { 1176 pixels[i] = jas_matrix_create(1, (unsigned int)width); 1177 if (pixels[i] == (jas_matrix_t *)NULL) 1178 return Error(ins, image, pixels, i + 1, out_scanline, B_ERROR); 1179 } 1180 1181 int32 y = 0; 1182 for (y = 0; y < (long)height; y++) { 1183 for (i = 0; i < (long)in_color_components; i++) { 1184 (void)jas_image_readcmpt(image, (short)i, 0, (unsigned int)y, 1185 (unsigned int)width, 1, pixels[i]); 1186 } 1187 1188 converter(pixels, out_scanline, (int32)width); 1189 1190 err = out->Write(out_scanline, out_row_bytes); 1191 if (err < out_row_bytes) { 1192 return (err < B_OK) ? Error(ins, image, pixels, in_color_components, 1193 out_scanline, err) 1194 : Error(ins, image, pixels, in_color_components, out_scanline, 1195 B_ERROR); 1196 } 1197 } 1198 1199 free(out_scanline); 1200 1201 for (i = 0; i < (long)in_color_components; i++) 1202 jas_matrix_destroy(pixels[i]); 1203 1204 jas_stream_close(ins); 1205 jas_image_destroy(image); 1206 jas_image_clearfmts(); 1207 1208 return B_OK; 1209 } 1210 1211 1212 /*! searches in both inputFormats & outputFormats */ 1213 status_t 1214 JP2Translator::PopulateInfoFromFormat(translator_info* info, 1215 uint32 formatType, translator_id id) 1216 { 1217 int32 formatCount; 1218 const translation_format* formats = OutputFormats(&formatCount); 1219 1220 for (int i = 0; i <= 1; formats = InputFormats(&formatCount), i++) { 1221 if (PopulateInfoFromFormat(info, formatType, 1222 formats, formatCount) == B_OK) { 1223 info->translator = id; 1224 return B_OK; 1225 } 1226 } 1227 1228 return B_ERROR; 1229 } 1230 1231 1232 status_t 1233 JP2Translator::PopulateInfoFromFormat(translator_info* info, 1234 uint32 formatType, const translation_format* formats, int32 formatCount) 1235 { 1236 for (int i = 0; i < formatCount; i++) { 1237 if (formats[i].type == formatType) { 1238 info->type = formatType; 1239 info->group = formats[i].group; 1240 info->quality = formats[i].quality; 1241 info->capability = formats[i].capability; 1242 if (strcmp(formats[i].name, B_TRANSLATOR_BITMAP_DESCRIPTION) 1243 == 0) { 1244 strlcpy(info->name, 1245 B_TRANSLATE(B_TRANSLATOR_BITMAP_DESCRIPTION), 1246 sizeof(info->name)); 1247 } else { 1248 strlcpy(info->name, formats[i].name, sizeof(info->name)); 1249 } 1250 strlcpy(info->MIME, formats[i].MIME, sizeof(info->MIME)); 1251 return B_OK; 1252 } 1253 } 1254 1255 return B_ERROR; 1256 } 1257 1258 1259 /*! 1260 Frees jpeg alocated memory 1261 Returns given error (B_ERROR by default) 1262 */ 1263 status_t 1264 Error(jas_stream_t* stream, jas_image_t* image, jas_matrix_t** pixels, 1265 int32 pixels_count, uchar* scanline, status_t error) 1266 { 1267 if (pixels) { 1268 int32 i; 1269 for (i = 0; i < (long)pixels_count; i++) { 1270 if (pixels[i] != NULL) 1271 jas_matrix_destroy(pixels[i]); 1272 } 1273 } 1274 if (stream) 1275 jas_stream_close(stream); 1276 if (image) 1277 jas_image_destroy(image); 1278 1279 jas_image_clearfmts(); 1280 free(scanline); 1281 1282 return error; 1283 } 1284 1285 1286 // #pragma mark - 1287 1288 BTranslator* 1289 make_nth_translator(int32 n, image_id you, uint32 flags, ...) 1290 { 1291 if (!n) 1292 return new JP2Translator(); 1293 1294 return NULL; 1295 } 1296 1297 1298 int 1299 main() 1300 { 1301 BApplication app("application/x-vnd.Haiku-JPEG2000Translator"); 1302 JP2Translator* translator = new JP2Translator(); 1303 if (LaunchTranslatorWindow(translator, sTranslatorName) == B_OK) 1304 app.Run(); 1305 1306 return 0; 1307 } 1308 1309