]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/libsdl-image/contrib/IMG_UIImage.m
4e53212e725e4ab3397d7f3a3521d1ac27ca9c43
[l4.git] / l4 / pkg / libsdl-image / contrib / IMG_UIImage.m
1 /*
2  *  IMG_ImageIO.c
3  *  SDL_image
4  *
5  *  Created by Eric Wing on 1/2/09.
6  *  Copyright 2009 __MyCompanyName__. All rights reserved.
7  *
8  */
9 #include "SDL_image.h"
10 #import <UIKit/UIKit.h>
11 #import <MobileCoreServices/MobileCoreServices.h> // for UTCoreTypes.h
12
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)
16 {
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.
23          */
24         
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}};
28         
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;
33         
34 //      CGImageAlphaInfo alpha_info = CGImageGetAlphaInfo(image_ref);
35         
36
37         SDL_Surface* sdl_surface = NULL;
38         Uint32 Rmask;
39         Uint32 Gmask;
40         Uint32 Bmask;
41         Uint32 Amask;
42
43         
44         CGContextRef bitmap_context = NULL;
45         
46         CGColorSpaceRef color_space = NULL;
47         CGBitmapInfo bitmap_info = CGImageGetBitmapInfo(image_ref);
48
49         
50         switch(bits_per_pixel)
51         {
52                 case 8:
53                 {
54                         bytes_per_row = the_width*4;
55                         //                              color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
56                         color_space = CGColorSpaceCreateDeviceRGB();
57                         //                              bitmap_info = kCGImageAlphaPremultipliedFirst;
58 #if __BIG_ENDIAN__
59                         bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Big; /* XRGB Big Endian */
60 #else
61                         bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little; /* XRGB Little Endian */
62 #endif
63
64                         Rmask = 0x00FF0000;
65                         Gmask = 0x0000FF00;
66                         Bmask = 0x000000FF;
67                         Amask = 0x00000000;
68
69                         sdl_surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
70                                                                                            the_width, the_height, 32, Rmask, Gmask, Bmask, Amask);
71
72
73                         
74                         break;
75                 }
76                 case 15:
77                 case 16:
78                 {
79                         bytes_per_row = the_width*4;
80
81                         color_space = CGColorSpaceCreateDeviceRGB();
82
83 #if __BIG_ENDIAN__
84                         bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Big; /* XRGB Big Endian */
85 #else
86                         bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little; /* XRGB Little Endian */
87 #endif
88                         Rmask = 0x00FF0000;
89                         Gmask = 0x0000FF00;
90                         Bmask = 0x000000FF;
91                         Amask = 0x00000000;
92
93
94                         sdl_surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
95                                                                                            the_width, the_height, 32, Rmask, Gmask, Bmask, Amask);
96
97                         break;
98                 }
99                 case 24:
100                 {
101                         bytes_per_row = the_width*4;
102                         //                      color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
103                         color_space = CGColorSpaceCreateDeviceRGB();
104                         //                      bitmap_info = kCGImageAlphaNone;
105 #if __BIG_ENDIAN__
106                         bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Big; /* XRGB Big Endian */
107 #else
108                         bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little; /* XRGB Little Endian */
109 #endif
110                         Rmask = 0x00FF0000;
111                         Gmask = 0x0000FF00;
112                         Bmask = 0x000000FF;
113                         Amask = 0x00000000;
114
115                         sdl_surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
116                                                                                            the_width, the_height, 32, Rmask, Gmask, Bmask, Amask);
117
118                         break;
119                 }
120                 case 32:
121                 {
122                                                 
123                         bytes_per_row = the_width*4;
124                         //                      color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
125                         color_space = CGColorSpaceCreateDeviceRGB();
126                         //                      bitmap_info = kCGImageAlphaPremultipliedFirst;
127 #if __BIG_ENDIAN__
128                         bitmap_info = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big; /* XRGB Big Endian */
129 #else
130                         bitmap_info = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little; /* XRGB Little Endian */
131 #endif 
132                         Amask = 0xFF000000;
133                         Rmask = 0x00FF0000;
134                         Gmask = 0x0000FF00;
135                         Bmask = 0x000000FF;
136
137                         sdl_surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
138                                                                                            the_width, the_height, 32, Rmask, Gmask, Bmask, Amask);
139                         break;
140                 }
141                 default:
142                 {
143             sdl_surface = NULL;
144             break;
145                 }
146                         
147         }
148
149         if(NULL == sdl_surface)
150         {
151                 if(color_space != NULL)
152                 {
153                         CGColorSpaceRelease(color_space);                       
154                 }
155                 return NULL;
156         }
157
158
159         // Sets up a context to be drawn to with sdl_surface->pixels as the area to be drawn to
160         bitmap_context = CGBitmapContextCreate(
161                                                                                                                 sdl_surface->pixels,
162                                                                                                                 the_width,
163                                                                                                                 the_height,
164                                                                                                                 bits_per_component,
165                                                                                                                 bytes_per_row,
166                                                                                                                 color_space,
167                                                                                                                 bitmap_info
168                                                                                                                 );
169         
170         // Draws the image into the context's image_data
171         CGContextDrawImage(bitmap_context, the_rect, image_ref);
172         
173         CGContextRelease(bitmap_context);
174         CGColorSpaceRelease(color_space);
175         
176         return sdl_surface;
177         
178         
179         
180 }
181
182 static SDL_Surface* LoadImageFromRWops(SDL_RWops* rw_ops, CFStringRef uti_string_hint)
183 {
184         NSAutoreleasePool* autorelease_pool = [[NSAutoreleasePool alloc] init];
185         SDL_Surface* sdl_surface;
186         UIImage* ui_image;
187
188         CGImageRef image_ref = NULL;
189         int bytes_read = 0;
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];
194         
195         NSMutableData* ns_data = [[NSMutableData alloc] initWithCapacity:1024*1024*4];
196
197         
198         do
199         {
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);
203
204         if(NULL == image_ref)
205         {
206                 return NULL;
207         }
208
209         ui_image = [[UIImage alloc] initWithData:ns_data];
210         
211         sdl_surface = Create_SDL_Surface_From_CGImage([ui_image CGImage]);
212
213         [ui_image release];
214         [ns_data release];
215
216         [autorelease_pool drain];
217
218         return sdl_surface;
219 }
220
221 static SDL_Surface* LoadImageFromFile(const char *file)
222 {
223         NSAutoreleasePool* autorelease_pool = [[NSAutoreleasePool alloc] init];
224         SDL_Surface* sdl_surface = NULL;
225         UIImage* ui_image;
226         NSString* ns_string;
227         
228         ns_string = [[NSString alloc] initWithUTF8String:file];
229         ui_image = [[UIImage alloc] initWithContentsOfFile:ns_string];
230         
231         sdl_surface = Create_SDL_Surface_From_CGImage([ui_image CGImage]);
232         
233         [ui_image release];
234         [ns_string release];
235         
236         [autorelease_pool drain];
237         
238         return sdl_surface;
239 }
240
241
242 /* Since UIImage doesn't really support streams well, we should optimize for the file case. */
243 SDL_Surface *IMG_Load(const char *file)
244 {
245         SDL_Surface* sdl_surface = NULL;
246
247         sdl_surface = LoadImageFromFile(file);
248         if(NULL == sdl_surface)
249         {
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.
252
253                 SDL_RWops *src = SDL_RWFromFile(file, "rb");
254                 char *ext = strrchr(file, '.');
255                 if(ext) {
256                         ext++;
257                 }
258                 if(!src) {
259                         /* The error message has been set in SDL_RWFromFile */
260                         return NULL;
261                 }
262                 sdl_surface = IMG_LoadTyped_RW(src, 1, ext);
263         }
264         return sdl_surface;
265 }
266
267
268
269 /* Copied straight from other files so I don't have to alter them. */
270 static int IMG_isICOCUR(SDL_RWops *src, int type)
271 {
272         int start;
273         int is_ICOCUR;
274
275         /* The Win32 ICO file header (14 bytes) */
276     Uint16 bfReserved;
277     Uint16 bfType;
278     Uint16 bfCount;
279
280         if ( !src )
281                 return 0;
282         start = SDL_RWtell(src);
283         is_ICOCUR = 0;
284     bfReserved = SDL_ReadLE16(src);
285     bfType = SDL_ReadLE16(src);
286     bfCount = SDL_ReadLE16(src);
287     if ((bfReserved == 0) && (bfType == type) && (bfCount != 0)) 
288         is_ICOCUR = 1;
289         SDL_RWseek(src, start, SEEK_SET);
290
291         return (is_ICOCUR);
292 }
293
294 int IMG_isICO(SDL_RWops *src)
295 {
296         return IMG_isICOCUR(src, 1);
297 }
298
299 int IMG_isCUR(SDL_RWops *src)
300 {
301         return IMG_isICOCUR(src, 2);
302 }
303
304 int IMG_isBMP(SDL_RWops *src)
305 {
306         int start;
307         int is_BMP;
308         char magic[2];
309         
310         if ( !src )
311                 return 0;
312         start = SDL_RWtell(src);
313         is_BMP = 0;
314         if ( SDL_RWread(src, magic, sizeof(magic), 1) ) {
315                 if ( strncmp(magic, "BM", 2) == 0 ) {
316                         is_BMP = 1;
317                 }
318         }
319         SDL_RWseek(src, start, SEEK_SET);
320         return(is_BMP);
321 }
322
323 int IMG_isGIF(SDL_RWops *src)
324 {
325         int start;
326         int is_GIF;
327         char magic[6];
328         
329         if ( !src )
330                 return 0;
331         start = SDL_RWtell(src);
332         is_GIF = 0;
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)) ) {
337                         is_GIF = 1;
338                 }
339         }
340         SDL_RWseek(src, start, SEEK_SET);
341         return(is_GIF);
342 }
343
344 int IMG_isJPG(SDL_RWops *src)
345 {
346         int start;
347         int is_JPG;
348         int in_scan;
349         Uint8 magic[4];
350         
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! */
354         
355         if ( !src )
356                 return 0;
357         start = SDL_RWtell(src);
358         is_JPG = 0;
359         in_scan = 0;
360         if ( SDL_RWread(src, magic, 2, 1) ) {
361                 if ( (magic[0] == 0xFF) && (magic[1] == 0xD8) ) {
362                         is_JPG = 1;
363                         while (is_JPG == 1) {
364                                 if(SDL_RWread(src, magic, 1, 2) != 2) {
365                                         is_JPG = 0;
366                                 } else if( (magic[0] != 0xFF) && (in_scan == 0) ) {
367                                         is_JPG = 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 */
374                                         break;
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) {
380                                         is_JPG = 0;
381                                 } else {
382                                         /* Yes, it's big-endian */
383                                         Uint32 start;
384                                         Uint32 size;
385                                         Uint32 end;
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 */
392 #ifdef  FAST_IS_JPEG
393                                                 /* Ok, I'm convinced.  It is a JPEG. */
394                                                 break;
395 #else
396                                                 /* I'm not convinced.  Prove it! */
397                                                 in_scan = 1;
398 #endif
399                                         }
400                                 }
401                         }
402                 }
403         }
404         SDL_RWseek(src, start, SEEK_SET);
405         return(is_JPG);
406 }
407
408 int IMG_isPNG(SDL_RWops *src)
409 {
410         int start;
411         int is_PNG;
412         Uint8 magic[4];
413         
414         if ( !src )
415                 return 0;
416         start = SDL_RWtell(src);
417         is_PNG = 0;
418         if ( SDL_RWread(src, magic, 1, sizeof(magic)) == sizeof(magic) ) {
419                 if ( magic[0] == 0x89 &&
420                         magic[1] == 'P' &&
421                         magic[2] == 'N' &&
422                         magic[3] == 'G' ) {
423                         is_PNG = 1;
424                 }
425         }
426         SDL_RWseek(src, start, SEEK_SET);
427         return(is_PNG);
428 }
429
430 int IMG_isTIF(SDL_RWops* src)
431 {
432         int start;
433         int is_TIF;
434         Uint8 magic[4];
435         
436         if ( !src )
437                 return 0;
438         start = SDL_RWtell(src);
439         is_TIF = 0;
440         if ( SDL_RWread(src, magic, 1, sizeof(magic)) == sizeof(magic) ) {
441                 if ( (magic[0] == 'I' &&
442                           magic[1] == 'I' &&
443                       magic[2] == 0x2a &&
444                           magic[3] == 0x00) ||
445                         (magic[0] == 'M' &&
446                          magic[1] == 'M' &&
447                          magic[2] == 0x00 &&
448                          magic[3] == 0x2a) ) {
449                         is_TIF = 1;
450                 }
451         }
452         SDL_RWseek(src, start, SEEK_SET);
453         return(is_TIF);
454 }
455
456 SDL_Surface* IMG_LoadCUR_RW(SDL_RWops *src)
457 {
458         /* FIXME: Is this a supported type? */
459         return LoadImageFromRWops(src, CFSTR("com.microsoft.cur"));
460 }
461 SDL_Surface* IMG_LoadICO_RW(SDL_RWops *src)
462 {
463         return LoadImageFromRWops(src, kUTTypeICO);
464 }
465 SDL_Surface* IMG_LoadBMP_RW(SDL_RWops *src)
466 {
467         return LoadImageFromRWops(src, kUTTypeBMP);
468 }
469 SDL_Surface* IMG_LoadGIF_RW(SDL_RWops *src)
470 {
471         return LoadImageFromRWops(src, kUTTypeGIF);
472 }
473 SDL_Surface* IMG_LoadJPG_RW(SDL_RWops *src)
474 {
475         return LoadImageFromRWops(src, kUTTypeJPEG);
476 }
477 SDL_Surface* IMG_LoadPNG_RW(SDL_RWops *src)
478 {
479         return LoadImageFromRWops(src, kUTTypePNG);
480 }
481 SDL_Surface* IMG_LoadTGA_RW(SDL_RWops *src)
482 {
483         return LoadImageFromRWops(src, CFSTR("com.truevision.tga-image"));
484 }
485 SDL_Surface* IMG_LoadTIF_RW(SDL_RWops *src)
486 {
487         return LoadImageFromRWops(src, kUTTypeTIFF);
488 }
489