Date: Fri, 2 Jan 2009 02:01:16 -0800
authorSam Lantinga <slouken@libsdl.org>
Sun, 04 Jan 2009 02:09:27 +0000
changeset 1873405ab551300
parent 186 5fbbeabf647f
child 188 1318044935ad
Date: Fri, 2 Jan 2009 02:01:16 -0800
From: "E. Wing"
Subject: [SDL] Submission: ImageIO backend for SDL_Image on Mac OS X

I have a submission for SDL_image. I have implemented an ImageIO
backend for Mac OS X.

I've uploaded the code here:
http://www.assembla.com/spaces/SDL_Image_ImageIO

A Mercurial repository and a raw tar-ball can be found there.


The existing SDL_image implementation relies on 3rd-party libjpeg,
libpng, libgif, and libtiff which is a pain to build and maintain. In
the Mac release, we currently statically link all these libraries into
the framework. But Mac OS X already comes with these libraries, but
they are hidden away underneath their ImageIO framework. This
submission uses ImageIO to load these image formats.

To further minimize duplicated code, I also moved the bmp and tga
loader to ImageIO. Incidentally, Apple seems to have an implementation
that can detect if a file is a TGA.


ImageIO was introduced in Tiger 10.4. So this submission is intended
to go with the SDL_image that will accompany the SDL 1.3 release.

This code works so far for everything I've thrown at it (both PowerPC
and Intel). But I don't have a comprehensive library of test images.
So this could would benefit greatly from more scrutiny and testing.
CHANGES
IMG.c
IMG_ImageIO.c
IMG_UIImage.m
Xcode.tar.gz
Xcode_iPhone.tar.gz
showimage.c
     1.1 --- a/CHANGES	Mon Dec 08 00:27:32 2008 +0000
     1.2 +++ b/CHANGES	Sun Jan 04 02:09:27 2009 +0000
     1.3 @@ -1,3 +1,8 @@
     1.4 +1.2.8:
     1.5 +Eric Wing - Fri, 2 Jan 2009 02:01:16 -0800
     1.6 + * Added ImageIO loading infrastructure for Mac OS X
     1.7 + * Added UIImage loading infrastructure for iPhone / iPod Touch
     1.8 +
     1.9  1.2.7:
    1.10  Sam Lantinga - Sun Nov  2 15:08:27 PST 2008
    1.11   * Fixed buffer overflow in BMP loading code, discovered by j00ru//vx
     2.1 --- a/IMG.c	Mon Dec 08 00:27:32 2008 +0000
     2.2 +++ b/IMG.c	Sun Jan 04 02:09:27 2009 +0000
     2.3 @@ -58,6 +58,7 @@
     2.4  	return(&linked_version);
     2.5  }
     2.6  
     2.7 +#if !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND)
     2.8  /* Load an image from a file */
     2.9  SDL_Surface *IMG_Load(const char *file)
    2.10  {
    2.11 @@ -72,6 +73,7 @@
    2.12      }
    2.13      return IMG_LoadTyped_RW(src, 1, ext);
    2.14  }
    2.15 +#endif
    2.16  
    2.17  /* Load an image from an SDL datasource (for compatibility) */
    2.18  SDL_Surface *IMG_Load_RW(SDL_RWops *src, int freesrc)
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/IMG_ImageIO.c	Sun Jan 04 02:09:27 2009 +0000
     3.3 @@ -0,0 +1,478 @@
     3.4 +/*
     3.5 + *  IMG_ImageIO.c
     3.6 + *  SDL_image
     3.7 + *
     3.8 + *  Created by Eric Wing on 1/1/09.
     3.9 + *  Copyright 2009 __MyCompanyName__. All rights reserved.
    3.10 + *
    3.11 + */
    3.12 +#include "SDL_image.h"
    3.13 +
    3.14 +// For ImageIO framework and also LaunchServices framework (for UTIs)
    3.15 +#include <ApplicationServices/ApplicationServices.h>
    3.16 +
    3.17 +/**************************************************************
    3.18 + ***** Begin Callback functions for block reading *************
    3.19 + **************************************************************/
    3.20 +
    3.21 +// This callback reads some bytes from an SDL_rwops and copies it
    3.22 +// to a Quartz buffer (supplied by Apple framework).
    3.23 +static size_t MyProviderGetBytesCallback(void* rwops_userdata, void* quartz_buffer, size_t the_count)
    3.24 +{
    3.25 +	return (size_t)SDL_RWread((struct SDL_RWops *)rwops_userdata, quartz_buffer, 1, the_count);
    3.26 +}
    3.27 +
    3.28 +// This callback is triggered when the data provider is released
    3.29 +// so you can clean up any resources.
    3.30 +static void MyProviderReleaseInfoCallback(void* rwops_userdata)
    3.31 +{
    3.32 +	// What should I put here? 
    3.33 +	// I think the user and SDL_RWops controls closing, so I don't do anything.
    3.34 +}
    3.35 +
    3.36 +static void MyProviderRewindCallback(void* rwops_userdata)
    3.37 +{
    3.38 +	SDL_RWseek((struct SDL_RWops *)rwops_userdata, 0, RW_SEEK_SET);
    3.39 +}
    3.40 +
    3.41 +static void MyProviderSkipBytesCallback(void* rwops_userdata, size_t the_count)
    3.42 +{
    3.43 +	SDL_RWseek((struct SDL_RWops *)rwops_userdata, the_count, RW_SEEK_CUR);
    3.44 +}
    3.45 +/**************************************************************
    3.46 + ***** End Callback functions for block reading ***************
    3.47 + **************************************************************/
    3.48 +
    3.49 +// This creates a CGImageSourceRef which is a handle to an image that can be used to examine information
    3.50 +// about the image or load the actual image data.
    3.51 +static CGImageSourceRef CreateCGImageSourceFromRWops(SDL_RWops* rw_ops, CFDictionaryRef hints_and_options)
    3.52 +{
    3.53 +	CGImageSourceRef source_ref;
    3.54 +
    3.55 +
    3.56 +	// Similar to SDL_RWops, Apple has their own callbacks for dealing with data streams.
    3.57 +	CGDataProviderCallbacks provider_callbacks =
    3.58 +	{
    3.59 +		MyProviderGetBytesCallback,
    3.60 +		MyProviderSkipBytesCallback,
    3.61 +		MyProviderRewindCallback,
    3.62 +		MyProviderReleaseInfoCallback
    3.63 +	};
    3.64 +	CGDataProviderRef data_provider = CGDataProviderCreate(rw_ops, &provider_callbacks);
    3.65 +
    3.66 +	// Get the CGImageSourceRef.
    3.67 +	// The dictionary can be NULL or contain hints to help ImageIO figure out the image type.
    3.68 +	source_ref = CGImageSourceCreateWithDataProvider(data_provider, hints_and_options);
    3.69 +	return source_ref;
    3.70 +}
    3.71 +
    3.72 +
    3.73 +/* Create a CGImageSourceRef from a file. */
    3.74 +/* Remember to CFRelease the created source when done. */
    3.75 +static CGImageSourceRef CreateCGImageSourceFromFile(const char* the_path)
    3.76 +{
    3.77 +    CFURLRef the_url = NULL;
    3.78 +    CGImageSourceRef source_ref = NULL;
    3.79 +	CFStringRef cf_string = NULL;
    3.80 +	
    3.81 +	/* Create a CFString from a C string */
    3.82 +	cf_string = CFStringCreateWithCString(
    3.83 +										  NULL,
    3.84 +										  the_path,
    3.85 +										  kCFStringEncodingUTF8
    3.86 +										  );
    3.87 +	if(!cf_string)
    3.88 +	{
    3.89 +		return NULL;
    3.90 +	}
    3.91 +	
    3.92 +	/* Create a CFURL from a CFString */
    3.93 +    the_url = CFURLCreateWithFileSystemPath(
    3.94 +											NULL, 
    3.95 +											cf_string,
    3.96 +											kCFURLPOSIXPathStyle,
    3.97 +											false
    3.98 +											);
    3.99 +	
   3.100 +	/* Don't need the CFString any more (error or not) */
   3.101 +	CFRelease(cf_string);
   3.102 +	
   3.103 +	if(!the_url)
   3.104 +	{
   3.105 +		return NULL;
   3.106 +	}
   3.107 +	
   3.108 +	
   3.109 +    source_ref = CGImageSourceCreateWithURL(the_url, NULL);
   3.110 +	/* Don't need the URL any more (error or not) */
   3.111 +	CFRelease(the_url);
   3.112 +	
   3.113 +	return source_ref;
   3.114 +}
   3.115 +
   3.116 +
   3.117 +
   3.118 +static CGImageRef CreateCGImageFromCGImageSource(CGImageSourceRef image_source)
   3.119 +{
   3.120 +	CGImageRef image_ref = NULL;
   3.121 +	
   3.122 +    if(NULL == image_source)
   3.123 +	{
   3.124 +		return NULL;
   3.125 +	}
   3.126 +	
   3.127 +	// Get the first item in the image source (some image formats may
   3.128 +	// contain multiple items).
   3.129 +	image_ref = CGImageSourceCreateImageAtIndex(image_source, 0, NULL);
   3.130 +	return image_ref;
   3.131 +}
   3.132 +
   3.133 +static CFDictionaryRef CreateHintDictionary(CFStringRef uti_string_hint)
   3.134 +{
   3.135 +	CFDictionaryRef hint_dictionary = NULL;
   3.136 +
   3.137 +	if(uti_string_hint != NULL)
   3.138 +	{
   3.139 +		// Do a bunch of work to setup a CFDictionary containing the jpeg compression properties.
   3.140 +		CFStringRef the_keys[1];
   3.141 +		CFStringRef the_values[1];
   3.142 +		
   3.143 +		the_keys[0] = kCGImageSourceTypeIdentifierHint;
   3.144 +		the_values[0] = uti_string_hint;
   3.145 +		
   3.146 +		// kCFTypeDictionaryKeyCallBacks or kCFCopyStringDictionaryKeyCallBacks?
   3.147 +		hint_dictionary = CFDictionaryCreate(NULL, (const void**)&the_keys, (const void**)&the_values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
   3.148 +	}
   3.149 +	return hint_dictionary;
   3.150 +}
   3.151 +
   3.152 +
   3.153 +
   3.154 +
   3.155 +static int Internal_isType(SDL_RWops* rw_ops, CFStringRef uti_string_to_test)
   3.156 +{
   3.157 +	CGImageSourceRef image_source;
   3.158 +	CFStringRef uti_type;
   3.159 +	Boolean is_type;
   3.160 +	
   3.161 +	CFDictionaryRef hint_dictionary = NULL;
   3.162 +	
   3.163 +	hint_dictionary = CreateHintDictionary(uti_string_to_test);	
   3.164 +	image_source = CreateCGImageSourceFromRWops(rw_ops, hint_dictionary);
   3.165 +	
   3.166 +	if(hint_dictionary != NULL)
   3.167 +	{
   3.168 +		CFRelease(hint_dictionary);		
   3.169 +	}
   3.170 +	
   3.171 +	if(NULL == image_source)
   3.172 +	{
   3.173 +		return 0;
   3.174 +	}
   3.175 +	
   3.176 +	// This will get the UTI of the container, not the image itself.
   3.177 +	// Under most cases, this won't be a problem.
   3.178 +	// But if a person passes an icon file which contains a bmp,
   3.179 +	// the format will be of the icon file.
   3.180 +	// But I think the main SDL_image codebase has this same problem so I'm not going to worry about it.	
   3.181 +	uti_type = CGImageSourceGetType(image_source);
   3.182 +	//	CFShow(uti_type);
   3.183 +	
   3.184 +	// Unsure if we really want conformance or equality
   3.185 +	is_type = UTTypeConformsTo(uti_string_to_test, uti_type);
   3.186 +	
   3.187 +	CFRelease(image_source);
   3.188 +	
   3.189 +	return (int)is_type;
   3.190 +}
   3.191 +
   3.192 +// Once we have our image, we need to get it into an SDL_Surface
   3.193 +static SDL_Surface* Create_SDL_Surface_From_CGImage(CGImageRef image_ref)
   3.194 +{
   3.195 +	/* This code is adapted from Apple's Documentation found here:
   3.196 +	 * http://developer.apple.com/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/index.html
   3.197 +	 * Listing 9-4††Using a Quartz image as a texture source.
   3.198 +	 * Unfortunately, this guide doesn't show what to do about
   3.199 +	 * non-RGBA image formats so I'm making the rest up.
   3.200 +	 * All this code should be scrutinized.
   3.201 +	 */
   3.202 +	
   3.203 +	size_t the_width = CGImageGetWidth(image_ref);
   3.204 +	size_t the_height = CGImageGetHeight(image_ref);
   3.205 +	CGRect the_rect = {{0, 0}, {the_width, the_height}};
   3.206 +	
   3.207 +	size_t bits_per_pixel = CGImageGetBitsPerPixel(image_ref);
   3.208 +	size_t bytes_per_row = CGImageGetBytesPerRow(image_ref);
   3.209 +	//	size_t bits_per_component = CGImageGetBitsPerComponent(image_ref);
   3.210 +	size_t bits_per_component = 8;
   3.211 +	
   3.212 +//	CGImageAlphaInfo alpha_info = CGImageGetAlphaInfo(image_ref);
   3.213 +	
   3.214 +
   3.215 +	SDL_Surface* sdl_surface = NULL;
   3.216 +	Uint32 Rmask;
   3.217 +	Uint32 Gmask;
   3.218 +	Uint32 Bmask;
   3.219 +	Uint32 Amask;
   3.220 +
   3.221 +	
   3.222 +	CGContextRef bitmap_context = NULL;
   3.223 +	
   3.224 +	CGColorSpaceRef color_space = NULL;
   3.225 +	CGBitmapInfo bitmap_info = CGImageGetBitmapInfo(image_ref);
   3.226 +
   3.227 +	
   3.228 +	switch(bits_per_pixel)
   3.229 +	{
   3.230 +		case 8:
   3.231 +		{
   3.232 +			bytes_per_row = the_width*4;
   3.233 +			//				color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
   3.234 +			color_space = CGColorSpaceCreateDeviceRGB();
   3.235 +			//				bitmap_info = kCGImageAlphaPremultipliedFirst;
   3.236 +#if __BIG_ENDIAN__
   3.237 +			bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Big; /* XRGB Big Endian */
   3.238 +#else
   3.239 +			bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little; /* XRGB Little Endian */
   3.240 +#endif
   3.241 +
   3.242 +			Rmask = 0x00FF0000;
   3.243 +			Gmask = 0x0000FF00;
   3.244 +			Bmask = 0x000000FF;
   3.245 +			Amask = 0x00000000;
   3.246 +
   3.247 +			sdl_surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
   3.248 +											   the_width, the_height, 32, Rmask, Gmask, Bmask, Amask);
   3.249 +
   3.250 +
   3.251 +			
   3.252 +			break;
   3.253 +		}
   3.254 +		case 15:
   3.255 +		case 16:
   3.256 +		{
   3.257 +			bytes_per_row = the_width*4;
   3.258 +
   3.259 +			color_space = CGColorSpaceCreateDeviceRGB();
   3.260 +
   3.261 +#if __BIG_ENDIAN__
   3.262 +			bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Big; /* XRGB Big Endian */
   3.263 +#else
   3.264 +			bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little; /* XRGB Little Endian */
   3.265 +#endif
   3.266 +			Rmask = 0x00FF0000;
   3.267 +			Gmask = 0x0000FF00;
   3.268 +			Bmask = 0x000000FF;
   3.269 +			Amask = 0x00000000;
   3.270 +
   3.271 +
   3.272 +			sdl_surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
   3.273 +											   the_width, the_height, 32, Rmask, Gmask, Bmask, Amask);
   3.274 +
   3.275 +			break;
   3.276 +		}
   3.277 +		case 24:
   3.278 +		{
   3.279 +			bytes_per_row = the_width*4;
   3.280 +			//			color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
   3.281 +			color_space = CGColorSpaceCreateDeviceRGB();
   3.282 +			//			bitmap_info = kCGImageAlphaNone;
   3.283 +#if __BIG_ENDIAN__
   3.284 +			bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Big; /* XRGB Big Endian */
   3.285 +#else
   3.286 +			bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little; /* XRGB Little Endian */
   3.287 +#endif
   3.288 +			Rmask = 0x00FF0000;
   3.289 +			Gmask = 0x0000FF00;
   3.290 +			Bmask = 0x000000FF;
   3.291 +			Amask = 0x00000000;
   3.292 +
   3.293 +			sdl_surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
   3.294 +											   the_width, the_height, 32, Rmask, Gmask, Bmask, Amask);
   3.295 +
   3.296 +			break;
   3.297 +		}
   3.298 +		case 32:
   3.299 +		{
   3.300 +						
   3.301 +			bytes_per_row = the_width*4;
   3.302 +			//			color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
   3.303 +			color_space = CGColorSpaceCreateDeviceRGB();
   3.304 +			//			bitmap_info = kCGImageAlphaPremultipliedFirst;
   3.305 +#if __BIG_ENDIAN__
   3.306 +			bitmap_info = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big; /* XRGB Big Endian */
   3.307 +#else
   3.308 +			bitmap_info = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little; /* XRGB Little Endian */
   3.309 +#endif 
   3.310 +
   3.311 +			Amask = 0xFF000000;
   3.312 +			Rmask = 0x00FF0000;
   3.313 +			Gmask = 0x0000FF00;
   3.314 +			Bmask = 0x000000FF;
   3.315 +
   3.316 +			sdl_surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
   3.317 +											   the_width, the_height, 32, Rmask, Gmask, Bmask, Amask);
   3.318 +			break;
   3.319 +		}
   3.320 +		default:
   3.321 +		{
   3.322 +            sdl_surface = NULL;
   3.323 +            break;
   3.324 +		}
   3.325 +			
   3.326 +	}
   3.327 +
   3.328 +	if(NULL == sdl_surface)
   3.329 +	{
   3.330 +		if(color_space != NULL)
   3.331 +		{
   3.332 +			CGColorSpaceRelease(color_space);			
   3.333 +		}
   3.334 +		return NULL;
   3.335 +	}
   3.336 +
   3.337 +
   3.338 +	// Sets up a context to be drawn to with sdl_surface->pixels as the area to be drawn to
   3.339 +	bitmap_context = CGBitmapContextCreate(
   3.340 +														sdl_surface->pixels,
   3.341 +														the_width,
   3.342 +														the_height,
   3.343 +														bits_per_component,
   3.344 +														bytes_per_row,
   3.345 +														color_space,
   3.346 +														bitmap_info
   3.347 +														);
   3.348 +	
   3.349 +	// Draws the image into the context's image_data
   3.350 +	CGContextDrawImage(bitmap_context, the_rect, image_ref);
   3.351 +	
   3.352 +	CGContextRelease(bitmap_context);
   3.353 +	CGColorSpaceRelease(color_space);
   3.354 +	
   3.355 +	return sdl_surface;
   3.356 +	
   3.357 +	
   3.358 +	
   3.359 +}
   3.360 +
   3.361 +
   3.362 +static SDL_Surface* LoadImageFromRWops(SDL_RWops* rw_ops, CFStringRef uti_string_hint)
   3.363 +{
   3.364 +	SDL_Surface* sdl_surface;
   3.365 +	CGImageSourceRef image_source;
   3.366 +	CGImageRef image_ref = NULL;
   3.367 +	CFDictionaryRef hint_dictionary = NULL;
   3.368 +
   3.369 +	hint_dictionary = CreateHintDictionary(uti_string_hint);
   3.370 +	image_source = CreateCGImageSourceFromRWops(rw_ops, hint_dictionary);
   3.371 +
   3.372 +	if(hint_dictionary != NULL)
   3.373 +	{
   3.374 +		CFRelease(hint_dictionary);		
   3.375 +	}
   3.376 +	
   3.377 +	if(NULL == image_source)
   3.378 +	{
   3.379 +		return NULL;
   3.380 +	}
   3.381 +	
   3.382 +	image_ref = CreateCGImageFromCGImageSource(image_source);
   3.383 +	CFRelease(image_source);
   3.384 +
   3.385 +	if(NULL == image_ref)
   3.386 +	{
   3.387 +		return NULL;
   3.388 +	}
   3.389 +	
   3.390 +	sdl_surface = Create_SDL_Surface_From_CGImage(image_ref);
   3.391 +	CFRelease(image_ref);
   3.392 +	return sdl_surface;
   3.393 +	
   3.394 +}
   3.395 +
   3.396 +
   3.397 +
   3.398 +int IMG_isBMP(SDL_RWops *src)
   3.399 +{
   3.400 +	return Internal_isType(src, kUTTypeBMP);
   3.401 +}
   3.402 +
   3.403 +int IMG_isGIF(SDL_RWops *src)
   3.404 +{
   3.405 +	return Internal_isType(src, kUTTypeGIF);
   3.406 +}
   3.407 +// Note: JPEG 2000 is kUTTypeJPEG2000
   3.408 +int IMG_isJPG(SDL_RWops *src)
   3.409 +{
   3.410 +	return Internal_isType(src, kUTTypeJPEG);
   3.411 +}
   3.412 +
   3.413 +int IMG_isPNG(SDL_RWops *src)
   3.414 +{
   3.415 +	return Internal_isType(src, kUTTypePNG);
   3.416 +}
   3.417 +
   3.418 +// This isn't a public API function. Apple seems to be able to identify tga's.
   3.419 +int IMG_isTGA(SDL_RWops *src)
   3.420 +{
   3.421 +	return Internal_isType(src, CFSTR("com.truevision.tga-image"));
   3.422 +}
   3.423 +
   3.424 +int IMG_isTIF(SDL_RWops *src)
   3.425 +{
   3.426 +	return Internal_isType(src, kUTTypeTIFF);
   3.427 +}
   3.428 +
   3.429 +SDL_Surface* IMG_LoadBMP_RW(SDL_RWops *src)
   3.430 +{
   3.431 +	return LoadImageFromRWops(src, kUTTypeBMP);
   3.432 +}
   3.433 +SDL_Surface* IMG_LoadGIF_RW(SDL_RWops *src)
   3.434 +{
   3.435 +	return LoadImageFromRWops(src, kUTTypeGIF);
   3.436 +}
   3.437 +SDL_Surface* IMG_LoadJPG_RW(SDL_RWops *src)
   3.438 +{
   3.439 +	return LoadImageFromRWops(src, kUTTypeJPEG);
   3.440 +}
   3.441 +SDL_Surface* IMG_LoadPNG_RW(SDL_RWops *src)
   3.442 +{
   3.443 +	return LoadImageFromRWops(src, kUTTypePNG);
   3.444 +}
   3.445 +SDL_Surface* IMG_LoadTGA_RW(SDL_RWops *src)
   3.446 +{
   3.447 +	return LoadImageFromRWops(src, CFSTR("com.truevision.tga-image"));
   3.448 +}
   3.449 +SDL_Surface* IMG_LoadTIF_RW(SDL_RWops *src)
   3.450 +{
   3.451 +	return LoadImageFromRWops(src, kUTTypeTIFF);
   3.452 +}
   3.453 +
   3.454 +// Apple provides both stream and file loading functions in ImageIO.
   3.455 +// Potentially, Apple can optimize for either case.
   3.456 +SDL_Surface* IMG_Load(const char *file)
   3.457 +{
   3.458 +	SDL_Surface* sdl_surface;
   3.459 +	CGImageSourceRef image_source;
   3.460 +	CGImageRef image_ref = NULL;
   3.461 +
   3.462 +	image_source = CreateCGImageSourceFromFile(file);
   3.463 +	
   3.464 +	if(NULL == image_source)
   3.465 +	{
   3.466 +		return NULL;
   3.467 +	}
   3.468 +	
   3.469 +	image_ref = CreateCGImageFromCGImageSource(image_source);
   3.470 +	CFRelease(image_source);
   3.471 +	
   3.472 +	if(NULL == image_ref)
   3.473 +	{
   3.474 +		return NULL;
   3.475 +	}
   3.476 +	
   3.477 +	sdl_surface = Create_SDL_Surface_From_CGImage(image_ref);
   3.478 +	CFRelease(image_ref);
   3.479 +	return sdl_surface;	
   3.480 +}
   3.481 +
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/IMG_UIImage.m	Sun Jan 04 02:09:27 2009 +0000
     4.3 @@ -0,0 +1,419 @@
     4.4 +/*
     4.5 + *  IMG_ImageIO.c
     4.6 + *  SDL_image
     4.7 + *
     4.8 + *  Created by Eric Wing on 1/2/09.
     4.9 + *  Copyright 2009 __MyCompanyName__. All rights reserved.
    4.10 + *
    4.11 + */
    4.12 +#include "SDL_image.h"
    4.13 +#import <UIKit/UIKit.h>
    4.14 +#import <Foundation/Foundation.h>
    4.15 +
    4.16 +
    4.17 +// Once we have our image, we need to get it into an SDL_Surface
    4.18 +// (Copied straight from the ImageIO backend.)
    4.19 +static SDL_Surface* Create_SDL_Surface_From_CGImage(CGImageRef image_ref)
    4.20 +{
    4.21 +	/* This code is adapted from Apple's Documentation found here:
    4.22 +	 * http://developer.apple.com/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/index.html
    4.23 +	 * Listing 9-4††Using a Quartz image as a texture source.
    4.24 +	 * Unfortunately, this guide doesn't show what to do about
    4.25 +	 * non-RGBA image formats so I'm making the rest up.
    4.26 +	 * All this code should be scrutinized.
    4.27 +	 */
    4.28 +	
    4.29 +	size_t the_width = CGImageGetWidth(image_ref);
    4.30 +	size_t the_height = CGImageGetHeight(image_ref);
    4.31 +	CGRect the_rect = {{0, 0}, {the_width, the_height}};
    4.32 +	
    4.33 +	size_t bits_per_pixel = CGImageGetBitsPerPixel(image_ref);
    4.34 +	size_t bytes_per_row = CGImageGetBytesPerRow(image_ref);
    4.35 +	//	size_t bits_per_component = CGImageGetBitsPerComponent(image_ref);
    4.36 +	size_t bits_per_component = 8;
    4.37 +	
    4.38 +//	CGImageAlphaInfo alpha_info = CGImageGetAlphaInfo(image_ref);
    4.39 +	
    4.40 +
    4.41 +	SDL_Surface* sdl_surface = NULL;
    4.42 +	Uint32 Rmask;
    4.43 +	Uint32 Gmask;
    4.44 +	Uint32 Bmask;
    4.45 +	Uint32 Amask;
    4.46 +
    4.47 +	
    4.48 +	CGContextRef bitmap_context = NULL;
    4.49 +	
    4.50 +	CGColorSpaceRef color_space = NULL;
    4.51 +	CGBitmapInfo bitmap_info = CGImageGetBitmapInfo(image_ref);
    4.52 +
    4.53 +	
    4.54 +	switch(bits_per_pixel)
    4.55 +	{
    4.56 +		case 8:
    4.57 +		{
    4.58 +			bytes_per_row = the_width*4;
    4.59 +			//				color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
    4.60 +			color_space = CGColorSpaceCreateDeviceRGB();
    4.61 +			//				bitmap_info = kCGImageAlphaPremultipliedFirst;
    4.62 +#if __BIG_ENDIAN__
    4.63 +			bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Big; /* XRGB Big Endian */
    4.64 +#else
    4.65 +			bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little; /* XRGB Little Endian */
    4.66 +#endif
    4.67 +
    4.68 +			Rmask = 0x00FF0000;
    4.69 +			Gmask = 0x0000FF00;
    4.70 +			Bmask = 0x000000FF;
    4.71 +			Amask = 0x00000000;
    4.72 +
    4.73 +			sdl_surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
    4.74 +											   the_width, the_height, 32, Rmask, Gmask, Bmask, Amask);
    4.75 +
    4.76 +
    4.77 +			
    4.78 +			break;
    4.79 +		}
    4.80 +		case 15:
    4.81 +		case 16:
    4.82 +		{
    4.83 +			bytes_per_row = the_width*4;
    4.84 +
    4.85 +			color_space = CGColorSpaceCreateDeviceRGB();
    4.86 +
    4.87 +#if __BIG_ENDIAN__
    4.88 +			bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Big; /* XRGB Big Endian */
    4.89 +#else
    4.90 +			bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little; /* XRGB Little Endian */
    4.91 +#endif
    4.92 +			Rmask = 0x00FF0000;
    4.93 +			Gmask = 0x0000FF00;
    4.94 +			Bmask = 0x000000FF;
    4.95 +			Amask = 0x00000000;
    4.96 +
    4.97 +
    4.98 +			sdl_surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
    4.99 +											   the_width, the_height, 32, Rmask, Gmask, Bmask, Amask);
   4.100 +
   4.101 +			break;
   4.102 +		}
   4.103 +		case 24:
   4.104 +		{
   4.105 +			bytes_per_row = the_width*4;
   4.106 +			//			color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
   4.107 +			color_space = CGColorSpaceCreateDeviceRGB();
   4.108 +			//			bitmap_info = kCGImageAlphaNone;
   4.109 +#if __BIG_ENDIAN__
   4.110 +			bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Big; /* XRGB Big Endian */
   4.111 +#else
   4.112 +			bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little; /* XRGB Little Endian */
   4.113 +#endif
   4.114 +			Rmask = 0x00FF0000;
   4.115 +			Gmask = 0x0000FF00;
   4.116 +			Bmask = 0x000000FF;
   4.117 +			Amask = 0x00000000;
   4.118 +
   4.119 +			sdl_surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
   4.120 +											   the_width, the_height, 32, Rmask, Gmask, Bmask, Amask);
   4.121 +
   4.122 +			break;
   4.123 +		}
   4.124 +		case 32:
   4.125 +		{
   4.126 +						
   4.127 +			bytes_per_row = the_width*4;
   4.128 +			//			color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
   4.129 +			color_space = CGColorSpaceCreateDeviceRGB();
   4.130 +			//			bitmap_info = kCGImageAlphaPremultipliedFirst;
   4.131 +#if __BIG_ENDIAN__
   4.132 +			bitmap_info = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big; /* XRGB Big Endian */
   4.133 +#else
   4.134 +			bitmap_info = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little; /* XRGB Little Endian */
   4.135 +#endif 
   4.136 +			Amask = 0xFF000000;
   4.137 +			Rmask = 0x00FF0000;
   4.138 +			Gmask = 0x0000FF00;
   4.139 +			Bmask = 0x000000FF;
   4.140 +
   4.141 +			sdl_surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
   4.142 +											   the_width, the_height, 32, Rmask, Gmask, Bmask, Amask);
   4.143 +			break;
   4.144 +		}
   4.145 +		default:
   4.146 +		{
   4.147 +            sdl_surface = NULL;
   4.148 +            break;
   4.149 +		}
   4.150 +			
   4.151 +	}
   4.152 +
   4.153 +	if(NULL == sdl_surface)
   4.154 +	{
   4.155 +		if(color_space != NULL)
   4.156 +		{
   4.157 +			CGColorSpaceRelease(color_space);			
   4.158 +		}
   4.159 +		return NULL;
   4.160 +	}
   4.161 +
   4.162 +
   4.163 +	// Sets up a context to be drawn to with sdl_surface->pixels as the area to be drawn to
   4.164 +	bitmap_context = CGBitmapContextCreate(
   4.165 +														sdl_surface->pixels,
   4.166 +														the_width,
   4.167 +														the_height,
   4.168 +														bits_per_component,
   4.169 +														bytes_per_row,
   4.170 +														color_space,
   4.171 +														bitmap_info
   4.172 +														);
   4.173 +	
   4.174 +	// Draws the image into the context's image_data
   4.175 +	CGContextDrawImage(bitmap_context, the_rect, image_ref);
   4.176 +	
   4.177 +	CGContextRelease(bitmap_context);
   4.178 +	CGColorSpaceRelease(color_space);
   4.179 +	
   4.180 +	return sdl_surface;
   4.181 +	
   4.182 +	
   4.183 +	
   4.184 +}
   4.185 +
   4.186 +static SDL_Surface* LoadImageFromRWops(SDL_RWops* rw_ops, CFStringRef uti_string_hint)
   4.187 +{
   4.188 +	NSAutoreleasePool* autorelease_pool = [[NSAutoreleasePool alloc] init];
   4.189 +	SDL_Surface* sdl_surface;
   4.190 +	UIImage* ui_image;
   4.191 +
   4.192 +	CGImageRef image_ref = NULL;
   4.193 +	int bytes_read = 0;
   4.194 +	// I don't know what a good size is. 
   4.195 +	// Max recommended texture size is 1024x1024 on iPhone so maybe base it on that?
   4.196 +	const int block_size = 1024*4;
   4.197 +	char temp_buffer[block_size];
   4.198 +	
   4.199 +	NSMutableData* ns_data = [[NSMutableData alloc] initWithCapacity:1024*1024*4];
   4.200 +
   4.201 +	
   4.202 +	do
   4.203 +	{
   4.204 +		bytes_read = SDL_RWread(rw_ops, temp_buffer, 1, block_size);
   4.205 +		[ns_data appendBytes:temp_buffer length:bytes_read];
   4.206 +	} while(bytes_read > 0);
   4.207 +
   4.208 +	if(NULL == image_ref)
   4.209 +	{
   4.210 +		return NULL;
   4.211 +	}
   4.212 +
   4.213 +	ui_image = [[UIImage alloc] initWithData:ns_data];
   4.214 +	
   4.215 +	sdl_surface = Create_SDL_Surface_From_CGImage([ui_image CGImage]);
   4.216 +
   4.217 +	[ui_image release];
   4.218 +	[ns_data release];
   4.219 +
   4.220 +	[autorelease_pool drain];
   4.221 +
   4.222 +	return sdl_surface;
   4.223 +}
   4.224 +
   4.225 +/* Since UIImage doesn't really support streams well, we should optimize for the file case. */
   4.226 +SDL_Surface *IMG_Load(const char *file)
   4.227 +{
   4.228 +	NSAutoreleasePool* autorelease_pool = [[NSAutoreleasePool alloc] init];
   4.229 +	SDL_Surface* sdl_surface = NULL;
   4.230 +	UIImage* ui_image;
   4.231 +	NSString* ns_string;
   4.232 +	
   4.233 +	ns_string = [[NSString alloc] initWithUTF8String:file];
   4.234 +	ui_image = [[UIImage alloc] initWithContentsOfFile:ns_string];
   4.235 +
   4.236 +	sdl_surface = Create_SDL_Surface_From_CGImage([ui_image CGImage]);
   4.237 +
   4.238 +	[ui_image release];
   4.239 +	[ns_string release];
   4.240 +	
   4.241 +	[autorelease_pool drain];
   4.242 +
   4.243 +	return sdl_surface;
   4.244 +}
   4.245 +
   4.246 +
   4.247 +
   4.248 +/* Copied straight from other files so I don't have to alter them. */
   4.249 +int IMG_isBMP(SDL_RWops *src)
   4.250 +{
   4.251 +	int start;
   4.252 +	int is_BMP;
   4.253 +	char magic[2];
   4.254 +	
   4.255 +	if ( !src )
   4.256 +		return 0;
   4.257 +	start = SDL_RWtell(src);
   4.258 +	is_BMP = 0;
   4.259 +	if ( SDL_RWread(src, magic, sizeof(magic), 1) ) {
   4.260 +		if ( strncmp(magic, "BM", 2) == 0 ) {
   4.261 +			is_BMP = 1;
   4.262 +		}
   4.263 +	}
   4.264 +	SDL_RWseek(src, start, SEEK_SET);
   4.265 +	return(is_BMP);
   4.266 +}
   4.267 +
   4.268 +int IMG_isGIF(SDL_RWops *src)
   4.269 +{
   4.270 +	int start;
   4.271 +	int is_GIF;
   4.272 +	char magic[6];
   4.273 +	
   4.274 +	if ( !src )
   4.275 +		return 0;
   4.276 +	start = SDL_RWtell(src);
   4.277 +	is_GIF = 0;
   4.278 +	if ( SDL_RWread(src, magic, sizeof(magic), 1) ) {
   4.279 +		if ( (strncmp(magic, "GIF", 3) == 0) &&
   4.280 +			((memcmp(magic + 3, "87a", 3) == 0) ||
   4.281 +			 (memcmp(magic + 3, "89a", 3) == 0)) ) {
   4.282 +			is_GIF = 1;
   4.283 +		}
   4.284 +	}
   4.285 +	SDL_RWseek(src, start, SEEK_SET);
   4.286 +	return(is_GIF);
   4.287 +}
   4.288 +
   4.289 +int IMG_isJPG(SDL_RWops *src)
   4.290 +{
   4.291 +	int start;
   4.292 +	int is_JPG;
   4.293 +	int in_scan;
   4.294 +	Uint8 magic[4];
   4.295 +	
   4.296 +	/* This detection code is by Steaphan Greene <stea@cs.binghamton.edu> */
   4.297 +	/* Blame me, not Sam, if this doesn't work right. */
   4.298 +	/* And don't forget to report the problem to the the sdl list too! */
   4.299 +	
   4.300 +	if ( !src )
   4.301 +		return 0;
   4.302 +	start = SDL_RWtell(src);
   4.303 +	is_JPG = 0;
   4.304 +	in_scan = 0;
   4.305 +	if ( SDL_RWread(src, magic, 2, 1) ) {
   4.306 +		if ( (magic[0] == 0xFF) && (magic[1] == 0xD8) ) {
   4.307 +			is_JPG = 1;
   4.308 +			while (is_JPG == 1) {
   4.309 +				if(SDL_RWread(src, magic, 1, 2) != 2) {
   4.310 +					is_JPG = 0;
   4.311 +				} else if( (magic[0] != 0xFF) && (in_scan == 0) ) {
   4.312 +					is_JPG = 0;
   4.313 +				} else if( (magic[0] != 0xFF) || (magic[1] == 0xFF) ) {
   4.314 +					/* Extra padding in JPEG (legal) */
   4.315 +					/* or this is data and we are scanning */
   4.316 +					SDL_RWseek(src, -1, SEEK_CUR);
   4.317 +				} else if(magic[1] == 0xD9) {
   4.318 +					/* Got to end of good JPEG */
   4.319 +					break;
   4.320 +				} else if( (in_scan == 1) && (magic[1] == 0x00) ) {
   4.321 +					/* This is an encoded 0xFF within the data */
   4.322 +				} else if( (magic[1] >= 0xD0) && (magic[1] < 0xD9) ) {
   4.323 +					/* These have nothing else */
   4.324 +				} else if(SDL_RWread(src, magic+2, 1, 2) != 2) {
   4.325 +					is_JPG = 0;
   4.326 +				} else {
   4.327 +					/* Yes, it's big-endian */
   4.328 +					Uint32 start;
   4.329 +					Uint32 size;
   4.330 +					Uint32 end;
   4.331 +					start = SDL_RWtell(src);
   4.332 +					size = (magic[2] << 8) + magic[3];
   4.333 +					end = SDL_RWseek(src, size-2, SEEK_CUR);
   4.334 +					if ( end != start + size - 2 ) is_JPG = 0;
   4.335 +					if ( magic[1] == 0xDA ) {
   4.336 +						/* Now comes the actual JPEG meat */
   4.337 +#ifdef	FAST_IS_JPEG
   4.338 +						/* Ok, I'm convinced.  It is a JPEG. */
   4.339 +						break;
   4.340 +#else
   4.341 +						/* I'm not convinced.  Prove it! */
   4.342 +						in_scan = 1;
   4.343 +#endif
   4.344 +					}
   4.345 +				}
   4.346 +			}
   4.347 +		}
   4.348 +	}
   4.349 +	SDL_RWseek(src, start, SEEK_SET);
   4.350 +	return(is_JPG);
   4.351 +}
   4.352 +
   4.353 +int IMG_isPNG(SDL_RWops *src)
   4.354 +{
   4.355 +	int start;
   4.356 +	int is_PNG;
   4.357 +	Uint8 magic[4];
   4.358 +	
   4.359 +	if ( !src )
   4.360 +		return 0;
   4.361 +	start = SDL_RWtell(src);
   4.362 +	is_PNG = 0;
   4.363 +	if ( SDL_RWread(src, magic, 1, sizeof(magic)) == sizeof(magic) ) {
   4.364 +		if ( magic[0] == 0x89 &&
   4.365 +			magic[1] == 'P' &&
   4.366 +			magic[2] == 'N' &&
   4.367 +			magic[3] == 'G' ) {
   4.368 +			is_PNG = 1;
   4.369 +		}
   4.370 +	}
   4.371 +	SDL_RWseek(src, start, SEEK_SET);
   4.372 +	return(is_PNG);
   4.373 +}
   4.374 +
   4.375 +int IMG_isTIF(SDL_RWops* src)
   4.376 +{
   4.377 +	int start;
   4.378 +	int is_TIF;
   4.379 +	Uint8 magic[4];
   4.380 +	
   4.381 +	if ( !src )
   4.382 +		return 0;
   4.383 +	start = SDL_RWtell(src);
   4.384 +	is_TIF = 0;
   4.385 +	if ( SDL_RWread(src, magic, 1, sizeof(magic)) == sizeof(magic) ) {
   4.386 +		if ( (magic[0] == 'I' &&
   4.387 +			  magic[1] == 'I' &&
   4.388 +		      magic[2] == 0x2a &&
   4.389 +			  magic[3] == 0x00) ||
   4.390 +			(magic[0] == 'M' &&
   4.391 +			 magic[1] == 'M' &&
   4.392 +			 magic[2] == 0x00 &&
   4.393 +			 magic[3] == 0x2a) ) {
   4.394 +			is_TIF = 1;
   4.395 +		}
   4.396 +	}
   4.397 +	SDL_RWseek(src, start, SEEK_SET);
   4.398 +	return(is_TIF);
   4.399 +}
   4.400 +
   4.401 +
   4.402 +SDL_Surface* IMG_LoadBMP_RW(SDL_RWops *src)
   4.403 +{
   4.404 +	return LoadImageFromRWops(src, kUTTypeBMP);
   4.405 +}
   4.406 +SDL_Surface* IMG_LoadGIF_RW(SDL_RWops *src)
   4.407 +{
   4.408 +	return LoadImageFromRWops(src, kUTTypeGIF);
   4.409 +}
   4.410 +SDL_Surface* IMG_LoadJPG_RW(SDL_RWops *src)
   4.411 +{
   4.412 +	return LoadImageFromRWops(src, kUTTypeJPEG);
   4.413 +}
   4.414 +SDL_Surface* IMG_LoadPNG_RW(SDL_RWops *src)
   4.415 +{
   4.416 +	return LoadImageFromRWops(src, kUTTypePNG);
   4.417 +}
   4.418 +SDL_Surface* IMG_LoadTIF_RW(SDL_RWops *src)
   4.419 +{
   4.420 +	return LoadImageFromRWops(src, kUTTypeTIFF);
   4.421 +}
   4.422 +
     5.1 Binary file Xcode.tar.gz has changed
     6.1 Binary file Xcode_iPhone.tar.gz has changed
     7.1 --- a/showimage.c	Mon Dec 08 00:27:32 2008 +0000
     7.2 +++ b/showimage.c	Sun Jan 04 02:09:27 2009 +0000
     7.3 @@ -80,6 +80,7 @@
     7.4  	SDL_Surface *screen, *image;
     7.5  	int i, depth, done;
     7.6  	SDL_Event event;
     7.7 +	SDL_RWops* rw_ops;
     7.8  
     7.9  	/* Check command line usage */
    7.10  	if ( ! argv[1] ) {
    7.11 @@ -100,6 +101,18 @@
    7.12  			flags |= SDL_FULLSCREEN;
    7.13  			continue;
    7.14  		}
    7.15 +#if 0
    7.16 +		rw_ops = SDL_RWFromFile(argv[1], "r");
    7.17 +		
    7.18 +		fprintf(stderr, "BMP:\t%d\n", IMG_isBMP(rw_ops));
    7.19 +		fprintf(stderr, "GIF:\t%d\n", IMG_isGIF(rw_ops));
    7.20 +		fprintf(stderr, "JPG:\t%d\n", IMG_isJPG(rw_ops));
    7.21 +		fprintf(stderr, "PNG:\t%d\n", IMG_isPNG(rw_ops));
    7.22 +		fprintf(stderr, "TIF:\t%d\n", IMG_isTIF(rw_ops));
    7.23 +		/* fprintf(stderr, "TGA:\t%d\n", IMG_isTGA(rw_ops)); */
    7.24 +		fprintf(stderr, "PCX:\t%d\n", IMG_isPCX(rw_ops));
    7.25 +#endif
    7.26 +
    7.27  		/* Open the image file */
    7.28  #ifdef XPM_INCLUDED
    7.29  		image = IMG_ReadXPMFromArray(picture_xpm);