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