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