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 "jp2_cod.h" 35 #include "jpc_cs.h" 36 #include "TranslatorWindow.h" 37 38 #include <syslog.h> 39 40 #include <LayoutBuilder.h> 41 #include <TabView.h> 42 #include <TextView.h> 43 44 45 #undef B_TRANSLATION_CONTEXT 46 #define B_TRANSLATION_CONTEXT "JPEG2000Translator" 47 48 // Set these accordingly 49 #define JP2_ACRONYM "JP2" 50 #define JP2_FORMAT 'JP2 ' 51 #define JP2_MIME_STRING "image/jp2" 52 #define JP2_DESCRIPTION "JPEG2000 image" 53 54 // The translation kit's native file type 55 #define B_TRANSLATOR_BITMAP_MIME_STRING "image/x-be-bitmap" 56 #define B_TRANSLATOR_BITMAP_DESCRIPTION "Be Bitmap Format (JPEG2000Translator)" 57 58 static int32 sTranslatorVersion = B_TRANSLATION_MAKE_VERSION(1, 0, 0); 59 60 static const char* sTranslatorName = B_TRANSLATE("JPEG2000 images"); 61 static const char* sTranslatorInfo = B_TRANSLATE("©2002-2003, Shard\n" 62 "©2005-2006, Haiku\n" 63 "\n" 64 "Based on JasPer library:\n" 65 "© 1999-2000, Image Power, Inc. and\n" 66 "the University of British Columbia, Canada.\n" 67 "© 2001-2003 Michael David Adams.\n" 68 "\thttp://www.ece.uvic.ca/~mdadams/jasper/\n" 69 "\n" 70 "ImageMagick's jp2 codec was used as \"tutorial\".\n" 71 "\thttp://www.imagemagick.org/\n"); 72 73 static const translation_format sInputFormats[] = { 74 { JP2_FORMAT, B_TRANSLATOR_BITMAP, 0.5, 0.5, 75 JP2_MIME_STRING, JP2_DESCRIPTION }, 76 { B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.5, 0.5, 77 B_TRANSLATOR_BITMAP_MIME_STRING, B_TRANSLATOR_BITMAP_DESCRIPTION }, 78 }; 79 80 static const translation_format sOutputFormats[] = { 81 { JP2_FORMAT, B_TRANSLATOR_BITMAP, 0.5, 0.5, 82 JP2_MIME_STRING, JP2_DESCRIPTION }, 83 { B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.5, 0.5, 84 B_TRANSLATOR_BITMAP_MIME_STRING, B_TRANSLATOR_BITMAP_DESCRIPTION }, 85 }; 86 87 88 static const TranSetting sDefaultSettings[] = { 89 {JP2_SET_QUALITY, TRAN_SETTING_INT32, 25}, 90 {JP2_SET_JPC, TRAN_SETTING_BOOL, false}, 91 {JP2_SET_GRAY1_AS_B_RGB24, TRAN_SETTING_BOOL, false}, 92 {JP2_SET_GRAY8_AS_B_RGB32, TRAN_SETTING_BOOL, true} 93 }; 94 95 const uint32 kNumInputFormats = sizeof(sInputFormats) / sizeof(translation_format); 96 const uint32 kNumOutputFormats = sizeof(sOutputFormats) / sizeof(translation_format); 97 const uint32 kNumDefaultSettings = sizeof(sDefaultSettings) / sizeof(TranSetting); 98 99 100 namespace conversion{ 101 //! Make RGB32 scanline from *pixels[3] 102 inline void 103 read_rgb24_to_rgb32(jas_matrix_t** pixels, jpr_uchar_t* scanline, int width) 104 { 105 int32 index = 0; 106 int32 x = 0; 107 while (x < width) { 108 scanline[index++] = (jpr_uchar_t)jas_matrix_getv(pixels[2], x); 109 scanline[index++] = (jpr_uchar_t)jas_matrix_getv(pixels[1], x); 110 scanline[index++] = (jpr_uchar_t)jas_matrix_getv(pixels[0], x); 111 scanline[index++] = 255; 112 x++; 113 } 114 } 115 116 117 //! Make gray scanline from *pixels[1] 118 inline void 119 read_gray_to_rgb32(jas_matrix_t** pixels, jpr_uchar_t* scanline, int width) 120 { 121 int32 index = 0; 122 int32 x = 0; 123 jpr_uchar_t color = 0; 124 while (x < width) { 125 color = (jpr_uchar_t)jas_matrix_getv(pixels[0], x++); 126 scanline[index++] = color; 127 scanline[index++] = color; 128 scanline[index++] = color; 129 scanline[index++] = 255; 130 } 131 } 132 133 134 /*! 135 Make RGBA32 scanline from *pixels[4] 136 (just read data to scanline) 137 */ 138 inline void 139 read_rgba32(jas_matrix_t** pixels, jpr_uchar_t *scanline, int width) 140 { 141 int32 index = 0; 142 int32 x = 0; 143 while (x < width) { 144 scanline[index++] = (jpr_uchar_t)jas_matrix_getv(pixels[2], x); 145 scanline[index++] = (jpr_uchar_t)jas_matrix_getv(pixels[1], x); 146 scanline[index++] = (jpr_uchar_t)jas_matrix_getv(pixels[0], x); 147 scanline[index++] = (jpr_uchar_t)jas_matrix_getv(pixels[3], x); 148 x++; 149 } 150 } 151 152 153 /*! 154 Make gray scanline from *pixels[1] 155 (just read data to scanline) 156 */ 157 inline void 158 read_gray(jas_matrix_t** pixels, jpr_uchar_t* scanline, int width) 159 { 160 int32 x = 0; 161 while (x < width) { 162 scanline[x] = (jpr_uchar_t)jas_matrix_getv(pixels[0], x); 163 x++; 164 } 165 } 166 167 168 //! Make *pixels[1] from gray1 scanline 169 inline void 170 write_gray1_to_gray(jas_matrix_t** pixels, jpr_uchar_t* scanline, int width) 171 { 172 int32 x = 0; 173 int32 index = 0; 174 while (x < (width/8)) { 175 unsigned char c = scanline[x++]; 176 for (int b = 128; b; b = b >> 1) { 177 if (c & b) 178 jas_matrix_setv(pixels[0], index++, 0); 179 else 180 jas_matrix_setv(pixels[0], index++, 255); 181 } 182 } 183 } 184 185 186 //! Make *pixels[3] from gray1 scanline 187 inline void 188 write_gray1_to_rgb24(jas_matrix_t** pixels, jpr_uchar_t* scanline, int width) 189 { 190 int32 x = 0; 191 int32 index = 0; 192 while (x < (width / 8)) { 193 unsigned char c = scanline[x++]; 194 for (int b = 128; b; b = b >> 1) { 195 if (c & b) { 196 jas_matrix_setv(pixels[0], index, 0); 197 jas_matrix_setv(pixels[1], index, 0); 198 jas_matrix_setv(pixels[2], index, 0); 199 } else { 200 jas_matrix_setv(pixels[0], index, 255); 201 jas_matrix_setv(pixels[1], index, 255); 202 jas_matrix_setv(pixels[2], index, 255); 203 } 204 index++; 205 } 206 } 207 } 208 209 210 //! Make *pixels[3] from cmap8 scanline 211 inline void 212 write_cmap8_to_rgb24(jas_matrix_t** pixels, jpr_uchar_t* scanline, int width) 213 { 214 const color_map* map = system_colors(); 215 int32 x = 0; 216 while (x < width) { 217 rgb_color color = map->color_list[scanline[x]]; 218 219 jas_matrix_setv(pixels[0], x, color.red); 220 jas_matrix_setv(pixels[1], x, color.green); 221 jas_matrix_setv(pixels[2], x, color.blue); 222 x++; 223 } 224 } 225 226 227 /*! 228 Make *pixels[1] from gray scanline 229 (just write data to pixels) 230 */ 231 inline void 232 write_gray(jas_matrix_t** pixels, jpr_uchar_t* scanline, int width) 233 { 234 int32 x = 0; 235 while (x < width) { 236 jas_matrix_setv(pixels[0], x, scanline[x]); 237 x++; 238 } 239 } 240 241 242 /*! 243 Make *pixels[3] from RGB15/RGBA15 scanline 244 (just write data to pixels) 245 */ 246 inline void 247 write_rgb15_to_rgb24(jas_matrix_t** pixels, jpr_uchar_t* scanline, int width) 248 { 249 int32 x = 0; 250 int32 index = 0; 251 int16 in_pixel; 252 while (x < width) { 253 in_pixel = scanline[index] | (scanline[index+1] << 8); 254 index += 2; 255 256 jas_matrix_setv(pixels[0], x, (char)(((in_pixel & 0x7c00)) >> 7) 257 | (((in_pixel & 0x7c00)) >> 12)); 258 jas_matrix_setv(pixels[1], x, (char)(((in_pixel & 0x3e0)) >> 2) 259 | (((in_pixel & 0x3e0)) >> 7)); 260 jas_matrix_setv(pixels[2], x, (char)(((in_pixel & 0x1f)) << 3) 261 | (((in_pixel & 0x1f)) >> 2)); 262 x++; 263 } 264 } 265 266 267 /*! 268 Make *pixels[3] from RGB15/RGBA15 bigendian scanline 269 (just write data to pixels) 270 */ 271 inline void 272 write_rgb15b_to_rgb24(jas_matrix_t** pixels, jpr_uchar_t* scanline, int width) 273 { 274 int32 x = 0; 275 int32 index = 0; 276 int16 in_pixel; 277 while (x < width) { 278 in_pixel = scanline[index + 1] | (scanline[index] << 8); 279 index += 2; 280 281 jas_matrix_setv(pixels[0], x, (char)(((in_pixel & 0x7c00)) >> 7) 282 | (((in_pixel & 0x7c00)) >> 12)); 283 jas_matrix_setv(pixels[1], x, (char)(((in_pixel & 0x3e0)) >> 2) 284 | (((in_pixel & 0x3e0)) >> 7)); 285 jas_matrix_setv(pixels[2], x, (char)(((in_pixel & 0x1f)) << 3) 286 | (((in_pixel & 0x1f)) >> 2)); 287 x++; 288 } 289 } 290 291 292 /*! 293 Make *pixels[3] from RGB16/RGBA16 scanline 294 (just write data to pixels) 295 */ 296 inline void 297 write_rgb16_to_rgb24(jas_matrix_t** pixels, jpr_uchar_t* scanline, int width) 298 { 299 int32 x = 0; 300 int32 index = 0; 301 int16 in_pixel; 302 while (x < width) { 303 in_pixel = scanline[index] | (scanline[index+1] << 8); 304 index += 2; 305 306 jas_matrix_setv(pixels[0], x, (char)(((in_pixel & 0xf800)) >> 8) 307 | (((in_pixel & 0x7c00)) >> 12)); 308 jas_matrix_setv(pixels[1], x, (char)(((in_pixel & 0x7e0)) >> 3) 309 | (((in_pixel & 0x7e0)) >> 9)); 310 jas_matrix_setv(pixels[2], x, (char)(((in_pixel & 0x1f)) << 3) 311 | (((in_pixel & 0x1f)) >> 2)); 312 x++; 313 } 314 } 315 316 317 /*! 318 Make *pixels[3] from RGB16/RGBA16 bigendian scanline 319 (just write data to pixels) 320 */ 321 inline void 322 write_rgb16b_to_rgb24(jas_matrix_t** pixels, jpr_uchar_t* scanline, int width) 323 { 324 int32 x = 0; 325 int32 index = 0; 326 int16 in_pixel; 327 while (x < width) { 328 in_pixel = scanline[index + 1] | (scanline[index] << 8); 329 index += 2; 330 331 jas_matrix_setv(pixels[0], x, (char)(((in_pixel & 0xf800)) >> 8) 332 | (((in_pixel & 0xf800)) >> 13)); 333 jas_matrix_setv(pixels[1], x, (char)(((in_pixel & 0x7e0)) >> 3) 334 | (((in_pixel & 0x7e0)) >> 9)); 335 jas_matrix_setv(pixels[2], x, (char)(((in_pixel & 0x1f)) << 3) 336 | (((in_pixel & 0x1f)) >> 2)); 337 x++; 338 } 339 } 340 341 342 /*! 343 Make *pixels[3] from RGB24 scanline 344 (just write data to pixels) 345 */ 346 inline void 347 write_rgb24(jas_matrix_t** pixels, jpr_uchar_t* scanline, int width) 348 { 349 int32 index = 0; 350 int32 x = 0; 351 while (x < width) { 352 jas_matrix_setv(pixels[2], x, scanline[index++]); 353 jas_matrix_setv(pixels[1], x, scanline[index++]); 354 jas_matrix_setv(pixels[0], x, scanline[index++]); 355 x++; 356 } 357 } 358 359 360 /*! 361 Make *pixels[3] from RGB24 bigendian scanline 362 (just write data to pixels) 363 */ 364 inline void 365 write_rgb24b(jas_matrix_t** pixels, jpr_uchar_t* scanline, int width) 366 { 367 int32 index = 0; 368 int32 x = 0; 369 while (x < width) { 370 jas_matrix_setv(pixels[0], x, scanline[index++]); 371 jas_matrix_setv(pixels[1], x, scanline[index++]); 372 jas_matrix_setv(pixels[2], x, scanline[index++]); 373 x++; 374 } 375 } 376 377 378 /*! 379 Make *pixels[3] from RGB32 scanline 380 (just write data to pixels) 381 */ 382 inline void 383 write_rgb32_to_rgb24(jas_matrix_t** pixels, jpr_uchar_t* scanline, int width) 384 { 385 int32 index = 0; 386 int32 x = 0; 387 while (x < width) { 388 jas_matrix_setv(pixels[2], x, scanline[index++]); 389 jas_matrix_setv(pixels[1], x, scanline[index++]); 390 jas_matrix_setv(pixels[0], x, scanline[index++]); 391 index++; 392 x++; 393 } 394 } 395 396 397 /*! 398 Make *pixels[3] from RGB32 bigendian scanline 399 (just write data to pixels) 400 */ 401 inline void 402 write_rgb32b_to_rgb24(jas_matrix_t** pixels, jpr_uchar_t* scanline, int width) 403 { 404 int32 index = 0; 405 int32 x = 0; 406 while (x < width) { 407 index++; 408 jas_matrix_setv(pixels[0], x, scanline[index++]); 409 jas_matrix_setv(pixels[1], x, scanline[index++]); 410 jas_matrix_setv(pixels[2], x, scanline[index++]); 411 x++; 412 } 413 } 414 415 416 /*! 417 Make *pixels[4] from RGBA32 scanline 418 (just write data to pixels) 419 !!! UNTESTED !!! 420 */ 421 inline void 422 write_rgba32(jas_matrix_t** pixels, jpr_uchar_t* scanline, int width) 423 { 424 int32 index = 0; 425 int32 x = 0; 426 while (x < width) { 427 jas_matrix_setv(pixels[3], x, scanline[index++]); 428 jas_matrix_setv(pixels[2], x, scanline[index++]); 429 jas_matrix_setv(pixels[1], x, scanline[index++]); 430 jas_matrix_setv(pixels[0], x, scanline[index++]); 431 x++; 432 } 433 } 434 435 436 /*! 437 Make *pixels[4] from RGBA32 bigendian scanline 438 (just write data to pixels) 439 !!! UNTESTED !!! 440 */ 441 inline void 442 write_rgba32b(jas_matrix_t** pixels, jpr_uchar_t* scanline, int width) 443 { 444 int32 index = 0; 445 int32 x = 0; 446 while (x < width) 447 { 448 jas_matrix_setv(pixels[0], x, scanline[index++]); 449 jas_matrix_setv(pixels[1], x, scanline[index++]); 450 jas_matrix_setv(pixels[2], x, scanline[index++]); 451 jas_matrix_setv(pixels[3], x, scanline[index++]); 452 x++; 453 } 454 } 455 456 457 }// end namespace conversion 458 459 460 // #pragma mark - jasper I/O 461 462 463 static int 464 Read(jas_stream_obj_t* object, char* buffer, const int length) 465 { 466 return (*(BPositionIO**)object)->Read(buffer, length); 467 } 468 469 470 static int 471 Write(jas_stream_obj_t* object, char* buffer, const int length) 472 { 473 return (*(BPositionIO**)object)->Write(buffer, length); 474 } 475 476 477 static long 478 Seek(jas_stream_obj_t* object, long offset, int origin) 479 { 480 return (*(BPositionIO**)object)->Seek(offset, origin); 481 } 482 483 484 static int 485 Close(jas_stream_obj_t* object) 486 { 487 return 0; 488 } 489 490 491 static jas_stream_ops_t positionIOops = { 492 Read, 493 Write, 494 Seek, 495 Close 496 }; 497 498 499 static jas_stream_t* 500 jas_stream_positionIOopen(BPositionIO *positionIO) 501 { 502 jas_stream_t* stream; 503 504 stream = (jas_stream_t *)malloc(sizeof(jas_stream_t)); 505 if (stream == (jas_stream_t *)NULL) 506 return (jas_stream_t *)NULL; 507 508 memset(stream, 0, sizeof(jas_stream_t)); 509 stream->rwlimit_ = -1; 510 stream->obj_=(jas_stream_obj_t *)malloc(sizeof(BPositionIO*)); 511 if (stream->obj_ == (jas_stream_obj_t *)NULL) { 512 free(stream); 513 return (jas_stream_t *)NULL; 514 } 515 516 *((BPositionIO**)stream->obj_) = positionIO; 517 stream->ops_ = (&positionIOops); 518 stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY; 519 stream->bufbase_ = stream->tinybuf_; 520 stream->bufsize_ = 1; 521 stream->bufstart_ = (&stream->bufbase_[JAS_STREAM_MAXPUTBACK]); 522 stream->ptr_ = stream->bufstart_; 523 stream->bufmode_ |= JAS_STREAM_UNBUF & JAS_STREAM_BUFMODEMASK; 524 525 return stream; 526 } 527 528 529 // #pragma mark - 530 531 532 SSlider::SSlider(const char* name, const char* label, 533 BMessage* message, int32 minValue, int32 maxValue, orientation posture, 534 thumb_style thumbType, uint32 flags) 535 : 536 BSlider(name, label, message, minValue, maxValue, 537 posture, thumbType, flags) 538 { 539 rgb_color barColor = { 0, 0, 229, 255 }; 540 UseFillColor(true, &barColor); 541 } 542 543 544 //! Update status string - show actual value 545 const char* 546 SSlider::UpdateText() const 547 { 548 snprintf(fStatusLabel, sizeof(fStatusLabel), "%" B_PRId32, Value()); 549 return fStatusLabel; 550 } 551 552 553 // #pragma mark - 554 555 556 TranslatorReadView::TranslatorReadView(const char* name, 557 TranslatorSettings* settings) 558 : 559 BView(name, 0, new BGroupLayout(B_VERTICAL)), 560 fSettings(settings) 561 { 562 fGrayAsRGB32 = new BCheckBox("grayasrgb32", 563 B_TRANSLATE("Read greyscale images as RGB32"), 564 new BMessage(VIEW_MSG_SET_GRAYASRGB32)); 565 if (fSettings->SetGetBool(JP2_SET_GRAY8_AS_B_RGB32)) 566 fGrayAsRGB32->SetValue(B_CONTROL_ON); 567 568 float padding = 10.0f; 569 BLayoutBuilder::Group<>(this, B_VERTICAL) 570 .SetInsets(padding) 571 .Add(fGrayAsRGB32) 572 .AddGlue(); 573 } 574 575 576 TranslatorReadView::~TranslatorReadView() 577 { 578 fSettings->Release(); 579 } 580 581 582 void 583 TranslatorReadView::AttachedToWindow() 584 { 585 fGrayAsRGB32->SetTarget(this); 586 } 587 588 589 void 590 TranslatorReadView::MessageReceived(BMessage* message) 591 { 592 switch (message->what) { 593 case VIEW_MSG_SET_GRAYASRGB32: 594 { 595 int32 value; 596 if (message->FindInt32("be:value", &value) == B_OK) { 597 bool boolValue = value; 598 fSettings->SetGetBool(JP2_SET_GRAY8_AS_B_RGB32, &boolValue); 599 fSettings->SaveSettings(); 600 } 601 break; 602 } 603 default: 604 BView::MessageReceived(message); 605 break; 606 } 607 } 608 609 610 // #pragma mark - TranslatorWriteView 611 612 613 TranslatorWriteView::TranslatorWriteView(const char* name, 614 TranslatorSettings* settings) 615 : 616 BView(name, 0, new BGroupLayout(B_VERTICAL)), 617 fSettings(settings) 618 { 619 fQualitySlider = new SSlider("quality", B_TRANSLATE("Output quality"), 620 new BMessage(VIEW_MSG_SET_QUALITY), 0, 100); 621 fQualitySlider->SetHashMarks(B_HASH_MARKS_BOTTOM); 622 fQualitySlider->SetHashMarkCount(10); 623 fQualitySlider->SetLimitLabels(B_TRANSLATE("Low"), B_TRANSLATE("High")); 624 fQualitySlider->SetValue(fSettings->SetGetInt32(JP2_SET_QUALITY)); 625 626 fGrayAsRGB24 = new BCheckBox("gray1asrgb24", 627 B_TRANSLATE("Write black-and-white images as RGB24"), 628 new BMessage(VIEW_MSG_SET_GRAY1ASRGB24)); 629 if (fSettings->SetGetBool(JP2_SET_GRAY1_AS_B_RGB24)) 630 fGrayAsRGB24->SetValue(B_CONTROL_ON); 631 632 fCodeStreamOnly = new BCheckBox("codestreamonly", 633 B_TRANSLATE("Output only codestream (.jpc)"), 634 new BMessage(VIEW_MSG_SET_JPC)); 635 if (fSettings->SetGetBool(JP2_SET_JPC)) 636 fCodeStreamOnly->SetValue(B_CONTROL_ON); 637 638 float padding = 10.0f; 639 BLayoutBuilder::Group<>(this, B_VERTICAL, padding) 640 .SetInsets(padding) 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[16]; 716 sprintf(versionString, "v%d.%d.%d", 717 static_cast<int>(sTranslatorVersion >> 8), 718 static_cast<int>((sTranslatorVersion >> 4) & 0xf), 719 static_cast<int>(sTranslatorVersion & 0xf)); 720 721 BStringView* version = new BStringView("Version", versionString); 722 version->SetExplicitAlignment(labelAlignment); 723 724 BTextView* infoView = new BTextView("info"); 725 infoView->SetText(sTranslatorInfo); 726 infoView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 727 infoView->MakeEditable(false); 728 729 float padding = 10.0f; 730 BLayoutBuilder::Group<>(this, B_VERTICAL, padding) 731 .SetInsets(padding) 732 .AddGroup(B_HORIZONTAL, padding) 733 .Add(title) 734 .Add(version) 735 .AddGlue() 736 .End() 737 .Add(infoView); 738 } 739 740 741 // #pragma mark - 742 743 744 TranslatorView::TranslatorView(const char* name, TranslatorSettings* settings) 745 : 746 BTabView(name) 747 { 748 AddTab(new TranslatorWriteView(B_TRANSLATE("Write"), 749 settings->Acquire())); 750 AddTab(new TranslatorReadView(B_TRANSLATE("Read"), 751 settings->Acquire())); 752 AddTab(new TranslatorAboutView(B_TRANSLATE("About"))); 753 754 settings->Release(); 755 756 BFont font; 757 GetFont(&font); 758 SetExplicitPreferredSize( 759 BSize((font.Size() * 380) / 12, (font.Size() * 250) / 12)); 760 } 761 762 763 // #pragma mark - 764 765 BView* 766 JP2Translator::NewConfigView(TranslatorSettings* settings) 767 { 768 BView* outView = new TranslatorView("TranslatorView", settings); 769 return outView; 770 } 771 772 773 JP2Translator::JP2Translator() 774 : BaseTranslator(sTranslatorName, sTranslatorInfo, sTranslatorVersion, 775 sInputFormats, kNumInputFormats, 776 sOutputFormats, kNumOutputFormats, 777 JP2_SETTINGS_FILE, 778 sDefaultSettings, kNumDefaultSettings, 779 B_TRANSLATOR_BITMAP, JP2_FORMAT) 780 { 781 } 782 783 784 //! Determine whether or not we can handle this data 785 status_t 786 JP2Translator::DerivedIdentify(BPositionIO* inSource, 787 const translation_format* inFormat, BMessage* ioExtension, 788 translator_info* outInfo, uint32 outType) 789 { 790 if ((outType != 0) && (outType != B_TRANSLATOR_BITMAP) 791 && outType != JP2_FORMAT) 792 return B_NO_TRANSLATOR; 793 794 // !!! You might need to make this buffer bigger to test for your 795 // native format 796 off_t position = inSource->Position(); 797 uint8 header[sizeof(TranslatorBitmap)]; 798 status_t err = inSource->Read(header, sizeof(TranslatorBitmap)); 799 inSource->Seek(position, SEEK_SET); 800 if (err < B_OK) 801 return err; 802 803 if (B_BENDIAN_TO_HOST_INT32(((TranslatorBitmap *)header)->magic) 804 == B_TRANSLATOR_BITMAP) { 805 if (PopulateInfoFromFormat(outInfo, B_TRANSLATOR_BITMAP) != B_OK) 806 return B_NO_TRANSLATOR; 807 } else { 808 if ((((header[4] << 24) | (header[5] << 16) | (header[6] << 8) 809 | header[7]) == JP2_BOX_JP) // JP2 810 || (header[0] == (JPC_MS_SOC >> 8) && header[1] 811 == (JPC_MS_SOC & 0xff))) // JPC 812 { 813 if (PopulateInfoFromFormat(outInfo, JP2_FORMAT) != B_OK) 814 return B_NO_TRANSLATOR; 815 } else 816 return B_NO_TRANSLATOR; 817 } 818 819 return B_OK; 820 } 821 822 823 status_t 824 JP2Translator::DerivedTranslate(BPositionIO* inSource, 825 const translator_info* inInfo, BMessage* ioExtension, uint32 outType, 826 BPositionIO* outDestination, int32 baseType) 827 { 828 // If no specific type was requested, convert to the interchange format 829 if (outType == 0) 830 outType = B_TRANSLATOR_BITMAP; 831 832 // What action to take, based on the findings of Identify() 833 if (outType == inInfo->type) 834 return Copy(inSource, outDestination); 835 if (inInfo->type == B_TRANSLATOR_BITMAP && outType == JP2_FORMAT) 836 return Compress(inSource, outDestination); 837 if (inInfo->type == JP2_FORMAT && outType == B_TRANSLATOR_BITMAP) 838 return Decompress(inSource, outDestination); 839 840 return B_NO_TRANSLATOR; 841 } 842 843 844 //! The user has requested the same format for input and output, so just copy 845 status_t 846 JP2Translator::Copy(BPositionIO* in, BPositionIO* out) 847 { 848 int block_size = 65536; 849 void* buffer = malloc(block_size); 850 char temp[1024]; 851 if (buffer == NULL) { 852 buffer = temp; 853 block_size = 1024; 854 } 855 status_t err = B_OK; 856 857 // Read until end of file or error 858 while (1) { 859 ssize_t to_read = block_size; 860 err = in->Read(buffer, to_read); 861 // Explicit check for EOF 862 if (err == -1) { 863 if (buffer != temp) 864 free(buffer); 865 return B_OK; 866 } 867 if (err <= B_OK) break; 868 to_read = err; 869 err = out->Write(buffer, to_read); 870 if (err != to_read) if (err >= 0) err = B_DEVICE_FULL; 871 if (err < B_OK) break; 872 } 873 874 if (buffer != temp) 875 free(buffer); 876 return (err >= 0) ? B_OK : err; 877 } 878 879 880 //! Encode into the native format 881 status_t 882 JP2Translator::Compress(BPositionIO* in, BPositionIO* out) 883 { 884 using namespace conversion; 885 886 // Read info about bitmap 887 TranslatorBitmap header; 888 status_t err = in->Read(&header, sizeof(TranslatorBitmap)); 889 if (err < B_OK) 890 return err; 891 if (err < (int)sizeof(TranslatorBitmap)) 892 return B_ERROR; 893 894 // Grab dimension, color space, and size information from the stream 895 BRect bounds; 896 bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left); 897 bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top); 898 bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right); 899 bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom); 900 901 int32 in_row_bytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes); 902 903 int width = bounds.IntegerWidth() + 1; 904 int height = bounds.IntegerHeight() + 1; 905 906 // Function pointer to write function 907 // It MUST point to proper function 908 void (*converter)(jas_matrix_t** pixels, jpr_uchar_t* inscanline, 909 int width) = write_rgba32; 910 911 // Default color info 912 int out_color_space = JAS_IMAGE_CS_RGB; 913 int out_color_components = 3; 914 915 switch ((color_space)B_BENDIAN_TO_HOST_INT32(header.colors)) { 916 case B_GRAY1: 917 if (fSettings->SetGetBool(JP2_SET_GRAY1_AS_B_RGB24)) { 918 converter = write_gray1_to_rgb24; 919 } else { 920 out_color_components = 1; 921 out_color_space = JAS_IMAGE_CS_GRAY; 922 converter = write_gray1_to_gray; 923 } 924 break; 925 926 case B_CMAP8: 927 converter = write_cmap8_to_rgb24; 928 break; 929 930 case B_GRAY8: 931 out_color_components = 1; 932 out_color_space = JAS_IMAGE_CS_GRAY; 933 converter = write_gray; 934 break; 935 936 case B_RGB15: 937 case B_RGBA15: 938 converter = write_rgb15_to_rgb24; 939 break; 940 941 case B_RGB15_BIG: 942 case B_RGBA15_BIG: 943 converter = write_rgb15b_to_rgb24; 944 break; 945 946 case B_RGB16: 947 converter = write_rgb16_to_rgb24; 948 break; 949 950 case B_RGB16_BIG: 951 converter = write_rgb16b_to_rgb24; 952 break; 953 954 case B_RGB24: 955 converter = write_rgb24; 956 break; 957 958 case B_RGB24_BIG: 959 converter = write_rgb24b; 960 break; 961 962 case B_RGB32: 963 converter = write_rgb32_to_rgb24; 964 break; 965 966 case B_RGB32_BIG: 967 converter = write_rgb32b_to_rgb24; 968 break; 969 970 case B_RGBA32: 971 /* 972 // In theory it should be possible to write 4 color components 973 // to jp2, so it should be possible to have transparency. 974 // Unfortunetly libjasper does not agree with that 975 // For now i don't know how to modify it :( 976 977 out_color_components = 4; 978 converter = write_rgba32; 979 */ 980 converter = write_rgb32_to_rgb24; 981 break; 982 983 case B_RGBA32_BIG: 984 /* 985 // In theory it should be possible to write 4 color components 986 // to jp2, so it should be possible to have transparency. 987 // Unfortunetly libjasper does not agree with that 988 // For now i don't know how to modify it :( 989 990 out_color_components = 4; 991 converter = write_rgba32b; 992 */ 993 converter = write_rgb32b_to_rgb24; 994 break; 995 996 default: 997 syslog(LOG_ERR, "Unknown color space.\n"); 998 return B_ERROR; 999 } 1000 1001 jas_image_t* image; 1002 jas_stream_t* outs; 1003 jas_matrix_t* pixels[4]; 1004 jas_image_cmptparm_t component_info[4]; 1005 1006 if (jas_init()) 1007 return B_ERROR; 1008 1009 if (!(outs = jas_stream_positionIOopen(out))) 1010 return B_ERROR; 1011 1012 int32 i = 0; 1013 for (i = 0; i < (long)out_color_components; i++) { 1014 (void) memset(component_info + i, 0, sizeof(jas_image_cmptparm_t)); 1015 component_info[i].hstep = 1; 1016 component_info[i].vstep = 1; 1017 component_info[i].width = (unsigned int)width; 1018 component_info[i].height = (unsigned int)height; 1019 component_info[i].prec = (unsigned int)8; 1020 } 1021 1022 image = jas_image_create((short)out_color_components, component_info, 1023 out_color_space); 1024 if (image == (jas_image_t *)NULL) 1025 return Error(outs, NULL, NULL, 0, NULL, B_ERROR); 1026 1027 jpr_uchar_t *in_scanline = (jpr_uchar_t*) malloc(in_row_bytes); 1028 if (in_scanline == NULL) 1029 return Error(outs, image, NULL, 0, NULL, B_ERROR); 1030 1031 for (i = 0; i < (long)out_color_components; i++) { 1032 pixels[i] = jas_matrix_create(1, (unsigned int)width); 1033 if (pixels[i] == (jas_matrix_t *)NULL) 1034 return Error(outs, image, pixels, i+1, in_scanline, B_ERROR); 1035 } 1036 1037 int32 y = 0; 1038 for (y = 0; y < (long)height; y++) { 1039 err = in->Read(in_scanline, in_row_bytes); 1040 if (err < in_row_bytes) { 1041 return (err < B_OK) ? Error(outs, image, pixels, 1042 out_color_components, in_scanline, err) 1043 : Error(outs, image, pixels, out_color_components, in_scanline, 1044 B_ERROR); 1045 } 1046 1047 converter(pixels, in_scanline, width); 1048 1049 for (i = 0; i < (long)out_color_components; i++) { 1050 (void)jas_image_writecmpt(image, (short)i, 0, (unsigned int)y, 1051 (unsigned int)width, 1, pixels[i]); 1052 } 1053 } 1054 1055 char opts[16]; 1056 sprintf(opts, "rate=%1f", 1057 (float)fSettings->SetGetInt32(JP2_SET_QUALITY) / 100.0); 1058 1059 if (jas_image_encode(image, outs, jas_image_strtofmt( 1060 fSettings->SetGetBool(JP2_SET_JPC) ? 1061 (char*)"jpc" : (char*)"jp2"), opts)) { 1062 return Error(outs, image, pixels, 1063 out_color_components, in_scanline, err); 1064 } 1065 1066 free(in_scanline); 1067 1068 for (i = 0; i < (long)out_color_components; i++) 1069 jas_matrix_destroy(pixels[i]); 1070 1071 jas_stream_close(outs); 1072 jas_image_destroy(image); 1073 jas_image_clearfmts(); 1074 1075 return B_OK; 1076 } 1077 1078 1079 //! Decode the native format 1080 status_t 1081 JP2Translator::Decompress(BPositionIO* in, BPositionIO* out) 1082 { 1083 using namespace conversion; 1084 1085 jas_image_t* image; 1086 jas_stream_t* ins; 1087 jas_matrix_t* pixels[4]; 1088 1089 if (jas_init()) 1090 return B_ERROR; 1091 1092 if (!(ins = jas_stream_positionIOopen(in))) 1093 return B_ERROR; 1094 1095 if (!(image = jas_image_decode(ins, -1, 0))) 1096 return Error(ins, NULL, NULL, 0, NULL, B_ERROR); 1097 1098 // Default color info 1099 color_space out_color_space; 1100 int out_color_components; 1101 int in_color_components = jas_image_numcmpts(image); 1102 1103 // Function pointer to read function 1104 // It MUST point to proper function 1105 void (*converter)(jas_matrix_t** pixels, jpr_uchar_t* outscanline, 1106 int width) = NULL; 1107 1108 switch (jas_image_colorspace(image)) { 1109 case JAS_IMAGE_CS_RGB: 1110 out_color_components = 4; 1111 if (in_color_components == 3) { 1112 out_color_space = B_RGB32; 1113 converter = read_rgb24_to_rgb32; 1114 } else if (in_color_components == 4) { 1115 out_color_space = B_RGBA32; 1116 converter = read_rgba32; 1117 } else { 1118 syslog(LOG_ERR, "Other than RGB with 3 or 4 color " 1119 "components not implemented.\n"); 1120 return Error(ins, image, NULL, 0, NULL, B_ERROR); 1121 } 1122 break; 1123 case JAS_IMAGE_CS_GRAY: 1124 if (fSettings->SetGetBool(JP2_SET_GRAY8_AS_B_RGB32)) { 1125 out_color_space = B_RGB32; 1126 out_color_components = 4; 1127 converter = read_gray_to_rgb32; 1128 } else { 1129 out_color_space = B_GRAY8; 1130 out_color_components = 1; 1131 converter = read_gray; 1132 } 1133 break; 1134 case JAS_IMAGE_CS_YCBCR: 1135 syslog(LOG_ERR, "Color space YCBCR not implemented yet.\n"); 1136 return Error(ins, image, NULL, 0, NULL, B_ERROR); 1137 break; 1138 case JAS_IMAGE_CS_UNKNOWN: 1139 default: 1140 syslog(LOG_ERR, "Color space unknown. \n"); 1141 return Error(ins, image, NULL, 0, NULL, B_ERROR); 1142 break; 1143 } 1144 1145 float width = (float)jas_image_width(image); 1146 float height = (float)jas_image_height(image); 1147 1148 // Bytes count in one line of image (scanline) 1149 int64 out_row_bytes = (int32)width * out_color_components; 1150 // NOTE: things will go wrong if "out_row_bytes" wouldn't fit into 32 bits 1151 1152 // !!! Initialize this bounds rect to the size of your image 1153 BRect bounds(0, 0, width - 1, height - 1); 1154 1155 1156 // Fill out the B_TRANSLATOR_BITMAP's header 1157 TranslatorBitmap header; 1158 header.magic = B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP); 1159 header.bounds.left = B_HOST_TO_BENDIAN_FLOAT(bounds.left); 1160 header.bounds.top = B_HOST_TO_BENDIAN_FLOAT(bounds.top); 1161 header.bounds.right = B_HOST_TO_BENDIAN_FLOAT(bounds.right); 1162 header.bounds.bottom = B_HOST_TO_BENDIAN_FLOAT(bounds.bottom); 1163 header.colors = (color_space)B_HOST_TO_BENDIAN_INT32(out_color_space); 1164 header.rowBytes = B_HOST_TO_BENDIAN_INT32(out_row_bytes); 1165 header.dataSize = B_HOST_TO_BENDIAN_INT32((int32)(out_row_bytes * height)); 1166 1167 // Write out the header 1168 status_t err = out->Write(&header, sizeof(TranslatorBitmap)); 1169 if (err < B_OK) 1170 return Error(ins, image, NULL, 0, NULL, err); 1171 if (err < (int)sizeof(TranslatorBitmap)) 1172 return Error(ins, image, NULL, 0, NULL, B_ERROR); 1173 1174 jpr_uchar_t *out_scanline = (jpr_uchar_t*) malloc(out_row_bytes); 1175 if (out_scanline == NULL) 1176 return Error(ins, image, NULL, 0, NULL, B_ERROR); 1177 1178 int32 i = 0; 1179 for (i = 0; i < (long)in_color_components; i++) { 1180 pixels[i] = jas_matrix_create(1, (unsigned int)width); 1181 if (pixels[i] == (jas_matrix_t *)NULL) 1182 return Error(ins, image, pixels, i + 1, out_scanline, B_ERROR); 1183 } 1184 1185 int32 y = 0; 1186 for (y = 0; y < (long)height; y++) { 1187 for (i = 0; i < (long)in_color_components; i++) { 1188 (void)jas_image_readcmpt(image, (short)i, 0, (unsigned int)y, 1189 (unsigned int)width, 1, pixels[i]); 1190 } 1191 1192 converter(pixels, out_scanline, (int32)width); 1193 1194 err = out->Write(out_scanline, out_row_bytes); 1195 if (err < out_row_bytes) { 1196 return (err < B_OK) ? Error(ins, image, pixels, in_color_components, 1197 out_scanline, err) 1198 : Error(ins, image, pixels, in_color_components, out_scanline, 1199 B_ERROR); 1200 } 1201 } 1202 1203 free(out_scanline); 1204 1205 for (i = 0; i < (long)in_color_components; i++) 1206 jas_matrix_destroy(pixels[i]); 1207 1208 jas_stream_close(ins); 1209 jas_image_destroy(image); 1210 jas_image_clearfmts(); 1211 1212 return B_OK; 1213 } 1214 1215 1216 /*! searches in both inputFormats & outputFormats */ 1217 status_t 1218 JP2Translator::PopulateInfoFromFormat(translator_info* info, 1219 uint32 formatType, translator_id id) 1220 { 1221 int32 formatCount; 1222 const translation_format* formats = OutputFormats(&formatCount); 1223 1224 for (int i = 0; i <= 1; formats = InputFormats(&formatCount), i++) { 1225 if (PopulateInfoFromFormat(info, formatType, 1226 formats, formatCount) == B_OK) { 1227 info->translator = id; 1228 return B_OK; 1229 } 1230 } 1231 1232 return B_ERROR; 1233 } 1234 1235 1236 status_t 1237 JP2Translator::PopulateInfoFromFormat(translator_info* info, 1238 uint32 formatType, const translation_format* formats, int32 formatCount) 1239 { 1240 for (int i = 0; i < formatCount; i++) { 1241 if (formats[i].type == formatType) { 1242 info->type = formatType; 1243 info->group = formats[i].group; 1244 info->quality = formats[i].quality; 1245 info->capability = formats[i].capability; 1246 if (strncmp(formats[i].name, 1247 "Be Bitmap Format (JPEG2000Translator)", 1248 sizeof("Be Bitmap Format (JPEG2000Translator)")) == 0) 1249 strncpy(info->name, 1250 B_TRANSLATE("Be Bitmap Format (JPEG2000Translator)"), 1251 sizeof(info->name)); 1252 else 1253 strncpy(info->name, formats[i].name, sizeof(info->name)); 1254 strncpy(info->MIME, formats[i].MIME, sizeof(info->MIME)); 1255 return B_OK; 1256 } 1257 } 1258 1259 return B_ERROR; 1260 } 1261 1262 1263 /*! 1264 Frees jpeg alocated memory 1265 Returns given error (B_ERROR by default) 1266 */ 1267 status_t 1268 Error(jas_stream_t* stream, jas_image_t* image, jas_matrix_t** pixels, 1269 int32 pixels_count, jpr_uchar_t* scanline, status_t error) 1270 { 1271 if (pixels) { 1272 int32 i; 1273 for (i = 0; i < (long)pixels_count; i++) { 1274 if (pixels[i] != NULL) 1275 jas_matrix_destroy(pixels[i]); 1276 } 1277 } 1278 if (stream) 1279 jas_stream_close(stream); 1280 if (image) 1281 jas_image_destroy(image); 1282 1283 jas_image_clearfmts(); 1284 free(scanline); 1285 1286 return error; 1287 } 1288 1289 1290 // #pragma mark - 1291 1292 BTranslator* 1293 make_nth_translator(int32 n, image_id you, uint32 flags, ...) 1294 { 1295 if (!n) 1296 return new JP2Translator(); 1297 1298 return NULL; 1299 } 1300 1301 1302 int 1303 main() 1304 { 1305 BApplication app("application/x-vnd.Haiku-JPEG2000Translator"); 1306 JP2Translator* translator = new JP2Translator(); 1307 if (LaunchTranslatorWindow(translator, sTranslatorName) == B_OK) 1308 app.Run(); 1309 1310 return 0; 1311 } 1312 1313