New comit of SDL2
[supertux.git] / src / SDL2 / IMG_png.c
1 /*
2   SDL_image:  An example image loading library for use with SDL
3   Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
4
5   This software is provided 'as-is', without any express or implied
6   warranty.  In no event will the authors be held liable for any damages
7   arising from the use of this software.
8
9   Permission is granted to anyone to use this software for any purpose,
10   including commercial applications, and to alter it and redistribute it
11   freely, subject to the following restrictions:
12
13   1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17   2. Altered source versions must be plainly marked as such, and must not be
18      misrepresented as being the original software.
19   3. This notice may not be removed or altered from any source distribution.
20 */
21
22 /* This is a PNG image file loading framework */
23
24 #include "SDL_image.h"
25
26 #if !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND)
27
28 #ifdef LOAD_PNG
29
30 /*=============================================================================
31         File: SDL_png.c
32      Purpose: A PNG loader and saver for the SDL library
33     Revision:
34   Created by: Philippe Lavoie          (2 November 1998)
35               lavoie@zeus.genie.uottawa.ca
36  Modified by:
37
38  Copyright notice:
39           Copyright (C) 1998 Philippe Lavoie
40
41           This library is free software; you can redistribute it and/or
42           modify it under the terms of the GNU Library General Public
43           License as published by the Free Software Foundation; either
44           version 2 of the License, or (at your option) any later version.
45
46           This library is distributed in the hope that it will be useful,
47           but WITHOUT ANY WARRANTY; without even the implied warranty of
48           MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
49           Library General Public License for more details.
50
51           You should have received a copy of the GNU Library General Public
52           License along with this library; if not, write to the Free
53           Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
54
55     Comments: The load and save routine are basically the ones you can find
56              in the example.c file from the libpng distribution.
57
58   Changes:
59     5/17/99 - Modified to use the new SDL data sources - Sam Lantinga
60
61 =============================================================================*/
62
63 #include "SDL_endian.h"
64
65 #ifdef macintosh
66 #define MACOS
67 #endif
68 #include <png.h>
69
70 /* Check for the older version of libpng */
71 #if (PNG_LIBPNG_VER_MAJOR == 1) 
72 #if (PNG_LIBPNG_VER_MINOR < 4)
73 #define LIBPNG_VERSION_12
74 typedef png_bytep png_const_bytep;
75 #endif
76 #if (PNG_LIBPNG_VER_MINOR < 6)
77 typedef png_structp png_const_structrp;
78 typedef png_infop png_const_inforp;
79 #endif
80 #endif
81
82 static struct {
83     int loaded;
84     void *handle;
85     png_infop (*png_create_info_struct) (png_const_structrp png_ptr);
86     png_structp (*png_create_read_struct) (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn);
87     void (*png_destroy_read_struct) (png_structpp png_ptr_ptr, png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr);
88     png_uint_32 (*png_get_IHDR) (png_const_structrp png_ptr, png_const_inforp info_ptr, png_uint_32 *width, png_uint_32 *height, int *bit_depth, int *color_type, int *interlace_method, int *compression_method, int *filter_method);
89     png_voidp (*png_get_io_ptr) (png_const_structrp png_ptr);
90     png_byte (*png_get_channels) (png_const_structrp png_ptr, png_const_inforp info_ptr);
91     png_uint_32 (*png_get_PLTE) (png_const_structrp png_ptr, png_infop info_ptr, png_colorp *palette, int *num_palette);
92     png_uint_32 (*png_get_tRNS) (png_const_structrp png_ptr, png_infop info_ptr, png_bytep *trans, int *num_trans, png_color_16p *trans_values);
93     png_uint_32 (*png_get_valid) (png_const_structrp png_ptr, png_const_inforp info_ptr, png_uint_32 flag);
94     void (*png_read_image) (png_structp png_ptr, png_bytepp image);
95     void (*png_read_info) (png_structp png_ptr, png_infop info_ptr);
96     void (*png_read_update_info) (png_structp png_ptr, png_infop info_ptr);
97     void (*png_set_expand) (png_structp png_ptr);
98     void (*png_set_gray_to_rgb) (png_structp png_ptr);
99     void (*png_set_packing) (png_structp png_ptr);
100     void (*png_set_read_fn) (png_structp png_ptr, png_voidp io_ptr, png_rw_ptr read_data_fn);
101     void (*png_set_strip_16) (png_structp png_ptr);
102     int (*png_sig_cmp) (png_const_bytep sig, png_size_t start, png_size_t num_to_check);
103 #ifndef LIBPNG_VERSION_12
104     jmp_buf* (*png_set_longjmp_fn) (png_structp, png_longjmp_ptr, size_t);
105 #endif
106 } lib;
107
108 #ifdef LOAD_PNG_DYNAMIC
109 int IMG_InitPNG()
110 {
111     if ( lib.loaded == 0 ) {
112         lib.handle = SDL_LoadObject(LOAD_PNG_DYNAMIC);
113         if ( lib.handle == NULL ) {
114             return -1;
115         }
116         lib.png_create_info_struct =
117             (png_infop (*) (png_const_structrp))
118             SDL_LoadFunction(lib.handle, "png_create_info_struct");
119         if ( lib.png_create_info_struct == NULL ) {
120             SDL_UnloadObject(lib.handle);
121             return -1;
122         }
123         lib.png_create_read_struct =
124             (png_structp (*) (png_const_charp, png_voidp, png_error_ptr, png_error_ptr))
125             SDL_LoadFunction(lib.handle, "png_create_read_struct");
126         if ( lib.png_create_read_struct == NULL ) {
127             SDL_UnloadObject(lib.handle);
128             return -1;
129         }
130         lib.png_destroy_read_struct =
131             (void (*) (png_structpp, png_infopp, png_infopp))
132             SDL_LoadFunction(lib.handle, "png_destroy_read_struct");
133         if ( lib.png_destroy_read_struct == NULL ) {
134             SDL_UnloadObject(lib.handle);
135             return -1;
136         }
137         lib.png_get_IHDR =
138             (png_uint_32 (*) (png_const_structrp, png_const_inforp, png_uint_32 *, png_uint_32 *, int *, int *, int *, int *, int *))
139             SDL_LoadFunction(lib.handle, "png_get_IHDR");
140         if ( lib.png_get_IHDR == NULL ) {
141             SDL_UnloadObject(lib.handle);
142             return -1;
143         }
144         lib.png_get_channels =
145             (png_byte (*) (png_const_structrp, png_const_inforp))
146             SDL_LoadFunction(lib.handle, "png_get_channels");
147         if ( lib.png_get_channels == NULL ) {
148             SDL_UnloadObject(lib.handle);
149             return -1;
150         }
151         lib.png_get_io_ptr =
152             (png_voidp (*) (png_const_structrp))
153             SDL_LoadFunction(lib.handle, "png_get_io_ptr");
154         if ( lib.png_get_io_ptr == NULL ) {
155             SDL_UnloadObject(lib.handle);
156             return -1;
157         }
158         lib.png_get_PLTE =
159             (png_uint_32 (*) (png_const_structrp, png_infop, png_colorp *, int *))
160             SDL_LoadFunction(lib.handle, "png_get_PLTE");
161         if ( lib.png_get_PLTE == NULL ) {
162             SDL_UnloadObject(lib.handle);
163             return -1;
164         }
165         lib.png_get_tRNS =
166             (png_uint_32 (*) (png_const_structrp, png_infop, png_bytep *, int *, png_color_16p *))
167             SDL_LoadFunction(lib.handle, "png_get_tRNS");
168         if ( lib.png_get_tRNS == NULL ) {
169             SDL_UnloadObject(lib.handle);
170             return -1;
171         }
172         lib.png_get_valid =
173             (png_uint_32 (*) (png_const_structrp, png_const_inforp, png_uint_32))
174             SDL_LoadFunction(lib.handle, "png_get_valid");
175         if ( lib.png_get_valid == NULL ) {
176             SDL_UnloadObject(lib.handle);
177             return -1;
178         }
179         lib.png_read_image =
180             (void (*) (png_structp, png_bytepp))
181             SDL_LoadFunction(lib.handle, "png_read_image");
182         if ( lib.png_read_image == NULL ) {
183             SDL_UnloadObject(lib.handle);
184             return -1;
185         }
186         lib.png_read_info =
187             (void (*) (png_structp, png_infop))
188             SDL_LoadFunction(lib.handle, "png_read_info");
189         if ( lib.png_read_info == NULL ) {
190             SDL_UnloadObject(lib.handle);
191             return -1;
192         }
193         lib.png_read_update_info =
194             (void (*) (png_structp, png_infop))
195             SDL_LoadFunction(lib.handle, "png_read_update_info");
196         if ( lib.png_read_update_info == NULL ) {
197             SDL_UnloadObject(lib.handle);
198             return -1;
199         }
200         lib.png_set_expand =
201             (void (*) (png_structp))
202             SDL_LoadFunction(lib.handle, "png_set_expand");
203         if ( lib.png_set_expand == NULL ) {
204             SDL_UnloadObject(lib.handle);
205             return -1;
206         }
207         lib.png_set_gray_to_rgb =
208             (void (*) (png_structp))
209             SDL_LoadFunction(lib.handle, "png_set_gray_to_rgb");
210         if ( lib.png_set_gray_to_rgb == NULL ) {
211             SDL_UnloadObject(lib.handle);
212             return -1;
213         }
214         lib.png_set_packing =
215             (void (*) (png_structp))
216             SDL_LoadFunction(lib.handle, "png_set_packing");
217         if ( lib.png_set_packing == NULL ) {
218             SDL_UnloadObject(lib.handle);
219             return -1;
220         }
221         lib.png_set_read_fn =
222             (void (*) (png_structp, png_voidp, png_rw_ptr))
223             SDL_LoadFunction(lib.handle, "png_set_read_fn");
224         if ( lib.png_set_read_fn == NULL ) {
225             SDL_UnloadObject(lib.handle);
226             return -1;
227         }
228         lib.png_set_strip_16 =
229             (void (*) (png_structp))
230             SDL_LoadFunction(lib.handle, "png_set_strip_16");
231         if ( lib.png_set_strip_16 == NULL ) {
232             SDL_UnloadObject(lib.handle);
233             return -1;
234         }
235         lib.png_sig_cmp =
236             (int (*) (png_const_bytep, png_size_t, png_size_t))
237             SDL_LoadFunction(lib.handle, "png_sig_cmp");
238         if ( lib.png_sig_cmp == NULL ) {
239             SDL_UnloadObject(lib.handle);
240             return -1;
241         }
242 #ifndef LIBPNG_VERSION_12
243         lib.png_set_longjmp_fn =
244             (jmp_buf * (*) (png_structp, png_longjmp_ptr, size_t))
245             SDL_LoadFunction(lib.handle, "png_set_longjmp_fn");
246         if ( lib.png_set_longjmp_fn == NULL ) {
247             SDL_UnloadObject(lib.handle);
248             return -1;
249         }
250 #endif
251     }
252     ++lib.loaded;
253
254     return 0;
255 }
256 void IMG_QuitPNG()
257 {
258     if ( lib.loaded == 0 ) {
259         return;
260     }
261     if ( lib.loaded == 1 ) {
262         SDL_UnloadObject(lib.handle);
263     }
264     --lib.loaded;
265 }
266 #else
267 int IMG_InitPNG()
268 {
269     if ( lib.loaded == 0 ) {
270         lib.png_create_info_struct = png_create_info_struct;
271         lib.png_create_read_struct = png_create_read_struct;
272         lib.png_destroy_read_struct = png_destroy_read_struct;
273         lib.png_get_IHDR = png_get_IHDR;
274         lib.png_get_channels = png_get_channels;
275         lib.png_get_io_ptr = png_get_io_ptr;
276         lib.png_get_PLTE = png_get_PLTE;
277         lib.png_get_tRNS = png_get_tRNS;
278         lib.png_get_valid = png_get_valid;
279         lib.png_read_image = png_read_image;
280         lib.png_read_info = png_read_info;
281         lib.png_read_update_info = png_read_update_info;
282         lib.png_set_expand = png_set_expand;
283         lib.png_set_gray_to_rgb = png_set_gray_to_rgb;
284         lib.png_set_packing = png_set_packing;
285         lib.png_set_read_fn = png_set_read_fn;
286         lib.png_set_strip_16 = png_set_strip_16;
287         lib.png_sig_cmp = png_sig_cmp;
288 #ifndef LIBPNG_VERSION_12
289         lib.png_set_longjmp_fn = png_set_longjmp_fn;
290 #endif
291     }
292     ++lib.loaded;
293
294     return 0;
295 }
296 void IMG_QuitPNG()
297 {
298     if ( lib.loaded == 0 ) {
299         return;
300     }
301     if ( lib.loaded == 1 ) {
302     }
303     --lib.loaded;
304 }
305 #endif /* LOAD_PNG_DYNAMIC */
306
307 /* See if an image is contained in a data source */
308 int IMG_isPNG(SDL_RWops *src)
309 {
310     Sint64 start;
311     int is_PNG;
312     Uint8 magic[4];
313
314     if ( !src ) {
315         return 0;
316     }
317
318     start = SDL_RWtell(src);
319     is_PNG = 0;
320     if ( SDL_RWread(src, magic, 1, sizeof(magic)) == sizeof(magic) ) {
321         if ( magic[0] == 0x89 &&
322              magic[1] == 'P' &&
323              magic[2] == 'N' &&
324              magic[3] == 'G' ) {
325             is_PNG = 1;
326         }
327     }
328     SDL_RWseek(src, start, RW_SEEK_SET);
329     return(is_PNG);
330 }
331
332 /* Load a PNG type image from an SDL datasource */
333 static void png_read_data(png_structp ctx, png_bytep area, png_size_t size)
334 {
335     SDL_RWops *src;
336
337     src = (SDL_RWops *)lib.png_get_io_ptr(ctx);
338     SDL_RWread(src, area, size, 1);
339 }
340 SDL_Surface *IMG_LoadPNG_RW(SDL_RWops *src)
341 {
342     Sint64 start;
343     const char *error;
344     SDL_Surface *volatile surface;
345     png_structp png_ptr;
346     png_infop info_ptr;
347     png_uint_32 width, height;
348     int bit_depth, color_type, interlace_type, num_channels;
349     Uint32 Rmask;
350     Uint32 Gmask;
351     Uint32 Bmask;
352     Uint32 Amask;
353     SDL_Palette *palette;
354     png_bytep *volatile row_pointers;
355     int row, i;
356     int ckey = -1;
357     png_color_16 *transv;
358
359     if ( !src ) {
360         /* The error message has been set in SDL_RWFromFile */
361         return NULL;
362     }
363     start = SDL_RWtell(src);
364
365     if ( !IMG_Init(IMG_INIT_PNG) ) {
366         return NULL;
367     }
368
369     /* Initialize the data we will clean up when we're done */
370     error = NULL;
371     png_ptr = NULL; info_ptr = NULL; row_pointers = NULL; surface = NULL;
372
373     /* Create the PNG loading context structure */
374     png_ptr = lib.png_create_read_struct(PNG_LIBPNG_VER_STRING,
375                       NULL,NULL,NULL);
376     if (png_ptr == NULL){
377         error = "Couldn't allocate memory for PNG file or incompatible PNG dll";
378         goto done;
379     }
380
381      /* Allocate/initialize the memory for image information.  REQUIRED. */
382     info_ptr = lib.png_create_info_struct(png_ptr);
383     if (info_ptr == NULL) {
384         error = "Couldn't create image information for PNG file";
385         goto done;
386     }
387
388     /* Set error handling if you are using setjmp/longjmp method (this is
389      * the normal method of doing things with libpng).  REQUIRED unless you
390      * set up your own error handlers in png_create_read_struct() earlier.
391      */
392 #ifndef LIBPNG_VERSION_12
393     if ( setjmp(*lib.png_set_longjmp_fn(png_ptr, longjmp, sizeof (jmp_buf))) )
394 #else
395     if ( setjmp(png_ptr->jmpbuf) )
396 #endif
397     {
398         error = "Error reading the PNG file.";
399         goto done;
400     }
401
402     /* Set up the input control */
403     lib.png_set_read_fn(png_ptr, src, png_read_data);
404
405     /* Read PNG header info */
406     lib.png_read_info(png_ptr, info_ptr);
407     lib.png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
408             &color_type, &interlace_type, NULL, NULL);
409
410     /* tell libpng to strip 16 bit/color files down to 8 bits/color */
411     lib.png_set_strip_16(png_ptr) ;
412
413     /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
414      * byte into separate bytes (useful for paletted and grayscale images).
415      */
416     lib.png_set_packing(png_ptr);
417
418     /* scale greyscale values to the range 0..255 */
419     if (color_type == PNG_COLOR_TYPE_GRAY)
420         lib.png_set_expand(png_ptr);
421
422     /* For images with a single "transparent colour", set colour key;
423        if more than one index has transparency, or if partially transparent
424        entries exist, use full alpha channel */
425     if (lib.png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
426         int num_trans;
427         Uint8 *trans;
428         lib.png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &transv);
429         if (color_type == PNG_COLOR_TYPE_PALETTE) {
430             /* Check if all tRNS entries are opaque except one */
431             int j, t = -1;
432             for (j = 0; j < num_trans; j++) {
433                 if (trans[j] == 0) {
434                     if (t >= 0) {
435                         break;
436                     }
437                     t = j;
438                 } else if (trans[j] != 255) {
439                     break;
440                 }
441             }
442             if (j == num_trans) {
443                 /* exactly one transparent index */
444                 ckey = t;
445             } else {
446                 /* more than one transparent index, or translucency */
447                 lib.png_set_expand(png_ptr);
448             }
449         } else {
450             ckey = 0; /* actual value will be set later */
451         }
452     }
453
454     if ( color_type == PNG_COLOR_TYPE_GRAY_ALPHA )
455         lib.png_set_gray_to_rgb(png_ptr);
456
457     lib.png_read_update_info(png_ptr, info_ptr);
458
459     lib.png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
460             &color_type, &interlace_type, NULL, NULL);
461
462     /* Allocate the SDL surface to hold the image */
463     Rmask = Gmask = Bmask = Amask = 0 ;
464     num_channels = lib.png_get_channels(png_ptr, info_ptr);
465     if ( num_channels >= 3 ) {
466 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
467         Rmask = 0x000000FF;
468         Gmask = 0x0000FF00;
469         Bmask = 0x00FF0000;
470         Amask = (num_channels == 4) ? 0xFF000000 : 0;
471 #else
472         int s = (num_channels == 4) ? 0 : 8;
473         Rmask = 0xFF000000 >> s;
474         Gmask = 0x00FF0000 >> s;
475         Bmask = 0x0000FF00 >> s;
476         Amask = 0x000000FF >> s;
477 #endif
478     }
479     surface = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height,
480             bit_depth*num_channels, Rmask,Gmask,Bmask,Amask);
481     if ( surface == NULL ) {
482         error = SDL_GetError();
483         goto done;
484     }
485
486     if (ckey != -1) {
487         if (color_type != PNG_COLOR_TYPE_PALETTE) {
488             /* FIXME: Should these be truncated or shifted down? */
489             ckey = SDL_MapRGB(surface->format,
490                          (Uint8)transv->red,
491                          (Uint8)transv->green,
492                          (Uint8)transv->blue);
493         }
494         SDL_SetColorKey(surface, SDL_TRUE, ckey);
495     }
496
497     /* Create the array of pointers to image data */
498     row_pointers = (png_bytep*) SDL_malloc(sizeof(png_bytep)*height);
499     if ( (row_pointers == NULL) ) {
500         error = "Out of memory";
501         goto done;
502     }
503     for (row = 0; row < (int)height; row++) {
504         row_pointers[row] = (png_bytep)
505                 (Uint8 *)surface->pixels + row*surface->pitch;
506     }
507
508     /* Read the entire image in one go */
509     lib.png_read_image(png_ptr, row_pointers);
510
511     /* and we're done!  (png_read_end() can be omitted if no processing of
512      * post-IDAT text/time/etc. is desired)
513      * In some cases it can't read PNG's created by some popular programs (ACDSEE),
514      * we do not want to process comments, so we omit png_read_end
515
516     lib.png_read_end(png_ptr, info_ptr);
517     */
518
519     /* Load the palette, if any */
520     palette = surface->format->palette;
521     if ( palette ) {
522         int png_num_palette;
523         png_colorp png_palette;
524         lib.png_get_PLTE(png_ptr, info_ptr, &png_palette, &png_num_palette);
525         if (color_type == PNG_COLOR_TYPE_GRAY) {
526             palette->ncolors = 256;
527             for (i = 0; i < 256; i++) {
528                 palette->colors[i].r = i;
529                 palette->colors[i].g = i;
530                 palette->colors[i].b = i;
531             }
532         } else if (png_num_palette > 0 ) {
533             palette->ncolors = png_num_palette;
534             for ( i=0; i<png_num_palette; ++i ) {
535                 palette->colors[i].b = png_palette[i].blue;
536                 palette->colors[i].g = png_palette[i].green;
537                 palette->colors[i].r = png_palette[i].red;
538             }
539         }
540     }
541
542 done:   /* Clean up and return */
543     if ( png_ptr ) {
544         lib.png_destroy_read_struct(&png_ptr,
545                                 info_ptr ? &info_ptr : (png_infopp)0,
546                                 (png_infopp)0);
547     }
548     if ( row_pointers ) {
549         SDL_free(row_pointers);
550     }
551     if ( error ) {
552         SDL_RWseek(src, start, RW_SEEK_SET);
553         if ( surface ) {
554             SDL_FreeSurface(surface);
555             surface = NULL;
556         }
557         IMG_SetError(error);
558     }
559     return(surface);
560 }
561
562 #else
563
564 int IMG_InitPNG()
565 {
566     IMG_SetError("PNG images are not supported");
567     return(-1);
568 }
569
570 void IMG_QuitPNG()
571 {
572 }
573
574 /* See if an image is contained in a data source */
575 int IMG_isPNG(SDL_RWops *src)
576 {
577     return(0);
578 }
579
580 /* Load a PNG type image from an SDL datasource */
581 SDL_Surface *IMG_LoadPNG_RW(SDL_RWops *src)
582 {
583     return(NULL);
584 }
585
586 #endif /* LOAD_PNG */
587
588 #endif /* !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND) */
589
590 /* We'll always have PNG save support */
591 #define SAVE_PNG
592
593 #ifdef SAVE_PNG
594
595 #include "miniz.h"
596
597 int IMG_SavePNG(SDL_Surface *surface, const char *file)
598 {
599     SDL_RWops *dst = SDL_RWFromFile(file, "wb");
600     if (dst) {
601         return IMG_SavePNG_RW(surface, dst, 1);
602     } else {
603         return -1;
604     }
605 }
606
607 int IMG_SavePNG_RW(SDL_Surface *surface, SDL_RWops *dst, int freedst)
608 {
609     int result = -1;
610
611     if (dst) {
612 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
613         static const Uint32 png_format = SDL_PIXELFORMAT_ABGR8888;
614 #else
615         static const Uint32 png_format = SDL_PIXELFORMAT_RGBA8888;
616 #endif
617         size_t size;
618         void *png;
619
620         if (surface->format->format == png_format) {
621             png = tdefl_write_image_to_png_file_in_memory(surface->pixels, surface->w, surface->h, surface->pitch, surface->format->BytesPerPixel, &size);
622         } else {
623             SDL_Surface *cvt = SDL_ConvertSurfaceFormat(surface, png_format, 0);
624             if (cvt) {
625                 png = tdefl_write_image_to_png_file_in_memory(cvt->pixels, cvt->w, cvt->h, cvt->pitch, cvt->format->BytesPerPixel, &size);
626                 SDL_FreeSurface(cvt);
627             }
628         }
629         if (png) {
630             if (SDL_RWwrite(dst, png, size, 1)) {
631                 result = 0;
632             }
633             SDL_free(png);
634         } else {
635             SDL_SetError("Failed to convert and save image");
636         }
637         if (freedst) {
638             SDL_RWclose(dst);
639         }
640     } else {
641         SDL_SetError("Passed NULL dst");
642     }
643     return result;
644 }
645
646 #endif /* SAVE_PNG */