Added ICO and CUR support to SDL_image
authorcouriersud
Tue, 13 Jan 2009 01:21:00 +0000
changeset 18939d5ac4ec0f8
parent 188 1318044935ad
child 190 4a25c40b7f2c
Added ICO and CUR support to SDL_image
IMG.c
IMG_bmp.c
SDL_image.h
configure.in
     1.1 --- a/IMG.c	Sun Jan 04 02:43:39 2009 +0000
     1.2 +++ b/IMG.c	Tue Jan 13 01:21:00 2009 +0000
     1.3 @@ -38,6 +38,8 @@
     1.4  } supported[] = {
     1.5  	/* keep magicless formats first */
     1.6  	{ "TGA", NULL,      IMG_LoadTGA_RW },
     1.7 +	{ "CUR", IMG_isCUR, IMG_LoadCUR_RW },
     1.8 +	{ "ICO", IMG_isICO, IMG_LoadICO_RW },
     1.9  	{ "BMP", IMG_isBMP, IMG_LoadBMP_RW },
    1.10  	{ "GIF", IMG_isGIF, IMG_LoadGIF_RW },
    1.11  	{ "JPG", IMG_isJPG, IMG_LoadJPG_RW },
     2.1 --- a/IMG_bmp.c	Sun Jan 04 02:43:39 2009 +0000
     2.2 +++ b/IMG_bmp.c	Tue Jan 13 01:21:00 2009 +0000
     2.3 @@ -21,6 +21,8 @@
     2.4  */
     2.5  
     2.6  /* This is a BMP image file loading framework */
     2.7 +/* ICO/CUR file support is here as well since it uses similar internal
     2.8 + * representation */
     2.9  
    2.10  #include <stdio.h>
    2.11  #include <string.h>
    2.12 @@ -49,6 +51,40 @@
    2.13  	return(is_BMP);
    2.14  }
    2.15  
    2.16 +static int IMG_isICOCUR(SDL_RWops *src, int type)
    2.17 +{
    2.18 +	int start;
    2.19 +	int is_ICOCUR;
    2.20 +
    2.21 +	/* The Win32 ICO file header (14 bytes) */
    2.22 +    Uint16 bfReserved;
    2.23 +    Uint16 bfType;
    2.24 +    Uint16 bfCount;
    2.25 +
    2.26 +	if ( !src )
    2.27 +		return 0;
    2.28 +	start = SDL_RWtell(src);
    2.29 +	is_ICOCUR = 0;
    2.30 +    bfReserved = SDL_ReadLE16(src);
    2.31 +    bfType = SDL_ReadLE16(src);
    2.32 +    bfCount = SDL_ReadLE16(src);
    2.33 +    if ((bfReserved == 0) && (bfType == type) && (bfCount != 0)) 
    2.34 +    	is_ICOCUR = 1;
    2.35 +	SDL_RWseek(src, start, SEEK_SET);
    2.36 +
    2.37 +	return (is_ICOCUR);
    2.38 +}
    2.39 +
    2.40 +int IMG_isICO(SDL_RWops *src)
    2.41 +{
    2.42 +	return IMG_isICOCUR(src, 1);
    2.43 +}
    2.44 +
    2.45 +int IMG_isCUR(SDL_RWops *src)
    2.46 +{
    2.47 +	return IMG_isICOCUR(src, 2);
    2.48 +}
    2.49 +
    2.50  #include "SDL_error.h"
    2.51  #include "SDL_video.h"
    2.52  #include "SDL_endian.h"
    2.53 @@ -448,12 +484,306 @@
    2.54  	return(surface);
    2.55  }
    2.56  
    2.57 +static Uint8
    2.58 +SDL_Read8(SDL_RWops * src)
    2.59 +{
    2.60 +    Uint8 value;
    2.61 +
    2.62 +    SDL_RWread(src, &value, 1, 1);
    2.63 +    return (value);
    2.64 +}
    2.65 +
    2.66 +static SDL_Surface *
    2.67 +LoadICOCUR_RW(SDL_RWops * src, int type, int freesrc)
    2.68 +{
    2.69 +    int was_error;
    2.70 +    long fp_offset;
    2.71 +    int bmpPitch;
    2.72 +    int i, pad;
    2.73 +    SDL_Surface *surface;
    2.74 +    Uint32 Rmask;
    2.75 +    Uint32 Gmask;
    2.76 +    Uint32 Bmask;
    2.77 +    Uint8 *bits;
    2.78 +    int ExpandBMP;
    2.79 +    int maxCol = 0;
    2.80 +    int icoOfs = 0;
    2.81 +    Uint32 palette[256];
    2.82 +
    2.83 +    /* The Win32 ICO file header (14 bytes) */
    2.84 +    Uint16 bfReserved;
    2.85 +    Uint16 bfType;
    2.86 +    Uint16 bfCount;
    2.87 +
    2.88 +    /* The Win32 BITMAPINFOHEADER struct (40 bytes) */
    2.89 +    Uint32 biSize;
    2.90 +    Sint32 biWidth;
    2.91 +    Sint32 biHeight;
    2.92 +    Uint16 biPlanes;
    2.93 +    Uint16 biBitCount;
    2.94 +    Uint32 biCompression;
    2.95 +    Uint32 biSizeImage;
    2.96 +    Sint32 biXPelsPerMeter;
    2.97 +    Sint32 biYPelsPerMeter;
    2.98 +    Uint32 biClrUsed;
    2.99 +    Uint32 biClrImportant;
   2.100 +
   2.101 +    /* Make sure we are passed a valid data source */
   2.102 +    surface = NULL;
   2.103 +    was_error = 0;
   2.104 +    if (src == NULL) {
   2.105 +        was_error = 1;
   2.106 +        goto done;
   2.107 +    }
   2.108 +
   2.109 +    /* Read in the ICO file header */
   2.110 +    fp_offset = SDL_RWtell(src);
   2.111 +    SDL_ClearError();
   2.112 +
   2.113 +    bfReserved = SDL_ReadLE16(src);
   2.114 +    bfType = SDL_ReadLE16(src);
   2.115 +    bfCount = SDL_ReadLE16(src);
   2.116 +    if ((bfReserved != 0) || (bfType != type) || (bfCount == 0)) {
   2.117 +        SDL_SetError("File is not a Windows %s file", type == 1 ? "ICO" : "CUR");
   2.118 +        was_error = 1;
   2.119 +        goto done;
   2.120 +    }
   2.121 +
   2.122 +    /* Read the Win32 Icon Directory */
   2.123 +    for (i = 0; i < bfCount; i++) {
   2.124 +        /* Icon Directory Entries */
   2.125 +        int bWidth = SDL_Read8(src);    /* Uint8, but 0 = 256 ! */
   2.126 +        int bHeight = SDL_Read8(src);   /* Uint8, but 0 = 256 ! */
   2.127 +        int bColorCount = SDL_Read8(src);       /* Uint8, but 0 = 256 ! */
   2.128 +        Uint8 bReserved = SDL_Read8(src);
   2.129 +        Uint16 wPlanes = SDL_ReadLE16(src);
   2.130 +        Uint16 wBitCount = SDL_ReadLE16(src);
   2.131 +        Uint32 dwBytesInRes = SDL_ReadLE32(src);
   2.132 +        Uint32 dwImageOffset = SDL_ReadLE32(src);
   2.133 +
   2.134 +        if (!bWidth)
   2.135 +            bWidth = 256;
   2.136 +        if (!bHeight)
   2.137 +            bHeight = 256;
   2.138 +        if (!bColorCount)
   2.139 +            bColorCount = 256;
   2.140 +
   2.141 +        //printf("%dx%d@%d - %08x\n", bWidth, bHeight, bColorCount, dwImageOffset);
   2.142 +        if (bColorCount > maxCol) {
   2.143 +            maxCol = bColorCount;
   2.144 +            icoOfs = dwImageOffset;
   2.145 +            //printf("marked\n");
   2.146 +        }
   2.147 +    }
   2.148 +
   2.149 +    /* Advance to the DIB Data */
   2.150 +    if (SDL_RWseek(src, icoOfs, RW_SEEK_SET) < 0) {
   2.151 +        SDL_Error(SDL_EFSEEK);
   2.152 +        was_error = 1;
   2.153 +        goto done;
   2.154 +    }
   2.155 +
   2.156 +    /* Read the Win32 BITMAPINFOHEADER */
   2.157 +    biSize = SDL_ReadLE32(src);
   2.158 +    if (biSize == 40) {
   2.159 +        biWidth = SDL_ReadLE32(src);
   2.160 +        biHeight = SDL_ReadLE32(src);
   2.161 +        biPlanes = SDL_ReadLE16(src);
   2.162 +        biBitCount = SDL_ReadLE16(src);
   2.163 +        biCompression = SDL_ReadLE32(src);
   2.164 +        biSizeImage = SDL_ReadLE32(src);
   2.165 +        biXPelsPerMeter = SDL_ReadLE32(src);
   2.166 +        biYPelsPerMeter = SDL_ReadLE32(src);
   2.167 +        biClrUsed = SDL_ReadLE32(src);
   2.168 +        biClrImportant = SDL_ReadLE32(src);
   2.169 +    } else {
   2.170 +        SDL_SetError("Unsupported ICO bitmap format");
   2.171 +        was_error = 1;
   2.172 +        goto done;
   2.173 +    }
   2.174 +
   2.175 +    /* Check for read error */
   2.176 +    if (SDL_strcmp(SDL_GetError(), "") != 0) {
   2.177 +        was_error = 1;
   2.178 +        goto done;
   2.179 +    }
   2.180 +
   2.181 +    /* We don't support any BMP compression right now */
   2.182 +    switch (biCompression) {
   2.183 +    case BI_RGB:
   2.184 +        /* Default values for the BMP format */
   2.185 +        switch (biBitCount) {
   2.186 +        case 1:
   2.187 +        case 4:
   2.188 +            ExpandBMP = biBitCount;
   2.189 +            biBitCount = 8;
   2.190 +            break;
   2.191 +        case 8:
   2.192 +            ExpandBMP = 8;
   2.193 +            break;
   2.194 +        case 32:
   2.195 +            Rmask = 0x00FF0000;
   2.196 +            Gmask = 0x0000FF00;
   2.197 +            Bmask = 0x000000FF;
   2.198 +            ExpandBMP = 0;
   2.199 +            break;
   2.200 +        default:
   2.201 +            SDL_SetError("ICO file with unsupported bit count");
   2.202 +            was_error = 1;
   2.203 +            goto done;
   2.204 +        }
   2.205 +        break;
   2.206 +    default:
   2.207 +        SDL_SetError("Compressed ICO files not supported");
   2.208 +        was_error = 1;
   2.209 +        goto done;
   2.210 +    }
   2.211 +
   2.212 +    /* Create a RGBA surface */
   2.213 +    biHeight = biHeight >> 1;
   2.214 +    //printf("%d x %d\n", biWidth, biHeight);
   2.215 +    surface =
   2.216 +        SDL_CreateRGBSurface(0, biWidth, biHeight, 32, 0x00FF0000,
   2.217 +                             0x0000FF00, 0x000000FF, 0xFF000000);
   2.218 +    if (surface == NULL) {
   2.219 +        was_error = 1;
   2.220 +        goto done;
   2.221 +    }
   2.222 +
   2.223 +    /* Load the palette, if any */
   2.224 +    //printf("bc %d bused %d\n", biBitCount, biClrUsed);
   2.225 +    if (biBitCount <= 8) {
   2.226 +        if (biClrUsed == 0) {
   2.227 +            biClrUsed = 1 << biBitCount;
   2.228 +        }
   2.229 +        for (i = 0; i < (int) biClrUsed; ++i) {
   2.230 +            SDL_RWread(src, &palette[i], 4, 1);
   2.231 +        }
   2.232 +    }
   2.233 +
   2.234 +    /* Read the surface pixels.  Note that the bmp image is upside down */
   2.235 +    bits = (Uint8 *) surface->pixels + (surface->h * surface->pitch);
   2.236 +    switch (ExpandBMP) {
   2.237 +    case 1:
   2.238 +        bmpPitch = (biWidth + 7) >> 3;
   2.239 +        pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
   2.240 +        break;
   2.241 +    case 4:
   2.242 +        bmpPitch = (biWidth + 1) >> 1;
   2.243 +        pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
   2.244 +        break;
   2.245 +    case 8:
   2.246 +        bmpPitch = biWidth;
   2.247 +        pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
   2.248 +        break;
   2.249 +    default:
   2.250 +        bmpPitch = biWidth * 4;
   2.251 +        pad = 0;
   2.252 +        break;
   2.253 +    }
   2.254 +    while (bits > (Uint8 *) surface->pixels) {
   2.255 +        bits -= surface->pitch;
   2.256 +        switch (ExpandBMP) {
   2.257 +        case 1:
   2.258 +        case 4:
   2.259 +        case 8:
   2.260 +            {
   2.261 +                Uint8 pixel = 0;
   2.262 +                int shift = (8 - ExpandBMP);
   2.263 +                for (i = 0; i < surface->w; ++i) {
   2.264 +                    if (i % (8 / ExpandBMP) == 0) {
   2.265 +                        if (!SDL_RWread(src, &pixel, 1, 1)) {
   2.266 +                            SDL_SetError("Error reading from ICO");
   2.267 +                            was_error = 1;
   2.268 +                            goto done;
   2.269 +                        }
   2.270 +                    }
   2.271 +                    *((Uint32 *) bits + i) = (palette[pixel >> shift]);
   2.272 +                    pixel <<= ExpandBMP;
   2.273 +                }
   2.274 +            }
   2.275 +            break;
   2.276 +
   2.277 +        default:
   2.278 +            if (SDL_RWread(src, bits, 1, surface->pitch)
   2.279 +                != surface->pitch) {
   2.280 +                SDL_Error(SDL_EFREAD);
   2.281 +                was_error = 1;
   2.282 +                goto done;
   2.283 +            }
   2.284 +            break;
   2.285 +        }
   2.286 +        /* Skip padding bytes, ugh */
   2.287 +        if (pad) {
   2.288 +            Uint8 padbyte;
   2.289 +            for (i = 0; i < pad; ++i) {
   2.290 +                SDL_RWread(src, &padbyte, 1, 1);
   2.291 +            }
   2.292 +        }
   2.293 +    }
   2.294 +    /* Read the mask pixels.  Note that the bmp image is upside down */
   2.295 +    bits = (Uint8 *) surface->pixels + (surface->h * surface->pitch);
   2.296 +    ExpandBMP = 1;
   2.297 +    bmpPitch = (biWidth + 7) >> 3;
   2.298 +    pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
   2.299 +    while (bits > (Uint8 *) surface->pixels) {
   2.300 +        Uint8 pixel = 0;
   2.301 +        int shift = (8 - ExpandBMP);
   2.302 +
   2.303 +        bits -= surface->pitch;
   2.304 +        for (i = 0; i < surface->w; ++i) {
   2.305 +            if (i % (8 / ExpandBMP) == 0) {
   2.306 +                if (!SDL_RWread(src, &pixel, 1, 1)) {
   2.307 +                    SDL_SetError("Error reading from ICO");
   2.308 +                    was_error = 1;
   2.309 +                    goto done;
   2.310 +                }
   2.311 +            }
   2.312 +            *((Uint32 *) bits + i) |= ((pixel >> shift) ? 0 : 0xFF000000);
   2.313 +            pixel <<= ExpandBMP;
   2.314 +        }
   2.315 +        /* Skip padding bytes, ugh */
   2.316 +        if (pad) {
   2.317 +            Uint8 padbyte;
   2.318 +            for (i = 0; i < pad; ++i) {
   2.319 +                SDL_RWread(src, &padbyte, 1, 1);
   2.320 +            }
   2.321 +        }
   2.322 +    }
   2.323 +  done:
   2.324 +    if (was_error) {
   2.325 +        if (src) {
   2.326 +            SDL_RWseek(src, fp_offset, RW_SEEK_SET);
   2.327 +        }
   2.328 +        if (surface) {
   2.329 +            SDL_FreeSurface(surface);
   2.330 +        }
   2.331 +        surface = NULL;
   2.332 +    }
   2.333 +    if (freesrc && src) {
   2.334 +        SDL_RWclose(src);
   2.335 +    }
   2.336 +    return (surface);
   2.337 +}
   2.338 +
   2.339  /* Load a BMP type image from an SDL datasource */
   2.340  SDL_Surface *IMG_LoadBMP_RW(SDL_RWops *src)
   2.341  {
   2.342  	return(LoadBMP_RW(src, 0));
   2.343  }
   2.344  
   2.345 +/* Load a ICO type image from an SDL datasource */
   2.346 +SDL_Surface *IMG_LoadICO_RW(SDL_RWops *src)
   2.347 +{
   2.348 +	return(LoadICOCUR_RW(src, 1, 0));
   2.349 +}
   2.350 +
   2.351 +/* Load a CUR type image from an SDL datasource */
   2.352 +SDL_Surface *IMG_LoadCUR_RW(SDL_RWops *src)
   2.353 +{
   2.354 +	return(LoadICOCUR_RW(src, 2, 0));
   2.355 +}
   2.356 +
   2.357  #else
   2.358  
   2.359  /* See if an image is contained in a data source */
   2.360 @@ -462,10 +792,32 @@
   2.361  	return(0);
   2.362  }
   2.363  
   2.364 +int IMG_isICO(SDL_RWops *src)
   2.365 +{
   2.366 +	return(0);
   2.367 +}
   2.368 +
   2.369 +int IMG_isCUR(SDL_RWops *src)
   2.370 +{
   2.371 +	return(0);
   2.372 +}
   2.373 +
   2.374  /* Load a BMP type image from an SDL datasource */
   2.375  SDL_Surface *IMG_LoadBMP_RW(SDL_RWops *src)
   2.376  {
   2.377  	return(NULL);
   2.378  }
   2.379  
   2.380 +/* Load a BMP type image from an SDL datasource */
   2.381 +SDL_Surface *IMG_LoadCUR_RW(SDL_RWops *src)
   2.382 +{
   2.383 +	return(NULL);
   2.384 +}
   2.385 +
   2.386 +/* Load a BMP type image from an SDL datasource */
   2.387 +SDL_Surface *IMG_LoadICO_RW(SDL_RWops *src)
   2.388 +{
   2.389 +	return(NULL);
   2.390 +}
   2.391 +
   2.392  #endif /* LOAD_BMP */
     3.1 --- a/SDL_image.h	Sun Jan 04 02:43:39 2009 +0000
     3.2 +++ b/SDL_image.h	Tue Jan 13 01:21:00 2009 +0000
     3.3 @@ -75,6 +75,8 @@
     3.4  extern DECLSPEC int SDLCALL IMG_InvertAlpha(int on);
     3.5  
     3.6  /* Functions to detect a file type, given a seekable source */
     3.7 +extern DECLSPEC int SDLCALL IMG_isICO(SDL_RWops *src);
     3.8 +extern DECLSPEC int SDLCALL IMG_isCUR(SDL_RWops *src);
     3.9  extern DECLSPEC int SDLCALL IMG_isBMP(SDL_RWops *src);
    3.10  extern DECLSPEC int SDLCALL IMG_isGIF(SDL_RWops *src);
    3.11  extern DECLSPEC int SDLCALL IMG_isJPG(SDL_RWops *src);
    3.12 @@ -88,6 +90,8 @@
    3.13  extern DECLSPEC int SDLCALL IMG_isXV(SDL_RWops *src);
    3.14  
    3.15  /* Individual loading functions */
    3.16 +extern DECLSPEC SDL_Surface * SDLCALL IMG_LoadICO_RW(SDL_RWops *src);
    3.17 +extern DECLSPEC SDL_Surface * SDLCALL IMG_LoadCUR_RW(SDL_RWops *src);
    3.18  extern DECLSPEC SDL_Surface * SDLCALL IMG_LoadBMP_RW(SDL_RWops *src);
    3.19  extern DECLSPEC SDL_Surface * SDLCALL IMG_LoadGIF_RW(SDL_RWops *src);
    3.20  extern DECLSPEC SDL_Surface * SDLCALL IMG_LoadJPG_RW(SDL_RWops *src);
     4.1 --- a/configure.in	Sun Jan 04 02:43:39 2009 +0000
     4.2 +++ b/configure.in	Tue Jan 13 01:21:00 2009 +0000
     4.3 @@ -89,7 +89,7 @@
     4.4  saved_LIBS="$LIBS"
     4.5  
     4.6  dnl Check command-line options
     4.7 -AC_ARG_ENABLE([bmp], [AC_HELP_STRING([--enable-bmp], [support loading BMP images [default=yes]])],
     4.8 +AC_ARG_ENABLE([bmp], [AC_HELP_STRING([--enable-bmp], [support loading BMP/ICO/CUR images [default=yes]])],
     4.9   [], [enable_bmp=yes])
    4.10  AC_ARG_ENABLE([gif], [AC_HELP_STRING([--enable-gif], [support loading GIF images [default=yes]])],
    4.11   [], [enable_gif=yes])