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