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