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