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 free(stream); 580 return (jas_stream_t *)NULL; 581 } 582 583 *((BPositionIO**)stream->obj_) = positionIO; 584 stream->ops_ = (&positionIOops); 585 stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY; 586 stream->bufbase_ = stream->tinybuf_; 587 stream->bufsize_ = 1; 588 stream->bufstart_ = (&stream->bufbase_[JAS_STREAM_MAXPUTBACK]); 589 stream->ptr_ = stream->bufstart_; 590 stream->bufmode_ |= JAS_STREAM_UNBUF & JAS_STREAM_BUFMODEMASK; 591 592 return stream; 593 } 594 595 596 // #pragma mark - SView 597 598 599 SView::SView(const char *name, float x, float y) 600 : BView(BRect(x, y, x, y), name, B_FOLLOW_NONE, B_WILL_DRAW) 601 { 602 fPreferredWidth = 0; 603 fPreferredHeight = 0; 604 605 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 606 SetLowColor(ViewColor()); 607 608 SetFont(be_plain_font); 609 } 610 611 612 void 613 SView::GetPreferredSize(float* _width, float* _height) 614 { 615 if (_width) 616 *_width = fPreferredWidth; 617 if (_height) 618 *_height = fPreferredHeight; 619 } 620 621 622 void 623 SView::ResizeToPreferred() 624 { 625 ResizeTo(fPreferredWidth, fPreferredHeight); 626 } 627 628 629 void 630 SView::ResizePreferredBy(float width, float height) 631 { 632 fPreferredWidth += width; 633 fPreferredHeight += height; 634 } 635 636 637 void 638 SView::AddChild(BView *child, BView *before) 639 { 640 BView::AddChild(child, before); 641 child->ResizeToPreferred(); 642 BRect frame = child->Frame(); 643 644 if (frame.right > fPreferredWidth) 645 fPreferredWidth = frame.right; 646 if (frame.bottom > fPreferredHeight) 647 fPreferredHeight = frame.bottom; 648 } 649 650 651 // #pragma mark - 652 653 654 SSlider::SSlider(BRect frame, const char *name, const char *label, 655 BMessage *message, int32 minValue, int32 maxValue, orientation posture, 656 thumb_style thumbType, uint32 resizingMode, uint32 flags) 657 : BSlider(frame, name, label, message, minValue, maxValue, 658 posture, thumbType, resizingMode, flags) 659 { 660 rgb_color barColor = { 0, 0, 229, 255 }; 661 UseFillColor(true, &barColor); 662 } 663 664 665 //! Update status string - show actual value 666 char* 667 SSlider::UpdateText() const 668 { 669 snprintf(fStatusLabel, sizeof(fStatusLabel), "%ld", Value()); 670 return fStatusLabel; 671 } 672 673 674 //! BSlider::ResizeToPreferred + Resize width if it's too small to show label 675 // and status 676 void 677 SSlider::ResizeToPreferred() 678 { 679 int32 width = (int32)ceil(StringWidth(Label()) + StringWidth("9999")); 680 if (width < 230) 681 width = 230; 682 683 float w, h; 684 GetPreferredSize(&w, &h); 685 ResizeTo(width, h); 686 } 687 688 689 // #pragma mark - 690 691 692 TranslatorReadView::TranslatorReadView(const char *name, jpeg_settings *settings, 693 float x, float y) 694 : SView(name, x, y), 695 fSettings(settings) 696 { 697 fGrayAsRGB32 = new BCheckBox(BRect(10, GetPreferredHeight(), 10, 698 GetPreferredHeight()), "grayasrgb32", VIEW_LABEL_GRAYASRGB32, 699 new BMessage(VIEW_MSG_SET_GRAYASRGB32)); 700 fGrayAsRGB32->SetFont(be_plain_font); 701 if (fSettings->B_GRAY8_as_B_RGB32) 702 fGrayAsRGB32->SetValue(1); 703 704 AddChild(fGrayAsRGB32); 705 706 ResizeToPreferred(); 707 } 708 709 710 void 711 TranslatorReadView::AttachedToWindow() 712 { 713 fGrayAsRGB32->SetTarget(this); 714 } 715 716 717 void 718 TranslatorReadView::MessageReceived(BMessage *message) 719 { 720 switch (message->what) { 721 case VIEW_MSG_SET_GRAYASRGB32: 722 { 723 int32 value; 724 if (message->FindInt32("be:value", &value) == B_OK) { 725 fSettings->B_GRAY8_as_B_RGB32 = value; 726 SaveSettings(fSettings); 727 } 728 break; 729 } 730 default: 731 BView::MessageReceived(message); 732 break; 733 } 734 } 735 736 737 // #pragma mark - TranslatorWriteView 738 739 740 TranslatorWriteView::TranslatorWriteView(const char *name, jpeg_settings *settings, 741 float x, float y) 742 : SView(name, x, y), 743 fSettings(settings) 744 { 745 fQualitySlider = new SSlider(BRect(10, GetPreferredHeight(), 10, 746 GetPreferredHeight()), "quality", VIEW_LABEL_QUALITY, 747 new BMessage(VIEW_MSG_SET_QUALITY), 0, 100); 748 fQualitySlider->SetHashMarks(B_HASH_MARKS_BOTTOM); 749 fQualitySlider->SetHashMarkCount(10); 750 fQualitySlider->SetLimitLabels("Low", "High"); 751 fQualitySlider->SetFont(be_plain_font); 752 fQualitySlider->SetValue(fSettings->Quality); 753 AddChild(fQualitySlider); 754 755 fGrayAsRGB24 = new BCheckBox(BRect(10, GetPreferredHeight() + 5, 25, 756 GetPreferredHeight() + 5), "gray1asrgb24", VIEW_LABEL_GRAY1ASRGB24, 757 new BMessage(VIEW_MSG_SET_GRAY1ASRGB24)); 758 fGrayAsRGB24->SetFont(be_plain_font); 759 if (fSettings->B_GRAY1_as_B_RGB24) 760 fGrayAsRGB24->SetValue(1); 761 762 AddChild(fGrayAsRGB24); 763 764 fCodeStreamOnly = new BCheckBox(BRect(10, GetPreferredHeight() + 5, 10, 765 GetPreferredHeight()), "codestreamonly", VIEW_LABEL_JPC, 766 new BMessage(VIEW_MSG_SET_JPC)); 767 fCodeStreamOnly->SetFont(be_plain_font); 768 if (fSettings->JPC) 769 fCodeStreamOnly->SetValue(1); 770 771 AddChild(fCodeStreamOnly); 772 773 ResizeToPreferred(); 774 } 775 776 777 void 778 TranslatorWriteView::AttachedToWindow() 779 { 780 fQualitySlider->SetTarget(this); 781 fGrayAsRGB24->SetTarget(this); 782 fCodeStreamOnly->SetTarget(this); 783 } 784 785 786 void 787 TranslatorWriteView::MessageReceived(BMessage *message) 788 { 789 switch (message->what) { 790 case VIEW_MSG_SET_QUALITY: 791 { 792 int32 value; 793 if (message->FindInt32("be:value", &value) == B_OK) { 794 fSettings->Quality = value; 795 SaveSettings(fSettings); 796 } 797 break; 798 } 799 case VIEW_MSG_SET_GRAY1ASRGB24: 800 { 801 int32 value; 802 if (message->FindInt32("be:value", &value) == B_OK) { 803 fSettings->B_GRAY1_as_B_RGB24 = value; 804 SaveSettings(fSettings); 805 } 806 break; 807 } 808 case VIEW_MSG_SET_JPC: 809 { 810 int32 value; 811 if (message->FindInt32("be:value", &value) == B_OK) { 812 fSettings->JPC = value; 813 SaveSettings(fSettings); 814 } 815 break; 816 } 817 default: 818 BView::MessageReceived(message); 819 break; 820 } 821 } 822 823 824 // #pragma mark - 825 826 827 TranslatorAboutView::TranslatorAboutView(const char *name, float x, float y) 828 : SView(name, x, y) 829 { 830 BStringView *title = new BStringView(BRect(10, 0, 10, 0), "Title", 831 translatorName); 832 title->SetFont(be_bold_font); 833 834 AddChild(title); 835 836 BRect rect = title->Bounds(); 837 float space = title->StringWidth(" "); 838 839 char versionString[16]; 840 sprintf(versionString, "v%d.%d.%d", (int)(translatorVersion >> 8), 841 (int)((translatorVersion >> 4) & 0xf), (int)(translatorVersion & 0xf)); 842 843 BStringView *version = new BStringView(BRect(rect.right+space, rect.top, 844 rect.right+space, rect.top), "Version", versionString); 845 version->SetFont(be_plain_font); 846 version->SetFontSize(9); 847 // Make version be in the same line as title 848 version->ResizeToPreferred(); 849 version->MoveBy(0, rect.bottom-version->Frame().bottom); 850 851 AddChild(version); 852 853 // Now for each line in translatorInfo add a BStringView 854 char* current = translatorInfo; 855 int32 index = 1; 856 while (current != NULL && current[0]) { 857 char text[128]; 858 char* newLine = strchr(current, '\n'); 859 if (newLine == NULL) { 860 strlcpy(text, current, sizeof(text)); 861 current = NULL; 862 } else { 863 strlcpy(text, current, min_c((int32)sizeof(text), 864 newLine + 1 - current)); 865 current = newLine + 1; 866 } 867 868 BStringView* string = new BStringView(BRect(10, GetPreferredHeight(), 869 10, GetPreferredHeight()), "copyright", text); 870 if (index > 3) 871 string->SetFontSize(9); 872 AddChild(string); 873 874 index++; 875 } 876 877 ResizeToPreferred(); 878 } 879 880 881 // #pragma mark - 882 883 884 TranslatorView::TranslatorView(const char *name) 885 : SView(name), 886 fTabWidth(30), 887 fActiveChild(0) 888 { 889 // Set global var to true 890 gAreSettingsRunning = true; 891 892 // Load settings to global settings struct 893 LoadSettings(&fSettings); 894 895 font_height fontHeight; 896 GetFontHeight(&fontHeight); 897 fTabHeight = (int32)ceilf(fontHeight.ascent + fontHeight.descent 898 + fontHeight.leading) + 7; 899 // Add left and top margins 900 float top = fTabHeight + 20; 901 float left = 0; 902 903 // This will remember longest string width 904 int32 nameWidth = 0; 905 906 SView *view = new TranslatorWriteView("Write", &fSettings, left, top); 907 AddChild(view); 908 nameWidth = (int32)StringWidth(view->Name()); 909 fTabs.AddItem(new BTab(view)); 910 911 view = new TranslatorReadView("Read", &fSettings, left, top); 912 AddChild(view); 913 if (nameWidth < StringWidth(view->Name())) 914 nameWidth = (int32)StringWidth(view->Name()); 915 fTabs.AddItem(new BTab(view)); 916 917 view = new TranslatorAboutView("About", left, top); 918 AddChild(view); 919 if (nameWidth < StringWidth(view->Name())) 920 nameWidth = (int32)StringWidth(view->Name()); 921 fTabs.AddItem(new BTab(view)); 922 923 fTabWidth += nameWidth; 924 if (fTabWidth * CountChildren() > GetPreferredWidth()) 925 ResizePreferredBy((fTabWidth * CountChildren()) - GetPreferredWidth(), 0); 926 927 // Add right and bottom margins 928 ResizePreferredBy(10, 15); 929 930 ResizeToPreferred(); 931 932 // Make TranslatorView resize itself with parent 933 SetFlags(Flags() | B_FOLLOW_ALL); 934 } 935 936 937 TranslatorView::~TranslatorView() 938 { 939 gAreSettingsRunning = false; 940 941 BTab* tab; 942 while ((tab = (BTab*)fTabs.RemoveItem((int32)0)) != NULL) { 943 delete tab; 944 } 945 } 946 947 948 //! Attached to window - resize parent to preferred 949 void 950 TranslatorView::AttachedToWindow() 951 { 952 // Hide all children except first one 953 BView *child; 954 int32 index = 1; 955 while ((child = ChildAt(index++)) != NULL) 956 child->Hide(); 957 958 } 959 960 961 BRect 962 TranslatorView::_TabFrame(int32 index) const 963 { 964 return BRect(index * fTabWidth, 10, (index + 1) * fTabWidth, 10 + fTabHeight); 965 } 966 967 968 void 969 TranslatorView::Draw(BRect updateRect) 970 { 971 // This is needed because DataTranslations app hides children 972 // after user changes translator 973 if (ChildAt(fActiveChild)->IsHidden()) 974 ChildAt(fActiveChild)->Show(); 975 976 // Clear 977 SetHighColor(ViewColor()); 978 BRect frame = _TabFrame(0); 979 FillRect(BRect(frame.left, frame.top, Bounds().right, frame.bottom - 1)); 980 981 int32 index = 0; 982 BTab* tab; 983 while ((tab = (BTab*)fTabs.ItemAt(index)) != NULL) { 984 tab_position position; 985 if (fActiveChild == index) 986 position = B_TAB_FRONT; 987 else if (index == 0) 988 position = B_TAB_FIRST; 989 else 990 position = B_TAB_ANY; 991 992 tab->DrawTab(this, _TabFrame(index), position, index + 1 != fActiveChild); 993 index++; 994 } 995 996 // Draw bottom edge 997 SetHighColor(tint_color(ViewColor(), B_LIGHTEN_MAX_TINT)); 998 999 BRect selectedFrame = _TabFrame(fActiveChild); 1000 float offset = ceilf(frame.Height() / 2.0); 1001 1002 if (selectedFrame.left > frame.left) { 1003 StrokeLine(BPoint(frame.left, frame.bottom), 1004 BPoint(selectedFrame.left, frame.bottom)); 1005 } 1006 if (selectedFrame.right + offset < Bounds().right) { 1007 StrokeLine(BPoint(selectedFrame.right + offset, frame.bottom), 1008 BPoint(Bounds().right, frame.bottom)); 1009 } 1010 } 1011 1012 1013 //! MouseDown, check if on tab, if so change tab if needed 1014 void 1015 TranslatorView::MouseDown(BPoint where) 1016 { 1017 BRect frame = _TabFrame(fTabs.CountItems() - 1); 1018 frame.left = 0; 1019 if (!frame.Contains(where)) 1020 return; 1021 1022 for (int32 index = fTabs.CountItems(); index-- > 0;) { 1023 if (!_TabFrame(index).Contains(where)) 1024 continue; 1025 1026 if (fActiveChild != index) { 1027 // Hide current visible child 1028 ChildAt(fActiveChild)->Hide(); 1029 1030 // This loop is needed because it looks like in DataTranslations 1031 // view gets hidden more than one time when user changes translator 1032 while (ChildAt(index)->IsHidden()) { 1033 ChildAt(index)->Show(); 1034 } 1035 1036 // Remember which one is currently visible 1037 fActiveChild = index; 1038 Invalidate(frame); 1039 break; 1040 } 1041 } 1042 } 1043 1044 1045 // #pragma mark - 1046 1047 1048 TranslatorWindow::TranslatorWindow(bool quitOnClose) 1049 : BWindow(BRect(100, 100, 100, 100), "JPEG Settings", B_TITLED_WINDOW, 1050 B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS) 1051 { 1052 BRect extent(0, 0, 0, 0); 1053 BView *config = NULL; 1054 MakeConfig(NULL, &config, &extent); 1055 1056 AddChild(config); 1057 ResizeTo(extent.Width(), extent.Height()); 1058 1059 // Make application quit after this window close 1060 if (quitOnClose) 1061 SetFlags(Flags() | B_QUIT_ON_WINDOW_CLOSE); 1062 } 1063 1064 1065 // #pragma mark - 1066 1067 1068 //! Hook to create and return our configuration view 1069 status_t 1070 MakeConfig(BMessage *ioExtension, BView **outView, BRect *outExtent) 1071 { 1072 *outView = new TranslatorView("TranslatorView"); 1073 *outExtent = (*outView)->Frame(); 1074 return B_OK; 1075 } 1076 1077 1078 //! Determine whether or not we can handle this data 1079 status_t 1080 Identify(BPositionIO *inSource, const translation_format *inFormat, 1081 BMessage *ioExtension, translator_info *outInfo, uint32 outType) 1082 { 1083 if ((outType != 0) && (outType != B_TRANSLATOR_BITMAP) 1084 && outType != JP2_FORMAT) 1085 return B_NO_TRANSLATOR; 1086 1087 // !!! You might need to make this buffer bigger to test for your 1088 // native format 1089 off_t position = inSource->Position(); 1090 uint8 header[sizeof(TranslatorBitmap)]; 1091 status_t err = inSource->Read(header, sizeof(TranslatorBitmap)); 1092 inSource->Seek(position, SEEK_SET); 1093 if (err < B_OK) 1094 return err; 1095 1096 if (B_BENDIAN_TO_HOST_INT32(((TranslatorBitmap *)header)->magic) 1097 == B_TRANSLATOR_BITMAP) { 1098 outInfo->type = inputFormats[1].type; 1099 outInfo->translator = 0; 1100 outInfo->group = inputFormats[1].group; 1101 outInfo->quality = inputFormats[1].quality; 1102 outInfo->capability = inputFormats[1].capability; 1103 strcpy(outInfo->name, inputFormats[1].name); 1104 strcpy(outInfo->MIME, inputFormats[1].MIME); 1105 } else { 1106 if ((((header[4] << 24) | (header[5] << 16) | (header[6] << 8) 1107 | header[7]) == JP2_BOX_JP) // JP2 1108 || (header[0] == (JPC_MS_SOC >> 8) && header[1] 1109 == (JPC_MS_SOC & 0xff))) // JPC 1110 { 1111 outInfo->type = inputFormats[0].type; 1112 outInfo->translator = 0; 1113 outInfo->group = inputFormats[0].group; 1114 outInfo->quality = inputFormats[0].quality; 1115 outInfo->capability = inputFormats[0].capability; 1116 strcpy(outInfo->name, inputFormats[0].name); 1117 strcpy(outInfo->MIME, inputFormats[0].MIME); 1118 return B_OK; 1119 } else 1120 return B_NO_TRANSLATOR; 1121 } 1122 1123 return B_OK; 1124 } 1125 1126 1127 //! Arguably the most important method in the add-on 1128 status_t 1129 Translate(BPositionIO *inSource, const translator_info *inInfo, 1130 BMessage *ioExtension, uint32 outType, BPositionIO *outDestination) 1131 { 1132 // If no specific type was requested, convert to the interchange format 1133 if (outType == 0) 1134 outType = B_TRANSLATOR_BITMAP; 1135 1136 // What action to take, based on the findings of Identify() 1137 if (outType == inInfo->type) 1138 return Copy(inSource, outDestination); 1139 if (inInfo->type == B_TRANSLATOR_BITMAP && outType == JP2_FORMAT) 1140 return Compress(inSource, outDestination); 1141 if (inInfo->type == JP2_FORMAT && outType == B_TRANSLATOR_BITMAP) 1142 return Decompress(inSource, outDestination); 1143 1144 return B_NO_TRANSLATOR; 1145 } 1146 1147 1148 //! The user has requested the same format for input and output, so just copy 1149 status_t 1150 Copy(BPositionIO *in, BPositionIO *out) 1151 { 1152 int block_size = 65536; 1153 void *buffer = malloc(block_size); 1154 char temp[1024]; 1155 if (buffer == NULL) { 1156 buffer = temp; 1157 block_size = 1024; 1158 } 1159 status_t err = B_OK; 1160 1161 // Read until end of file or error 1162 while (1) { 1163 ssize_t to_read = block_size; 1164 err = in->Read(buffer, to_read); 1165 // Explicit check for EOF 1166 if (err == -1) { 1167 if (buffer != temp) 1168 free(buffer); 1169 return B_OK; 1170 } 1171 if (err <= B_OK) break; 1172 to_read = err; 1173 err = out->Write(buffer, to_read); 1174 if (err != to_read) if (err >= 0) err = B_DEVICE_FULL; 1175 if (err < B_OK) break; 1176 } 1177 1178 if (buffer != temp) 1179 free(buffer); 1180 return (err >= 0) ? B_OK : err; 1181 } 1182 1183 1184 //! Encode into the native format 1185 status_t 1186 Compress(BPositionIO *in, BPositionIO *out) 1187 { 1188 // Load settings 1189 jpeg_settings settings; 1190 LoadSettings(&settings); 1191 1192 // Read info about bitmap 1193 TranslatorBitmap header; 1194 status_t err = in->Read(&header, sizeof(TranslatorBitmap)); 1195 if (err < B_OK) 1196 return err; 1197 if (err < (int)sizeof(TranslatorBitmap)) 1198 return B_ERROR; 1199 1200 // Grab dimension, color space, and size information from the stream 1201 BRect bounds; 1202 bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left); 1203 bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top); 1204 bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right); 1205 bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom); 1206 1207 int32 in_row_bytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes); 1208 1209 int width = bounds.IntegerWidth() + 1; 1210 int height = bounds.IntegerHeight() + 1; 1211 1212 // Function pointer to write function 1213 // It MUST point to proper function 1214 void (*converter)(jas_matrix_t **pixels, jpr_uchar_t *inscanline, 1215 int width) = write_rgba32; 1216 1217 // Default color info 1218 int out_color_space = JAS_IMAGE_CS_RGB; 1219 int out_color_components = 3; 1220 1221 switch ((color_space)B_BENDIAN_TO_HOST_INT32(header.colors)) { 1222 case B_GRAY1: 1223 if (settings.B_GRAY1_as_B_RGB24) { 1224 converter = write_gray1_to_rgb24; 1225 } else { 1226 out_color_components = 1; 1227 out_color_space = JAS_IMAGE_CS_GRAY; 1228 converter = write_gray1_to_gray; 1229 } 1230 break; 1231 1232 case B_CMAP8: 1233 converter = write_cmap8_to_rgb24; 1234 break; 1235 1236 case B_GRAY8: 1237 out_color_components = 1; 1238 out_color_space = JAS_IMAGE_CS_GRAY; 1239 converter = write_gray; 1240 break; 1241 1242 case B_RGB15: 1243 case B_RGBA15: 1244 converter = write_rgb15_to_rgb24; 1245 break; 1246 1247 case B_RGB15_BIG: 1248 case B_RGBA15_BIG: 1249 converter = write_rgb15b_to_rgb24; 1250 break; 1251 1252 case B_RGB16: 1253 converter = write_rgb16_to_rgb24; 1254 break; 1255 1256 case B_RGB16_BIG: 1257 converter = write_rgb16b_to_rgb24; 1258 break; 1259 1260 case B_RGB24: 1261 converter = write_rgb24; 1262 break; 1263 1264 case B_RGB24_BIG: 1265 converter = write_rgb24b; 1266 break; 1267 1268 case B_RGB32: 1269 converter = write_rgb32_to_rgb24; 1270 break; 1271 1272 case B_RGB32_BIG: 1273 converter = write_rgb32b_to_rgb24; 1274 break; 1275 1276 case B_RGBA32: 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_rgba32; 1285 */ 1286 converter = write_rgb32_to_rgb24; 1287 break; 1288 1289 case B_RGBA32_BIG: 1290 /* 1291 // In theory it should be possible to write 4 color components 1292 // to jp2, so it should be possible to have transparency. 1293 // Unfortunetly libjasper does not agree with that 1294 // For now i don't know how to modify it :( 1295 1296 out_color_components = 4; 1297 converter = write_rgba32b; 1298 */ 1299 converter = write_rgb32b_to_rgb24; 1300 break; 1301 1302 default: 1303 (new BAlert("Error", "Unknown color space.", "Quit"))->Go(); 1304 return B_ERROR; 1305 } 1306 1307 jas_image_t *image; 1308 jas_stream_t *outs; 1309 jas_matrix_t *pixels[4]; 1310 jas_image_cmptparm_t component_info[4]; 1311 1312 if (jas_init()) 1313 return B_ERROR; 1314 1315 if (!(outs = jas_stream_positionIOopen(out))) 1316 return B_ERROR; 1317 1318 int32 i = 0; 1319 for (i = 0; i < (long)out_color_components; i++) { 1320 (void) memset(component_info + i, 0, sizeof(jas_image_cmptparm_t)); 1321 component_info[i].hstep = 1; 1322 component_info[i].vstep = 1; 1323 component_info[i].width = (unsigned int)width; 1324 component_info[i].height = (unsigned int)height; 1325 component_info[i].prec = (unsigned int)8; 1326 } 1327 1328 image = jas_image_create((short)out_color_components, component_info, 1329 out_color_space); 1330 if (image == (jas_image_t *)NULL) 1331 return Error(outs, NULL, NULL, 0, NULL, B_ERROR); 1332 1333 jpr_uchar_t *in_scanline = (jpr_uchar_t*) malloc(in_row_bytes); 1334 if (in_scanline == NULL) 1335 return Error(outs, image, NULL, 0, NULL, B_ERROR); 1336 1337 for (i = 0; i < (long)out_color_components; i++) { 1338 pixels[i] = jas_matrix_create(1, (unsigned int)width); 1339 if (pixels[i] == (jas_matrix_t *)NULL) 1340 return Error(outs, image, pixels, i+1, in_scanline, B_ERROR); 1341 } 1342 1343 int32 y = 0; 1344 for (y = 0; y < (long)height; y++) { 1345 err = in->Read(in_scanline, in_row_bytes); 1346 if (err < in_row_bytes) { 1347 return (err < B_OK) ? 1348 Error(outs, image, pixels, out_color_components, in_scanline, 1349 err) 1350 : Error(outs, image, pixels, out_color_components, in_scanline, 1351 B_ERROR); 1352 } 1353 1354 converter(pixels, in_scanline, width); 1355 1356 for (i = 0; i < (long)out_color_components; i++) { 1357 (void)jas_image_writecmpt(image, (short)i, 0, (unsigned int)y, 1358 (unsigned int)width, 1, pixels[i]); 1359 } 1360 } 1361 1362 char opts[16]; 1363 sprintf(opts, "rate=%1f", (float)settings.Quality / 100.0); 1364 if (jas_image_encode(image, outs, jas_image_strtofmt(settings.JPC ? 1365 (char*)"jpc" : (char*)"jp2"), opts)) { 1366 return Error(outs, image, pixels, out_color_components, in_scanline, err); 1367 } 1368 1369 free(in_scanline); 1370 1371 for (i = 0; i < (long)out_color_components; i++) 1372 jas_matrix_destroy(pixels[i]); 1373 1374 jas_stream_close(outs); 1375 jas_image_destroy(image); 1376 jas_image_clearfmts(); 1377 1378 return B_OK; 1379 } 1380 1381 1382 //! Decode the native format 1383 status_t 1384 Decompress(BPositionIO *in, BPositionIO *out) 1385 { 1386 jpeg_settings settings; 1387 LoadSettings(&settings); 1388 1389 jas_image_t *image; 1390 jas_stream_t *ins; 1391 jas_matrix_t *pixels[4]; 1392 1393 if (jas_init()) 1394 return B_ERROR; 1395 1396 if (!(ins = jas_stream_positionIOopen(in))) 1397 return B_ERROR; 1398 1399 if (!(image = jas_image_decode(ins, -1, 0))) 1400 return Error(ins, NULL, NULL, 0, NULL, B_ERROR); 1401 1402 // Default color info 1403 color_space out_color_space; 1404 int out_color_components; 1405 int in_color_components = jas_image_numcmpts(image); 1406 1407 // Function pointer to read function 1408 // It MUST point to proper function 1409 void (*converter)(jas_matrix_t **pixels, jpr_uchar_t *outscanline, 1410 int width) = NULL; 1411 1412 switch (jas_image_colorspace(image)) { 1413 case JAS_IMAGE_CS_RGB: 1414 out_color_components = 4; 1415 if (in_color_components == 3) { 1416 out_color_space = B_RGB32; 1417 converter = read_rgb24_to_rgb32; 1418 } else if (in_color_components == 4) { 1419 out_color_space = B_RGBA32; 1420 converter = read_rgba32; 1421 } else { 1422 (new BAlert("Error", "Other than RGB with 3 or 4 color " 1423 "components not implemented.", "Quit"))->Go(); 1424 return Error(ins, image, NULL, 0, NULL, B_ERROR); 1425 } 1426 break; 1427 case JAS_IMAGE_CS_GRAY: 1428 if (settings.B_GRAY8_as_B_RGB32) { 1429 out_color_space = B_RGB32; 1430 out_color_components = 4; 1431 converter = read_gray_to_rgb32; 1432 } else { 1433 out_color_space = B_GRAY8; 1434 out_color_components = 1; 1435 converter = read_gray; 1436 } 1437 break; 1438 case JAS_IMAGE_CS_YCBCR: 1439 (new BAlert("Error", "color space YCBCR not implemented yet.", 1440 "Quit"))->Go(); 1441 return Error(ins, image, NULL, 0, NULL, B_ERROR); 1442 break; 1443 case JAS_IMAGE_CS_UNKNOWN: 1444 default: 1445 (new BAlert("Error", "color space unknown.", "Quit"))->Go(); 1446 return Error(ins, image, NULL, 0, NULL, B_ERROR); 1447 break; 1448 } 1449 1450 float width = (float)jas_image_width(image); 1451 float height = (float)jas_image_height(image); 1452 1453 // Bytes count in one line of image (scanline) 1454 int64 out_row_bytes = (int32)width * out_color_components; 1455 // NOTE: things will go wrong if "out_row_bytes" wouldn't fit into 32 bits 1456 1457 // !!! Initialize this bounds rect to the size of your image 1458 BRect bounds(0, 0, width-1, height-1); 1459 1460 // Fill out the B_TRANSLATOR_BITMAP's header 1461 TranslatorBitmap header; 1462 header.magic = B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP); 1463 header.bounds.left = B_HOST_TO_BENDIAN_FLOAT(bounds.left); 1464 header.bounds.top = B_HOST_TO_BENDIAN_FLOAT(bounds.top); 1465 header.bounds.right = B_HOST_TO_BENDIAN_FLOAT(bounds.right); 1466 header.bounds.bottom = B_HOST_TO_BENDIAN_FLOAT(bounds.bottom); 1467 header.colors = (color_space)B_HOST_TO_BENDIAN_INT32(out_color_space); 1468 header.rowBytes = B_HOST_TO_BENDIAN_INT32(out_row_bytes); 1469 header.dataSize = B_HOST_TO_BENDIAN_INT32((int32)(out_row_bytes * height)); 1470 1471 // Write out the header 1472 status_t err = out->Write(&header, sizeof(TranslatorBitmap)); 1473 if (err < B_OK) 1474 return Error(ins, image, NULL, 0, NULL, err); 1475 if (err < (int)sizeof(TranslatorBitmap)) 1476 return Error(ins, image, NULL, 0, NULL, B_ERROR); 1477 1478 jpr_uchar_t *out_scanline = (jpr_uchar_t*) malloc(out_row_bytes); 1479 if (out_scanline == NULL) 1480 return Error(ins, image, NULL, 0, NULL, B_ERROR); 1481 1482 int32 i = 0; 1483 for (i = 0; i < (long)in_color_components; i++) { 1484 pixels[i] = jas_matrix_create(1, (unsigned int)width); 1485 if (pixels[i] == (jas_matrix_t *)NULL) 1486 return Error(ins, image, pixels, i+1, out_scanline, B_ERROR); 1487 } 1488 1489 int32 y = 0; 1490 for (y = 0; y < (long)height; y++) { 1491 for (i = 0; i < (long)in_color_components; i++) { 1492 (void)jas_image_readcmpt(image, (short)i, 0, (unsigned int)y, 1493 (unsigned int)width, 1, pixels[i]); 1494 } 1495 1496 converter(pixels, out_scanline, (int32)width); 1497 1498 err = out->Write(out_scanline, out_row_bytes); 1499 if (err < out_row_bytes) { 1500 return (err < B_OK) ? 1501 Error(ins, image, pixels, in_color_components, out_scanline, 1502 err) 1503 : Error(ins, image, pixels, in_color_components, out_scanline, 1504 B_ERROR); 1505 } 1506 } 1507 1508 free(out_scanline); 1509 1510 for (i = 0; i < (long)in_color_components; i++) 1511 jas_matrix_destroy(pixels[i]); 1512 1513 jas_stream_close(ins); 1514 jas_image_destroy(image); 1515 jas_image_clearfmts(); 1516 1517 return B_OK; 1518 } 1519 1520 1521 /*! 1522 Frees jpeg alocated memory 1523 Returns given error (B_ERROR by default) 1524 */ 1525 status_t 1526 Error(jas_stream_t *stream, jas_image_t *image, jas_matrix_t **pixels, 1527 int32 pixels_count, jpr_uchar_t *scanline, status_t error) 1528 { 1529 if (pixels) { 1530 int32 i; 1531 for (i = 0; i < (long)pixels_count; i++) { 1532 if (pixels[i] != NULL) 1533 jas_matrix_destroy(pixels[i]); 1534 } 1535 } 1536 if (stream) 1537 jas_stream_close(stream); 1538 if (image) 1539 jas_image_destroy(image); 1540 1541 jas_image_clearfmts(); 1542 free(scanline); 1543 1544 return error; 1545 } 1546 1547 1548 // #pragma mark - 1549 1550 1551 int 1552 main() 1553 { 1554 BApplication app("application/x-vnd.Haiku-JPEG2000Translator"); 1555 1556 TranslatorWindow *window = new TranslatorWindow(); 1557 window->Show(); 1558 1559 app.Run(); 1560 return 0; 1561 } 1562 1563