IMG_ImageIO.m 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803
  1. /*
  2. * IMG_ImageIO.c
  3. * SDL_image
  4. *
  5. * Created by Eric Wing on 1/1/09.
  6. * Copyright 2009 __MyCompanyName__. All rights reserved.
  7. *
  8. */
  9. #if defined(__APPLE__) && !defined(SDL_IMAGE_USE_COMMON_BACKEND)
  10. #include "SDL_image.h"
  11. // Used because CGDataProviderCreate became deprecated in 10.5
  12. #include <AvailabilityMacros.h>
  13. #include <TargetConditionals.h>
  14. #include <Foundation/Foundation.h>
  15. #if (TARGET_OS_IPHONE == 1) || (TARGET_IPHONE_SIMULATOR == 1)
  16. #ifdef ALLOW_UIIMAGE_FALLBACK
  17. #define USE_UIIMAGE_BACKEND() ([UIImage instancesRespondToSelector:@selector(initWithCGImage:scale:orientation:)] == NO)
  18. #else
  19. #define USE_UIIMAGE_BACKEND() (Internal_checkImageIOisAvailable())
  20. #endif
  21. #import <MobileCoreServices/MobileCoreServices.h> // for UTCoreTypes.h
  22. #import <ImageIO/ImageIO.h>
  23. #import <UIKit/UIImage.h>
  24. #else
  25. // For ImageIO framework and also LaunchServices framework (for UTIs)
  26. #include <ApplicationServices/ApplicationServices.h>
  27. #endif
  28. /**************************************************************
  29. ***** Begin Callback functions for block reading *************
  30. **************************************************************/
  31. // This callback reads some bytes from an SDL_rwops and copies it
  32. // to a Quartz buffer (supplied by Apple framework).
  33. static size_t MyProviderGetBytesCallback(void* rwops_userdata, void* quartz_buffer, size_t the_count)
  34. {
  35. return (size_t)SDL_RWread((struct SDL_RWops *)rwops_userdata, quartz_buffer, 1, the_count);
  36. }
  37. // This callback is triggered when the data provider is released
  38. // so you can clean up any resources.
  39. static void MyProviderReleaseInfoCallback(void* rwops_userdata)
  40. {
  41. // What should I put here?
  42. // I think the user and SDL_RWops controls closing, so I don't do anything.
  43. }
  44. static void MyProviderRewindCallback(void* rwops_userdata)
  45. {
  46. SDL_RWseek((struct SDL_RWops *)rwops_userdata, 0, RW_SEEK_SET);
  47. }
  48. #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 // CGDataProviderCreateSequential was introduced in 10.5; CGDataProviderCreate is deprecated
  49. off_t MyProviderSkipForwardBytesCallback(void* rwops_userdata, off_t the_count)
  50. {
  51. off_t start_position = SDL_RWtell((struct SDL_RWops *)rwops_userdata);
  52. SDL_RWseek((struct SDL_RWops *)rwops_userdata, the_count, RW_SEEK_CUR);
  53. off_t end_position = SDL_RWtell((struct SDL_RWops *)rwops_userdata);
  54. return (end_position - start_position);
  55. }
  56. #else // CGDataProviderCreate was deprecated in 10.5
  57. static void MyProviderSkipBytesCallback(void* rwops_userdata, size_t the_count)
  58. {
  59. SDL_RWseek((struct SDL_RWops *)rwops_userdata, the_count, RW_SEEK_CUR);
  60. }
  61. #endif
  62. /**************************************************************
  63. ***** End Callback functions for block reading ***************
  64. **************************************************************/
  65. // This creates a CGImageSourceRef which is a handle to an image that can be used to examine information
  66. // about the image or load the actual image data.
  67. static CGImageSourceRef CreateCGImageSourceFromRWops(SDL_RWops* rw_ops, CFDictionaryRef hints_and_options)
  68. {
  69. CGImageSourceRef source_ref;
  70. // Similar to SDL_RWops, Apple has their own callbacks for dealing with data streams.
  71. #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 // CGDataProviderCreateSequential was introduced in 10.5; CGDataProviderCreate is deprecated
  72. CGDataProviderSequentialCallbacks provider_callbacks =
  73. {
  74. 0,
  75. MyProviderGetBytesCallback,
  76. MyProviderSkipForwardBytesCallback,
  77. MyProviderRewindCallback,
  78. MyProviderReleaseInfoCallback
  79. };
  80. CGDataProviderRef data_provider = CGDataProviderCreateSequential(rw_ops, &provider_callbacks);
  81. #else // CGDataProviderCreate was deprecated in 10.5
  82. CGDataProviderCallbacks provider_callbacks =
  83. {
  84. MyProviderGetBytesCallback,
  85. MyProviderSkipBytesCallback,
  86. MyProviderRewindCallback,
  87. MyProviderReleaseInfoCallback
  88. };
  89. CGDataProviderRef data_provider = CGDataProviderCreate(rw_ops, &provider_callbacks);
  90. #endif
  91. // Get the CGImageSourceRef.
  92. // The dictionary can be NULL or contain hints to help ImageIO figure out the image type.
  93. source_ref = CGImageSourceCreateWithDataProvider(data_provider, hints_and_options);
  94. CGDataProviderRelease(data_provider);
  95. return source_ref;
  96. }
  97. /* Create a CGImageSourceRef from a file. */
  98. /* Remember to CFRelease the created source when done. */
  99. static CGImageSourceRef CreateCGImageSourceFromFile(const char* the_path)
  100. {
  101. CFURLRef the_url = NULL;
  102. CGImageSourceRef source_ref = NULL;
  103. CFStringRef cf_string = NULL;
  104. /* Create a CFString from a C string */
  105. cf_string = CFStringCreateWithCString(NULL, the_path, kCFStringEncodingUTF8);
  106. if (!cf_string) {
  107. return NULL;
  108. }
  109. /* Create a CFURL from a CFString */
  110. the_url = CFURLCreateWithFileSystemPath(NULL, cf_string, kCFURLPOSIXPathStyle, false);
  111. /* Don't need the CFString any more (error or not) */
  112. CFRelease(cf_string);
  113. if(!the_url)
  114. {
  115. return NULL;
  116. }
  117. source_ref = CGImageSourceCreateWithURL(the_url, NULL);
  118. /* Don't need the URL any more (error or not) */
  119. CFRelease(the_url);
  120. return source_ref;
  121. }
  122. static CGImageRef CreateCGImageFromCGImageSource(CGImageSourceRef image_source)
  123. {
  124. CGImageRef image_ref = NULL;
  125. if(NULL == image_source)
  126. {
  127. return NULL;
  128. }
  129. // Get the first item in the image source (some image formats may
  130. // contain multiple items).
  131. image_ref = CGImageSourceCreateImageAtIndex(image_source, 0, NULL);
  132. if(NULL == image_ref)
  133. {
  134. IMG_SetError("CGImageSourceCreateImageAtIndex() failed");
  135. }
  136. return image_ref;
  137. }
  138. static CFDictionaryRef CreateHintDictionary(CFStringRef uti_string_hint)
  139. {
  140. CFDictionaryRef hint_dictionary = NULL;
  141. if(uti_string_hint != NULL)
  142. {
  143. // Do a bunch of work to setup a CFDictionary containing the jpeg compression properties.
  144. CFStringRef the_keys[1];
  145. CFStringRef the_values[1];
  146. the_keys[0] = kCGImageSourceTypeIdentifierHint;
  147. the_values[0] = uti_string_hint;
  148. // kCFTypeDictionaryKeyCallBacks or kCFCopyStringDictionaryKeyCallBacks?
  149. hint_dictionary = CFDictionaryCreate(NULL, (const void**)&the_keys, (const void**)&the_values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
  150. }
  151. return hint_dictionary;
  152. }
  153. // Once we have our image, we need to get it into an SDL_Surface
  154. static SDL_Surface* Create_SDL_Surface_From_CGImage_RGB(CGImageRef image_ref)
  155. {
  156. /* This code is adapted from Apple's Documentation found here:
  157. * http://developer.apple.com/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/index.html
  158. * Listing 9-4††Using a Quartz image as a texture source.
  159. * Unfortunately, this guide doesn't show what to do about
  160. * non-RGBA image formats so I'm making the rest up.
  161. * All this code should be scrutinized.
  162. */
  163. size_t w = CGImageGetWidth(image_ref);
  164. size_t h = CGImageGetHeight(image_ref);
  165. CGRect rect = {{0, 0}, {w, h}};
  166. CGImageAlphaInfo alpha = CGImageGetAlphaInfo(image_ref);
  167. //size_t bits_per_pixel = CGImageGetBitsPerPixel(image_ref);
  168. size_t bits_per_component = 8;
  169. SDL_Surface* surface;
  170. Uint32 Amask;
  171. Uint32 Rmask;
  172. Uint32 Gmask;
  173. Uint32 Bmask;
  174. CGContextRef bitmap_context;
  175. CGBitmapInfo bitmap_info;
  176. /* This sets up a color space that results in identical values
  177. * as the image data itself, which is the same as the standalone
  178. * libpng loader.
  179. * Thanks to Allegro. :)
  180. */
  181. CGFloat whitePoint[3] = { 0.950, 1.000, 1.089 };
  182. CGFloat blackPoint[3] = { 0.000, 0.000, 0.000 };
  183. CGFloat gamma[3] = { 2.2, 2.2, 2.2 };
  184. CGFloat matrix[9] = {
  185. 0.412, 0.213, 0.019,
  186. 0.358, 0.715, 0.119,
  187. 0.180, 0.072, 0.950
  188. };
  189. CGColorSpaceRef color_space =
  190. CGColorSpaceCreateCalibratedRGB(
  191. whitePoint, blackPoint, gamma, matrix
  192. );
  193. if (alpha == kCGImageAlphaNone ||
  194. alpha == kCGImageAlphaNoneSkipFirst ||
  195. alpha == kCGImageAlphaNoneSkipLast) {
  196. bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host; /* XRGB */
  197. Amask = 0x00000000;
  198. } else {
  199. /* kCGImageAlphaFirst isn't supported */
  200. //bitmap_info = kCGImageAlphaFirst | kCGBitmapByteOrder32Host; /* ARGB */
  201. bitmap_info = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host; /* ARGB */
  202. Amask = 0xFF000000;
  203. }
  204. Rmask = 0x00FF0000;
  205. Gmask = 0x0000FF00;
  206. Bmask = 0x000000FF;
  207. surface = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32, Rmask, Gmask, Bmask, Amask);
  208. if (surface)
  209. {
  210. // Sets up a context to be drawn to with surface->pixels as the area to be drawn to
  211. bitmap_context = CGBitmapContextCreate(
  212. surface->pixels,
  213. surface->w,
  214. surface->h,
  215. bits_per_component,
  216. surface->pitch,
  217. color_space,
  218. bitmap_info
  219. );
  220. // Draws the image into the context's image_data
  221. CGContextDrawImage(bitmap_context, rect, image_ref);
  222. CGContextRelease(bitmap_context);
  223. // FIXME: Reverse the premultiplied alpha
  224. if ((bitmap_info & kCGBitmapAlphaInfoMask) == kCGImageAlphaPremultipliedFirst) {
  225. int i, j;
  226. Uint8 *p = (Uint8 *)surface->pixels;
  227. for (i = surface->h * surface->pitch/4; i--; ) {
  228. #if __LITTLE_ENDIAN__
  229. Uint8 A = p[3];
  230. if (A) {
  231. for (j = 0; j < 3; ++j) {
  232. p[j] = (p[j] * 255) / A;
  233. }
  234. }
  235. #else
  236. Uint8 A = p[0];
  237. if (A) {
  238. for (j = 1; j < 4; ++j) {
  239. p[j] = (p[j] * 255) / A;
  240. }
  241. }
  242. #endif /* ENDIAN */
  243. p += 4;
  244. }
  245. }
  246. }
  247. if (color_space)
  248. {
  249. CGColorSpaceRelease(color_space);
  250. }
  251. return surface;
  252. }
  253. static SDL_Surface* Create_SDL_Surface_From_CGImage_Index(CGImageRef image_ref)
  254. {
  255. size_t w = CGImageGetWidth(image_ref);
  256. size_t h = CGImageGetHeight(image_ref);
  257. size_t bits_per_pixel = CGImageGetBitsPerPixel(image_ref);
  258. size_t bytes_per_row = CGImageGetBytesPerRow(image_ref);
  259. SDL_Surface* surface;
  260. SDL_Palette* palette;
  261. CGColorSpaceRef color_space = CGImageGetColorSpace(image_ref);
  262. CGColorSpaceRef base_color_space = CGColorSpaceGetBaseColorSpace(color_space);
  263. size_t num_components = CGColorSpaceGetNumberOfComponents(base_color_space);
  264. size_t num_entries = CGColorSpaceGetColorTableCount(color_space);
  265. uint8_t *entry, entries[num_components * num_entries];
  266. /* What do we do if it's not RGB? */
  267. if (num_components != 3) {
  268. SDL_SetError("Unknown colorspace components %lu", num_components);
  269. return NULL;
  270. }
  271. if (bits_per_pixel != 8) {
  272. SDL_SetError("Unknown bits_per_pixel %lu", bits_per_pixel);
  273. return NULL;
  274. }
  275. CGColorSpaceGetColorTable(color_space, entries);
  276. surface = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, bits_per_pixel, 0, 0, 0, 0);
  277. if (surface) {
  278. uint8_t* pixels = (uint8_t*)surface->pixels;
  279. CGDataProviderRef provider = CGImageGetDataProvider(image_ref);
  280. NSData* data = (id)CGDataProviderCopyData(provider);
  281. [data autorelease];
  282. const uint8_t* bytes = [data bytes];
  283. size_t i;
  284. palette = surface->format->palette;
  285. for (i = 0, entry = entries; i < num_entries; ++i) {
  286. palette->colors[i].r = entry[0];
  287. palette->colors[i].g = entry[1];
  288. palette->colors[i].b = entry[2];
  289. entry += num_components;
  290. }
  291. for (i = 0; i < h; ++i) {
  292. SDL_memcpy(pixels, bytes, w);
  293. pixels += surface->pitch;
  294. bytes += bytes_per_row;
  295. }
  296. }
  297. return surface;
  298. }
  299. static SDL_Surface* Create_SDL_Surface_From_CGImage(CGImageRef image_ref)
  300. {
  301. CGColorSpaceRef color_space = CGImageGetColorSpace(image_ref);
  302. if (CGColorSpaceGetModel(color_space) == kCGColorSpaceModelIndexed) {
  303. return Create_SDL_Surface_From_CGImage_Index(image_ref);
  304. } else {
  305. return Create_SDL_Surface_From_CGImage_RGB(image_ref);
  306. }
  307. }
  308. #pragma mark -
  309. #pragma mark IMG_Init stubs
  310. #if !defined(ALLOW_UIIMAGE_FALLBACK) && ((TARGET_OS_IPHONE == 1) || (TARGET_IPHONE_SIMULATOR == 1))
  311. static int Internal_checkImageIOisAvailable() {
  312. // just check if we are running on ios 4 or more, else throw exception
  313. if ([UIImage instancesRespondToSelector:@selector(initWithCGImage:scale:orientation:)])
  314. return 0;
  315. [NSException raise:@"UIImage fallback not enabled at compile time"
  316. format:@"ImageIO is not available on your platform, please recompile SDL_Image with ALLOW_UIIMAGE_FALLBACK."];
  317. return -1;
  318. }
  319. #endif
  320. int IMG_InitJPG()
  321. {
  322. return 0;
  323. }
  324. void IMG_QuitJPG()
  325. {
  326. }
  327. int IMG_InitPNG()
  328. {
  329. return 0;
  330. }
  331. void IMG_QuitPNG()
  332. {
  333. }
  334. int IMG_InitTIF()
  335. {
  336. return 0;
  337. }
  338. void IMG_QuitTIF()
  339. {
  340. }
  341. #pragma mark -
  342. #pragma mark Get type of image
  343. static int Internal_isType_UIImage (SDL_RWops *rw_ops, CFStringRef uti_string_to_test)
  344. {
  345. int is_type = 0;
  346. #if defined(ALLOW_UIIMAGE_FALLBACK) && ((TARGET_OS_IPHONE == 1) || (TARGET_IPHONE_SIMULATOR == 1))
  347. int start = SDL_RWtell(rw_ops);
  348. if ((0 == CFStringCompare(uti_string_to_test, kUTTypeICO, 0)) ||
  349. (0 == CFStringCompare(uti_string_to_test, CFSTR("com.microsoft.cur"), 0))) {
  350. // The Win32 ICO file header (14 bytes)
  351. Uint16 bfReserved;
  352. Uint16 bfType;
  353. Uint16 bfCount;
  354. int type = (0 == CFStringCompare(uti_string_to_test, kUTTypeICO, 0)) ? 1 : 2;
  355. bfReserved = SDL_ReadLE16(rw_ops);
  356. bfType = SDL_ReadLE16(rw_ops);
  357. bfCount = SDL_ReadLE16(rw_ops);
  358. if ((bfReserved == 0) && (bfType == type) && (bfCount != 0))
  359. is_type = 1;
  360. } else if (0 == CFStringCompare(uti_string_to_test, kUTTypeBMP, 0)) {
  361. char magic[2];
  362. if ( SDL_RWread(rw_ops, magic, sizeof(magic), 1) ) {
  363. if ( strncmp(magic, "BM", 2) == 0 ) {
  364. is_type = 1;
  365. }
  366. }
  367. } else if (0 == CFStringCompare(uti_string_to_test, kUTTypeGIF, 0)) {
  368. char magic[6];
  369. if ( SDL_RWread(rw_ops, magic, sizeof(magic), 1) ) {
  370. if ( (strncmp(magic, "GIF", 3) == 0) &&
  371. ((memcmp(magic + 3, "87a", 3) == 0) ||
  372. (memcmp(magic + 3, "89a", 3) == 0)) ) {
  373. is_type = 1;
  374. }
  375. }
  376. } else if (0 == CFStringCompare(uti_string_to_test, kUTTypeJPEG, 0)) {
  377. int in_scan = 0;
  378. Uint8 magic[4];
  379. // This detection code is by Steaphan Greene <[email protected]>
  380. // Blame me, not Sam, if this doesn't work right. */
  381. // And don't forget to report the problem to the the sdl list too! */
  382. if ( SDL_RWread(rw_ops, magic, 2, 1) ) {
  383. if ( (magic[0] == 0xFF) && (magic[1] == 0xD8) ) {
  384. is_type = 1;
  385. while (is_type == 1) {
  386. if(SDL_RWread(rw_ops, magic, 1, 2) != 2) {
  387. is_type = 0;
  388. } else if( (magic[0] != 0xFF) && (in_scan == 0) ) {
  389. is_type = 0;
  390. } else if( (magic[0] != 0xFF) || (magic[1] == 0xFF) ) {
  391. /* Extra padding in JPEG (legal) */
  392. /* or this is data and we are scanning */
  393. SDL_RWseek(rw_ops, -1, SEEK_CUR);
  394. } else if(magic[1] == 0xD9) {
  395. /* Got to end of good JPEG */
  396. break;
  397. } else if( (in_scan == 1) && (magic[1] == 0x00) ) {
  398. /* This is an encoded 0xFF within the data */
  399. } else if( (magic[1] >= 0xD0) && (magic[1] < 0xD9) ) {
  400. /* These have nothing else */
  401. } else if(SDL_RWread(rw_ops, magic+2, 1, 2) != 2) {
  402. is_type = 0;
  403. } else {
  404. /* Yes, it's big-endian */
  405. Uint32 start;
  406. Uint32 size;
  407. Uint32 end;
  408. start = SDL_RWtell(rw_ops);
  409. size = (magic[2] << 8) + magic[3];
  410. end = SDL_RWseek(rw_ops, size-2, SEEK_CUR);
  411. if ( end != start + size - 2 ) is_type = 0;
  412. if ( magic[1] == 0xDA ) {
  413. /* Now comes the actual JPEG meat */
  414. #ifdef FAST_IS_JPEG
  415. /* Ok, I'm convinced. It is a JPEG. */
  416. break;
  417. #else
  418. /* I'm not convinced. Prove it! */
  419. in_scan = 1;
  420. #endif
  421. }
  422. }
  423. }
  424. }
  425. }
  426. } else if (0 == CFStringCompare(uti_string_to_test, kUTTypePNG, 0)) {
  427. Uint8 magic[4];
  428. if ( SDL_RWread(rw_ops, magic, 1, sizeof(magic)) == sizeof(magic) ) {
  429. if ( magic[0] == 0x89 &&
  430. magic[1] == 'P' &&
  431. magic[2] == 'N' &&
  432. magic[3] == 'G' ) {
  433. is_type = 1;
  434. }
  435. }
  436. } else if (0 == CFStringCompare(uti_string_to_test, CFSTR("com.truevision.tga-image"), 0)) {
  437. //TODO: fill me!
  438. } else if (0 == CFStringCompare(uti_string_to_test, kUTTypeTIFF, 0)) {
  439. Uint8 magic[4];
  440. if ( SDL_RWread(rw_ops, 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_type = 1;
  450. }
  451. }
  452. }
  453. // reset the file descption pointer
  454. SDL_RWseek(rw_ops, start, SEEK_SET);
  455. #endif /* #if defined(ALLOW_UIIMAGE_FALLBACK) && ((TARGET_OS_IPHONE == 1) || (TARGET_IPHONE_SIMULATOR == 1)) */
  456. return is_type;
  457. }
  458. static int Internal_isType_ImageIO (SDL_RWops *rw_ops, CFStringRef uti_string_to_test)
  459. {
  460. int is_type = 0;
  461. CFDictionaryRef hint_dictionary = CreateHintDictionary(uti_string_to_test);
  462. CGImageSourceRef image_source = CreateCGImageSourceFromRWops(rw_ops, hint_dictionary);
  463. if (hint_dictionary != NULL) {
  464. CFRelease(hint_dictionary);
  465. }
  466. if (NULL == image_source) {
  467. return 0;
  468. }
  469. // This will get the UTI of the container, not the image itself.
  470. // Under most cases, this won't be a problem.
  471. // But if a person passes an icon file which contains a bmp,
  472. // the format will be of the icon file.
  473. // But I think the main SDL_image codebase has this same problem so I'm not going to worry about it.
  474. CFStringRef uti_type = CGImageSourceGetType(image_source);
  475. // CFShow(uti_type);
  476. // Unsure if we really want conformance or equality
  477. is_type = (int)UTTypeConformsTo(uti_string_to_test, uti_type);
  478. CFRelease(image_source);
  479. return is_type;
  480. }
  481. static int Internal_isType (SDL_RWops *rw_ops, CFStringRef uti_string_to_test)
  482. {
  483. if (rw_ops == NULL)
  484. return 0;
  485. #if (TARGET_OS_IPHONE == 1) || (TARGET_IPHONE_SIMULATOR == 1)
  486. if (USE_UIIMAGE_BACKEND())
  487. return Internal_isType_UIImage(rw_ops, uti_string_to_test);
  488. else
  489. #endif
  490. return Internal_isType_ImageIO(rw_ops, uti_string_to_test);
  491. }
  492. #ifdef BMP_USES_IMAGEIO
  493. int IMG_isCUR(SDL_RWops *src)
  494. {
  495. /* FIXME: Is this a supported type? */
  496. return Internal_isType(src, CFSTR("com.microsoft.cur"));
  497. }
  498. int IMG_isICO(SDL_RWops *src)
  499. {
  500. return Internal_isType(src, kUTTypeICO);
  501. }
  502. int IMG_isBMP(SDL_RWops *src)
  503. {
  504. return Internal_isType(src, kUTTypeBMP);
  505. }
  506. #endif /* BMP_USES_IMAGEIO */
  507. int IMG_isGIF(SDL_RWops *src)
  508. {
  509. return Internal_isType(src, kUTTypeGIF);
  510. }
  511. // Note: JPEG 2000 is kUTTypeJPEG2000
  512. int IMG_isJPG(SDL_RWops *src)
  513. {
  514. return Internal_isType(src, kUTTypeJPEG);
  515. }
  516. int IMG_isPNG(SDL_RWops *src)
  517. {
  518. return Internal_isType(src, kUTTypePNG);
  519. }
  520. // This isn't a public API function. Apple seems to be able to identify tga's.
  521. int IMG_isTGA(SDL_RWops *src)
  522. {
  523. return Internal_isType(src, CFSTR("com.truevision.tga-image"));
  524. }
  525. int IMG_isTIF(SDL_RWops *src)
  526. {
  527. return Internal_isType(src, kUTTypeTIFF);
  528. }
  529. #pragma mark -
  530. #pragma mark Load image engine
  531. static SDL_Surface *LoadImageFromRWops_UIImage (SDL_RWops* rw_ops, CFStringRef uti_string_hint)
  532. {
  533. SDL_Surface *sdl_surface = NULL;
  534. #if defined(ALLOW_UIIMAGE_FALLBACK) && ((TARGET_OS_IPHONE == 1) || (TARGET_IPHONE_SIMULATOR == 1))
  535. NSAutoreleasePool* autorelease_pool = [[NSAutoreleasePool alloc] init];
  536. UIImage *ui_image;
  537. int bytes_read = 0;
  538. // I don't know what a good size is.
  539. // Max recommended texture size is 1024x1024 on iPhone so maybe base it on that?
  540. const int block_size = 1024*4;
  541. char temp_buffer[block_size];
  542. NSMutableData* ns_data = [[NSMutableData alloc] initWithCapacity:1024*1024*4];
  543. do {
  544. bytes_read = SDL_RWread(rw_ops, temp_buffer, 1, block_size);
  545. [ns_data appendBytes:temp_buffer length:bytes_read];
  546. } while (bytes_read > 0);
  547. ui_image = [[UIImage alloc] initWithData:ns_data];
  548. if (ui_image != nil)
  549. sdl_surface = Create_SDL_Surface_From_CGImage([ui_image CGImage]);
  550. [ui_image release];
  551. [ns_data release];
  552. [autorelease_pool drain];
  553. #endif /* #if defined(ALLOW_UIIMAGE_FALLBACK) && ((TARGET_OS_IPHONE == 1) || (TARGET_IPHONE_SIMULATOR == 1)) */
  554. return sdl_surface;
  555. }
  556. static SDL_Surface *LoadImageFromRWops_ImageIO (SDL_RWops *rw_ops, CFStringRef uti_string_hint)
  557. {
  558. CFDictionaryRef hint_dictionary = CreateHintDictionary(uti_string_hint);
  559. CGImageSourceRef image_source = CreateCGImageSourceFromRWops(rw_ops, hint_dictionary);
  560. if (hint_dictionary != NULL)
  561. CFRelease(hint_dictionary);
  562. if (NULL == image_source)
  563. return NULL;
  564. CGImageRef image_ref = CreateCGImageFromCGImageSource(image_source);
  565. CFRelease(image_source);
  566. if (NULL == image_ref)
  567. return NULL;
  568. SDL_Surface *sdl_surface = Create_SDL_Surface_From_CGImage(image_ref);
  569. CFRelease(image_ref);
  570. return sdl_surface;
  571. }
  572. static SDL_Surface *LoadImageFromRWops (SDL_RWops *rw_ops, CFStringRef uti_string_hint)
  573. {
  574. #if (TARGET_OS_IPHONE == 1) || (TARGET_IPHONE_SIMULATOR == 1)
  575. if (USE_UIIMAGE_BACKEND())
  576. return LoadImageFromRWops_UIImage(rw_ops, uti_string_hint);
  577. else
  578. #endif
  579. return LoadImageFromRWops_ImageIO(rw_ops, uti_string_hint);
  580. }
  581. static SDL_Surface* LoadImageFromFile_UIImage (const char *file)
  582. {
  583. SDL_Surface *sdl_surface = NULL;
  584. #if defined(ALLOW_UIIMAGE_FALLBACK) && ((TARGET_OS_IPHONE == 1) || (TARGET_IPHONE_SIMULATOR == 1))
  585. NSAutoreleasePool* autorelease_pool = [[NSAutoreleasePool alloc] init];
  586. NSString *ns_string = [[NSString alloc] initWithUTF8String:file];
  587. UIImage *ui_image = [[UIImage alloc] initWithContentsOfFile:ns_string];
  588. if (ui_image != nil)
  589. sdl_surface = Create_SDL_Surface_From_CGImage([ui_image CGImage]);
  590. [ui_image release];
  591. [ns_string release];
  592. [autorelease_pool drain];
  593. #endif /* #if defined(ALLOW_UIIMAGE_FALLBACK) && ((TARGET_OS_IPHONE == 1) || (TARGET_IPHONE_SIMULATOR == 1)) */
  594. return sdl_surface;
  595. }
  596. static SDL_Surface* LoadImageFromFile_ImageIO (const char *file)
  597. {
  598. CGImageSourceRef image_source = NULL;
  599. image_source = CreateCGImageSourceFromFile(file);
  600. if(NULL == image_source)
  601. return NULL;
  602. CGImageRef image_ref = CreateCGImageFromCGImageSource(image_source);
  603. CFRelease(image_source);
  604. if (NULL == image_ref)
  605. return NULL;
  606. SDL_Surface *sdl_surface = Create_SDL_Surface_From_CGImage(image_ref);
  607. CFRelease(image_ref);
  608. return sdl_surface;
  609. }
  610. static SDL_Surface* LoadImageFromFile (const char *file)
  611. {
  612. #if (TARGET_OS_IPHONE == 1) || (TARGET_IPHONE_SIMULATOR == 1)
  613. if (USE_UIIMAGE_BACKEND())
  614. return LoadImageFromFile_UIImage(file);
  615. else
  616. #endif
  617. return LoadImageFromFile_ImageIO(file);
  618. }
  619. #ifdef BMP_USES_IMAGEIO
  620. SDL_Surface* IMG_LoadCUR_RW (SDL_RWops *src)
  621. {
  622. /* FIXME: Is this a supported type? */
  623. return LoadImageFromRWops(src, CFSTR("com.microsoft.cur"));
  624. }
  625. SDL_Surface* IMG_LoadICO_RW (SDL_RWops *src)
  626. {
  627. return LoadImageFromRWops(src, kUTTypeICO);
  628. }
  629. SDL_Surface* IMG_LoadBMP_RW (SDL_RWops *src)
  630. {
  631. return LoadImageFromRWops(src, kUTTypeBMP);
  632. }
  633. #endif /* BMP_USES_IMAGEIO */
  634. SDL_Surface* IMG_LoadGIF_RW (SDL_RWops *src)
  635. {
  636. return LoadImageFromRWops (src, kUTTypeGIF);
  637. }
  638. SDL_Surface* IMG_LoadJPG_RW (SDL_RWops *src)
  639. {
  640. return LoadImageFromRWops (src, kUTTypeJPEG);
  641. }
  642. SDL_Surface* IMG_LoadPNG_RW (SDL_RWops *src)
  643. {
  644. return LoadImageFromRWops (src, kUTTypePNG);
  645. }
  646. SDL_Surface* IMG_LoadTGA_RW (SDL_RWops *src)
  647. {
  648. return LoadImageFromRWops(src, CFSTR("com.truevision.tga-image"));
  649. }
  650. SDL_Surface* IMG_LoadTIF_RW (SDL_RWops *src)
  651. {
  652. return LoadImageFromRWops(src, kUTTypeTIFF);
  653. }
  654. // Since UIImage doesn't really support streams well, we should optimize for the file case.
  655. // Apple provides both stream and file loading functions in ImageIO.
  656. // Potentially, Apple can optimize for either case.
  657. SDL_Surface* IMG_Load (const char *file)
  658. {
  659. SDL_Surface* sdl_surface = NULL;
  660. sdl_surface = LoadImageFromFile(file);
  661. if(NULL == sdl_surface)
  662. {
  663. // Either the file doesn't exist or ImageIO doesn't understand the format.
  664. // For the latter case, fallback to the native SDL_image handlers.
  665. SDL_RWops *src = SDL_RWFromFile(file, "rb");
  666. char *ext = strrchr(file, '.');
  667. if (ext) {
  668. ext++;
  669. }
  670. if (!src) {
  671. /* The error message has been set in SDL_RWFromFile */
  672. return NULL;
  673. }
  674. sdl_surface = IMG_LoadTyped_RW(src, 1, ext);
  675. }
  676. return sdl_surface;
  677. }
  678. #endif /* defined(__APPLE__) && !defined(SDL_IMAGE_USE_COMMON_BACKEND) */