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