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