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 <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 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 status_t 296 PNGTranslator::translate_from_png_to_bits(BPositionIO *inSource, 297 BPositionIO *outDestination) 298 { 299 if (identify_png_header(inSource, NULL) != B_OK) 300 return B_NO_TRANSLATOR; 301 302 status_t result = B_ERROR; 303 // if a libpng errors before this is set 304 // to a different value, the above is what 305 // will be returned from this function 306 307 bool bheaderonly = false, bdataonly = false; 308 309 // for storing decoded PNG row data 310 uint8 **prows = NULL, *prow = NULL; 311 png_uint_32 nalloc = 0; 312 313 png_structp ppng = NULL; 314 png_infop pinfo = NULL; 315 while (ppng == NULL) { 316 // create PNG read pointer with default error handling routines 317 ppng = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 318 if (!ppng) 319 break; 320 // alocate / init memory for image information 321 pinfo = png_create_info_struct(ppng); 322 if (!pinfo) 323 break; 324 // set error handling 325 if (setjmp(png_jmpbuf(ppng))) 326 // When an error occurs in libpng, it uses 327 // the longjmp function to continue execution 328 // from this point 329 break; 330 331 // set read callback function 332 png_set_read_fn(ppng, static_cast<void *>(inSource), pngcb_read_data); 333 334 // Read in PNG image info 335 png_set_sig_bytes(ppng, 8); 336 png_read_info(ppng, pinfo); 337 338 png_uint_32 width, height; 339 int bit_depth, color_type, interlace_type; 340 png_get_IHDR(ppng, pinfo, &width, &height, &bit_depth, &color_type, 341 &interlace_type, NULL, NULL); 342 343 // Setup image transformations to make converting it easier 344 bool balpha = false; 345 346 if (bit_depth == 16) 347 png_set_strip_16(ppng); 348 else if (bit_depth < 8) 349 png_set_packing(ppng); 350 351 if (color_type == PNG_COLOR_TYPE_PALETTE) 352 png_set_palette_to_rgb(ppng); 353 354 if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) 355 // In order to convert from low-depth gray images to RGB, 356 // I first need to convert them to grayscale, 8 bpp 357 png_set_expand_gray_1_2_4_to_8(ppng); 358 359 if (png_get_valid(ppng, pinfo, PNG_INFO_tRNS)) { 360 // if there is transparency data in the 361 // PNG, but not in the form of an alpha channel 362 balpha = true; 363 png_set_tRNS_to_alpha(ppng); 364 } 365 366 // change RGB to BGR as it is in 'bits' 367 if (color_type & PNG_COLOR_MASK_COLOR) 368 png_set_bgr(ppng); 369 370 // have libpng convert gray to RGB for me 371 if (color_type == PNG_COLOR_TYPE_GRAY || 372 color_type == PNG_COLOR_TYPE_GRAY_ALPHA) 373 png_set_gray_to_rgb(ppng); 374 375 if (color_type & PNG_COLOR_MASK_ALPHA) 376 // if image contains an alpha channel 377 balpha = true; 378 379 if (!balpha) 380 // add filler byte for images without alpha 381 // so that the pixels are 4 bytes each 382 png_set_filler(ppng, 0xff, PNG_FILLER_AFTER); 383 384 // Check that transformed PNG rowbytes matches 385 // what is expected 386 const int32 kbytes = 4; 387 png_uint_32 rowbytes = png_get_rowbytes(ppng, pinfo); 388 if (rowbytes < kbytes * width) 389 rowbytes = kbytes * width; 390 391 if (!bdataonly) { 392 // Write out the data to outDestination 393 // Construct and write Be bitmap header 394 TranslatorBitmap bitsHeader; 395 bitsHeader.magic = B_TRANSLATOR_BITMAP; 396 bitsHeader.bounds.left = 0; 397 bitsHeader.bounds.top = 0; 398 bitsHeader.bounds.right = width - 1; 399 bitsHeader.bounds.bottom = height - 1; 400 bitsHeader.rowBytes = 4 * width; 401 if (balpha) 402 bitsHeader.colors = B_RGBA32; 403 else 404 bitsHeader.colors = B_RGB32; 405 bitsHeader.dataSize = bitsHeader.rowBytes * height; 406 if (swap_data(B_UINT32_TYPE, &bitsHeader, 407 sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN) != B_OK) { 408 result = B_ERROR; 409 break; 410 } 411 outDestination->Write(&bitsHeader, sizeof(TranslatorBitmap)); 412 413 if (bheaderonly) { 414 result = B_OK; 415 break; 416 } 417 } 418 419 if (interlace_type == PNG_INTERLACE_NONE) { 420 // allocate buffer for storing PNG row 421 prow = new uint8[rowbytes]; 422 if (!prow) { 423 result = B_NO_MEMORY; 424 break; 425 } 426 for (png_uint_32 i = 0; i < height; i++) { 427 png_read_row(ppng, prow, NULL); 428 outDestination->Write(prow, width * kbytes); 429 } 430 result = B_OK; 431 // Set OK status here, because, in the event of 432 // an error, png_read_end() will longjmp to error 433 // handler above and not execute lines below it 434 435 // finish reading, pass NULL for info because I 436 // don't need the extra data 437 png_read_end(ppng, NULL); 438 439 break; 440 441 } else { 442 // interlaced PNG image 443 prows = new uint8 *[height]; 444 if (!prows) { 445 result = B_NO_MEMORY; 446 break; 447 } 448 // allocate enough memory to store the whole image 449 for (nalloc = 0; nalloc < height; nalloc++) { 450 prows[nalloc] = new uint8[rowbytes]; 451 if (!prows[nalloc]) 452 break; 453 } 454 455 if (nalloc < height) 456 result = B_NO_MEMORY; 457 else { 458 png_read_image(ppng, prows); 459 460 for (png_uint_32 i = 0; i < height; i++) 461 outDestination->Write(prows[i], width * kbytes); 462 result = B_OK; 463 // Set OK status here, because, in the event of 464 // an error, png_read_end() will longjmp to error 465 // handler above and not execute lines below it 466 467 png_read_end(ppng, NULL); 468 } 469 470 break; 471 } 472 } 473 474 if (ppng) { 475 delete[] prow; 476 prow = NULL; 477 478 // delete row pointers and array of pointers to rows 479 while (nalloc) { 480 nalloc--; 481 delete[] prows[nalloc]; 482 } 483 delete[] prows; 484 prows = NULL; 485 486 // free PNG handle / info structures 487 if (!pinfo) 488 png_destroy_read_struct(&ppng, NULL, NULL); 489 else 490 png_destroy_read_struct(&ppng, &pinfo, NULL); 491 } 492 493 return result; 494 } 495 496 status_t 497 PNGTranslator::translate_from_png(BPositionIO *inSource, uint32 outType, 498 BPositionIO *outDestination) 499 { 500 if (outType == B_TRANSLATOR_BITMAP) 501 return translate_from_png_to_bits(inSource, outDestination); 502 else { 503 // Translate from PNG to PNG 504 translate_direct_copy(inSource, outDestination); 505 return B_OK; 506 } 507 } 508 509 // Convert width pixels from pbits to PNG format, storing the 510 // result in ppng 511 status_t 512 pix_bits_to_png(uint8 *pbits, uint8 *ppng, color_space fromspace, 513 uint32 width, const color_map *pmap, int32 bitsBytesPerPixel) 514 { 515 status_t bytescopied = 0; 516 uint16 val; 517 518 switch (fromspace) { 519 case B_RGBA32: 520 bytescopied = width * bitsBytesPerPixel; 521 memcpy(ppng, pbits, bytescopied); 522 break; 523 524 case B_RGB32: 525 case B_RGB24: 526 bytescopied = width * bitsBytesPerPixel; 527 while (width--) { 528 memcpy(ppng, pbits, 3); 529 ppng += 3; 530 pbits += bitsBytesPerPixel; 531 } 532 break; 533 534 case B_RGBA32_BIG: 535 bytescopied = width * 4; 536 while (width--) { 537 ppng[0] = pbits[3]; 538 ppng[1] = pbits[2]; 539 ppng[2] = pbits[1]; 540 ppng[3] = pbits[0]; 541 542 ppng += 4; 543 pbits += 4; 544 } 545 break; 546 547 case B_CMYA32: 548 bytescopied = width * 4; 549 while (width--) { 550 ppng[0] = 255 - pbits[2]; 551 ppng[1] = 255 - pbits[1]; 552 ppng[2] = 255 - pbits[0]; 553 ppng[3] = pbits[3]; 554 555 ppng += 4; 556 pbits += 4; 557 } 558 break; 559 560 case B_CMYK32: 561 { 562 int32 comp; 563 bytescopied = width * 3; 564 while (width--) { 565 comp = 255 - pbits[2] - pbits[3]; 566 ppng[0] = (comp < 0) ? 0 : comp; 567 568 comp = 255 - pbits[1] - pbits[3]; 569 ppng[1] = (comp < 0) ? 0 : comp; 570 571 comp = 255 - pbits[0] - pbits[3]; 572 ppng[2] = (comp < 0) ? 0 : comp; 573 574 ppng += 3; 575 pbits += 4; 576 } 577 break; 578 } 579 580 case B_CMY32: 581 case B_CMY24: 582 bytescopied = width * 3; 583 while (width--) { 584 ppng[0] = 255 - pbits[2]; 585 ppng[1] = 255 - pbits[1]; 586 ppng[2] = 255 - pbits[0]; 587 588 ppng += 3; 589 pbits += bitsBytesPerPixel; 590 } 591 break; 592 593 case B_RGB16: 594 case B_RGB16_BIG: 595 bytescopied = width * 3; 596 while (width--) { 597 if (fromspace == B_RGB16) 598 val = pbits[0] + (pbits[1] << 8); 599 else 600 val = pbits[1] + (pbits[0] << 8); 601 602 ppng[0] = 603 ((val & 0x1f) << 3) | ((val & 0x1f) >> 2); 604 ppng[1] = 605 ((val & 0x7e0) >> 3) | ((val & 0x7e0) >> 9); 606 ppng[2] = 607 ((val & 0xf800) >> 8) | ((val & 0xf800) >> 13); 608 609 ppng += 3; 610 pbits += 2; 611 } 612 break; 613 614 case B_RGB15: 615 case B_RGB15_BIG: 616 bytescopied = width * 3; 617 while (width--) { 618 if (fromspace == B_RGB15) 619 val = pbits[0] + (pbits[1] << 8); 620 else 621 val = pbits[1] + (pbits[0] << 8); 622 ppng[0] = 623 ((val & 0x1f) << 3) | ((val & 0x1f) >> 2); 624 ppng[1] = 625 ((val & 0x3e0) >> 2) | ((val & 0x3e0) >> 7); 626 ppng[2] = 627 ((val & 0x7c00) >> 7) | ((val & 0x7c00) >> 12); 628 629 ppng += 3; 630 pbits += 2; 631 } 632 break; 633 634 case B_RGBA15: 635 case B_RGBA15_BIG: 636 bytescopied = width * 4; 637 while (width--) { 638 if (fromspace == B_RGBA15) 639 val = pbits[0] + (pbits[1] << 8); 640 else 641 val = pbits[1] + (pbits[0] << 8); 642 ppng[0] = 643 ((val & 0x1f) << 3) | ((val & 0x1f) >> 2); 644 ppng[1] = 645 ((val & 0x3e0) >> 2) | ((val & 0x3e0) >> 7); 646 ppng[2] = 647 ((val & 0x7c00) >> 7) | ((val & 0x7c00) >> 12); 648 ppng[3] = (val & 0x8000) ? 255 : 0; 649 650 ppng += 4; 651 pbits += 2; 652 } 653 break; 654 655 case B_RGB32_BIG: 656 bytescopied = width * 3; 657 while (width--) { 658 ppng[0] = pbits[3]; 659 ppng[1] = pbits[2]; 660 ppng[2] = pbits[1]; 661 662 ppng += 3; 663 pbits += 4; 664 } 665 break; 666 667 case B_RGB24_BIG: 668 bytescopied = width * 3; 669 while (width--) { 670 ppng[0] = pbits[2]; 671 ppng[1] = pbits[1]; 672 ppng[2] = pbits[0]; 673 674 ppng += 3; 675 pbits += 3; 676 } 677 break; 678 679 case B_CMAP8: 680 { 681 rgb_color c; 682 bytescopied = width * 3; 683 while (width--) { 684 c = pmap->color_list[pbits[0]]; 685 ppng[0] = c.blue; 686 ppng[1] = c.green; 687 ppng[2] = c.red; 688 689 ppng += 3; 690 pbits++; 691 } 692 break; 693 } 694 695 case B_GRAY8: 696 bytescopied = width; 697 memcpy(ppng, pbits, bytescopied); 698 break; 699 700 default: 701 bytescopied = B_ERROR; 702 break; 703 } // switch (fromspace) 704 705 return bytescopied; 706 } 707 708 status_t 709 PNGTranslator::translate_from_bits_to_png(BPositionIO *inSource, 710 BPositionIO *outDestination) 711 { 712 TranslatorBitmap bitsHeader; 713 714 status_t result; 715 716 result = identify_bits_header(inSource, NULL, &bitsHeader); 717 if (result != B_OK) 718 return result; 719 720 const color_map *pmap = NULL; 721 if (bitsHeader.colors == B_CMAP8) { 722 pmap = system_colors(); 723 if (!pmap) 724 return B_ERROR; 725 } 726 727 png_uint_32 width, height; 728 width = static_cast<png_uint_32>(bitsHeader.bounds.Width() + 1); 729 height = static_cast<png_uint_32>(bitsHeader.bounds.Height() + 1); 730 731 int32 pngBytesPerPixel = 0; 732 int bit_depth, color_type, interlace_type; 733 bit_depth = 8; 734 switch (bitsHeader.colors) { 735 case B_RGBA32: 736 case B_RGBA32_BIG: 737 case B_CMYA32: 738 case B_RGBA15: 739 case B_RGBA15_BIG: 740 pngBytesPerPixel = 4; 741 color_type = PNG_COLOR_TYPE_RGB_ALPHA; 742 break; 743 744 case B_RGB32: 745 case B_RGB32_BIG: 746 case B_RGB24: 747 case B_RGB24_BIG: 748 case B_CMY32: 749 case B_CMYK32: 750 case B_CMY24: 751 case B_RGB16: 752 case B_RGB16_BIG: 753 case B_RGB15: 754 case B_RGB15_BIG: 755 pngBytesPerPixel = 3; 756 color_type = PNG_COLOR_TYPE_RGB; 757 break; 758 759 // ADD SUPPORT FOR B_CMAP8 HERE (later) 760 761 case B_GRAY8: 762 pngBytesPerPixel = 1; 763 color_type = PNG_COLOR_TYPE_GRAY; 764 break; 765 766 default: 767 return B_NO_TRANSLATOR; 768 } 769 interlace_type = fSettings->SetGetInt32(PNG_SETTING_INTERLACE); 770 771 int32 bitsBytesPerPixel = 0; 772 switch (bitsHeader.colors) { 773 case B_RGBA32: 774 case B_RGBA32_BIG: 775 case B_RGB32: 776 case B_RGB32_BIG: 777 case B_CMYA32: 778 case B_CMYK32: 779 case B_CMY32: 780 bitsBytesPerPixel = 4; 781 break; 782 783 case B_RGB24: 784 case B_RGB24_BIG: 785 case B_CMY24: 786 bitsBytesPerPixel = 3; 787 break; 788 789 case B_RGB16: 790 case B_RGB16_BIG: 791 case B_RGBA15: 792 case B_RGBA15_BIG: 793 case B_RGB15: 794 case B_RGB15_BIG: 795 bitsBytesPerPixel = 2; 796 break; 797 798 case B_GRAY8: 799 case B_CMAP8: 800 bitsBytesPerPixel = 1; 801 break; 802 803 default: 804 return B_NO_TRANSLATOR; 805 }; 806 807 uint8 *pbitsrow = NULL, *prow = NULL; 808 // row buffers 809 // image buffer for writing whole png image at once 810 uint8 **prows = NULL; 811 png_uint_32 nalloc = 0; 812 813 png_structp ppng = NULL; 814 png_infop pinfo = NULL; 815 816 result = B_NO_TRANSLATOR; 817 while (ppng == NULL) { 818 // create PNG read pointer with default error handling routines 819 ppng = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, 820 NULL, NULL); 821 if (!ppng) { 822 result = B_ERROR; 823 break; 824 } 825 // alocate / init memory for image information 826 pinfo = png_create_info_struct(ppng); 827 if (!pinfo) { 828 result = B_ERROR; 829 break; 830 } 831 // set error handling 832 if (setjmp(png_jmpbuf(ppng))) { 833 // When an error occurs in libpng, it uses 834 // the longjmp function to continue execution 835 // from this point 836 result = B_ERROR; 837 break; 838 } 839 840 png_set_write_fn(ppng, static_cast<void *>(outDestination), 841 pngcb_write_data, pngcb_flush_data); 842 843 // Allocate memory needed to buffer image data 844 pbitsrow = new uint8[bitsHeader.rowBytes]; 845 if (!pbitsrow) { 846 result = B_NO_MEMORY; 847 break; 848 } 849 if (interlace_type == PNG_INTERLACE_NONE) { 850 prow = new uint8[width * pngBytesPerPixel]; 851 if (!prow) { 852 result = B_NO_MEMORY; 853 break; 854 } 855 } else { 856 prows = new uint8 *[height]; 857 if (!prows) { 858 result = B_NO_MEMORY; 859 break; 860 } 861 // allocate enough memory to store the whole image 862 for (nalloc = 0; nalloc < height; nalloc++) { 863 prows[nalloc] = new uint8[width * pngBytesPerPixel]; 864 if (!prows[nalloc]) 865 break; 866 } 867 if (nalloc < height) { 868 result = B_NO_MEMORY; 869 // clear out rest of the pointers, 870 // so we don't call delete[] with invalid pointers 871 for (; nalloc < height; nalloc++) 872 prows[nalloc] = NULL; 873 break; 874 } 875 } 876 877 // Specify image info 878 png_set_IHDR(ppng, pinfo, width, height, bit_depth, color_type, 879 interlace_type, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); 880 png_write_info(ppng, pinfo); 881 882 png_set_bgr(ppng); 883 884 // write out image data 885 if (interlace_type == PNG_INTERLACE_NONE) { 886 for (png_uint_32 i = 0; i < height; i++) { 887 inSource->Read(pbitsrow, bitsHeader.rowBytes); 888 889 pix_bits_to_png(pbitsrow, prow, bitsHeader.colors, width, 890 pmap, bitsBytesPerPixel); 891 892 png_write_row(ppng, prow); 893 } 894 } else { 895 for (png_uint_32 i = 0; i < height; i++) { 896 inSource->Read(pbitsrow, bitsHeader.rowBytes); 897 898 pix_bits_to_png(pbitsrow, prows[i], bitsHeader.colors, width, 899 pmap, bitsBytesPerPixel); 900 } 901 png_write_image(ppng, prows); 902 } 903 png_write_end(ppng, NULL); 904 905 result = B_OK; 906 break; 907 } 908 909 if (ppng) { 910 delete[] pbitsrow; 911 pbitsrow = NULL; 912 913 delete[] prow; 914 prow = NULL; 915 916 // delete row pointers and array of pointers to rows 917 while (nalloc) { 918 nalloc--; 919 delete[] prows[nalloc]; 920 } 921 delete[] prows; 922 prows = NULL; 923 924 // free PNG handle / info structures 925 if (!pinfo) 926 png_destroy_write_struct(&ppng, NULL); 927 else 928 png_destroy_write_struct(&ppng, &pinfo); 929 } 930 931 return result; 932 } 933 934 // --------------------------------------------------------------- 935 // DerivedTranslate 936 // 937 // Translates the data in inSource to the type outType and stores 938 // the translated data in outDestination. 939 // 940 // Preconditions: 941 // 942 // Parameters: inSource, the data to be translated 943 // 944 // inInfo, hint about the data in inSource (not used) 945 // 946 // ioExtension, configuration options for the 947 // translator 948 // 949 // outType, the type to convert inSource to 950 // 951 // outDestination, where the translated data is 952 // put 953 // 954 // baseType, indicates whether inSource is in the 955 // bits format, not in the bits format or 956 // is unknown 957 // 958 // Postconditions: 959 // 960 // Returns: B_BAD_VALUE, if the options in ioExtension are bad 961 // 962 // B_NO_TRANSLATOR, if this translator doesn't understand the data 963 // 964 // B_ERROR, if there was an error allocating memory or converting 965 // data 966 // 967 // B_OK, if all went well 968 // --------------------------------------------------------------- 969 status_t 970 PNGTranslator::DerivedTranslate(BPositionIO *inSource, 971 const translator_info *inInfo, BMessage *ioExtension, uint32 outType, 972 BPositionIO *outDestination, int32 baseType) 973 { 974 if (baseType == 1) 975 // if inSource is in bits format 976 return translate_from_bits_to_png(inSource, outDestination); 977 else if (baseType == 0) 978 // if inSource is NOT in bits format 979 return translate_from_png(inSource, outType, outDestination); 980 else 981 return B_NO_TRANSLATOR; 982 } 983 984 BView * 985 PNGTranslator::NewConfigView(TranslatorSettings *settings) 986 { 987 return new PNGView(BRect(0, 0, PNG_VIEW_WIDTH, PNG_VIEW_HEIGHT), 988 B_TRANSLATE("PNGTranslator Settings"), B_FOLLOW_ALL, 989 B_WILL_DRAW, settings); 990 } 991 992