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 <GroupLayoutBuilder.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), "%ld", 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 AddChild(BGroupLayoutBuilder(B_VERTICAL) 570 .Add(fGrayAsRGB32) 571 .AddGlue() 572 .SetInsets(padding, padding, padding, padding) 573 ); 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 float padding = 10.0f; 640 AddChild(BGroupLayoutBuilder(B_VERTICAL, padding) 641 .Add(fQualitySlider) 642 .Add(fGrayAsRGB24) 643 .Add(fCodeStreamOnly) 644 .AddGlue() 645 .SetInsets(padding, padding, padding, padding) 646 ); 647 } 648 649 650 TranslatorWriteView::~TranslatorWriteView() 651 { 652 fSettings->Release(); 653 } 654 655 656 void 657 TranslatorWriteView::AttachedToWindow() 658 { 659 fQualitySlider->SetTarget(this); 660 fGrayAsRGB24->SetTarget(this); 661 fCodeStreamOnly->SetTarget(this); 662 } 663 664 665 void 666 TranslatorWriteView::MessageReceived(BMessage* message) 667 { 668 switch (message->what) { 669 case VIEW_MSG_SET_QUALITY: 670 { 671 int32 value; 672 if (message->FindInt32("be:value", &value) == B_OK) { 673 fSettings->SetGetInt32(JP2_SET_QUALITY, &value); 674 fSettings->SaveSettings(); 675 } 676 break; 677 } 678 case VIEW_MSG_SET_GRAY1ASRGB24: 679 { 680 int32 value; 681 if (message->FindInt32("be:value", &value) == B_OK) { 682 bool boolValue = value; 683 fSettings->SetGetBool(JP2_SET_GRAY1_AS_B_RGB24, &boolValue); 684 fSettings->SaveSettings(); 685 } 686 break; 687 } 688 case VIEW_MSG_SET_JPC: 689 { 690 int32 value; 691 if (message->FindInt32("be:value", &value) == B_OK) { 692 bool boolValue = value; 693 fSettings->SetGetBool(JP2_SET_JPC, &boolValue); 694 fSettings->SaveSettings(); 695 } 696 break; 697 } 698 default: 699 BView::MessageReceived(message); 700 break; 701 } 702 } 703 704 705 // #pragma mark - 706 707 708 TranslatorAboutView::TranslatorAboutView(const char* name) 709 : 710 BView(name, 0, new BGroupLayout(B_VERTICAL)) 711 { 712 BAlignment labelAlignment = BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP); 713 BStringView* title = new BStringView("Title", sTranslatorName); 714 title->SetFont(be_bold_font); 715 title->SetExplicitAlignment(labelAlignment); 716 717 char versionString[16]; 718 sprintf(versionString, "v%d.%d.%d", 719 static_cast<int>(sTranslatorVersion >> 8), 720 static_cast<int>((sTranslatorVersion >> 4) & 0xf), 721 static_cast<int>(sTranslatorVersion & 0xf)); 722 723 BStringView* version = new BStringView("Version", versionString); 724 version->SetExplicitAlignment(labelAlignment); 725 726 BTextView* infoView = new BTextView("info"); 727 infoView->SetText(sTranslatorInfo); 728 infoView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 729 infoView->MakeEditable(false); 730 731 float padding = 10.0f; 732 AddChild(BGroupLayoutBuilder(B_VERTICAL, padding) 733 .Add(BGroupLayoutBuilder(B_HORIZONTAL, padding) 734 .Add(title) 735 .Add(version) 736 .AddGlue() 737 ) 738 .Add(infoView) 739 .SetInsets(padding, padding, padding, padding) 740 ); 741 } 742 743 744 // #pragma mark - 745 746 747 TranslatorView::TranslatorView(const char* name, TranslatorSettings* settings) 748 : 749 BTabView(name) 750 { 751 AddTab(new TranslatorWriteView(B_TRANSLATE("Write"), 752 settings->Acquire())); 753 AddTab(new TranslatorReadView(B_TRANSLATE("Read"), 754 settings->Acquire())); 755 AddTab(new TranslatorAboutView(B_TRANSLATE("About"))); 756 757 settings->Release(); 758 759 BFont font; 760 GetFont(&font); 761 SetExplicitPreferredSize( 762 BSize((font.Size() * 380) / 12, (font.Size() * 250) / 12)); 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, jpr_uchar_t* inscanline, 912 int width) = write_rgba32; 913 914 // Default color info 915 int out_color_space = JAS_IMAGE_CS_RGB; 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_IMAGE_CS_GRAY; 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_IMAGE_CS_GRAY; 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 jpr_uchar_t *in_scanline = (jpr_uchar_t*) 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, jpr_uchar_t* outscanline, 1109 int width) = NULL; 1110 1111 switch (jas_image_colorspace(image)) { 1112 case JAS_IMAGE_CS_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_IMAGE_CS_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_IMAGE_CS_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_IMAGE_CS_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 jpr_uchar_t *out_scanline = (jpr_uchar_t*) 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 (strncmp(formats[i].name, 1250 "Be Bitmap Format (JPEG2000Translator)", 1251 sizeof("Be Bitmap Format (JPEG2000Translator)")) == 0) 1252 strncpy(info->name, 1253 B_TRANSLATE("Be Bitmap Format (JPEG2000Translator)"), 1254 sizeof(info->name)); 1255 else 1256 strncpy(info->name, formats[i].name, sizeof(info->name)); 1257 strncpy(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, jpr_uchar_t* 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