vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / translators / png / PNGTranslator.cpp
blob97925075260ffb184fac536d230662fec25435ff
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 //
11 // Copyright (c) 2003, OpenBeOS Project
12 // Copyright (c) 2009, Haiku, Inc. All rights reserved.
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:
21 // The above copyright notice and this permission notice shall be included
22 // in all copies or substantial portions of the Software.
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 /*****************************************************************************/
34 #include "PNGTranslator.h"
36 #include <stdio.h>
37 #include <string.h>
39 #include <Catalog.h>
40 #include <OS.h>
41 #define PNG_NO_PEDANTIC_WARNINGS
42 #include <png.h>
44 #include "PNGView.h"
46 #undef B_TRANSLATION_CONTEXT
47 #define B_TRANSLATION_CONTEXT "PNGTranslator"
49 // The input formats that this translator supports.
50 static const translation_format sInputFormats[] = {
52 B_PNG_FORMAT,
53 B_TRANSLATOR_BITMAP,
54 PNG_IN_QUALITY,
55 PNG_IN_CAPABILITY,
56 "image/png",
57 "PNG image"
60 B_PNG_FORMAT,
61 B_TRANSLATOR_BITMAP,
62 PNG_IN_QUALITY,
63 PNG_IN_CAPABILITY,
64 "image/x-png",
65 "PNG image"
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)"
77 // The output formats that this translator supports.
78 static const translation_format sOutputFormats[] = {
80 B_PNG_FORMAT,
81 B_TRANSLATOR_BITMAP,
82 PNG_OUT_QUALITY,
83 PNG_OUT_CAPABILITY,
84 "image/png",
85 "PNG image"
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)"
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
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);
110 // ---------------------------------------------------------------
111 // make_nth_translator
113 // Creates a PNGTranslator object to be used by BTranslatorRoster
115 // Preconditions:
117 // Parameters: n, The translator to return. Since
118 // PNGTranslator only publishes one
119 // translator, it only returns a
120 // PNGTranslator if n == 0
122 // you, The image_id of the add-on that
123 // contains code (not used).
125 // flags, Has no meaning yet, should be 0.
127 // Postconditions:
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, ...)
135 if (!n)
136 return new PNGTranslator();
137 else
138 return NULL;
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!).
147 #ifndef png_jmpbuf
148 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
149 #endif
151 //// libpng Callback functions!
153 BPositionIO *
154 get_pio(png_structp ppng)
156 BPositionIO *pio = NULL;
157 pio = static_cast<BPositionIO *>(png_get_io_ptr(ppng));
158 return pio;
161 void
162 pngcb_read_data(png_structp ppng, png_bytep pdata, png_size_t length)
164 BPositionIO *pio = get_pio(ppng);
165 pio->Read(pdata, static_cast<size_t>(length));
168 void
169 pngcb_write_data(png_structp ppng, png_bytep pdata, png_size_t length)
171 BPositionIO *pio = get_pio(ppng);
172 pio->Write(pdata, static_cast<size_t>(length));
175 void
176 pngcb_flush_data(png_structp ppng)
178 // I don't think I really need to do anything here
181 // ---------------------------------------------------------------
182 // Constructor
184 // Sets up the version info and the name of the translator so that
185 // these values can be returned when they are requested.
187 // Preconditions:
189 // Parameters:
191 // Postconditions:
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)
207 // ---------------------------------------------------------------
208 // Destructor
210 // Does nothing
212 // Preconditions:
214 // Parameters:
216 // Postconditions:
218 // Returns:
219 // ---------------------------------------------------------------
220 PNGTranslator::~PNGTranslator()
224 status_t
225 identify_png_header(BPositionIO *inSource, translator_info *outInfo)
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;
235 if (outInfo) {
236 outInfo->type = B_PNG_FORMAT;
237 outInfo->group = B_TRANSLATOR_BITMAP;
238 outInfo->quality = PNG_IN_QUALITY;
239 outInfo->capability = PNG_IN_CAPABILITY;
240 strcpy(outInfo->MIME, "image/png");
241 strlcpy(outInfo->name, B_TRANSLATE("PNG image"),
242 sizeof(outInfo->name));
245 return B_OK;
248 // ---------------------------------------------------------------
249 // DerivedIdentify
251 // Examines the data from inSource and determines if it is in a
252 // format that this translator knows how to work with.
254 // Preconditions:
256 // Parameters: inSource, where the data to examine is
258 // inFormat, a hint about the data in inSource,
259 // it is ignored since it is only a hint
261 // ioExtension, configuration settings for the
262 // translator (not used)
264 // outInfo, information about what data is in
265 // inSource and how well this translator
266 // can handle that data is stored here
268 // outType, The format that the user wants
269 // the data in inSource to be
270 // converted to
272 // Postconditions:
274 // Returns: B_NO_TRANSLATOR, if this translator can't handle
275 // the data in inSource
277 // B_ERROR, if there was an error converting the data to the host
278 // format
280 // B_BAD_VALUE, if the settings in ioExtension are bad
282 // B_OK, if this translator understood the data and there were
283 // no errors found
285 // Other errors if BPositionIO::Read() returned an error value
286 // ---------------------------------------------------------------
287 status_t
288 PNGTranslator::DerivedIdentify(BPositionIO *inSource,
289 const translation_format *inFormat, BMessage *ioExtension,
290 translator_info *outInfo, uint32 outType)
292 return identify_png_header(inSource, outInfo);
295 void throw_error(png_structp ppng, png_const_charp error_msg)
297 throw std::exception();
300 void alert_warning(png_structp ppng, png_const_charp error_msg)
302 // Ignore
303 // TODO show a BAlert?
306 status_t
307 PNGTranslator::translate_from_png_to_bits(BPositionIO *inSource,
308 BPositionIO *outDestination)
310 if (identify_png_header(inSource, NULL) != B_OK)
311 return B_NO_TRANSLATOR;
313 status_t result = B_ERROR;
314 // if a libpng errors before this is set
315 // to a different value, the above is what
316 // will be returned from this function
318 bool bheaderonly = false, bdataonly = false;
320 // for storing decoded PNG row data
321 uint8 **prows = NULL, *prow = NULL;
322 png_uint_32 nalloc = 0;
324 png_structp ppng = NULL;
325 png_infop pinfo = NULL;
326 while (ppng == NULL) {
327 // create PNG read pointer with default error handling routines
328 ppng = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
329 if (!ppng)
330 break;
332 // alocate / init memory for image information
333 pinfo = png_create_info_struct(ppng);
334 if (!pinfo)
335 break;
337 // set up erorr handling to use C++ exceptions instead of setjmp
338 png_set_error_fn(ppng, png_get_error_ptr(ppng), throw_error,
339 alert_warning);
341 try {
342 // set read callback function
343 png_set_read_fn(ppng, static_cast<void *>(inSource), pngcb_read_data);
345 // Read in PNG image info
346 png_set_sig_bytes(ppng, 8);
347 png_read_info(ppng, pinfo);
349 png_uint_32 width, height;
350 int bit_depth, color_type, interlace_type;
351 png_get_IHDR(ppng, pinfo, &width, &height, &bit_depth, &color_type,
352 &interlace_type, NULL, NULL);
354 // Setup image transformations to make converting it easier
355 bool balpha = false;
357 if (bit_depth == 16)
358 png_set_strip_16(ppng);
359 else if (bit_depth < 8)
360 png_set_packing(ppng);
362 if (color_type == PNG_COLOR_TYPE_PALETTE)
363 png_set_palette_to_rgb(ppng);
365 if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
366 // In order to convert from low-depth gray images to RGB,
367 // I first need to convert them to grayscale, 8 bpp
368 png_set_expand_gray_1_2_4_to_8(ppng);
371 if (png_get_valid(ppng, pinfo, PNG_INFO_tRNS)) {
372 // if there is transparency data in the
373 // PNG, but not in the form of an alpha channel
374 balpha = true;
375 png_set_tRNS_to_alpha(ppng);
378 // change RGB to BGR as it is in 'bits'
379 if (color_type & PNG_COLOR_MASK_COLOR)
380 png_set_bgr(ppng);
382 // have libpng convert gray to RGB for me
383 if (color_type == PNG_COLOR_TYPE_GRAY ||
384 color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
385 png_set_gray_to_rgb(ppng);
388 if (color_type & PNG_COLOR_MASK_ALPHA) {
389 // if image contains an alpha channel
390 balpha = true;
393 if (!balpha) {
394 // add filler byte for images without alpha
395 // so that the pixels are 4 bytes each
396 png_set_filler(ppng, 0xff, PNG_FILLER_AFTER);
399 // Check that transformed PNG rowbytes matches
400 // what is expected
401 const int32 kbytes = 4;
402 png_uint_32 rowbytes = png_get_rowbytes(ppng, pinfo);
403 if (rowbytes < kbytes * width)
404 rowbytes = kbytes * width;
406 if (!bdataonly) {
407 // Write out the data to outDestination
408 // Construct and write Be bitmap header
409 TranslatorBitmap bitsHeader;
410 bitsHeader.magic = B_TRANSLATOR_BITMAP;
411 bitsHeader.bounds.left = 0;
412 bitsHeader.bounds.top = 0;
413 bitsHeader.bounds.right = width - 1;
414 bitsHeader.bounds.bottom = height - 1;
415 bitsHeader.rowBytes = 4 * width;
416 if (balpha)
417 bitsHeader.colors = B_RGBA32;
418 else
419 bitsHeader.colors = B_RGB32;
420 bitsHeader.dataSize = bitsHeader.rowBytes * height;
421 if (swap_data(B_UINT32_TYPE, &bitsHeader,
422 sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN) != B_OK) {
423 result = B_ERROR;
424 break;
426 outDestination->Write(&bitsHeader, sizeof(TranslatorBitmap));
428 if (bheaderonly) {
429 result = B_OK;
430 break;
434 if (interlace_type == PNG_INTERLACE_NONE) {
435 // allocate buffer for storing PNG row
436 prow = new uint8[rowbytes];
437 if (!prow) {
438 result = B_NO_MEMORY;
439 break;
441 for (png_uint_32 i = 0; i < height; i++) {
442 png_read_row(ppng, prow, NULL);
443 outDestination->Write(prow, width * kbytes);
446 // finish reading, pass NULL for info because I
447 // don't need the extra data
448 png_read_end(ppng, NULL);
449 result = B_OK;
451 break;
453 } else {
454 // interlaced PNG image
455 prows = new uint8 *[height];
456 if (!prows) {
457 result = B_NO_MEMORY;
458 break;
460 // allocate enough memory to store the whole image
461 for (nalloc = 0; nalloc < height; nalloc++) {
462 prows[nalloc] = new uint8[rowbytes];
463 if (!prows[nalloc])
464 break;
467 if (nalloc < height)
468 result = B_NO_MEMORY;
469 else {
470 png_read_image(ppng, prows);
472 for (png_uint_32 i = 0; i < height; i++)
473 outDestination->Write(prows[i], width * kbytes);
475 result = B_OK;
476 // If png_read_end throws an exception, we still accept
477 // the image as valid.
478 png_read_end(ppng, NULL);
481 break;
483 } catch (std::exception& e) {
484 // An error occured, abort decoding and cleanup
485 break;
489 if (ppng) {
490 delete[] prow;
491 prow = NULL;
493 // delete row pointers and array of pointers to rows
494 while (nalloc) {
495 nalloc--;
496 delete[] prows[nalloc];
498 delete[] prows;
499 prows = NULL;
501 // free PNG handle / info structures
502 if (!pinfo)
503 png_destroy_read_struct(&ppng, NULL, NULL);
504 else
505 png_destroy_read_struct(&ppng, &pinfo, NULL);
508 return result;
511 status_t
512 PNGTranslator::translate_from_png(BPositionIO *inSource, uint32 outType,
513 BPositionIO *outDestination)
515 if (outType == B_TRANSLATOR_BITMAP)
516 return translate_from_png_to_bits(inSource, outDestination);
517 else {
518 // Translate from PNG to PNG
519 translate_direct_copy(inSource, outDestination);
520 return B_OK;
524 // Convert width pixels from pbits to PNG format, storing the
525 // result in ppng
526 status_t
527 pix_bits_to_png(uint8 *pbits, uint8 *ppng, color_space fromspace,
528 uint32 width, const color_map *pmap, int32 bitsBytesPerPixel)
530 status_t bytescopied = 0;
531 uint16 val;
533 switch (fromspace) {
534 case B_RGBA32:
535 bytescopied = width * bitsBytesPerPixel;
536 memcpy(ppng, pbits, bytescopied);
537 break;
539 case B_RGB32:
540 case B_RGB24:
541 bytescopied = width * bitsBytesPerPixel;
542 while (width--) {
543 memcpy(ppng, pbits, 3);
544 ppng += 3;
545 pbits += bitsBytesPerPixel;
547 break;
549 case B_RGBA32_BIG:
550 bytescopied = width * 4;
551 while (width--) {
552 ppng[0] = pbits[3];
553 ppng[1] = pbits[2];
554 ppng[2] = pbits[1];
555 ppng[3] = pbits[0];
557 ppng += 4;
558 pbits += 4;
560 break;
562 case B_CMYA32:
563 bytescopied = width * 4;
564 while (width--) {
565 ppng[0] = 255 - pbits[2];
566 ppng[1] = 255 - pbits[1];
567 ppng[2] = 255 - pbits[0];
568 ppng[3] = pbits[3];
570 ppng += 4;
571 pbits += 4;
573 break;
575 case B_CMYK32:
577 int32 comp;
578 bytescopied = width * 3;
579 while (width--) {
580 comp = 255 - pbits[2] - pbits[3];
581 ppng[0] = (comp < 0) ? 0 : comp;
583 comp = 255 - pbits[1] - pbits[3];
584 ppng[1] = (comp < 0) ? 0 : comp;
586 comp = 255 - pbits[0] - pbits[3];
587 ppng[2] = (comp < 0) ? 0 : comp;
589 ppng += 3;
590 pbits += 4;
592 break;
595 case B_CMY32:
596 case B_CMY24:
597 bytescopied = width * 3;
598 while (width--) {
599 ppng[0] = 255 - pbits[2];
600 ppng[1] = 255 - pbits[1];
601 ppng[2] = 255 - pbits[0];
603 ppng += 3;
604 pbits += bitsBytesPerPixel;
606 break;
608 case B_RGB16:
609 case B_RGB16_BIG:
610 bytescopied = width * 3;
611 while (width--) {
612 if (fromspace == B_RGB16)
613 val = pbits[0] + (pbits[1] << 8);
614 else
615 val = pbits[1] + (pbits[0] << 8);
617 ppng[0] =
618 ((val & 0x1f) << 3) | ((val & 0x1f) >> 2);
619 ppng[1] =
620 ((val & 0x7e0) >> 3) | ((val & 0x7e0) >> 9);
621 ppng[2] =
622 ((val & 0xf800) >> 8) | ((val & 0xf800) >> 13);
624 ppng += 3;
625 pbits += 2;
627 break;
629 case B_RGB15:
630 case B_RGB15_BIG:
631 bytescopied = width * 3;
632 while (width--) {
633 if (fromspace == B_RGB15)
634 val = pbits[0] + (pbits[1] << 8);
635 else
636 val = pbits[1] + (pbits[0] << 8);
637 ppng[0] =
638 ((val & 0x1f) << 3) | ((val & 0x1f) >> 2);
639 ppng[1] =
640 ((val & 0x3e0) >> 2) | ((val & 0x3e0) >> 7);
641 ppng[2] =
642 ((val & 0x7c00) >> 7) | ((val & 0x7c00) >> 12);
644 ppng += 3;
645 pbits += 2;
647 break;
649 case B_RGBA15:
650 case B_RGBA15_BIG:
651 bytescopied = width * 4;
652 while (width--) {
653 if (fromspace == B_RGBA15)
654 val = pbits[0] + (pbits[1] << 8);
655 else
656 val = pbits[1] + (pbits[0] << 8);
657 ppng[0] =
658 ((val & 0x1f) << 3) | ((val & 0x1f) >> 2);
659 ppng[1] =
660 ((val & 0x3e0) >> 2) | ((val & 0x3e0) >> 7);
661 ppng[2] =
662 ((val & 0x7c00) >> 7) | ((val & 0x7c00) >> 12);
663 ppng[3] = (val & 0x8000) ? 255 : 0;
665 ppng += 4;
666 pbits += 2;
668 break;
670 case B_RGB32_BIG:
671 bytescopied = width * 3;
672 while (width--) {
673 ppng[0] = pbits[3];
674 ppng[1] = pbits[2];
675 ppng[2] = pbits[1];
677 ppng += 3;
678 pbits += 4;
680 break;
682 case B_RGB24_BIG:
683 bytescopied = width * 3;
684 while (width--) {
685 ppng[0] = pbits[2];
686 ppng[1] = pbits[1];
687 ppng[2] = pbits[0];
689 ppng += 3;
690 pbits += 3;
692 break;
694 case B_CMAP8:
696 rgb_color c;
697 bytescopied = width * 3;
698 while (width--) {
699 c = pmap->color_list[pbits[0]];
700 ppng[0] = c.blue;
701 ppng[1] = c.green;
702 ppng[2] = c.red;
704 ppng += 3;
705 pbits++;
707 break;
710 case B_GRAY8:
711 bytescopied = width;
712 memcpy(ppng, pbits, bytescopied);
713 break;
715 default:
716 bytescopied = B_ERROR;
717 break;
718 } // switch (fromspace)
720 return bytescopied;
723 status_t
724 PNGTranslator::translate_from_bits_to_png(BPositionIO *inSource,
725 BPositionIO *outDestination)
727 TranslatorBitmap bitsHeader;
729 status_t result;
731 result = identify_bits_header(inSource, NULL, &bitsHeader);
732 if (result != B_OK)
733 return result;
735 const color_map *pmap = NULL;
736 if (bitsHeader.colors == B_CMAP8) {
737 pmap = system_colors();
738 if (!pmap)
739 return B_ERROR;
742 png_uint_32 width, height;
743 width = static_cast<png_uint_32>(bitsHeader.bounds.Width() + 1);
744 height = static_cast<png_uint_32>(bitsHeader.bounds.Height() + 1);
746 int32 pngBytesPerPixel = 0;
747 int bit_depth, color_type, interlace_type;
748 bit_depth = 8;
749 switch (bitsHeader.colors) {
750 case B_RGBA32:
751 case B_RGBA32_BIG:
752 case B_CMYA32:
753 case B_RGBA15:
754 case B_RGBA15_BIG:
755 pngBytesPerPixel = 4;
756 color_type = PNG_COLOR_TYPE_RGB_ALPHA;
757 break;
759 case B_RGB32:
760 case B_RGB32_BIG:
761 case B_RGB24:
762 case B_RGB24_BIG:
763 case B_CMY32:
764 case B_CMYK32:
765 case B_CMY24:
766 case B_RGB16:
767 case B_RGB16_BIG:
768 case B_RGB15:
769 case B_RGB15_BIG:
770 pngBytesPerPixel = 3;
771 color_type = PNG_COLOR_TYPE_RGB;
772 break;
774 // ADD SUPPORT FOR B_CMAP8 HERE (later)
776 case B_GRAY8:
777 pngBytesPerPixel = 1;
778 color_type = PNG_COLOR_TYPE_GRAY;
779 break;
781 default:
782 return B_NO_TRANSLATOR;
784 interlace_type = fSettings->SetGetInt32(PNG_SETTING_INTERLACE);
786 int32 bitsBytesPerPixel = 0;
787 switch (bitsHeader.colors) {
788 case B_RGBA32:
789 case B_RGBA32_BIG:
790 case B_RGB32:
791 case B_RGB32_BIG:
792 case B_CMYA32:
793 case B_CMYK32:
794 case B_CMY32:
795 bitsBytesPerPixel = 4;
796 break;
798 case B_RGB24:
799 case B_RGB24_BIG:
800 case B_CMY24:
801 bitsBytesPerPixel = 3;
802 break;
804 case B_RGB16:
805 case B_RGB16_BIG:
806 case B_RGBA15:
807 case B_RGBA15_BIG:
808 case B_RGB15:
809 case B_RGB15_BIG:
810 bitsBytesPerPixel = 2;
811 break;
813 case B_GRAY8:
814 case B_CMAP8:
815 bitsBytesPerPixel = 1;
816 break;
818 default:
819 return B_NO_TRANSLATOR;
822 uint8 *pbitsrow = NULL, *prow = NULL;
823 // row buffers
824 // image buffer for writing whole png image at once
825 uint8 **prows = NULL;
826 png_uint_32 nalloc = 0;
828 png_structp ppng = NULL;
829 png_infop pinfo = NULL;
831 result = B_NO_TRANSLATOR;
832 while (ppng == NULL) {
833 // create PNG read pointer with default error handling routines
834 ppng = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
835 NULL, NULL);
836 if (!ppng) {
837 result = B_ERROR;
838 break;
840 // alocate / init memory for image information
841 pinfo = png_create_info_struct(ppng);
842 if (!pinfo) {
843 result = B_ERROR;
844 break;
847 // set up erorr handling to use C++ exceptions instead of setjmp
848 png_set_error_fn(ppng, png_get_error_ptr(ppng), throw_error,
849 alert_warning);
851 try {
852 png_set_write_fn(ppng, static_cast<void *>(outDestination),
853 pngcb_write_data, pngcb_flush_data);
855 // Allocate memory needed to buffer image data
856 pbitsrow = new uint8[bitsHeader.rowBytes];
857 if (!pbitsrow) {
858 result = B_NO_MEMORY;
859 break;
861 if (interlace_type == PNG_INTERLACE_NONE) {
862 prow = new uint8[width * pngBytesPerPixel];
863 if (!prow) {
864 result = B_NO_MEMORY;
865 break;
867 } else {
868 prows = new uint8 *[height];
869 if (!prows) {
870 result = B_NO_MEMORY;
871 break;
873 // allocate enough memory to store the whole image
874 for (nalloc = 0; nalloc < height; nalloc++) {
875 prows[nalloc] = new uint8[width * pngBytesPerPixel];
876 if (!prows[nalloc])
877 break;
879 if (nalloc < height) {
880 result = B_NO_MEMORY;
881 // clear out rest of the pointers,
882 // so we don't call delete[] with invalid pointers
883 for (; nalloc < height; nalloc++)
884 prows[nalloc] = NULL;
885 break;
889 // Specify image info
890 png_set_IHDR(ppng, pinfo, width, height, bit_depth, color_type,
891 interlace_type, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
892 png_write_info(ppng, pinfo);
894 png_set_bgr(ppng);
896 // write out image data
897 if (interlace_type == PNG_INTERLACE_NONE) {
898 for (png_uint_32 i = 0; i < height; i++) {
899 inSource->Read(pbitsrow, bitsHeader.rowBytes);
901 pix_bits_to_png(pbitsrow, prow, bitsHeader.colors, width,
902 pmap, bitsBytesPerPixel);
904 png_write_row(ppng, prow);
906 } else {
907 for (png_uint_32 i = 0; i < height; i++) {
908 inSource->Read(pbitsrow, bitsHeader.rowBytes);
910 pix_bits_to_png(pbitsrow, prows[i], bitsHeader.colors,
911 width, pmap, bitsBytesPerPixel);
913 png_write_image(ppng, prows);
915 result = B_OK;
916 // If png_read_end throws an exception, we still accept
917 // the image as valid.
918 png_write_end(ppng, NULL);
920 break;
921 } catch(std::exception& e) {
922 break;
926 if (ppng) {
927 delete[] pbitsrow;
928 pbitsrow = NULL;
930 delete[] prow;
931 prow = NULL;
933 // delete row pointers and array of pointers to rows
934 while (nalloc) {
935 nalloc--;
936 delete[] prows[nalloc];
938 delete[] prows;
939 prows = NULL;
941 // free PNG handle / info structures
942 if (!pinfo)
943 png_destroy_write_struct(&ppng, NULL);
944 else
945 png_destroy_write_struct(&ppng, &pinfo);
948 return result;
951 // ---------------------------------------------------------------
952 // DerivedTranslate
954 // Translates the data in inSource to the type outType and stores
955 // the translated data in outDestination.
957 // Preconditions:
959 // Parameters: inSource, the data to be translated
961 // inInfo, hint about the data in inSource (not used)
963 // ioExtension, configuration options for the
964 // translator
966 // outType, the type to convert inSource to
968 // outDestination, where the translated data is
969 // put
971 // baseType, indicates whether inSource is in the
972 // bits format, not in the bits format or
973 // is unknown
975 // Postconditions:
977 // Returns: B_BAD_VALUE, if the options in ioExtension are bad
979 // B_NO_TRANSLATOR, if this translator doesn't understand the data
981 // B_ERROR, if there was an error allocating memory or converting
982 // data
984 // B_OK, if all went well
985 // ---------------------------------------------------------------
986 status_t
987 PNGTranslator::DerivedTranslate(BPositionIO *inSource,
988 const translator_info *inInfo, BMessage *ioExtension, uint32 outType,
989 BPositionIO *outDestination, int32 baseType)
991 if (baseType == 1)
992 // if inSource is in bits format
993 return translate_from_bits_to_png(inSource, outDestination);
994 else if (baseType == 0)
995 // if inSource is NOT in bits format
996 return translate_from_png(inSource, outType, outDestination);
997 else
998 return B_NO_TRANSLATOR;
1001 BView *
1002 PNGTranslator::NewConfigView(TranslatorSettings *settings)
1004 return new PNGView(BRect(0, 0, PNG_VIEW_WIDTH, PNG_VIEW_HEIGHT),
1005 B_TRANSLATE("PNGTranslator Settings"), B_FOLLOW_ALL,
1006 B_WILL_DRAW, settings);