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