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