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