IMG_UIImage.m
author Sam Lantinga <slouken@libsdl.org>
Sun, 15 Jun 2014 13:16:42 -0700
changeset 451 48116d511e5d
parent 368 8a61842d00ce
permissions -rw-r--r--
Fixed format warnings: format not a string literal and no format arguments
slouken@187
     1
/*
slouken@187
     2
 *  IMG_ImageIO.c
slouken@187
     3
 *  SDL_image
slouken@187
     4
 *
slouken@187
     5
 *  Created by Eric Wing on 1/2/09.
slouken@187
     6
 *  Copyright 2009 __MyCompanyName__. All rights reserved.
slouken@187
     7
 *
slouken@187
     8
 */
slouken@187
     9
#include "SDL_image.h"
slouken@187
    10
#import <UIKit/UIKit.h>
slouken@219
    11
#import <MobileCoreServices/MobileCoreServices.h> // for UTCoreTypes.h
slouken@187
    12
slouken@187
    13
// Once we have our image, we need to get it into an SDL_Surface
slouken@187
    14
// (Copied straight from the ImageIO backend.)
slouken@187
    15
static SDL_Surface* Create_SDL_Surface_From_CGImage(CGImageRef image_ref)
slouken@187
    16
{
slouken@368
    17
    /* This code is adapted from Apple's Documentation found here:
slouken@368
    18
     * http://developer.apple.com/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/index.html
slouken@368
    19
     * Listing 9-4††Using a Quartz image as a texture source.
slouken@368
    20
     * Unfortunately, this guide doesn't show what to do about
slouken@368
    21
     * non-RGBA image formats so I'm making the rest up.
slouken@368
    22
     * All this code should be scrutinized.
slouken@368
    23
     */
slouken@237
    24
slouken@368
    25
    size_t w = CGImageGetWidth(image_ref);
slouken@368
    26
    size_t h = CGImageGetHeight(image_ref);
slouken@368
    27
    CGRect rect = {{0, 0}, {w, h}};
slouken@237
    28
slouken@368
    29
    CGImageAlphaInfo alpha = CGImageGetAlphaInfo(image_ref);
slouken@368
    30
    //size_t bits_per_pixel = CGImageGetBitsPerPixel(image_ref);
slouken@368
    31
    size_t bits_per_component = 8;
slouken@187
    32
slouken@368
    33
    SDL_Surface* surface;
slouken@368
    34
    Uint32 Amask;
slouken@368
    35
    Uint32 Rmask;
slouken@368
    36
    Uint32 Gmask;
slouken@368
    37
    Uint32 Bmask;
slouken@187
    38
slouken@368
    39
    CGContextRef bitmap_context;
slouken@368
    40
    CGBitmapInfo bitmap_info;
slouken@368
    41
    CGColorSpaceRef color_space = CGColorSpaceCreateDeviceRGB();
slouken@187
    42
slouken@368
    43
    if (alpha == kCGImageAlphaNone ||
slouken@368
    44
        alpha == kCGImageAlphaNoneSkipFirst ||
slouken@368
    45
        alpha == kCGImageAlphaNoneSkipLast) {
slouken@368
    46
        bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host; /* XRGB */
slouken@368
    47
        Amask = 0x00000000;
slouken@368
    48
    } else {
slouken@368
    49
        /* kCGImageAlphaFirst isn't supported */
slouken@368
    50
        //bitmap_info = kCGImageAlphaFirst | kCGBitmapByteOrder32Host; /* ARGB */
slouken@368
    51
        bitmap_info = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host; /* ARGB */
slouken@368
    52
        Amask = 0xFF000000;
slouken@368
    53
    }
slouken@187
    54
slouken@368
    55
    Rmask = 0x00FF0000;
slouken@368
    56
    Gmask = 0x0000FF00;
slouken@368
    57
    Bmask = 0x000000FF;
slouken@239
    58
slouken@368
    59
    surface = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32, Rmask, Gmask, Bmask, Amask);
slouken@368
    60
    if (surface)
slouken@368
    61
    {
slouken@368
    62
        // Sets up a context to be drawn to with surface->pixels as the area to be drawn to
slouken@368
    63
        bitmap_context = CGBitmapContextCreate(
slouken@368
    64
                                                            surface->pixels,
slouken@368
    65
                                                            surface->w,
slouken@368
    66
                                                            surface->h,
slouken@368
    67
                                                            bits_per_component,
slouken@368
    68
                                                            surface->pitch,
slouken@368
    69
                                                            color_space,
slouken@368
    70
                                                            bitmap_info
slouken@368
    71
                                                            );
slouken@237
    72
slouken@368
    73
        // Draws the image into the context's image_data
slouken@368
    74
        CGContextDrawImage(bitmap_context, rect, image_ref);
slouken@237
    75
slouken@368
    76
        CGContextRelease(bitmap_context);
slouken@239
    77
slouken@368
    78
        // FIXME: Reverse the premultiplied alpha
slouken@368
    79
        if ((bitmap_info & kCGBitmapAlphaInfoMask) == kCGImageAlphaPremultipliedFirst) {
slouken@368
    80
            int i, j;
slouken@368
    81
            Uint8 *p = (Uint8 *)surface->pixels;
slouken@368
    82
            for (i = surface->h * surface->pitch/4; i--; ) {
slouken@240
    83
#if __LITTLE_ENDIAN__
slouken@368
    84
                Uint8 A = p[3];
slouken@368
    85
                if (A) {
slouken@368
    86
                    for (j = 0; j < 3; ++j) {
slouken@368
    87
                        p[j] = (p[j] * 255) / A;
slouken@368
    88
                    }
slouken@368
    89
                }
slouken@240
    90
#else
slouken@368
    91
                Uint8 A = p[0];
slouken@368
    92
                if (A) {
slouken@368
    93
                    for (j = 1; j < 4; ++j) {
slouken@368
    94
                        p[j] = (p[j] * 255) / A;
slouken@368
    95
                    }
slouken@368
    96
                }
slouken@240
    97
#endif /* ENDIAN */
slouken@368
    98
                p += 4;
slouken@368
    99
            }
slouken@368
   100
        }
slouken@368
   101
    }
slouken@187
   102
slouken@368
   103
    if (color_space)
slouken@368
   104
    {
slouken@368
   105
        CGColorSpaceRelease(color_space);
slouken@368
   106
    }
slouken@187
   107
slouken@368
   108
    return surface;
slouken@187
   109
}
slouken@187
   110
slouken@187
   111
static SDL_Surface* LoadImageFromRWops(SDL_RWops* rw_ops, CFStringRef uti_string_hint)
slouken@187
   112
{
slouken@368
   113
    NSAutoreleasePool* autorelease_pool = [[NSAutoreleasePool alloc] init];
slouken@368
   114
    SDL_Surface* sdl_surface;
slouken@368
   115
    UIImage* ui_image;
slouken@187
   116
slouken@368
   117
    int bytes_read = 0;
slouken@368
   118
    // I don't know what a good size is.
slouken@368
   119
    // Max recommended texture size is 1024x1024 on iPhone so maybe base it on that?
slouken@368
   120
    const int block_size = 1024*4;
slouken@368
   121
    char temp_buffer[block_size];
slouken@187
   122
slouken@368
   123
    NSMutableData* ns_data = [[NSMutableData alloc] initWithCapacity:1024*1024*4];
slouken@187
   124
slouken@187
   125
slouken@368
   126
    do
slouken@368
   127
    {
slouken@368
   128
        bytes_read = SDL_RWread(rw_ops, temp_buffer, 1, block_size);
slouken@368
   129
        [ns_data appendBytes:temp_buffer length:bytes_read];
slouken@368
   130
    } while(bytes_read > 0);
slouken@187
   131
slouken@368
   132
    ui_image = [[UIImage alloc] initWithData:ns_data];
slouken@187
   133
slouken@368
   134
    sdl_surface = Create_SDL_Surface_From_CGImage([ui_image CGImage]);
slouken@368
   135
slouken@368
   136
    [ui_image release];
slouken@368
   137
    [ns_data release];
slouken@368
   138
slouken@368
   139
    [autorelease_pool drain];
slouken@368
   140
slouken@368
   141
    return sdl_surface;
slouken@187
   142
}
slouken@187
   143
slouken@188
   144
static SDL_Surface* LoadImageFromFile(const char *file)
slouken@187
   145
{
slouken@368
   146
    NSAutoreleasePool* autorelease_pool = [[NSAutoreleasePool alloc] init];
slouken@368
   147
    SDL_Surface* sdl_surface = NULL;
slouken@368
   148
    UIImage* ui_image;
slouken@368
   149
    NSString* ns_string;
slouken@368
   150
slouken@368
   151
    ns_string = [[NSString alloc] initWithUTF8String:file];
slouken@368
   152
    ui_image = [[UIImage alloc] initWithContentsOfFile:ns_string];
slouken@368
   153
    if(ui_image != NULL)
slouken@368
   154
    {
slouken@368
   155
        sdl_surface = Create_SDL_Surface_From_CGImage([ui_image CGImage]);
slouken@368
   156
    }
slouken@368
   157
slouken@368
   158
    [ui_image release];
slouken@368
   159
    [ns_string release];
slouken@368
   160
slouken@368
   161
    [autorelease_pool drain];
slouken@368
   162
slouken@368
   163
    return sdl_surface;
slouken@188
   164
}
slouken@187
   165
slouken@188
   166
slouken@188
   167
/* Since UIImage doesn't really support streams well, we should optimize for the file case. */
slouken@188
   168
SDL_Surface *IMG_Load(const char *file)
slouken@188
   169
{
slouken@368
   170
    SDL_Surface* sdl_surface = NULL;
slouken@188
   171
slouken@368
   172
    sdl_surface = LoadImageFromFile(file);
slouken@368
   173
    if(NULL == sdl_surface)
slouken@368
   174
    {
slouken@368
   175
        // Either the file doesn't exist or ImageIO doesn't understand the format.
slouken@368
   176
        // For the latter case, fallback to the native SDL_image handlers.
slouken@188
   177
slouken@368
   178
        SDL_RWops *src = SDL_RWFromFile(file, "rb");
slouken@368
   179
        char *ext = strrchr(file, '.');
slouken@368
   180
        if(ext) {
slouken@368
   181
            ext++;
slouken@368
   182
        }
slouken@368
   183
        if(!src) {
slouken@368
   184
            /* The error message has been set in SDL_RWFromFile */
slouken@368
   185
            return NULL;
slouken@368
   186
        }
slouken@368
   187
        sdl_surface = IMG_LoadTyped_RW(src, 1, ext);
slouken@368
   188
    }
slouken@368
   189
    return sdl_surface;
slouken@187
   190
}
slouken@187
   191
slouken@187
   192
slouken@233
   193
int IMG_InitJPG()
slouken@233
   194
{
slouken@368
   195
    return 0;
slouken@233
   196
}
slouken@233
   197
slouken@233
   198
void IMG_QuitJPG()
slouken@233
   199
{
slouken@233
   200
}
slouken@233
   201
slouken@233
   202
int IMG_InitPNG()
slouken@233
   203
{
slouken@368
   204
    return 0;
slouken@233
   205
}
slouken@233
   206
slouken@233
   207
void IMG_QuitPNG()
slouken@233
   208
{
slouken@233
   209
}
slouken@233
   210
slouken@233
   211
int IMG_InitTIF()
slouken@233
   212
{
slouken@368
   213
    return 0;
slouken@233
   214
}
slouken@233
   215
slouken@233
   216
void IMG_QuitTIF()
slouken@233
   217
{
slouken@233
   218
}
slouken@187
   219
slouken@187
   220
/* Copied straight from other files so I don't have to alter them. */
slouken@195
   221
static int IMG_isICOCUR(SDL_RWops *src, int type)
slouken@195
   222
{
slouken@368
   223
    int start;
slouken@368
   224
    int is_ICOCUR;
slouken@195
   225
slouken@368
   226
    /* The Win32 ICO file header (14 bytes) */
slouken@195
   227
    Uint16 bfReserved;
slouken@195
   228
    Uint16 bfType;
slouken@195
   229
    Uint16 bfCount;
slouken@195
   230
slouken@368
   231
    if ( !src )
slouken@368
   232
        return 0;
slouken@368
   233
    start = SDL_RWtell(src);
slouken@368
   234
    is_ICOCUR = 0;
slouken@195
   235
    bfReserved = SDL_ReadLE16(src);
slouken@195
   236
    bfType = SDL_ReadLE16(src);
slouken@195
   237
    bfCount = SDL_ReadLE16(src);
slouken@368
   238
    if ((bfReserved == 0) && (bfType == type) && (bfCount != 0))
slouken@368
   239
        is_ICOCUR = 1;
slouken@368
   240
    SDL_RWseek(src, start, SEEK_SET);
slouken@195
   241
slouken@368
   242
    return (is_ICOCUR);
slouken@195
   243
}
slouken@195
   244
slouken@195
   245
int IMG_isICO(SDL_RWops *src)
slouken@195
   246
{
slouken@368
   247
    return IMG_isICOCUR(src, 1);
slouken@195
   248
}
slouken@195
   249
slouken@195
   250
int IMG_isCUR(SDL_RWops *src)
slouken@195
   251
{
slouken@368
   252
    return IMG_isICOCUR(src, 2);
slouken@195
   253
}
slouken@195
   254
slouken@187
   255
int IMG_isBMP(SDL_RWops *src)
slouken@187
   256
{
slouken@368
   257
    int start;
slouken@368
   258
    int is_BMP;
slouken@368
   259
    char magic[2];
slouken@368
   260
slouken@368
   261
    if ( !src )
slouken@368
   262
        return 0;
slouken@368
   263
    start = SDL_RWtell(src);
slouken@368
   264
    is_BMP = 0;
slouken@368
   265
    if ( SDL_RWread(src, magic, sizeof(magic), 1) ) {
slouken@368
   266
        if ( strncmp(magic, "BM", 2) == 0 ) {
slouken@368
   267
            is_BMP = 1;
slouken@368
   268
        }
slouken@368
   269
    }
slouken@368
   270
    SDL_RWseek(src, start, SEEK_SET);
slouken@368
   271
    return(is_BMP);
slouken@187
   272
}
slouken@187
   273
slouken@187
   274
int IMG_isGIF(SDL_RWops *src)
slouken@187
   275
{
slouken@368
   276
    int start;
slouken@368
   277
    int is_GIF;
slouken@368
   278
    char magic[6];
slouken@368
   279
slouken@368
   280
    if ( !src )
slouken@368
   281
        return 0;
slouken@368
   282
    start = SDL_RWtell(src);
slouken@368
   283
    is_GIF = 0;
slouken@368
   284
    if ( SDL_RWread(src, magic, sizeof(magic), 1) ) {
slouken@368
   285
        if ( (strncmp(magic, "GIF", 3) == 0) &&
slouken@368
   286
            ((memcmp(magic + 3, "87a", 3) == 0) ||
slouken@368
   287
             (memcmp(magic + 3, "89a", 3) == 0)) ) {
slouken@368
   288
            is_GIF = 1;
slouken@368
   289
        }
slouken@368
   290
    }
slouken@368
   291
    SDL_RWseek(src, start, SEEK_SET);
slouken@368
   292
    return(is_GIF);
slouken@187
   293
}
slouken@187
   294
slouken@187
   295
int IMG_isJPG(SDL_RWops *src)
slouken@187
   296
{
slouken@368
   297
    int start;
slouken@368
   298
    int is_JPG;
slouken@368
   299
    int in_scan;
slouken@368
   300
    Uint8 magic[4];
slouken@368
   301
slouken@368
   302
    /* This detection code is by Steaphan Greene <stea@cs.binghamton.edu> */
slouken@368
   303
    /* Blame me, not Sam, if this doesn't work right. */
slouken@368
   304
    /* And don't forget to report the problem to the the sdl list too! */
slouken@368
   305
slouken@368
   306
    if ( !src )
slouken@368
   307
        return 0;
slouken@368
   308
    start = SDL_RWtell(src);
slouken@368
   309
    is_JPG = 0;
slouken@368
   310
    in_scan = 0;
slouken@368
   311
    if ( SDL_RWread(src, magic, 2, 1) ) {
slouken@368
   312
        if ( (magic[0] == 0xFF) && (magic[1] == 0xD8) ) {
slouken@368
   313
            is_JPG = 1;
slouken@368
   314
            while (is_JPG == 1) {
slouken@368
   315
                if(SDL_RWread(src, magic, 1, 2) != 2) {
slouken@368
   316
                    is_JPG = 0;
slouken@368
   317
                } else if( (magic[0] != 0xFF) && (in_scan == 0) ) {
slouken@368
   318
                    is_JPG = 0;
slouken@368
   319
                } else if( (magic[0] != 0xFF) || (magic[1] == 0xFF) ) {
slouken@368
   320
                    /* Extra padding in JPEG (legal) */
slouken@368
   321
                    /* or this is data and we are scanning */
slouken@368
   322
                    SDL_RWseek(src, -1, SEEK_CUR);
slouken@368
   323
                } else if(magic[1] == 0xD9) {
slouken@368
   324
                    /* Got to end of good JPEG */
slouken@368
   325
                    break;
slouken@368
   326
                } else if( (in_scan == 1) && (magic[1] == 0x00) ) {
slouken@368
   327
                    /* This is an encoded 0xFF within the data */
slouken@368
   328
                } else if( (magic[1] >= 0xD0) && (magic[1] < 0xD9) ) {
slouken@368
   329
                    /* These have nothing else */
slouken@368
   330
                } else if(SDL_RWread(src, magic+2, 1, 2) != 2) {
slouken@368
   331
                    is_JPG = 0;
slouken@368
   332
                } else {
slouken@368
   333
                    /* Yes, it's big-endian */
slouken@368
   334
                    Uint32 start;
slouken@368
   335
                    Uint32 size;
slouken@368
   336
                    Uint32 end;
slouken@368
   337
                    start = SDL_RWtell(src);
slouken@368
   338
                    size = (magic[2] << 8) + magic[3];
slouken@368
   339
                    end = SDL_RWseek(src, size-2, SEEK_CUR);
slouken@368
   340
                    if ( end != start + size - 2 ) is_JPG = 0;
slouken@368
   341
                    if ( magic[1] == 0xDA ) {
slouken@368
   342
                        /* Now comes the actual JPEG meat */
slouken@368
   343
#ifdef  FAST_IS_JPEG
slouken@368
   344
                        /* Ok, I'm convinced.  It is a JPEG. */
slouken@368
   345
                        break;
slouken@187
   346
#else
slouken@368
   347
                        /* I'm not convinced.  Prove it! */
slouken@368
   348
                        in_scan = 1;
slouken@187
   349
#endif
slouken@368
   350
                    }
slouken@368
   351
                }
slouken@368
   352
            }
slouken@368
   353
        }
slouken@368
   354
    }
slouken@368
   355
    SDL_RWseek(src, start, SEEK_SET);
slouken@368
   356
    return(is_JPG);
slouken@187
   357
}
slouken@187
   358
slouken@187
   359
int IMG_isPNG(SDL_RWops *src)
slouken@187
   360
{
slouken@368
   361
    int start;
slouken@368
   362
    int is_PNG;
slouken@368
   363
    Uint8 magic[4];
slouken@368
   364
slouken@368
   365
    if ( !src )
slouken@368
   366
        return 0;
slouken@368
   367
    start = SDL_RWtell(src);
slouken@368
   368
    is_PNG = 0;
slouken@368
   369
    if ( SDL_RWread(src, magic, 1, sizeof(magic)) == sizeof(magic) ) {
slouken@368
   370
        if ( magic[0] == 0x89 &&
slouken@368
   371
            magic[1] == 'P' &&
slouken@368
   372
            magic[2] == 'N' &&
slouken@368
   373
            magic[3] == 'G' ) {
slouken@368
   374
            is_PNG = 1;
slouken@368
   375
        }
slouken@368
   376
    }
slouken@368
   377
    SDL_RWseek(src, start, SEEK_SET);
slouken@368
   378
    return(is_PNG);
slouken@187
   379
}
slouken@187
   380
slouken@187
   381
int IMG_isTIF(SDL_RWops* src)
slouken@187
   382
{
slouken@368
   383
    int start;
slouken@368
   384
    int is_TIF;
slouken@368
   385
    Uint8 magic[4];
slouken@368
   386
slouken@368
   387
    if ( !src )
slouken@368
   388
        return 0;
slouken@368
   389
    start = SDL_RWtell(src);
slouken@368
   390
    is_TIF = 0;
slouken@368
   391
    if ( SDL_RWread(src, magic, 1, sizeof(magic)) == sizeof(magic) ) {
slouken@368
   392
        if ( (magic[0] == 'I' &&
slouken@368
   393
              magic[1] == 'I' &&
slouken@368
   394
              magic[2] == 0x2a &&
slouken@368
   395
              magic[3] == 0x00) ||
slouken@368
   396
            (magic[0] == 'M' &&
slouken@368
   397
             magic[1] == 'M' &&
slouken@368
   398
             magic[2] == 0x00 &&
slouken@368
   399
             magic[3] == 0x2a) ) {
slouken@368
   400
            is_TIF = 1;
slouken@368
   401
        }
slouken@368
   402
    }
slouken@368
   403
    SDL_RWseek(src, start, SEEK_SET);
slouken@368
   404
    return(is_TIF);
slouken@187
   405
}
slouken@187
   406
slouken@195
   407
SDL_Surface* IMG_LoadCUR_RW(SDL_RWops *src)
slouken@195
   408
{
slouken@368
   409
    /* FIXME: Is this a supported type? */
slouken@368
   410
    return LoadImageFromRWops(src, CFSTR("com.microsoft.cur"));
slouken@195
   411
}
slouken@195
   412
SDL_Surface* IMG_LoadICO_RW(SDL_RWops *src)
slouken@195
   413
{
slouken@368
   414
    return LoadImageFromRWops(src, kUTTypeICO);
slouken@195
   415
}
slouken@187
   416
SDL_Surface* IMG_LoadBMP_RW(SDL_RWops *src)
slouken@187
   417
{
slouken@368
   418
    return LoadImageFromRWops(src, kUTTypeBMP);
slouken@187
   419
}
slouken@187
   420
SDL_Surface* IMG_LoadGIF_RW(SDL_RWops *src)
slouken@187
   421
{
slouken@368
   422
    return LoadImageFromRWops(src, kUTTypeGIF);
slouken@187
   423
}
slouken@187
   424
SDL_Surface* IMG_LoadJPG_RW(SDL_RWops *src)
slouken@187
   425
{
slouken@368
   426
    return LoadImageFromRWops(src, kUTTypeJPEG);
slouken@187
   427
}
slouken@187
   428
SDL_Surface* IMG_LoadPNG_RW(SDL_RWops *src)
slouken@187
   429
{
slouken@368
   430
    return LoadImageFromRWops(src, kUTTypePNG);
slouken@187
   431
}
slouken@256
   432
SDL_Surface* IMG_LoadTGA_RW(SDL_RWops *src)
slouken@256
   433
{
slouken@368
   434
    return LoadImageFromRWops(src, CFSTR("com.truevision.tga-image"));
slouken@256
   435
}
slouken@187
   436
SDL_Surface* IMG_LoadTIF_RW(SDL_RWops *src)
slouken@187
   437
{
slouken@368
   438
    return LoadImageFromRWops(src, kUTTypeTIFF);
slouken@187
   439
}
slouken@187
   440