1 /*****************************************************************************/ 2 // PNGTranslator 3 // Written by Michael Wilber, Haiku Translation Kit Team 4 // 5 // PNGTranslator.cpp 6 // 7 // This BTranslator based object is for opening and writing 8 // PNG images. 9 // 10 // 11 // Copyright (c) 2003, Haiku Project 12 // Copyright (c) 2009, Haiku, Inc. All rights reserved. 13 // 14 // Permission is hereby granted, free of charge, to any person obtaining a 15 // copy of this software and associated documentation files (the "Software"), 16 // to deal in the Software without restriction, including without limitation 17 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 18 // and/or sell copies of the Software, and to permit persons to whom the 19 // Software is furnished to do so, subject to the following conditions: 20 // 21 // The above copyright notice and this permission notice shall be included 22 // in all copies or substantial portions of the Software. 23 // 24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 25 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 27 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 29 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 30 // DEALINGS IN THE SOFTWARE. 31 /*****************************************************************************/ 32 33 34 #include "PNGTranslator.h" 35 36 #include <stdio.h> 37 #include <string.h> 38 39 #include <Catalog.h> 40 #include <OS.h> 41 #define PNG_NO_PEDANTIC_WARNINGS 42 #include <png.h> 43 44 #include "PNGView.h" 45 46 #undef B_TRANSLATION_CONTEXT 47 #define B_TRANSLATION_CONTEXT "PNGTranslator" 48 49 // The input formats that this translator supports. 50 static const translation_format sInputFormats[] = { 51 { 52 B_PNG_FORMAT, 53 B_TRANSLATOR_BITMAP, 54 PNG_IN_QUALITY, 55 PNG_IN_CAPABILITY, 56 "image/png", 57 "PNG image" 58 }, 59 { 60 B_PNG_FORMAT, 61 B_TRANSLATOR_BITMAP, 62 PNG_IN_QUALITY, 63 PNG_IN_CAPABILITY, 64 "image/x-png", 65 "PNG image" 66 }, 67 { 68 B_TRANSLATOR_BITMAP, 69 B_TRANSLATOR_BITMAP, 70 BBT_IN_QUALITY, 71 BBT_IN_CAPABILITY, 72 "image/x-be-bitmap", 73 "Be Bitmap Format (PNGTranslator)" 74 } 75 }; 76 77 // The output formats that this translator supports. 78 static const translation_format sOutputFormats[] = { 79 { 80 B_PNG_FORMAT, 81 B_TRANSLATOR_BITMAP, 82 PNG_OUT_QUALITY, 83 PNG_OUT_CAPABILITY, 84 "image/png", 85 "PNG image" 86 }, 87 { 88 B_TRANSLATOR_BITMAP, 89 B_TRANSLATOR_BITMAP, 90 BBT_OUT_QUALITY, 91 BBT_OUT_CAPABILITY, 92 "image/x-be-bitmap", 93 "Be Bitmap Format (PNGTranslator)" 94 } 95 }; 96 97 // Default settings for the Translator 98 static const TranSetting sDefaultSettings[] = { 99 {B_TRANSLATOR_EXT_HEADER_ONLY, TRAN_SETTING_BOOL, false}, 100 {B_TRANSLATOR_EXT_DATA_ONLY, TRAN_SETTING_BOOL, false}, 101 {PNG_SETTING_INTERLACE, TRAN_SETTING_INT32, PNG_INTERLACE_NONE} 102 // interlacing is off by default 103 }; 104 105 const uint32 kNumInputFormats = sizeof(sInputFormats) / sizeof(translation_format); 106 const uint32 kNumOutputFormats = sizeof(sOutputFormats) / sizeof(translation_format); 107 const uint32 kNumDefaultSettings = sizeof(sDefaultSettings) / sizeof(TranSetting); 108 109 110 // --------------------------------------------------------------- 111 // make_nth_translator 112 // 113 // Creates a PNGTranslator object to be used by BTranslatorRoster 114 // 115 // Preconditions: 116 // 117 // Parameters: n, The translator to return. Since 118 // PNGTranslator only publishes one 119 // translator, it only returns a 120 // PNGTranslator if n == 0 121 // 122 // you, The image_id of the add-on that 123 // contains code (not used). 124 // 125 // flags, Has no meaning yet, should be 0. 126 // 127 // Postconditions: 128 // 129 // Returns: NULL if n is not zero, 130 // a new PNGTranslator if n is zero 131 // --------------------------------------------------------------- 132 BTranslator * 133 make_nth_translator(int32 n, image_id you, uint32 flags, ...) 134 { 135 if (!n) 136 return new(std::nothrow) PNGTranslator(); 137 else 138 return NULL; 139 } 140 141 /* The png_jmpbuf() macro, used in error handling, became available in 142 * libpng version 1.0.6. If you want to be able to run your code with older 143 * versions of libpng, you must define the macro yourself (but only if it 144 * is not already defined by libpng!). 145 */ 146 147 #ifndef png_jmpbuf 148 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) 149 #endif 150 151 //// libpng Callback functions! 152 153 BPositionIO * 154 get_pio(png_structp ppng) 155 { 156 BPositionIO *pio = NULL; 157 pio = static_cast<BPositionIO *>(png_get_io_ptr(ppng)); 158 return pio; 159 } 160 161 void 162 pngcb_read_data(png_structp ppng, png_bytep pdata, png_size_t length) 163 { 164 BPositionIO *pio = get_pio(ppng); 165 pio->Read(pdata, static_cast<size_t>(length)); 166 } 167 168 void 169 pngcb_write_data(png_structp ppng, png_bytep pdata, png_size_t length) 170 { 171 BPositionIO *pio = get_pio(ppng); 172 pio->Write(pdata, static_cast<size_t>(length)); 173 } 174 175 void 176 pngcb_flush_data(png_structp ppng) 177 { 178 // I don't think I really need to do anything here 179 } 180 181 // --------------------------------------------------------------- 182 // Constructor 183 // 184 // Sets up the version info and the name of the translator so that 185 // these values can be returned when they are requested. 186 // 187 // Preconditions: 188 // 189 // Parameters: 190 // 191 // Postconditions: 192 // 193 // Returns: 194 // --------------------------------------------------------------- 195 PNGTranslator::PNGTranslator() 196 : BaseTranslator(B_TRANSLATE("PNG images"), 197 B_TRANSLATE("PNG image translator"), 198 PNG_TRANSLATOR_VERSION, 199 sInputFormats, kNumInputFormats, 200 sOutputFormats, kNumOutputFormats, 201 "PNGTranslator_Settings", 202 sDefaultSettings, kNumDefaultSettings, 203 B_TRANSLATOR_BITMAP, B_PNG_FORMAT) 204 { 205 } 206 207 // --------------------------------------------------------------- 208 // Destructor 209 // 210 // Does nothing 211 // 212 // Preconditions: 213 // 214 // Parameters: 215 // 216 // Postconditions: 217 // 218 // Returns: 219 // --------------------------------------------------------------- 220 PNGTranslator::~PNGTranslator() 221 { 222 } 223 224 status_t 225 identify_png_header(BPositionIO *inSource, translator_info *outInfo) 226 { 227 const int32 kSigSize = 8; 228 uint8 buf[kSigSize]; 229 if (inSource->Read(buf, kSigSize) != kSigSize) 230 return B_NO_TRANSLATOR; 231 if (png_sig_cmp(buf, 0, kSigSize)) 232 // if first 8 bytes of stream don't match PNG signature bail 233 return B_NO_TRANSLATOR; 234 235 if (outInfo) { 236 outInfo->type = B_PNG_FORMAT; 237 outInfo->group = B_TRANSLATOR_BITMAP; 238 outInfo->quality = PNG_IN_QUALITY; 239 outInfo->capability = PNG_IN_CAPABILITY; 240 strcpy(outInfo->MIME, "image/png"); 241 strlcpy(outInfo->name, B_TRANSLATE("PNG image"), 242 sizeof(outInfo->name)); 243 } 244 245 return B_OK; 246 } 247 248 // --------------------------------------------------------------- 249 // DerivedIdentify 250 // 251 // Examines the data from inSource and determines if it is in a 252 // format that this translator knows how to work with. 253 // 254 // Preconditions: 255 // 256 // Parameters: inSource, where the data to examine is 257 // 258 // inFormat, a hint about the data in inSource, 259 // it is ignored since it is only a hint 260 // 261 // ioExtension, configuration settings for the 262 // translator (not used) 263 // 264 // outInfo, information about what data is in 265 // inSource and how well this translator 266 // can handle that data is stored here 267 // 268 // outType, The format that the user wants 269 // the data in inSource to be 270 // converted to 271 // 272 // Postconditions: 273 // 274 // Returns: B_NO_TRANSLATOR, if this translator can't handle 275 // the data in inSource 276 // 277 // B_ERROR, if there was an error converting the data to the host 278 // format 279 // 280 // B_BAD_VALUE, if the settings in ioExtension are bad 281 // 282 // B_OK, if this translator understood the data and there were 283 // no errors found 284 // 285 // Other errors if BPositionIO::Read() returned an error value 286 // --------------------------------------------------------------- 287 status_t 288 PNGTranslator::DerivedIdentify(BPositionIO *inSource, 289 const translation_format *inFormat, BMessage *ioExtension, 290 translator_info *outInfo, uint32 outType) 291 { 292 return identify_png_header(inSource, outInfo); 293 } 294 295 void throw_error(png_structp ppng, png_const_charp error_msg) 296 { 297 throw std::exception(); 298 } 299 300 void alert_warning(png_structp ppng, png_const_charp error_msg) 301 { 302 // These are only warnings and the image can still be decoded. We have no 303 // way to convey this to the calling app using the current translator API, 304 // so the warnings are just ignored. 305 } 306 307 status_t 308 PNGTranslator::translate_from_png_to_bits(BPositionIO *inSource, 309 BPositionIO *outDestination) 310 { 311 if (identify_png_header(inSource, NULL) != B_OK) 312 return B_NO_TRANSLATOR; 313 314 status_t result = B_ERROR; 315 // if a libpng errors before this is set 316 // to a different value, the above is what 317 // will be returned from this function 318 319 bool bheaderonly = false, bdataonly = false; 320 321 // for storing decoded PNG row data 322 uint8 **prows = NULL, *prow = NULL; 323 png_uint_32 nalloc = 0; 324 325 png_structp ppng = NULL; 326 png_infop pinfo = NULL; 327 while (ppng == NULL) { 328 // create PNG read pointer with default error handling routines 329 ppng = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 330 if (!ppng) 331 break; 332 333 // alocate / init memory for image information 334 pinfo = png_create_info_struct(ppng); 335 if (!pinfo) 336 break; 337 338 // set up erorr handling to use C++ exceptions instead of setjmp 339 png_set_error_fn(ppng, png_get_error_ptr(ppng), throw_error, 340 alert_warning); 341 342 try { 343 // set read callback function 344 png_set_read_fn(ppng, static_cast<void *>(inSource), pngcb_read_data); 345 346 // Read in PNG image info 347 png_set_sig_bytes(ppng, 8); 348 png_read_info(ppng, pinfo); 349 350 png_uint_32 width, height; 351 int bit_depth, color_type, interlace_type; 352 png_get_IHDR(ppng, pinfo, &width, &height, &bit_depth, &color_type, 353 &interlace_type, NULL, NULL); 354 355 // Setup image transformations to make converting it easier 356 bool balpha = false; 357 358 if (bit_depth == 16) 359 png_set_strip_16(ppng); 360 else if (bit_depth < 8) 361 png_set_packing(ppng); 362 363 if (color_type == PNG_COLOR_TYPE_PALETTE) 364 png_set_palette_to_rgb(ppng); 365 366 if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { 367 // In order to convert from low-depth gray images to RGB, 368 // I first need to convert them to grayscale, 8 bpp 369 png_set_expand_gray_1_2_4_to_8(ppng); 370 } 371 372 if (png_get_valid(ppng, pinfo, PNG_INFO_tRNS)) { 373 // if there is transparency data in the 374 // PNG, but not in the form of an alpha channel 375 balpha = true; 376 png_set_tRNS_to_alpha(ppng); 377 } 378 379 // change RGB to BGR as it is in 'bits' 380 if (color_type & PNG_COLOR_MASK_COLOR) 381 png_set_bgr(ppng); 382 383 // have libpng convert gray to RGB for me 384 if (color_type == PNG_COLOR_TYPE_GRAY || 385 color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { 386 png_set_gray_to_rgb(ppng); 387 } 388 389 if (color_type & PNG_COLOR_MASK_ALPHA) { 390 // if image contains an alpha channel 391 balpha = true; 392 } 393 394 if (!balpha) { 395 // add filler byte for images without alpha 396 // so that the pixels are 4 bytes each 397 png_set_filler(ppng, 0xff, PNG_FILLER_AFTER); 398 } 399 400 // Check that transformed PNG rowbytes matches 401 // what is expected 402 const int32 kbytes = 4; 403 png_uint_32 rowbytes = png_get_rowbytes(ppng, pinfo); 404 if (rowbytes < kbytes * width) 405 rowbytes = kbytes * width; 406 407 if (!bdataonly) { 408 // Write out the data to outDestination 409 // Construct and write Be bitmap header 410 TranslatorBitmap bitsHeader; 411 bitsHeader.magic = B_TRANSLATOR_BITMAP; 412 bitsHeader.bounds.left = 0; 413 bitsHeader.bounds.top = 0; 414 bitsHeader.bounds.right = width - 1; 415 bitsHeader.bounds.bottom = height - 1; 416 bitsHeader.rowBytes = 4 * width; 417 if (balpha) 418 bitsHeader.colors = B_RGBA32; 419 else 420 bitsHeader.colors = B_RGB32; 421 bitsHeader.dataSize = bitsHeader.rowBytes * height; 422 if (swap_data(B_UINT32_TYPE, &bitsHeader, 423 sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN) != B_OK) { 424 result = B_ERROR; 425 break; 426 } 427 outDestination->Write(&bitsHeader, sizeof(TranslatorBitmap)); 428 429 if (bheaderonly) { 430 result = B_OK; 431 break; 432 } 433 } 434 435 if (interlace_type == PNG_INTERLACE_NONE) { 436 // allocate buffer for storing PNG row 437 prow = new(std::nothrow) uint8[rowbytes]; 438 if (!prow) { 439 result = B_NO_MEMORY; 440 break; 441 } 442 for (png_uint_32 i = 0; i < height; i++) { 443 png_read_row(ppng, prow, NULL); 444 outDestination->Write(prow, width * kbytes); 445 } 446 447 // finish reading, pass NULL for info because I 448 // don't need the extra data 449 png_read_end(ppng, NULL); 450 result = B_OK; 451 452 break; 453 454 } else { 455 // interlaced PNG image 456 prows = new(std::nothrow) uint8 *[height]; 457 if (!prows) { 458 result = B_NO_MEMORY; 459 break; 460 } 461 // allocate enough memory to store the whole image 462 for (nalloc = 0; nalloc < height; nalloc++) { 463 prows[nalloc] = new(std::nothrow) uint8[rowbytes]; 464 if (!prows[nalloc]) 465 break; 466 } 467 468 if (nalloc < height) 469 result = B_NO_MEMORY; 470 else { 471 png_read_image(ppng, prows); 472 473 for (png_uint_32 i = 0; i < height; i++) 474 outDestination->Write(prows[i], width * kbytes); 475 476 result = B_OK; 477 // If png_read_end throws an exception, we still accept 478 // the image as valid. 479 png_read_end(ppng, NULL); 480 } 481 482 break; 483 } 484 } catch (std::exception& e) { 485 // An error occured, abort decoding and cleanup 486 break; 487 } 488 } 489 490 if (ppng) { 491 delete[] prow; 492 prow = NULL; 493 494 // delete row pointers and array of pointers to rows 495 while (nalloc) { 496 nalloc--; 497 delete[] prows[nalloc]; 498 } 499 delete[] prows; 500 prows = NULL; 501 502 // free PNG handle / info structures 503 if (!pinfo) 504 png_destroy_read_struct(&ppng, NULL, NULL); 505 else 506 png_destroy_read_struct(&ppng, &pinfo, NULL); 507 } 508 509 return result; 510 } 511 512 status_t 513 PNGTranslator::translate_from_png(BPositionIO *inSource, uint32 outType, 514 BPositionIO *outDestination) 515 { 516 if (outType == B_TRANSLATOR_BITMAP) 517 return translate_from_png_to_bits(inSource, outDestination); 518 else { 519 // Translate from PNG to PNG 520 translate_direct_copy(inSource, outDestination); 521 return B_OK; 522 } 523 } 524 525 // Convert width pixels from pbits to PNG format, storing the 526 // result in ppng 527 status_t 528 pix_bits_to_png(uint8 *pbits, uint8 *ppng, color_space fromspace, 529 uint32 width, const color_map *pmap, int32 bitsBytesPerPixel) 530 { 531 status_t bytescopied = 0; 532 uint16 val; 533 534 switch (fromspace) { 535 case B_RGBA32: 536 bytescopied = width * bitsBytesPerPixel; 537 memcpy(ppng, pbits, bytescopied); 538 break; 539 540 case B_RGB32: 541 case B_RGB24: 542 bytescopied = width * bitsBytesPerPixel; 543 while (width--) { 544 memcpy(ppng, pbits, 3); 545 ppng += 3; 546 pbits += bitsBytesPerPixel; 547 } 548 break; 549 550 case B_RGBA32_BIG: 551 bytescopied = width * 4; 552 while (width--) { 553 ppng[0] = pbits[3]; 554 ppng[1] = pbits[2]; 555 ppng[2] = pbits[1]; 556 ppng[3] = pbits[0]; 557 558 ppng += 4; 559 pbits += 4; 560 } 561 break; 562 563 case B_CMYA32: 564 bytescopied = width * 4; 565 while (width--) { 566 ppng[0] = 255 - pbits[2]; 567 ppng[1] = 255 - pbits[1]; 568 ppng[2] = 255 - pbits[0]; 569 ppng[3] = pbits[3]; 570 571 ppng += 4; 572 pbits += 4; 573 } 574 break; 575 576 case B_CMYK32: 577 { 578 int32 comp; 579 bytescopied = width * 3; 580 while (width--) { 581 comp = 255 - pbits[2] - pbits[3]; 582 ppng[0] = (comp < 0) ? 0 : comp; 583 584 comp = 255 - pbits[1] - pbits[3]; 585 ppng[1] = (comp < 0) ? 0 : comp; 586 587 comp = 255 - pbits[0] - pbits[3]; 588 ppng[2] = (comp < 0) ? 0 : comp; 589 590 ppng += 3; 591 pbits += 4; 592 } 593 break; 594 } 595 596 case B_CMY32: 597 case B_CMY24: 598 bytescopied = width * 3; 599 while (width--) { 600 ppng[0] = 255 - pbits[2]; 601 ppng[1] = 255 - pbits[1]; 602 ppng[2] = 255 - pbits[0]; 603 604 ppng += 3; 605 pbits += bitsBytesPerPixel; 606 } 607 break; 608 609 case B_RGB16: 610 case B_RGB16_BIG: 611 bytescopied = width * 3; 612 while (width--) { 613 if (fromspace == B_RGB16) 614 val = pbits[0] + (pbits[1] << 8); 615 else 616 val = pbits[1] + (pbits[0] << 8); 617 618 ppng[0] = 619 ((val & 0x1f) << 3) | ((val & 0x1f) >> 2); 620 ppng[1] = 621 ((val & 0x7e0) >> 3) | ((val & 0x7e0) >> 9); 622 ppng[2] = 623 ((val & 0xf800) >> 8) | ((val & 0xf800) >> 13); 624 625 ppng += 3; 626 pbits += 2; 627 } 628 break; 629 630 case B_RGB15: 631 case B_RGB15_BIG: 632 bytescopied = width * 3; 633 while (width--) { 634 if (fromspace == B_RGB15) 635 val = pbits[0] + (pbits[1] << 8); 636 else 637 val = pbits[1] + (pbits[0] << 8); 638 ppng[0] = 639 ((val & 0x1f) << 3) | ((val & 0x1f) >> 2); 640 ppng[1] = 641 ((val & 0x3e0) >> 2) | ((val & 0x3e0) >> 7); 642 ppng[2] = 643 ((val & 0x7c00) >> 7) | ((val & 0x7c00) >> 12); 644 645 ppng += 3; 646 pbits += 2; 647 } 648 break; 649 650 case B_RGBA15: 651 case B_RGBA15_BIG: 652 bytescopied = width * 4; 653 while (width--) { 654 if (fromspace == B_RGBA15) 655 val = pbits[0] + (pbits[1] << 8); 656 else 657 val = pbits[1] + (pbits[0] << 8); 658 ppng[0] = 659 ((val & 0x1f) << 3) | ((val & 0x1f) >> 2); 660 ppng[1] = 661 ((val & 0x3e0) >> 2) | ((val & 0x3e0) >> 7); 662 ppng[2] = 663 ((val & 0x7c00) >> 7) | ((val & 0x7c00) >> 12); 664 ppng[3] = (val & 0x8000) ? 255 : 0; 665 666 ppng += 4; 667 pbits += 2; 668 } 669 break; 670 671 case B_RGB32_BIG: 672 bytescopied = width * 3; 673 while (width--) { 674 ppng[0] = pbits[3]; 675 ppng[1] = pbits[2]; 676 ppng[2] = pbits[1]; 677 678 ppng += 3; 679 pbits += 4; 680 } 681 break; 682 683 case B_RGB24_BIG: 684 bytescopied = width * 3; 685 while (width--) { 686 ppng[0] = pbits[2]; 687 ppng[1] = pbits[1]; 688 ppng[2] = pbits[0]; 689 690 ppng += 3; 691 pbits += 3; 692 } 693 break; 694 695 case B_CMAP8: 696 { 697 rgb_color c; 698 bytescopied = width * 3; 699 while (width--) { 700 c = pmap->color_list[pbits[0]]; 701 ppng[0] = c.blue; 702 ppng[1] = c.green; 703 ppng[2] = c.red; 704 705 ppng += 3; 706 pbits++; 707 } 708 break; 709 } 710 711 case B_GRAY8: 712 bytescopied = width; 713 memcpy(ppng, pbits, bytescopied); 714 break; 715 716 default: 717 bytescopied = B_ERROR; 718 break; 719 } // switch (fromspace) 720 721 return bytescopied; 722 } 723 724 status_t 725 PNGTranslator::translate_from_bits_to_png(BPositionIO *inSource, 726 BPositionIO *outDestination) 727 { 728 TranslatorBitmap bitsHeader; 729 730 status_t result; 731 732 result = identify_bits_header(inSource, NULL, &bitsHeader); 733 if (result != B_OK) 734 return result; 735 736 const color_map *pmap = NULL; 737 if (bitsHeader.colors == B_CMAP8) { 738 pmap = system_colors(); 739 if (!pmap) 740 return B_ERROR; 741 } 742 743 png_uint_32 width, height; 744 width = static_cast<png_uint_32>(bitsHeader.bounds.Width() + 1); 745 height = static_cast<png_uint_32>(bitsHeader.bounds.Height() + 1); 746 747 int32 pngBytesPerPixel = 0; 748 int bit_depth, color_type, interlace_type; 749 bit_depth = 8; 750 switch (bitsHeader.colors) { 751 case B_RGBA32: 752 case B_RGBA32_BIG: 753 case B_CMYA32: 754 case B_RGBA15: 755 case B_RGBA15_BIG: 756 pngBytesPerPixel = 4; 757 color_type = PNG_COLOR_TYPE_RGB_ALPHA; 758 break; 759 760 case B_RGB32: 761 case B_RGB32_BIG: 762 case B_RGB24: 763 case B_RGB24_BIG: 764 case B_CMY32: 765 case B_CMYK32: 766 case B_CMY24: 767 case B_RGB16: 768 case B_RGB16_BIG: 769 case B_RGB15: 770 case B_RGB15_BIG: 771 pngBytesPerPixel = 3; 772 color_type = PNG_COLOR_TYPE_RGB; 773 break; 774 775 // ADD SUPPORT FOR B_CMAP8 HERE (later) 776 777 case B_GRAY8: 778 pngBytesPerPixel = 1; 779 color_type = PNG_COLOR_TYPE_GRAY; 780 break; 781 782 default: 783 return B_NO_TRANSLATOR; 784 } 785 interlace_type = fSettings->SetGetInt32(PNG_SETTING_INTERLACE); 786 787 int32 bitsBytesPerPixel = 0; 788 switch (bitsHeader.colors) { 789 case B_RGBA32: 790 case B_RGBA32_BIG: 791 case B_RGB32: 792 case B_RGB32_BIG: 793 case B_CMYA32: 794 case B_CMYK32: 795 case B_CMY32: 796 bitsBytesPerPixel = 4; 797 break; 798 799 case B_RGB24: 800 case B_RGB24_BIG: 801 case B_CMY24: 802 bitsBytesPerPixel = 3; 803 break; 804 805 case B_RGB16: 806 case B_RGB16_BIG: 807 case B_RGBA15: 808 case B_RGBA15_BIG: 809 case B_RGB15: 810 case B_RGB15_BIG: 811 bitsBytesPerPixel = 2; 812 break; 813 814 case B_GRAY8: 815 case B_CMAP8: 816 bitsBytesPerPixel = 1; 817 break; 818 819 default: 820 return B_NO_TRANSLATOR; 821 }; 822 823 uint8 *pbitsrow = NULL, *prow = NULL; 824 // row buffers 825 // image buffer for writing whole png image at once 826 uint8 **prows = NULL; 827 png_uint_32 nalloc = 0; 828 829 png_structp ppng = NULL; 830 png_infop pinfo = NULL; 831 832 result = B_NO_TRANSLATOR; 833 while (ppng == NULL) { 834 // create PNG read pointer with default error handling routines 835 ppng = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, 836 NULL, NULL); 837 if (!ppng) { 838 result = B_ERROR; 839 break; 840 } 841 // alocate / init memory for image information 842 pinfo = png_create_info_struct(ppng); 843 if (!pinfo) { 844 result = B_ERROR; 845 break; 846 } 847 848 // set up erorr handling to use C++ exceptions instead of setjmp 849 png_set_error_fn(ppng, png_get_error_ptr(ppng), throw_error, 850 alert_warning); 851 852 try { 853 png_set_write_fn(ppng, static_cast<void *>(outDestination), 854 pngcb_write_data, pngcb_flush_data); 855 856 // Allocate memory needed to buffer image data 857 pbitsrow = new(std::nothrow) uint8[bitsHeader.rowBytes]; 858 if (!pbitsrow) { 859 result = B_NO_MEMORY; 860 break; 861 } 862 if (interlace_type == PNG_INTERLACE_NONE) { 863 prow = new(std::nothrow) uint8[width * pngBytesPerPixel]; 864 if (!prow) { 865 result = B_NO_MEMORY; 866 break; 867 } 868 } else { 869 prows = new(std::nothrow) uint8 *[height]; 870 if (!prows) { 871 result = B_NO_MEMORY; 872 break; 873 } 874 // allocate enough memory to store the whole image 875 for (nalloc = 0; nalloc < height; nalloc++) { 876 prows[nalloc] = 877 new(std::nothrow) uint8[width * pngBytesPerPixel]; 878 if (!prows[nalloc]) 879 break; 880 } 881 if (nalloc < height) { 882 result = B_NO_MEMORY; 883 // clear out rest of the pointers, 884 // so we don't call delete[] with invalid pointers 885 for (; nalloc < height; nalloc++) 886 prows[nalloc] = NULL; 887 break; 888 } 889 } 890 891 // Specify image info 892 png_set_IHDR(ppng, pinfo, width, height, bit_depth, color_type, 893 interlace_type, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); 894 png_write_info(ppng, pinfo); 895 896 png_set_bgr(ppng); 897 898 // write out image data 899 if (interlace_type == PNG_INTERLACE_NONE) { 900 for (png_uint_32 i = 0; i < height; i++) { 901 inSource->Read(pbitsrow, bitsHeader.rowBytes); 902 903 pix_bits_to_png(pbitsrow, prow, bitsHeader.colors, width, 904 pmap, bitsBytesPerPixel); 905 906 png_write_row(ppng, prow); 907 } 908 } else { 909 for (png_uint_32 i = 0; i < height; i++) { 910 inSource->Read(pbitsrow, bitsHeader.rowBytes); 911 912 pix_bits_to_png(pbitsrow, prows[i], bitsHeader.colors, 913 width, pmap, bitsBytesPerPixel); 914 } 915 png_write_image(ppng, prows); 916 } 917 result = B_OK; 918 // If png_read_end throws an exception, we still accept 919 // the image as valid. 920 png_write_end(ppng, NULL); 921 922 break; 923 } catch(std::exception& e) { 924 break; 925 } 926 } 927 928 if (ppng) { 929 delete[] pbitsrow; 930 pbitsrow = NULL; 931 932 delete[] prow; 933 prow = NULL; 934 935 // delete row pointers and array of pointers to rows 936 while (nalloc) { 937 nalloc--; 938 delete[] prows[nalloc]; 939 } 940 delete[] prows; 941 prows = NULL; 942 943 // free PNG handle / info structures 944 if (!pinfo) 945 png_destroy_write_struct(&ppng, NULL); 946 else 947 png_destroy_write_struct(&ppng, &pinfo); 948 } 949 950 return result; 951 } 952 953 // --------------------------------------------------------------- 954 // DerivedTranslate 955 // 956 // Translates the data in inSource to the type outType and stores 957 // the translated data in outDestination. 958 // 959 // Preconditions: 960 // 961 // Parameters: inSource, the data to be translated 962 // 963 // inInfo, hint about the data in inSource (not used) 964 // 965 // ioExtension, configuration options for the 966 // translator 967 // 968 // outType, the type to convert inSource to 969 // 970 // outDestination, where the translated data is 971 // put 972 // 973 // baseType, indicates whether inSource is in the 974 // bits format, not in the bits format or 975 // is unknown 976 // 977 // Postconditions: 978 // 979 // Returns: B_BAD_VALUE, if the options in ioExtension are bad 980 // 981 // B_NO_TRANSLATOR, if this translator doesn't understand the data 982 // 983 // B_ERROR, if there was an error allocating memory or converting 984 // data 985 // 986 // B_OK, if all went well 987 // --------------------------------------------------------------- 988 status_t 989 PNGTranslator::DerivedTranslate(BPositionIO *inSource, 990 const translator_info *inInfo, BMessage *ioExtension, uint32 outType, 991 BPositionIO *outDestination, int32 baseType) 992 { 993 if (baseType == 1) 994 // if inSource is in bits format 995 return translate_from_bits_to_png(inSource, outDestination); 996 else if (baseType == 0) 997 // if inSource is NOT in bits format 998 return translate_from_png(inSource, outType, outDestination); 999 else 1000 return B_NO_TRANSLATOR; 1001 } 1002 1003 BView * 1004 PNGTranslator::NewConfigView(TranslatorSettings *settings) 1005 { 1006 return new(std::nothrow) PNGView(BRect(0, 0, PNG_VIEW_WIDTH, PNG_VIEW_HEIGHT), 1007 B_TRANSLATE("PNGTranslator Settings"), B_FOLLOW_ALL, 1008 B_WILL_DRAW, settings); 1009 } 1010 1011