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