1 /*
2   ==============================================================================
3 
4    This file is part of the JUCE library.
5    Copyright (c) 2020 - Raw Material Software Limited
6 
7    JUCE is an open source library subject to commercial or open-source
8    licensing.
9 
10    By using JUCE, you agree to the terms of both the JUCE 6 End-User License
11    Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
12 
13    End User License Agreement: www.juce.com/juce-6-licence
14    Privacy Policy: www.juce.com/juce-privacy-policy
15 
16    Or: You may also use this code under the terms of the GPL v3 (see
17    www.gnu.org/licenses).
18 
19    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21    DISCLAIMED.
22 
23   ==============================================================================
24 */
25 
26 namespace juce
27 {
28 
29 JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4390 4611 4365 4267 4616 2544 2545)
30 
31 namespace zlibNamespace
32 {
33 #if JUCE_INCLUDE_ZLIB_CODE
34   #undef OS_CODE
35   #undef fdopen
36   #define ZLIB_INTERNAL
37   #define NO_DUMMY_DECL
38   #include <juce_core/zip/zlib/zlib.h>
39   #undef OS_CODE
40 #else
41   #include JUCE_ZLIB_INCLUDE_PATH
42 #endif
43 }
44 
45 #if ! defined (jmp_buf) || ! defined (longjmp)
46  #include <setjmp.h>
47 #endif
48 
49 namespace pnglibNamespace
50 {
51   using namespace zlibNamespace;
52 
53 #if JUCE_INCLUDE_PNGLIB_CODE || ! defined (JUCE_INCLUDE_PNGLIB_CODE)
54 
55   #if _MSC_VER != 1310
56    using std::calloc; // (causes conflict in VS.NET 2003)
57    using std::malloc;
58    using std::free;
59   #endif
60 
61    JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wsign-conversion",
62                                         "-Wimplicit-fallthrough",
63                                         "-Wtautological-constant-out-of-range-compare",
64                                         "-Wzero-as-null-pointer-constant",
65                                         "-Wcomma")
66 
67   #undef check
68   using std::abs;
69   #define NO_DUMMY_DECL
70   #define PNGLCONF_H 1
71 
72  #if JUCE_ANDROID
73   #define PNG_ARM_NEON_SUPPORTED
74  #endif
75 
76  #ifndef Byte
77   using Byte = uint8_t;
78  #endif
79 
80   #define PNG_16BIT_SUPPORTED
81   #define PNG_ALIGNED_MEMORY_SUPPORTED
82   #define PNG_BENIGN_ERRORS_SUPPORTED
83   #define PNG_BENIGN_READ_ERRORS_SUPPORTED
84   #define PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
85   #define PNG_COLORSPACE_SUPPORTED
86   #define PNG_CONSOLE_IO_SUPPORTED
87   #define PNG_EASY_ACCESS_SUPPORTED
88   #define PNG_FIXED_POINT_SUPPORTED
89   #define PNG_FLOATING_ARITHMETIC_SUPPORTED
90   #define PNG_FLOATING_POINT_SUPPORTED
91   #define PNG_FORMAT_AFIRST_SUPPORTED
92   #define PNG_FORMAT_BGR_SUPPORTED
93   #define PNG_GAMMA_SUPPORTED
94   #define PNG_GET_PALETTE_MAX_SUPPORTED
95   #define PNG_HANDLE_AS_UNKNOWN_SUPPORTED
96   #define PNG_INCH_CONVERSIONS_SUPPORTED
97   #define PNG_INFO_IMAGE_SUPPORTED
98   #define PNG_IO_STATE_SUPPORTED
99   #define PNG_POINTER_INDEXING_SUPPORTED
100   #define PNG_PROGRESSIVE_READ_SUPPORTED
101   #define PNG_READ_16BIT_SUPPORTED
102   #define PNG_READ_ALPHA_MODE_SUPPORTED
103   #define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED
104   #define PNG_READ_BACKGROUND_SUPPORTED
105   #define PNG_READ_BGR_SUPPORTED
106   #define PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
107   #define PNG_READ_COMPOSITE_NODIV_SUPPORTED
108   #define PNG_READ_COMPRESSED_TEXT_SUPPORTED
109   #define PNG_READ_EXPAND_16_SUPPORTED
110   #define PNG_READ_EXPAND_SUPPORTED
111   #define PNG_READ_FILLER_SUPPORTED
112   #define PNG_READ_GAMMA_SUPPORTED
113   #define PNG_READ_GET_PALETTE_MAX_SUPPORTED
114   #define PNG_READ_GRAY_TO_RGB_SUPPORTED
115   #define PNG_READ_INTERLACING_SUPPORTED
116   #define PNG_READ_INT_FUNCTIONS_SUPPORTED
117   #define PNG_READ_INVERT_ALPHA_SUPPORTED
118   #define PNG_READ_INVERT_SUPPORTED
119   #define PNG_READ_OPT_PLTE_SUPPORTED
120   #define PNG_READ_PACKSWAP_SUPPORTED
121   #define PNG_READ_PACK_SUPPORTED
122   #define PNG_READ_QUANTIZE_SUPPORTED
123   #define PNG_READ_RGB_TO_GRAY_SUPPORTED
124   #define PNG_READ_SCALE_16_TO_8_SUPPORTED
125   #define PNG_READ_SHIFT_SUPPORTED
126   #define PNG_READ_STRIP_16_TO_8_SUPPORTED
127   #define PNG_READ_STRIP_ALPHA_SUPPORTED
128   #define PNG_READ_SUPPORTED
129   #define PNG_READ_SWAP_ALPHA_SUPPORTED
130   #define PNG_READ_SWAP_SUPPORTED
131   #define PNG_READ_TEXT_SUPPORTED
132   #define PNG_READ_TRANSFORMS_SUPPORTED
133   #define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
134   #define PNG_READ_USER_CHUNKS_SUPPORTED
135   #define PNG_READ_USER_TRANSFORM_SUPPORTED
136   #define PNG_READ_bKGD_SUPPORTED
137   #define PNG_READ_cHRM_SUPPORTED
138   #define PNG_READ_gAMA_SUPPORTED
139   #define PNG_READ_hIST_SUPPORTED
140   #define PNG_READ_iCCP_SUPPORTED
141   #define PNG_READ_iTXt_SUPPORTED
142   #define PNG_READ_oFFs_SUPPORTED
143   #define PNG_READ_pCAL_SUPPORTED
144   #define PNG_READ_pHYs_SUPPORTED
145   #define PNG_READ_sBIT_SUPPORTED
146   #define PNG_READ_sCAL_SUPPORTED
147   #define PNG_READ_sPLT_SUPPORTED
148   #define PNG_READ_sRGB_SUPPORTED
149   #define PNG_READ_tEXt_SUPPORTED
150   #define PNG_READ_tIME_SUPPORTED
151   #define PNG_READ_tRNS_SUPPORTED
152   #define PNG_READ_zTXt_SUPPORTED
153   #define PNG_SAVE_INT_32_SUPPORTED
154   #define PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
155   #define PNG_SEQUENTIAL_READ_SUPPORTED
156   #define PNG_SET_CHUNK_CACHE_LIMIT_SUPPORTED
157   #define PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED
158   #define PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
159   #define PNG_SET_USER_LIMITS_SUPPORTED
160   #define PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED
161   #define PNG_SIMPLIFIED_READ_BGR_SUPPORTED
162   #define PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED
163   #define PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED
164   #define PNG_STDIO_SUPPORTED
165   #define PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
166   #define PNG_TEXT_SUPPORTED
167   #define PNG_TIME_RFC1123_SUPPORTED
168   #define PNG_UNKNOWN_CHUNKS_SUPPORTED
169   #define PNG_USER_CHUNKS_SUPPORTED
170   #define PNG_USER_LIMITS_SUPPORTED
171   #define PNG_USER_TRANSFORM_INFO_SUPPORTED
172   #define PNG_USER_TRANSFORM_PTR_SUPPORTED
173   #define PNG_WARNINGS_SUPPORTED
174   #define PNG_WRITE_16BIT_SUPPORTED
175   #define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED
176   #define PNG_WRITE_BGR_SUPPORTED
177   #define PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
178   #define PNG_WRITE_COMPRESSED_TEXT_SUPPORTED
179   #define PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
180   #define PNG_WRITE_FILLER_SUPPORTED
181   #define PNG_WRITE_FILTER_SUPPORTED
182   #define PNG_WRITE_FLUSH_SUPPORTED
183   #define PNG_WRITE_GET_PALETTE_MAX_SUPPORTED
184   #define PNG_WRITE_INTERLACING_SUPPORTED
185   #define PNG_WRITE_INT_FUNCTIONS_SUPPORTED
186   #define PNG_WRITE_INVERT_ALPHA_SUPPORTED
187   #define PNG_WRITE_INVERT_SUPPORTED
188   #define PNG_WRITE_OPTIMIZE_CMF_SUPPORTED
189   #define PNG_WRITE_PACKSWAP_SUPPORTED
190   #define PNG_WRITE_PACK_SUPPORTED
191   #define PNG_WRITE_SHIFT_SUPPORTED
192   #define PNG_WRITE_SUPPORTED
193   #define PNG_WRITE_SWAP_ALPHA_SUPPORTED
194   #define PNG_WRITE_SWAP_SUPPORTED
195   #define PNG_WRITE_TEXT_SUPPORTED
196   #define PNG_WRITE_TRANSFORMS_SUPPORTED
197   #define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
198   #define PNG_WRITE_USER_TRANSFORM_SUPPORTED
199   #define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
200   #define PNG_WRITE_bKGD_SUPPORTED
201   #define PNG_WRITE_cHRM_SUPPORTED
202   #define PNG_WRITE_gAMA_SUPPORTED
203   #define PNG_WRITE_hIST_SUPPORTED
204   #define PNG_WRITE_iCCP_SUPPORTED
205   #define PNG_WRITE_iTXt_SUPPORTED
206   #define PNG_WRITE_oFFs_SUPPORTED
207   #define PNG_WRITE_pCAL_SUPPORTED
208   #define PNG_WRITE_pHYs_SUPPORTED
209   #define PNG_WRITE_sBIT_SUPPORTED
210   #define PNG_WRITE_sCAL_SUPPORTED
211   #define PNG_WRITE_sPLT_SUPPORTED
212   #define PNG_WRITE_sRGB_SUPPORTED
213   #define PNG_WRITE_tEXt_SUPPORTED
214   #define PNG_WRITE_tIME_SUPPORTED
215   #define PNG_WRITE_tRNS_SUPPORTED
216   #define PNG_WRITE_zTXt_SUPPORTED
217   #define PNG_bKGD_SUPPORTED
218   #define PNG_cHRM_SUPPORTED
219   #define PNG_gAMA_SUPPORTED
220   #define PNG_hIST_SUPPORTED
221   #define PNG_iCCP_SUPPORTED
222   #define PNG_iTXt_SUPPORTED
223   #define PNG_oFFs_SUPPORTED
224   #define PNG_pCAL_SUPPORTED
225   #define PNG_pHYs_SUPPORTED
226   #define PNG_sBIT_SUPPORTED
227   #define PNG_sCAL_SUPPORTED
228   #define PNG_sPLT_SUPPORTED
229   #define PNG_sRGB_SUPPORTED
230   #define PNG_tEXt_SUPPORTED
231   #define PNG_tIME_SUPPORTED
232   #define PNG_tRNS_SUPPORTED
233   #define PNG_zTXt_SUPPORTED
234 
235   #define PNG_STRING_COPYRIGHT "";
236   #define PNG_STRING_NEWLINE "\n"
237   #define PNG_LITERAL_SHARP 0x23
238   #define PNG_LITERAL_LEFT_SQUARE_BRACKET 0x5b
239   #define PNG_LITERAL_RIGHT_SQUARE_BRACKET 0x5d
240 
241   #define PNG_API_RULE 0
242   #define PNG_CALLOC_SUPPORTED
243   #define PNG_COST_SHIFT 3
244   #define PNG_DEFAULT_READ_MACROS 1
245   #define PNG_GAMMA_THRESHOLD_FIXED 5000
246   #define PNG_IDAT_READ_SIZE PNG_ZBUF_SIZE
247   #define PNG_INFLATE_BUF_SIZE 1024
248   #define PNG_MAX_GAMMA_8 11
249   #define PNG_QUANTIZE_BLUE_BITS 5
250   #define PNG_QUANTIZE_GREEN_BITS 5
251   #define PNG_QUANTIZE_RED_BITS 5
252   #define PNG_TEXT_Z_DEFAULT_COMPRESSION (-1)
253   #define PNG_TEXT_Z_DEFAULT_STRATEGY 0
254   #define PNG_WEIGHT_SHIFT 8
255   #define PNG_ZBUF_SIZE 8192
256   #define PNG_Z_DEFAULT_COMPRESSION (-1)
257   #define PNG_Z_DEFAULT_NOFILTER_STRATEGY 0
258   #define PNG_Z_DEFAULT_STRATEGY 1
259   #define PNG_sCAL_PRECISION 5
260   #define PNG_sRGB_PROFILE_CHECKS 2
261 
262   #define PNG_LINKAGE_API
263   #define PNG_LINKAGE_FUNCTION
264 
265   #define PNG_ARM_NEON_OPT 0
266 
267   #if ! defined (PNG_USER_WIDTH_MAX)
268    #define PNG_USER_WIDTH_MAX 1000000
269   #endif
270 
271   #if ! defined (PNG_USER_HEIGHT_MAX)
272    #define PNG_USER_HEIGHT_MAX 1000000
273   #endif
274 
275   #define png_debug(a, b)
276   #define png_debug1(a, b, c)
277   #define png_debug2(a, b, c, d)
278 
279   #include "pnglib/png.h"
280   #include "pnglib/pngconf.h"
281 
282   #define PNG_NO_EXTERN
283   #include "pnglib/png.c"
284   #include "pnglib/pngerror.c"
285   #include "pnglib/pngget.c"
286   #include "pnglib/pngmem.c"
287   #include "pnglib/pngread.c"
288   #include "pnglib/pngpread.c"
289   #include "pnglib/pngrio.c"
290 
291   void png_do_expand_palette (png_row_infop, png_bytep, png_const_colorp, png_const_bytep, int);
292   void png_do_expand (png_row_infop, png_bytep, png_const_color_16p);
293   void png_do_chop (png_row_infop, png_bytep);
294   void png_do_quantize (png_row_infop, png_bytep, png_const_bytep, png_const_bytep);
295   void png_do_gray_to_rgb (png_row_infop, png_bytep);
296   void png_do_unshift (png_row_infop, png_bytep, png_const_color_8p);
297   void png_do_unpack (png_row_infop, png_bytep);
298   int png_do_rgb_to_gray (png_structrp, png_row_infop, png_bytep);
299   void png_do_compose (png_row_infop, png_bytep, png_structrp);
300   void png_do_gamma (png_row_infop, png_bytep, png_structrp);
301   void png_do_encode_alpha (png_row_infop, png_bytep, png_structrp);
302   void png_do_scale_16_to_8 (png_row_infop, png_bytep);
303   void png_do_expand_16 (png_row_infop, png_bytep);
304   void png_do_read_filler (png_row_infop, png_bytep, png_uint_32, png_uint_32);
305   void png_do_read_invert_alpha (png_row_infop, png_bytep);
306   void png_do_read_swap_alpha (png_row_infop, png_bytep);
307 
308   #include "pnglib/pngrtran.c"
309   #include "pnglib/pngrutil.c"
310   #include "pnglib/pngset.c"
311   #include "pnglib/pngtrans.c"
312   #include "pnglib/pngwio.c"
313   #include "pnglib/pngwrite.c"
314   #include "pnglib/pngwtran.c"
315   #include "pnglib/pngwutil.c"
316 
317   JUCE_END_IGNORE_WARNINGS_GCC_LIKE
318 
319 #else
320   extern "C"
321   {
322     #include <png.h>
323     #include <pngconf.h>
324   }
325 #endif
326 }
327 
328 #undef max
329 #undef min
330 #undef fdopen
331 
332 JUCE_END_IGNORE_WARNINGS_MSVC
333 
334 //==============================================================================
335 namespace PNGHelpers
336 {
337     using namespace pnglibNamespace;
338 
writeDataCallback(png_structp png,png_bytep data,png_size_t length)339     static void JUCE_CDECL writeDataCallback (png_structp png, png_bytep data, png_size_t length)
340     {
341         static_cast<OutputStream*> (png_get_io_ptr (png))->write (data, length);
342     }
343 
344    #if ! JUCE_USING_COREIMAGE_LOADER
readCallback(png_structp png,png_bytep data,png_size_t length)345     static void JUCE_CDECL readCallback (png_structp png, png_bytep data, png_size_t length)
346     {
347         static_cast<InputStream*> (png_get_io_ptr (png))->read (data, (int) length);
348     }
349 
350     struct PNGErrorStruct {};
351 
errorCallback(png_structp p,png_const_charp)352     static void JUCE_CDECL errorCallback (png_structp p, png_const_charp)
353     {
354        #ifdef PNG_SETJMP_SUPPORTED
355         setjmp(png_jmpbuf(p));
356        #else
357         longjmp (*(jmp_buf*) p->error_ptr, 1);
358        #endif
359     }
360 
warningCallback(png_structp,png_const_charp)361     static void JUCE_CDECL warningCallback (png_structp, png_const_charp) {}
362 
363     JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4611)
364 
readHeader(InputStream & in,png_structp pngReadStruct,png_infop pngInfoStruct,jmp_buf & errorJumpBuf,png_uint_32 & width,png_uint_32 & height,int & bitDepth,int & colorType,int & interlaceType)365     static bool readHeader (InputStream& in, png_structp pngReadStruct, png_infop pngInfoStruct, jmp_buf& errorJumpBuf,
366                             png_uint_32& width, png_uint_32& height, int& bitDepth, int& colorType, int& interlaceType) noexcept
367     {
368         if (setjmp (errorJumpBuf) == 0)
369         {
370             // read the header..
371             png_set_read_fn (pngReadStruct, &in, readCallback);
372 
373             png_read_info (pngReadStruct, pngInfoStruct);
374 
375             png_get_IHDR (pngReadStruct, pngInfoStruct,
376                           &width, &height,
377                           &bitDepth, &colorType,
378                           &interlaceType, nullptr, nullptr);
379 
380             if (bitDepth == 16)
381                 png_set_strip_16 (pngReadStruct);
382 
383             if (colorType == PNG_COLOR_TYPE_PALETTE)
384                 png_set_expand (pngReadStruct);
385 
386             if (bitDepth < 8)
387                 png_set_expand (pngReadStruct);
388 
389             if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA)
390                 png_set_gray_to_rgb (pngReadStruct);
391 
392             return true;
393         }
394 
395         return false;
396     }
397 
readImageData(png_structp pngReadStruct,png_infop pngInfoStruct,jmp_buf & errorJumpBuf,png_bytepp rows)398     static bool readImageData (png_structp pngReadStruct, png_infop pngInfoStruct, jmp_buf& errorJumpBuf, png_bytepp rows) noexcept
399     {
400         if (setjmp (errorJumpBuf) == 0)
401         {
402             if (png_get_valid (pngReadStruct, pngInfoStruct, PNG_INFO_tRNS))
403                 png_set_expand (pngReadStruct);
404 
405             png_set_add_alpha (pngReadStruct, 0xff, PNG_FILLER_AFTER);
406 
407             png_read_image (pngReadStruct, rows);
408             png_read_end (pngReadStruct, pngInfoStruct);
409             return true;
410         }
411 
412         return false;
413     }
414 
415     JUCE_END_IGNORE_WARNINGS_MSVC
416 
createImageFromData(bool hasAlphaChan,int width,int height,png_bytepp rows)417     static Image createImageFromData (bool hasAlphaChan, int width, int height, png_bytepp rows)
418     {
419         // now convert the data to a juce image format..
420         Image image (hasAlphaChan ? Image::ARGB : Image::RGB, width, height, hasAlphaChan);
421 
422         image.getProperties()->set ("originalImageHadAlpha", image.hasAlphaChannel());
423         hasAlphaChan = image.hasAlphaChannel(); // (the native image creator may not give back what we expect)
424 
425         const Image::BitmapData destData (image, Image::BitmapData::writeOnly);
426 
427         for (int y = 0; y < (int) height; ++y)
428         {
429             const uint8* src = rows[y];
430             uint8* dest = destData.getLinePointer (y);
431 
432             if (hasAlphaChan)
433             {
434                 for (int i = (int) width; --i >= 0;)
435                 {
436                     ((PixelARGB*) dest)->setARGB (src[3], src[0], src[1], src[2]);
437                     ((PixelARGB*) dest)->premultiply();
438                     dest += destData.pixelStride;
439                     src += 4;
440                 }
441             }
442             else
443             {
444                 for (int i = (int) width; --i >= 0;)
445                 {
446                     ((PixelRGB*) dest)->setARGB (0, src[0], src[1], src[2]);
447                     dest += destData.pixelStride;
448                     src += 4;
449                 }
450             }
451         }
452 
453         return image;
454     }
455 
readImage(InputStream & in,png_structp pngReadStruct,png_infop pngInfoStruct)456     static Image readImage (InputStream& in, png_structp pngReadStruct, png_infop pngInfoStruct)
457     {
458         jmp_buf errorJumpBuf;
459         png_set_error_fn (pngReadStruct, &errorJumpBuf, errorCallback, warningCallback);
460 
461         png_uint_32 width = 0, height = 0;
462         int bitDepth = 0, colorType = 0, interlaceType = 0;
463 
464         if (readHeader (in, pngReadStruct, pngInfoStruct, errorJumpBuf,
465                         width, height, bitDepth, colorType, interlaceType))
466         {
467             // Load the image into a temp buffer..
468             const size_t lineStride = width * 4;
469             HeapBlock<uint8> tempBuffer (height * lineStride);
470             HeapBlock<png_bytep> rows (height);
471 
472             for (size_t y = 0; y < height; ++y)
473                 rows[y] = (png_bytep) (tempBuffer + lineStride * y);
474 
475             png_bytep trans_alpha = nullptr;
476             png_color_16p trans_color = nullptr;
477             int num_trans = 0;
478             png_get_tRNS (pngReadStruct, pngInfoStruct, &trans_alpha, &num_trans, &trans_color);
479 
480             if (readImageData (pngReadStruct, pngInfoStruct, errorJumpBuf, rows))
481                 return createImageFromData ((colorType & PNG_COLOR_MASK_ALPHA) != 0 || num_trans != 0,
482                                             (int) width, (int) height, rows);
483         }
484 
485         return Image();
486     }
487 
readImage(InputStream & in)488     static Image readImage (InputStream& in)
489     {
490         if (png_structp pngReadStruct = png_create_read_struct (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr))
491         {
492             if (png_infop pngInfoStruct = png_create_info_struct (pngReadStruct))
493             {
494                 Image image (readImage (in, pngReadStruct, pngInfoStruct));
495                 png_destroy_read_struct (&pngReadStruct, &pngInfoStruct, nullptr);
496                 return image;
497             }
498 
499             png_destroy_read_struct (&pngReadStruct, nullptr, nullptr);
500         }
501 
502         return Image();
503     }
504    #endif
505 }
506 
507 //==============================================================================
PNGImageFormat()508 PNGImageFormat::PNGImageFormat()    {}
~PNGImageFormat()509 PNGImageFormat::~PNGImageFormat()   {}
510 
getFormatName()511 String PNGImageFormat::getFormatName()                   { return "PNG"; }
usesFileExtension(const File & f)512 bool PNGImageFormat::usesFileExtension (const File& f)   { return f.hasFileExtension ("png"); }
513 
canUnderstand(InputStream & in)514 bool PNGImageFormat::canUnderstand (InputStream& in)
515 {
516     const int bytesNeeded = 4;
517     char header [bytesNeeded];
518 
519     return in.read (header, bytesNeeded) == bytesNeeded
520             && header[1] == 'P'
521             && header[2] == 'N'
522             && header[3] == 'G';
523 }
524 
525 #if JUCE_USING_COREIMAGE_LOADER
526  Image juce_loadWithCoreImage (InputStream&);
527 #endif
528 
decodeImage(InputStream & in)529 Image PNGImageFormat::decodeImage (InputStream& in)
530 {
531    #if JUCE_USING_COREIMAGE_LOADER
532     return juce_loadWithCoreImage (in);
533    #else
534     return PNGHelpers::readImage (in);
535    #endif
536 }
537 
writeImageToStream(const Image & image,OutputStream & out)538 bool PNGImageFormat::writeImageToStream (const Image& image, OutputStream& out)
539 {
540     using namespace pnglibNamespace;
541     auto width = image.getWidth();
542     auto height = image.getHeight();
543 
544     auto pngWriteStruct = png_create_write_struct (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
545 
546     if (pngWriteStruct == nullptr)
547         return false;
548 
549     auto pngInfoStruct = png_create_info_struct (pngWriteStruct);
550 
551     if (pngInfoStruct == nullptr)
552     {
553         png_destroy_write_struct (&pngWriteStruct, nullptr);
554         return false;
555     }
556 
557     png_set_write_fn (pngWriteStruct, &out, PNGHelpers::writeDataCallback, nullptr);
558 
559     png_set_IHDR (pngWriteStruct, pngInfoStruct, (png_uint_32) width, (png_uint_32) height, 8,
560                   image.hasAlphaChannel() ? PNG_COLOR_TYPE_RGB_ALPHA
561                                           : PNG_COLOR_TYPE_RGB,
562                   PNG_INTERLACE_NONE,
563                   PNG_COMPRESSION_TYPE_BASE,
564                   PNG_FILTER_TYPE_BASE);
565 
566     HeapBlock<uint8> rowData (width * 4);
567 
568     png_color_8 sig_bit;
569     sig_bit.red   = 8;
570     sig_bit.green = 8;
571     sig_bit.blue  = 8;
572     sig_bit.gray  = 0;
573     sig_bit.alpha = 8;
574     png_set_sBIT (pngWriteStruct, pngInfoStruct, &sig_bit);
575 
576     png_write_info (pngWriteStruct, pngInfoStruct);
577 
578     png_set_shift (pngWriteStruct, &sig_bit);
579     png_set_packing (pngWriteStruct);
580 
581     const Image::BitmapData srcData (image, Image::BitmapData::readOnly);
582 
583     for (int y = 0; y < height; ++y)
584     {
585         uint8* dst = rowData;
586         const uint8* src = srcData.getLinePointer (y);
587 
588         if (image.hasAlphaChannel())
589         {
590             for (int i = width; --i >= 0;)
591             {
592                 PixelARGB p (*(const PixelARGB*) src);
593                 p.unpremultiply();
594 
595                 *dst++ = p.getRed();
596                 *dst++ = p.getGreen();
597                 *dst++ = p.getBlue();
598                 *dst++ = p.getAlpha();
599                 src += srcData.pixelStride;
600             }
601         }
602         else
603         {
604             for (int i = width; --i >= 0;)
605             {
606                 *dst++ = ((const PixelRGB*) src)->getRed();
607                 *dst++ = ((const PixelRGB*) src)->getGreen();
608                 *dst++ = ((const PixelRGB*) src)->getBlue();
609                 src += srcData.pixelStride;
610             }
611         }
612 
613         png_bytep rowPtr = rowData;
614         png_write_rows (pngWriteStruct, &rowPtr, 1);
615     }
616 
617     png_write_end (pngWriteStruct, pngInfoStruct);
618     png_destroy_write_struct (&pngWriteStruct, &pngInfoStruct);
619 
620     return true;
621 }
622 
623 } // namespace juce
624