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