5 * Created by Eric Wing on 1/2/09.
6 * Copyright 2009 __MyCompanyName__. All rights reserved.
10 #import <UIKit/UIKit.h>
11 #import <MobileCoreServices/MobileCoreServices.h> // for UTCoreTypes.h
13 // Once we have our image, we need to get it into an SDL_Surface
14 // (Copied straight from the ImageIO backend.)
15 static SDL_Surface* Create_SDL_Surface_From_CGImage(CGImageRef image_ref)
17 /* This code is adapted from Apple's Documentation found here:
18 * http://developer.apple.com/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/index.html
19 * Listing 9-4††Using a Quartz image as a texture source.
20 * Unfortunately, this guide doesn't show what to do about
21 * non-RGBA image formats so I'm making the rest up.
22 * All this code should be scrutinized.
25 size_t the_width = CGImageGetWidth(image_ref);
26 size_t the_height = CGImageGetHeight(image_ref);
27 CGRect the_rect = {{0, 0}, {the_width, the_height}};
29 size_t bits_per_pixel = CGImageGetBitsPerPixel(image_ref);
30 size_t bytes_per_row = CGImageGetBytesPerRow(image_ref);
31 // size_t bits_per_component = CGImageGetBitsPerComponent(image_ref);
32 size_t bits_per_component = 8;
34 // CGImageAlphaInfo alpha_info = CGImageGetAlphaInfo(image_ref);
37 SDL_Surface* sdl_surface = NULL;
44 CGContextRef bitmap_context = NULL;
46 CGColorSpaceRef color_space = NULL;
47 CGBitmapInfo bitmap_info = CGImageGetBitmapInfo(image_ref);
50 switch(bits_per_pixel)
54 bytes_per_row = the_width*4;
55 // color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
56 color_space = CGColorSpaceCreateDeviceRGB();
57 // bitmap_info = kCGImageAlphaPremultipliedFirst;
59 bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Big; /* XRGB Big Endian */
61 bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little; /* XRGB Little Endian */
69 sdl_surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
70 the_width, the_height, 32, Rmask, Gmask, Bmask, Amask);
79 bytes_per_row = the_width*4;
81 color_space = CGColorSpaceCreateDeviceRGB();
84 bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Big; /* XRGB Big Endian */
86 bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little; /* XRGB Little Endian */
94 sdl_surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
95 the_width, the_height, 32, Rmask, Gmask, Bmask, Amask);
101 bytes_per_row = the_width*4;
102 // color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
103 color_space = CGColorSpaceCreateDeviceRGB();
104 // bitmap_info = kCGImageAlphaNone;
106 bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Big; /* XRGB Big Endian */
108 bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little; /* XRGB Little Endian */
115 sdl_surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
116 the_width, the_height, 32, Rmask, Gmask, Bmask, Amask);
123 bytes_per_row = the_width*4;
124 // color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
125 color_space = CGColorSpaceCreateDeviceRGB();
126 // bitmap_info = kCGImageAlphaPremultipliedFirst;
128 bitmap_info = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big; /* XRGB Big Endian */
130 bitmap_info = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little; /* XRGB Little Endian */
137 sdl_surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
138 the_width, the_height, 32, Rmask, Gmask, Bmask, Amask);
149 if(NULL == sdl_surface)
151 if(color_space != NULL)
153 CGColorSpaceRelease(color_space);
159 // Sets up a context to be drawn to with sdl_surface->pixels as the area to be drawn to
160 bitmap_context = CGBitmapContextCreate(
170 // Draws the image into the context's image_data
171 CGContextDrawImage(bitmap_context, the_rect, image_ref);
173 CGContextRelease(bitmap_context);
174 CGColorSpaceRelease(color_space);
182 static SDL_Surface* LoadImageFromRWops(SDL_RWops* rw_ops, CFStringRef uti_string_hint)
184 NSAutoreleasePool* autorelease_pool = [[NSAutoreleasePool alloc] init];
185 SDL_Surface* sdl_surface;
188 CGImageRef image_ref = NULL;
190 // I don't know what a good size is.
191 // Max recommended texture size is 1024x1024 on iPhone so maybe base it on that?
192 const int block_size = 1024*4;
193 char temp_buffer[block_size];
195 NSMutableData* ns_data = [[NSMutableData alloc] initWithCapacity:1024*1024*4];
200 bytes_read = SDL_RWread(rw_ops, temp_buffer, 1, block_size);
201 [ns_data appendBytes:temp_buffer length:bytes_read];
202 } while(bytes_read > 0);
204 if(NULL == image_ref)
209 ui_image = [[UIImage alloc] initWithData:ns_data];
211 sdl_surface = Create_SDL_Surface_From_CGImage([ui_image CGImage]);
216 [autorelease_pool drain];
221 static SDL_Surface* LoadImageFromFile(const char *file)
223 NSAutoreleasePool* autorelease_pool = [[NSAutoreleasePool alloc] init];
224 SDL_Surface* sdl_surface = NULL;
228 ns_string = [[NSString alloc] initWithUTF8String:file];
229 ui_image = [[UIImage alloc] initWithContentsOfFile:ns_string];
231 sdl_surface = Create_SDL_Surface_From_CGImage([ui_image CGImage]);
236 [autorelease_pool drain];
242 /* Since UIImage doesn't really support streams well, we should optimize for the file case. */
243 SDL_Surface *IMG_Load(const char *file)
245 SDL_Surface* sdl_surface = NULL;
247 sdl_surface = LoadImageFromFile(file);
248 if(NULL == sdl_surface)
250 // Either the file doesn't exist or ImageIO doesn't understand the format.
251 // For the latter case, fallback to the native SDL_image handlers.
253 SDL_RWops *src = SDL_RWFromFile(file, "rb");
254 char *ext = strrchr(file, '.');
259 /* The error message has been set in SDL_RWFromFile */
262 sdl_surface = IMG_LoadTyped_RW(src, 1, ext);
269 /* Copied straight from other files so I don't have to alter them. */
270 static int IMG_isICOCUR(SDL_RWops *src, int type)
275 /* The Win32 ICO file header (14 bytes) */
282 start = SDL_RWtell(src);
284 bfReserved = SDL_ReadLE16(src);
285 bfType = SDL_ReadLE16(src);
286 bfCount = SDL_ReadLE16(src);
287 if ((bfReserved == 0) && (bfType == type) && (bfCount != 0))
289 SDL_RWseek(src, start, SEEK_SET);
294 int IMG_isICO(SDL_RWops *src)
296 return IMG_isICOCUR(src, 1);
299 int IMG_isCUR(SDL_RWops *src)
301 return IMG_isICOCUR(src, 2);
304 int IMG_isBMP(SDL_RWops *src)
312 start = SDL_RWtell(src);
314 if ( SDL_RWread(src, magic, sizeof(magic), 1) ) {
315 if ( strncmp(magic, "BM", 2) == 0 ) {
319 SDL_RWseek(src, start, SEEK_SET);
323 int IMG_isGIF(SDL_RWops *src)
331 start = SDL_RWtell(src);
333 if ( SDL_RWread(src, magic, sizeof(magic), 1) ) {
334 if ( (strncmp(magic, "GIF", 3) == 0) &&
335 ((memcmp(magic + 3, "87a", 3) == 0) ||
336 (memcmp(magic + 3, "89a", 3) == 0)) ) {
340 SDL_RWseek(src, start, SEEK_SET);
344 int IMG_isJPG(SDL_RWops *src)
351 /* This detection code is by Steaphan Greene <stea@cs.binghamton.edu> */
352 /* Blame me, not Sam, if this doesn't work right. */
353 /* And don't forget to report the problem to the the sdl list too! */
357 start = SDL_RWtell(src);
360 if ( SDL_RWread(src, magic, 2, 1) ) {
361 if ( (magic[0] == 0xFF) && (magic[1] == 0xD8) ) {
363 while (is_JPG == 1) {
364 if(SDL_RWread(src, magic, 1, 2) != 2) {
366 } else if( (magic[0] != 0xFF) && (in_scan == 0) ) {
368 } else if( (magic[0] != 0xFF) || (magic[1] == 0xFF) ) {
369 /* Extra padding in JPEG (legal) */
370 /* or this is data and we are scanning */
371 SDL_RWseek(src, -1, SEEK_CUR);
372 } else if(magic[1] == 0xD9) {
373 /* Got to end of good JPEG */
375 } else if( (in_scan == 1) && (magic[1] == 0x00) ) {
376 /* This is an encoded 0xFF within the data */
377 } else if( (magic[1] >= 0xD0) && (magic[1] < 0xD9) ) {
378 /* These have nothing else */
379 } else if(SDL_RWread(src, magic+2, 1, 2) != 2) {
382 /* Yes, it's big-endian */
386 start = SDL_RWtell(src);
387 size = (magic[2] << 8) + magic[3];
388 end = SDL_RWseek(src, size-2, SEEK_CUR);
389 if ( end != start + size - 2 ) is_JPG = 0;
390 if ( magic[1] == 0xDA ) {
391 /* Now comes the actual JPEG meat */
393 /* Ok, I'm convinced. It is a JPEG. */
396 /* I'm not convinced. Prove it! */
404 SDL_RWseek(src, start, SEEK_SET);
408 int IMG_isPNG(SDL_RWops *src)
416 start = SDL_RWtell(src);
418 if ( SDL_RWread(src, magic, 1, sizeof(magic)) == sizeof(magic) ) {
419 if ( magic[0] == 0x89 &&
426 SDL_RWseek(src, start, SEEK_SET);
430 int IMG_isTIF(SDL_RWops* src)
438 start = SDL_RWtell(src);
440 if ( SDL_RWread(src, magic, 1, sizeof(magic)) == sizeof(magic) ) {
441 if ( (magic[0] == 'I' &&
448 magic[3] == 0x2a) ) {
452 SDL_RWseek(src, start, SEEK_SET);
456 SDL_Surface* IMG_LoadCUR_RW(SDL_RWops *src)
458 /* FIXME: Is this a supported type? */
459 return LoadImageFromRWops(src, CFSTR("com.microsoft.cur"));
461 SDL_Surface* IMG_LoadICO_RW(SDL_RWops *src)
463 return LoadImageFromRWops(src, kUTTypeICO);
465 SDL_Surface* IMG_LoadBMP_RW(SDL_RWops *src)
467 return LoadImageFromRWops(src, kUTTypeBMP);
469 SDL_Surface* IMG_LoadGIF_RW(SDL_RWops *src)
471 return LoadImageFromRWops(src, kUTTypeGIF);
473 SDL_Surface* IMG_LoadJPG_RW(SDL_RWops *src)
475 return LoadImageFromRWops(src, kUTTypeJPEG);
477 SDL_Surface* IMG_LoadPNG_RW(SDL_RWops *src)
479 return LoadImageFromRWops(src, kUTTypePNG);
481 SDL_Surface* IMG_LoadTGA_RW(SDL_RWops *src)
483 return LoadImageFromRWops(src, CFSTR("com.truevision.tga-image"));
485 SDL_Surface* IMG_LoadTIF_RW(SDL_RWops *src)
487 return LoadImageFromRWops(src, kUTTypeTIFF);