IMG_png.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 01 Jan 2017 18:50:51 -0800
changeset 496 6332f9425dcc
parent 490 fd7214657669
child 506 4076ac7cf0a1
permissions -rw-r--r--
Updated copyright for 2017
     1 /*
     2   SDL_image:  An example image loading library for use with SDL
     3   Copyright (C) 1997-2017 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 < 5)
    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) & IMG_INIT_PNG) == 0 ) {
   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) {
   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("%s", 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 = NULL;
   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->format->BytesPerPixel, surface->pitch, &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->format->BytesPerPixel, cvt->pitch, &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 */