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