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 { 450 jas_matrix_setv(pixels[0], x, scanline[index++]); 451 jas_matrix_setv(pixels[1], x, scanline[index++]); 452 jas_matrix_setv(pixels[2], x, scanline[index++]); 453 jas_matrix_setv(pixels[3], x, scanline[index++]); 454 x++; 455 } 456 } 457 458 459 }// end namespace conversion 460 461 462 // #pragma mark - jasper I/O 463 464 465 static int 466 Read(jas_stream_obj_t* object, char* buffer, const int length) 467 { 468 return (*(BPositionIO**)object)->Read(buffer, length); 469 } 470 471 472 static int 473 Write(jas_stream_obj_t* object, char* buffer, const int length) 474 { 475 return (*(BPositionIO**)object)->Write(buffer, length); 476 } 477 478 479 static long 480 Seek(jas_stream_obj_t* object, long offset, int origin) 481 { 482 return (*(BPositionIO**)object)->Seek(offset, origin); 483 } 484 485 486 static int 487 Close(jas_stream_obj_t* object) 488 { 489 return 0; 490 } 491 492 493 static jas_stream_ops_t positionIOops = { 494 Read, 495 Write, 496 Seek, 497 Close 498 }; 499 500 501 static jas_stream_t* 502 jas_stream_positionIOopen(BPositionIO *positionIO) 503 { 504 jas_stream_t* stream; 505 506 stream = (jas_stream_t *)malloc(sizeof(jas_stream_t)); 507 if (stream == (jas_stream_t *)NULL) 508 return (jas_stream_t *)NULL; 509 510 memset(stream, 0, sizeof(jas_stream_t)); 511 stream->rwlimit_ = -1; 512 stream->obj_=(jas_stream_obj_t *)malloc(sizeof(BPositionIO*)); 513 if (stream->obj_ == (jas_stream_obj_t *)NULL) { 514 free(stream); 515 return (jas_stream_t *)NULL; 516 } 517 518 *((BPositionIO**)stream->obj_) = positionIO; 519 stream->ops_ = (&positionIOops); 520 stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY; 521 stream->bufbase_ = stream->tinybuf_; 522 stream->bufsize_ = 1; 523 stream->bufstart_ = (&stream->bufbase_[JAS_STREAM_MAXPUTBACK]); 524 stream->ptr_ = stream->bufstart_; 525 stream->bufmode_ |= JAS_STREAM_UNBUF & JAS_STREAM_BUFMODEMASK; 526 527 return stream; 528 } 529 530 531 // #pragma mark - 532 533 534 SSlider::SSlider(const char* name, const char* label, 535 BMessage* message, int32 minValue, int32 maxValue, orientation posture, 536 thumb_style thumbType, uint32 flags) 537 : 538 BSlider(name, label, message, minValue, maxValue, 539 posture, thumbType, flags) 540 { 541 rgb_color barColor = { 0, 0, 229, 255 }; 542 UseFillColor(true, &barColor); 543 } 544 545 546 //! Update status string - show actual value 547 const char* 548 SSlider::UpdateText() const 549 { 550 snprintf(fStatusLabel, sizeof(fStatusLabel), "%" B_PRId32, Value()); 551 return fStatusLabel; 552 } 553 554 555 // #pragma mark - 556 557 558 TranslatorReadView::TranslatorReadView(const char* name, 559 TranslatorSettings* settings) 560 : 561 BView(name, 0, new BGroupLayout(B_VERTICAL)), 562 fSettings(settings) 563 { 564 fGrayAsRGB32 = new BCheckBox("grayasrgb32", 565 B_TRANSLATE("Read greyscale images as RGB32"), 566 new BMessage(VIEW_MSG_SET_GRAYASRGB32)); 567 if (fSettings->SetGetBool(JP2_SET_GRAY8_AS_B_RGB32)) 568 fGrayAsRGB32->SetValue(B_CONTROL_ON); 569 570 float padding = 10.0f; 571 BLayoutBuilder::Group<>(this, B_VERTICAL) 572 .SetInsets(padding) 573 .Add(fGrayAsRGB32) 574 .AddGlue(); 575 } 576 577 578 TranslatorReadView::~TranslatorReadView() 579 { 580 fSettings->Release(); 581 } 582 583 584 void 585 TranslatorReadView::AttachedToWindow() 586 { 587 fGrayAsRGB32->SetTarget(this); 588 } 589 590 591 void 592 TranslatorReadView::MessageReceived(BMessage* message) 593 { 594 switch (message->what) { 595 case VIEW_MSG_SET_GRAYASRGB32: 596 { 597 int32 value; 598 if (message->FindInt32("be:value", &value) == B_OK) { 599 bool boolValue = value; 600 fSettings->SetGetBool(JP2_SET_GRAY8_AS_B_RGB32, &boolValue); 601 fSettings->SaveSettings(); 602 } 603 break; 604 } 605 default: 606 BView::MessageReceived(message); 607 break; 608 } 609 } 610 611 612 // #pragma mark - TranslatorWriteView 613 614 615 TranslatorWriteView::TranslatorWriteView(const char* name, 616 TranslatorSettings* settings) 617 : 618 BView(name, 0, new BGroupLayout(B_VERTICAL)), 619 fSettings(settings) 620 { 621 fQualitySlider = new SSlider("quality", B_TRANSLATE("Output quality"), 622 new BMessage(VIEW_MSG_SET_QUALITY), 0, 100); 623 fQualitySlider->SetHashMarks(B_HASH_MARKS_BOTTOM); 624 fQualitySlider->SetHashMarkCount(10); 625 fQualitySlider->SetLimitLabels(B_TRANSLATE("Low"), B_TRANSLATE("High")); 626 fQualitySlider->SetValue(fSettings->SetGetInt32(JP2_SET_QUALITY)); 627 628 fGrayAsRGB24 = new BCheckBox("gray1asrgb24", 629 B_TRANSLATE("Write black-and-white images as RGB24"), 630 new BMessage(VIEW_MSG_SET_GRAY1ASRGB24)); 631 if (fSettings->SetGetBool(JP2_SET_GRAY1_AS_B_RGB24)) 632 fGrayAsRGB24->SetValue(B_CONTROL_ON); 633 634 fCodeStreamOnly = new BCheckBox("codestreamonly", 635 B_TRANSLATE("Output only codestream (.jpc)"), 636 new BMessage(VIEW_MSG_SET_JPC)); 637 if (fSettings->SetGetBool(JP2_SET_JPC)) 638 fCodeStreamOnly->SetValue(B_CONTROL_ON); 639 640 BLayoutBuilder::Group<>(this, B_VERTICAL) 641 .SetInsets(B_USE_DEFAULT_SPACING) 642 .Add(fQualitySlider) 643 .Add(fGrayAsRGB24) 644 .Add(fCodeStreamOnly) 645 .AddGlue(); 646 } 647 648 649 TranslatorWriteView::~TranslatorWriteView() 650 { 651 fSettings->Release(); 652 } 653 654 655 void 656 TranslatorWriteView::AttachedToWindow() 657 { 658 fQualitySlider->SetTarget(this); 659 fGrayAsRGB24->SetTarget(this); 660 fCodeStreamOnly->SetTarget(this); 661 } 662 663 664 void 665 TranslatorWriteView::MessageReceived(BMessage* message) 666 { 667 switch (message->what) { 668 case VIEW_MSG_SET_QUALITY: 669 { 670 int32 value; 671 if (message->FindInt32("be:value", &value) == B_OK) { 672 fSettings->SetGetInt32(JP2_SET_QUALITY, &value); 673 fSettings->SaveSettings(); 674 } 675 break; 676 } 677 case VIEW_MSG_SET_GRAY1ASRGB24: 678 { 679 int32 value; 680 if (message->FindInt32("be:value", &value) == B_OK) { 681 bool boolValue = value; 682 fSettings->SetGetBool(JP2_SET_GRAY1_AS_B_RGB24, &boolValue); 683 fSettings->SaveSettings(); 684 } 685 break; 686 } 687 case VIEW_MSG_SET_JPC: 688 { 689 int32 value; 690 if (message->FindInt32("be:value", &value) == B_OK) { 691 bool boolValue = value; 692 fSettings->SetGetBool(JP2_SET_JPC, &boolValue); 693 fSettings->SaveSettings(); 694 } 695 break; 696 } 697 default: 698 BView::MessageReceived(message); 699 break; 700 } 701 } 702 703 704 // #pragma mark - 705 706 707 TranslatorAboutView::TranslatorAboutView(const char* name) 708 : 709 BView(name, 0, new BGroupLayout(B_VERTICAL)) 710 { 711 BAlignment labelAlignment = BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP); 712 BStringView* title = new BStringView("Title", sTranslatorName); 713 title->SetFont(be_bold_font); 714 title->SetExplicitAlignment(labelAlignment); 715 716 char versionString[100]; 717 snprintf(versionString, sizeof(versionString), 718 B_TRANSLATE("Version %d.%d.%d"), 719 static_cast<int>(sTranslatorVersion >> 8), 720 static_cast<int>((sTranslatorVersion >> 4) & 0xf), 721 static_cast<int>(sTranslatorVersion & 0xf)); 722 723 BStringView* version = new BStringView("Version", versionString); 724 version->SetExplicitAlignment(labelAlignment); 725 726 BTextView* infoView = new BTextView("info"); 727 infoView->SetText(sTranslatorInfo); 728 infoView->SetViewUIColor(B_PANEL_BACKGROUND_COLOR); 729 infoView->MakeEditable(false); 730 731 BLayoutBuilder::Group<>(this, B_VERTICAL, 0) 732 .SetInsets(B_USE_DEFAULT_SPACING) 733 .Add(title) 734 .Add(version) 735 .Add(infoView); 736 } 737 738 739 // #pragma mark - 740 741 742 TranslatorView::TranslatorView(const char* name, TranslatorSettings* settings) 743 : 744 BTabView(name, B_WIDTH_FROM_LABEL) 745 { 746 SetBorder(B_NO_BORDER); 747 748 AddTab(new TranslatorWriteView(B_TRANSLATE("Write"), 749 settings->Acquire())); 750 AddTab(new TranslatorReadView(B_TRANSLATE("Read"), 751 settings->Acquire())); 752 AddTab(new TranslatorAboutView(B_TRANSLATE("About"))); 753 754 settings->Release(); 755 756 BFont font; 757 GetFont(&font); 758 SetExplicitPreferredSize( 759 BSize((font.Size() * 380) / 12, (font.Size() * 250) / 12)); 760 } 761 762 763 // #pragma mark - 764 765 BView* 766 JP2Translator::NewConfigView(TranslatorSettings* settings) 767 { 768 BView* outView = new TranslatorView("TranslatorView", settings); 769 return outView; 770 } 771 772 773 JP2Translator::JP2Translator() 774 : BaseTranslator(sTranslatorName, sTranslatorInfo, sTranslatorVersion, 775 sInputFormats, kNumInputFormats, 776 sOutputFormats, kNumOutputFormats, 777 JP2_SETTINGS_FILE, 778 sDefaultSettings, kNumDefaultSettings, 779 B_TRANSLATOR_BITMAP, JP2_FORMAT) 780 { 781 } 782 783 784 //! Determine whether or not we can handle this data 785 status_t 786 JP2Translator::DerivedIdentify(BPositionIO* inSource, 787 const translation_format* inFormat, BMessage* ioExtension, 788 translator_info* outInfo, uint32 outType) 789 { 790 if ((outType != 0) && (outType != B_TRANSLATOR_BITMAP) 791 && outType != JP2_FORMAT) 792 return B_NO_TRANSLATOR; 793 794 // !!! You might need to make this buffer bigger to test for your 795 // native format 796 off_t position = inSource->Position(); 797 uint8 header[sizeof(TranslatorBitmap)]; 798 status_t err = inSource->Read(header, sizeof(TranslatorBitmap)); 799 inSource->Seek(position, SEEK_SET); 800 if (err < B_OK) 801 return err; 802 803 if (B_BENDIAN_TO_HOST_INT32(((TranslatorBitmap *)header)->magic) 804 == B_TRANSLATOR_BITMAP) { 805 if (PopulateInfoFromFormat(outInfo, B_TRANSLATOR_BITMAP) != B_OK) 806 return B_NO_TRANSLATOR; 807 } else { 808 if ((((header[4] << 24) | (header[5] << 16) | (header[6] << 8) 809 | header[7]) == JP2_BOX_JP) // JP2 810 || (header[0] == (JPC_MS_SOC >> 8) && header[1] 811 == (JPC_MS_SOC & 0xff))) // JPC 812 { 813 if (PopulateInfoFromFormat(outInfo, JP2_FORMAT) != B_OK) 814 return B_NO_TRANSLATOR; 815 } else 816 return B_NO_TRANSLATOR; 817 } 818 819 return B_OK; 820 } 821 822 823 status_t 824 JP2Translator::DerivedTranslate(BPositionIO* inSource, 825 const translator_info* inInfo, BMessage* ioExtension, uint32 outType, 826 BPositionIO* outDestination, int32 baseType) 827 { 828 // If no specific type was requested, convert to the interchange format 829 if (outType == 0) 830 outType = B_TRANSLATOR_BITMAP; 831 832 // What action to take, based on the findings of Identify() 833 if (outType == inInfo->type) 834 return Copy(inSource, outDestination); 835 if (inInfo->type == B_TRANSLATOR_BITMAP && outType == JP2_FORMAT) 836 return Compress(inSource, outDestination); 837 if (inInfo->type == JP2_FORMAT && outType == B_TRANSLATOR_BITMAP) 838 return Decompress(inSource, outDestination); 839 840 return B_NO_TRANSLATOR; 841 } 842 843 844 //! The user has requested the same format for input and output, so just copy 845 status_t 846 JP2Translator::Copy(BPositionIO* in, BPositionIO* out) 847 { 848 int block_size = 65536; 849 void* buffer = malloc(block_size); 850 char temp[1024]; 851 if (buffer == NULL) { 852 buffer = temp; 853 block_size = 1024; 854 } 855 status_t err = B_OK; 856 857 // Read until end of file or error 858 while (1) { 859 ssize_t to_read = block_size; 860 err = in->Read(buffer, to_read); 861 // Explicit check for EOF 862 if (err == -1) { 863 if (buffer != temp) 864 free(buffer); 865 return B_OK; 866 } 867 if (err <= B_OK) break; 868 to_read = err; 869 err = out->Write(buffer, to_read); 870 if (err != to_read) if (err >= 0) err = B_DEVICE_FULL; 871 if (err < B_OK) break; 872 } 873 874 if (buffer != temp) 875 free(buffer); 876 return (err >= 0) ? B_OK : err; 877 } 878 879 880 //! Encode into the native format 881 status_t 882 JP2Translator::Compress(BPositionIO* in, BPositionIO* out) 883 { 884 using namespace conversion; 885 886 // Read info about bitmap 887 TranslatorBitmap header; 888 status_t err = in->Read(&header, sizeof(TranslatorBitmap)); 889 if (err < B_OK) 890 return err; 891 if (err < (int)sizeof(TranslatorBitmap)) 892 return B_ERROR; 893 894 // Grab dimension, color space, and size information from the stream 895 BRect bounds; 896 bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left); 897 bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top); 898 bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right); 899 bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom); 900 901 int32 in_row_bytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes); 902 903 int width = bounds.IntegerWidth() + 1; 904 int height = bounds.IntegerHeight() + 1; 905 906 // Function pointer to write function 907 // It MUST point to proper function 908 void (*converter)(jas_matrix_t** pixels, uchar* inscanline, 909 int width) = write_rgba32; 910 911 // Default color info 912 int out_color_space = JAS_CLRSPC_SRGB; 913 int out_color_components = 3; 914 915 switch ((color_space)B_BENDIAN_TO_HOST_INT32(header.colors)) { 916 case B_GRAY1: 917 if (fSettings->SetGetBool(JP2_SET_GRAY1_AS_B_RGB24)) { 918 converter = write_gray1_to_rgb24; 919 } else { 920 out_color_components = 1; 921 out_color_space = JAS_CLRSPC_SGRAY; 922 converter = write_gray1_to_gray; 923 } 924 break; 925 926 case B_CMAP8: 927 converter = write_cmap8_to_rgb24; 928 break; 929 930 case B_GRAY8: 931 out_color_components = 1; 932 out_color_space = JAS_CLRSPC_SGRAY; 933 converter = write_gray; 934 break; 935 936 case B_RGB15: 937 case B_RGBA15: 938 converter = write_rgb15_to_rgb24; 939 break; 940 941 case B_RGB15_BIG: 942 case B_RGBA15_BIG: 943 converter = write_rgb15b_to_rgb24; 944 break; 945 946 case B_RGB16: 947 converter = write_rgb16_to_rgb24; 948 break; 949 950 case B_RGB16_BIG: 951 converter = write_rgb16b_to_rgb24; 952 break; 953 954 case B_RGB24: 955 converter = write_rgb24; 956 break; 957 958 case B_RGB24_BIG: 959 converter = write_rgb24b; 960 break; 961 962 case B_RGB32: 963 converter = write_rgb32_to_rgb24; 964 break; 965 966 case B_RGB32_BIG: 967 converter = write_rgb32b_to_rgb24; 968 break; 969 970 case B_RGBA32: 971 /* 972 // In theory it should be possible to write 4 color components 973 // to jp2, so it should be possible to have transparency. 974 // Unfortunetly libjasper does not agree with that 975 // For now i don't know how to modify it :( 976 977 out_color_components = 4; 978 converter = write_rgba32; 979 */ 980 converter = write_rgb32_to_rgb24; 981 break; 982 983 case B_RGBA32_BIG: 984 /* 985 // In theory it should be possible to write 4 color components 986 // to jp2, so it should be possible to have transparency. 987 // Unfortunetly libjasper does not agree with that 988 // For now i don't know how to modify it :( 989 990 out_color_components = 4; 991 converter = write_rgba32b; 992 */ 993 converter = write_rgb32b_to_rgb24; 994 break; 995 996 default: 997 syslog(LOG_ERR, "Unknown color space.\n"); 998 return B_ERROR; 999 } 1000 1001 jas_image_t* image; 1002 jas_stream_t* outs; 1003 jas_matrix_t* pixels[4]; 1004 jas_image_cmptparm_t component_info[4]; 1005 1006 if (jas_init()) 1007 return B_ERROR; 1008 1009 if (!(outs = jas_stream_positionIOopen(out))) 1010 return B_ERROR; 1011 1012 int32 i = 0; 1013 for (i = 0; i < (long)out_color_components; i++) { 1014 (void) memset(component_info + i, 0, sizeof(jas_image_cmptparm_t)); 1015 component_info[i].hstep = 1; 1016 component_info[i].vstep = 1; 1017 component_info[i].width = (unsigned int)width; 1018 component_info[i].height = (unsigned int)height; 1019 component_info[i].prec = (unsigned int)8; 1020 } 1021 1022 image = jas_image_create((short)out_color_components, component_info, 1023 out_color_space); 1024 if (image == (jas_image_t *)NULL) 1025 return Error(outs, NULL, NULL, 0, NULL, B_ERROR); 1026 1027 uchar *in_scanline = (uchar*) malloc(in_row_bytes); 1028 if (in_scanline == NULL) 1029 return Error(outs, image, NULL, 0, NULL, B_ERROR); 1030 1031 for (i = 0; i < (long)out_color_components; i++) { 1032 pixels[i] = jas_matrix_create(1, (unsigned int)width); 1033 if (pixels[i] == (jas_matrix_t *)NULL) 1034 return Error(outs, image, pixels, i+1, in_scanline, B_ERROR); 1035 } 1036 1037 int32 y = 0; 1038 for (y = 0; y < (long)height; y++) { 1039 err = in->Read(in_scanline, in_row_bytes); 1040 if (err < in_row_bytes) { 1041 return (err < B_OK) ? Error(outs, image, pixels, 1042 out_color_components, in_scanline, err) 1043 : Error(outs, image, pixels, out_color_components, in_scanline, 1044 B_ERROR); 1045 } 1046 1047 converter(pixels, in_scanline, width); 1048 1049 for (i = 0; i < (long)out_color_components; i++) { 1050 (void)jas_image_writecmpt(image, (short)i, 0, (unsigned int)y, 1051 (unsigned int)width, 1, pixels[i]); 1052 } 1053 } 1054 1055 char opts[16]; 1056 sprintf(opts, "rate=%1f", 1057 (float)fSettings->SetGetInt32(JP2_SET_QUALITY) / 100.0); 1058 1059 if (jas_image_encode(image, outs, jas_image_strtofmt( 1060 fSettings->SetGetBool(JP2_SET_JPC) ? 1061 (char*)"jpc" : (char*)"jp2"), opts)) { 1062 return Error(outs, image, pixels, 1063 out_color_components, in_scanline, err); 1064 } 1065 1066 free(in_scanline); 1067 1068 for (i = 0; i < (long)out_color_components; i++) 1069 jas_matrix_destroy(pixels[i]); 1070 1071 jas_stream_close(outs); 1072 jas_image_destroy(image); 1073 jas_image_clearfmts(); 1074 1075 return B_OK; 1076 } 1077 1078 1079 //! Decode the native format 1080 status_t 1081 JP2Translator::Decompress(BPositionIO* in, BPositionIO* out) 1082 { 1083 using namespace conversion; 1084 1085 jas_image_t* image; 1086 jas_stream_t* ins; 1087 jas_matrix_t* pixels[4]; 1088 1089 if (jas_init()) 1090 return B_ERROR; 1091 1092 if (!(ins = jas_stream_positionIOopen(in))) 1093 return B_ERROR; 1094 1095 if (!(image = jas_image_decode(ins, -1, 0))) 1096 return Error(ins, NULL, NULL, 0, NULL, B_ERROR); 1097 1098 // Default color info 1099 color_space out_color_space; 1100 int out_color_components; 1101 int in_color_components = jas_image_numcmpts(image); 1102 1103 // Function pointer to read function 1104 // It MUST point to proper function 1105 void (*converter)(jas_matrix_t** pixels, uchar* outscanline, 1106 int width) = NULL; 1107 1108 switch (jas_clrspc_fam(jas_image_clrspc(image))) { 1109 case JAS_CLRSPC_FAM_RGB: 1110 out_color_components = 4; 1111 if (in_color_components == 3) { 1112 out_color_space = B_RGB32; 1113 converter = read_rgb24_to_rgb32; 1114 } else if (in_color_components == 4) { 1115 out_color_space = B_RGBA32; 1116 converter = read_rgba32; 1117 } else { 1118 syslog(LOG_ERR, "Other than RGB with 3 or 4 color " 1119 "components not implemented.\n"); 1120 return Error(ins, image, NULL, 0, NULL, B_ERROR); 1121 } 1122 break; 1123 case JAS_CLRSPC_FAM_GRAY: 1124 if (fSettings->SetGetBool(JP2_SET_GRAY8_AS_B_RGB32)) { 1125 out_color_space = B_RGB32; 1126 out_color_components = 4; 1127 converter = read_gray_to_rgb32; 1128 } else { 1129 out_color_space = B_GRAY8; 1130 out_color_components = 1; 1131 converter = read_gray; 1132 } 1133 break; 1134 case JAS_CLRSPC_FAM_YCBCR: 1135 syslog(LOG_ERR, "Color space YCBCR not implemented yet.\n"); 1136 return Error(ins, image, NULL, 0, NULL, B_ERROR); 1137 break; 1138 case JAS_CLRSPC_UNKNOWN: 1139 default: 1140 syslog(LOG_ERR, "Color space unknown. \n"); 1141 return Error(ins, image, NULL, 0, NULL, B_ERROR); 1142 break; 1143 } 1144 1145 float width = (float)jas_image_width(image); 1146 float height = (float)jas_image_height(image); 1147 1148 // Bytes count in one line of image (scanline) 1149 int64 out_row_bytes = (int32)width * out_color_components; 1150 // NOTE: things will go wrong if "out_row_bytes" wouldn't fit into 32 bits 1151 1152 // !!! Initialize this bounds rect to the size of your image 1153 BRect bounds(0, 0, width - 1, height - 1); 1154 1155 1156 // Fill out the B_TRANSLATOR_BITMAP's header 1157 TranslatorBitmap header; 1158 header.magic = B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP); 1159 header.bounds.left = B_HOST_TO_BENDIAN_FLOAT(bounds.left); 1160 header.bounds.top = B_HOST_TO_BENDIAN_FLOAT(bounds.top); 1161 header.bounds.right = B_HOST_TO_BENDIAN_FLOAT(bounds.right); 1162 header.bounds.bottom = B_HOST_TO_BENDIAN_FLOAT(bounds.bottom); 1163 header.colors = (color_space)B_HOST_TO_BENDIAN_INT32(out_color_space); 1164 header.rowBytes = B_HOST_TO_BENDIAN_INT32(out_row_bytes); 1165 header.dataSize = B_HOST_TO_BENDIAN_INT32((int32)(out_row_bytes * height)); 1166 1167 // Write out the header 1168 status_t err = out->Write(&header, sizeof(TranslatorBitmap)); 1169 if (err < B_OK) 1170 return Error(ins, image, NULL, 0, NULL, err); 1171 if (err < (int)sizeof(TranslatorBitmap)) 1172 return Error(ins, image, NULL, 0, NULL, B_ERROR); 1173 1174 uchar *out_scanline = (uchar*) malloc(out_row_bytes); 1175 if (out_scanline == NULL) 1176 return Error(ins, image, NULL, 0, NULL, B_ERROR); 1177 1178 int32 i = 0; 1179 for (i = 0; i < (long)in_color_components; i++) { 1180 pixels[i] = jas_matrix_create(1, (unsigned int)width); 1181 if (pixels[i] == (jas_matrix_t *)NULL) 1182 return Error(ins, image, pixels, i + 1, out_scanline, B_ERROR); 1183 } 1184 1185 int32 y = 0; 1186 for (y = 0; y < (long)height; y++) { 1187 for (i = 0; i < (long)in_color_components; i++) { 1188 (void)jas_image_readcmpt(image, (short)i, 0, (unsigned int)y, 1189 (unsigned int)width, 1, pixels[i]); 1190 } 1191 1192 converter(pixels, out_scanline, (int32)width); 1193 1194 err = out->Write(out_scanline, out_row_bytes); 1195 if (err < out_row_bytes) { 1196 return (err < B_OK) ? Error(ins, image, pixels, in_color_components, 1197 out_scanline, err) 1198 : Error(ins, image, pixels, in_color_components, out_scanline, 1199 B_ERROR); 1200 } 1201 } 1202 1203 free(out_scanline); 1204 1205 for (i = 0; i < (long)in_color_components; i++) 1206 jas_matrix_destroy(pixels[i]); 1207 1208 jas_stream_close(ins); 1209 jas_image_destroy(image); 1210 jas_image_clearfmts(); 1211 1212 return B_OK; 1213 } 1214 1215 1216 /*! searches in both inputFormats & outputFormats */ 1217 status_t 1218 JP2Translator::PopulateInfoFromFormat(translator_info* info, 1219 uint32 formatType, translator_id id) 1220 { 1221 int32 formatCount; 1222 const translation_format* formats = OutputFormats(&formatCount); 1223 1224 for (int i = 0; i <= 1; formats = InputFormats(&formatCount), i++) { 1225 if (PopulateInfoFromFormat(info, formatType, 1226 formats, formatCount) == B_OK) { 1227 info->translator = id; 1228 return B_OK; 1229 } 1230 } 1231 1232 return B_ERROR; 1233 } 1234 1235 1236 status_t 1237 JP2Translator::PopulateInfoFromFormat(translator_info* info, 1238 uint32 formatType, const translation_format* formats, int32 formatCount) 1239 { 1240 for (int i = 0; i < formatCount; i++) { 1241 if (formats[i].type == formatType) { 1242 info->type = formatType; 1243 info->group = formats[i].group; 1244 info->quality = formats[i].quality; 1245 info->capability = formats[i].capability; 1246 if (strncmp(formats[i].name, 1247 "Be Bitmap Format (JPEG2000Translator)", 1248 sizeof("Be Bitmap Format (JPEG2000Translator)")) == 0) 1249 strncpy(info->name, 1250 B_TRANSLATE("Be Bitmap Format (JPEG2000Translator)"), 1251 sizeof(info->name)); 1252 else 1253 strncpy(info->name, formats[i].name, sizeof(info->name)); 1254 strncpy(info->MIME, formats[i].MIME, sizeof(info->MIME)); 1255 return B_OK; 1256 } 1257 } 1258 1259 return B_ERROR; 1260 } 1261 1262 1263 /*! 1264 Frees jpeg alocated memory 1265 Returns given error (B_ERROR by default) 1266 */ 1267 status_t 1268 Error(jas_stream_t* stream, jas_image_t* image, jas_matrix_t** pixels, 1269 int32 pixels_count, uchar* scanline, status_t error) 1270 { 1271 if (pixels) { 1272 int32 i; 1273 for (i = 0; i < (long)pixels_count; i++) { 1274 if (pixels[i] != NULL) 1275 jas_matrix_destroy(pixels[i]); 1276 } 1277 } 1278 if (stream) 1279 jas_stream_close(stream); 1280 if (image) 1281 jas_image_destroy(image); 1282 1283 jas_image_clearfmts(); 1284 free(scanline); 1285 1286 return error; 1287 } 1288 1289 1290 // #pragma mark - 1291 1292 BTranslator* 1293 make_nth_translator(int32 n, image_id you, uint32 flags, ...) 1294 { 1295 if (!n) 1296 return new JP2Translator(); 1297 1298 return NULL; 1299 } 1300 1301 1302 int 1303 main() 1304 { 1305 BApplication app("application/x-vnd.Haiku-JPEG2000Translator"); 1306 JP2Translator* translator = new JP2Translator(); 1307 if (LaunchTranslatorWindow(translator, sTranslatorName) == B_OK) 1308 app.Run(); 1309 1310 return 0; 1311 } 1312 1313