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