Add SDL_LoadICO_RW to SDL. Loads best quality icon from *.ico file.
authorCouriersud <couriersud@arcor.de>
Sun, 11 Jan 2009 23:56:19 +0000
changeset 30241a08749aebce
parent 3023 d72a0dd80e8b
child 3025 54fac87e1f34
Add SDL_LoadICO_RW to SDL. Loads best quality icon from *.ico file.
include/SDL_surface.h
src/video/SDL_bmp.c
     1.1 --- a/include/SDL_surface.h	Sun Jan 11 23:49:23 2009 +0000
     1.2 +++ b/include/SDL_surface.h	Sun Jan 11 23:56:19 2009 +0000
     1.3 @@ -157,6 +157,12 @@
     1.4  extern DECLSPEC SDL_Surface *SDLCALL SDL_LoadBMP_RW(SDL_RWops * src,
     1.5                                                      int freesrc);
     1.6  
     1.7 +/* 
     1.8 + * Load Icon best quality icon from ICO file and return as RGBA surface 
     1.9 + */
    1.10 +extern DECLSPEC SDL_Surface *SDLCALL SDL_LoadICO_RW(SDL_RWops * src,
    1.11 +                                                    int freesrc);
    1.12 +
    1.13  /* Convenience macro -- load a surface from a file */
    1.14  #define SDL_LoadBMP(file)	SDL_LoadBMP_RW(SDL_RWFromFile(file, "rb"), 1)
    1.15  
     2.1 --- a/src/video/SDL_bmp.c	Sun Jan 11 23:49:23 2009 +0000
     2.2 +++ b/src/video/SDL_bmp.c	Sun Jan 11 23:56:19 2009 +0000
     2.3 @@ -46,6 +46,288 @@
     2.4  #endif
     2.5  
     2.6  
     2.7 +static Uint8
     2.8 +SDL_Read8(SDL_RWops * src)
     2.9 +{
    2.10 +    Uint8 value;
    2.11 +
    2.12 +    SDL_RWread(src, &value, 1, 1);
    2.13 +    return (value);
    2.14 +}
    2.15 +
    2.16 +SDL_Surface *
    2.17 +SDL_LoadICO_RW(SDL_RWops * src, int freesrc)
    2.18 +{
    2.19 +    int was_error;
    2.20 +    long fp_offset;
    2.21 +    int bmpPitch;
    2.22 +    int i, pad;
    2.23 +    SDL_Surface *surface;
    2.24 +    Uint32 Rmask;
    2.25 +    Uint32 Gmask;
    2.26 +    Uint32 Bmask;
    2.27 +    Uint8 *bits;
    2.28 +    int ExpandBMP;
    2.29 +    int maxCol = 0;
    2.30 +    int icoOfs = 0;
    2.31 +    Uint32 palette[256];
    2.32 +
    2.33 +    /* The Win32 ICO file header (14 bytes) */
    2.34 +    Uint16 bfReserved;
    2.35 +    Uint16 bfType;
    2.36 +    Uint16 bfCount;
    2.37 +
    2.38 +    /* The Win32 BITMAPINFOHEADER struct (40 bytes) */
    2.39 +    Uint32 biSize;
    2.40 +    Sint32 biWidth;
    2.41 +    Sint32 biHeight;
    2.42 +    Uint16 biPlanes;
    2.43 +    Uint16 biBitCount;
    2.44 +    Uint32 biCompression;
    2.45 +    Uint32 biSizeImage;
    2.46 +    Sint32 biXPelsPerMeter;
    2.47 +    Sint32 biYPelsPerMeter;
    2.48 +    Uint32 biClrUsed;
    2.49 +    Uint32 biClrImportant;
    2.50 +
    2.51 +    /* Make sure we are passed a valid data source */
    2.52 +    surface = NULL;
    2.53 +    was_error = 0;
    2.54 +    if (src == NULL) {
    2.55 +        was_error = 1;
    2.56 +        goto done;
    2.57 +    }
    2.58 +
    2.59 +    /* Read in the ICO file header */
    2.60 +    fp_offset = SDL_RWtell(src);
    2.61 +    SDL_ClearError();
    2.62 +
    2.63 +    bfReserved = SDL_ReadLE16(src);
    2.64 +    bfType = SDL_ReadLE16(src);
    2.65 +    bfCount = SDL_ReadLE16(src);
    2.66 +    if ((bfType != 1 && bfType != 2) || (bfCount == 0)) {
    2.67 +        SDL_SetError("File is not a Windows ICO file");
    2.68 +        was_error = 1;
    2.69 +        goto done;
    2.70 +    }
    2.71 +
    2.72 +    /* Read the Win32 Icon Directory */
    2.73 +    for (i = 0; i < bfCount; i++) {
    2.74 +        /* Icon Directory Entries */
    2.75 +        int bWidth = SDL_Read8(src);    /* Uint8, but 0 = 256 ! */
    2.76 +        int bHeight = SDL_Read8(src);   /* Uint8, but 0 = 256 ! */
    2.77 +        int bColorCount = SDL_Read8(src);       /* Uint8, but 0 = 256 ! */
    2.78 +        Uint8 bReserved = SDL_Read8(src);
    2.79 +        Uint16 wPlanes = SDL_ReadLE16(src);
    2.80 +        Uint16 wBitCount = SDL_ReadLE16(src);
    2.81 +        Uint32 dwBytesInRes = SDL_ReadLE32(src);
    2.82 +        Uint32 dwImageOffset = SDL_ReadLE32(src);
    2.83 +
    2.84 +        if (!bWidth)
    2.85 +            bWidth = 256;
    2.86 +        if (!bHeight)
    2.87 +            bHeight = 256;
    2.88 +        if (!bColorCount)
    2.89 +            bColorCount = 256;
    2.90 +
    2.91 +        //printf("%dx%d@%d - %08x\n", bWidth, bHeight, bColorCount, dwImageOffset);
    2.92 +        if (bColorCount > maxCol) {
    2.93 +            maxCol = bColorCount;
    2.94 +            icoOfs = dwImageOffset;
    2.95 +            //printf("marked\n");
    2.96 +        }
    2.97 +    }
    2.98 +
    2.99 +    /* Advance to the DIB Data */
   2.100 +    if (SDL_RWseek(src, icoOfs, RW_SEEK_SET) < 0) {
   2.101 +        SDL_Error(SDL_EFSEEK);
   2.102 +        was_error = 1;
   2.103 +        goto done;
   2.104 +    }
   2.105 +
   2.106 +    /* Read the Win32 BITMAPINFOHEADER */
   2.107 +    biSize = SDL_ReadLE32(src);
   2.108 +    if (biSize == 40) {
   2.109 +        biWidth = SDL_ReadLE32(src);
   2.110 +        biHeight = SDL_ReadLE32(src);
   2.111 +        biPlanes = SDL_ReadLE16(src);
   2.112 +        biBitCount = SDL_ReadLE16(src);
   2.113 +        biCompression = SDL_ReadLE32(src);
   2.114 +        biSizeImage = SDL_ReadLE32(src);
   2.115 +        biXPelsPerMeter = SDL_ReadLE32(src);
   2.116 +        biYPelsPerMeter = SDL_ReadLE32(src);
   2.117 +        biClrUsed = SDL_ReadLE32(src);
   2.118 +        biClrImportant = SDL_ReadLE32(src);
   2.119 +    } else {
   2.120 +        SDL_SetError("Unsupported ICO bitmap format");
   2.121 +        was_error = 1;
   2.122 +        goto done;
   2.123 +    }
   2.124 +
   2.125 +    /* Check for read error */
   2.126 +    if (SDL_strcmp(SDL_GetError(), "") != 0) {
   2.127 +        was_error = 1;
   2.128 +        goto done;
   2.129 +    }
   2.130 +
   2.131 +    /* We don't support any BMP compression right now */
   2.132 +    switch (biCompression) {
   2.133 +    case BI_RGB:
   2.134 +        /* Default values for the BMP format */
   2.135 +        switch (biBitCount) {
   2.136 +        case 1:
   2.137 +        case 4:
   2.138 +            ExpandBMP = biBitCount;
   2.139 +            biBitCount = 8;
   2.140 +            break;
   2.141 +        case 8:
   2.142 +            ExpandBMP = 8;
   2.143 +            break;
   2.144 +        case 32:
   2.145 +            Rmask = 0x00FF0000;
   2.146 +            Gmask = 0x0000FF00;
   2.147 +            Bmask = 0x000000FF;
   2.148 +            ExpandBMP = 0;
   2.149 +            break;
   2.150 +        default:
   2.151 +            SDL_SetError("ICO file with unsupported bit count");
   2.152 +            was_error = 1;
   2.153 +            goto done;
   2.154 +        }
   2.155 +        break;
   2.156 +    default:
   2.157 +        SDL_SetError("Compressed ICO files not supported");
   2.158 +        was_error = 1;
   2.159 +        goto done;
   2.160 +    }
   2.161 +
   2.162 +    /* Create a RGBA surface */
   2.163 +    biHeight = biHeight >> 1;
   2.164 +    //printf("%d x %d\n", biWidth, biHeight);
   2.165 +    surface =
   2.166 +        SDL_CreateRGBSurface(0, biWidth, biHeight, 32, 0x00FF0000,
   2.167 +                             0x0000FF00, 0x000000FF, 0xFF000000);
   2.168 +    if (surface == NULL) {
   2.169 +        was_error = 1;
   2.170 +        goto done;
   2.171 +    }
   2.172 +
   2.173 +    /* Load the palette, if any */
   2.174 +    //printf("bc %d bused %d\n", biBitCount, biClrUsed);
   2.175 +    if (biBitCount <= 8) {
   2.176 +        if (biClrUsed == 0) {
   2.177 +            biClrUsed = 1 << biBitCount;
   2.178 +        }
   2.179 +        for (i = 0; i < (int) biClrUsed; ++i) {
   2.180 +            SDL_RWread(src, &palette[i], 4, 1);
   2.181 +        }
   2.182 +    }
   2.183 +
   2.184 +    /* Read the surface pixels.  Note that the bmp image is upside down */
   2.185 +    bits = (Uint8 *) surface->pixels + (surface->h * surface->pitch);
   2.186 +    switch (ExpandBMP) {
   2.187 +    case 1:
   2.188 +        bmpPitch = (biWidth + 7) >> 3;
   2.189 +        pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
   2.190 +        break;
   2.191 +    case 4:
   2.192 +        bmpPitch = (biWidth + 1) >> 1;
   2.193 +        pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
   2.194 +        break;
   2.195 +    case 8:
   2.196 +        bmpPitch = biWidth;
   2.197 +        pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
   2.198 +        break;
   2.199 +    default:
   2.200 +        bmpPitch = biWidth * 4;
   2.201 +        pad = 0;
   2.202 +        break;
   2.203 +    }
   2.204 +    while (bits > (Uint8 *) surface->pixels) {
   2.205 +        bits -= surface->pitch;
   2.206 +        switch (ExpandBMP) {
   2.207 +        case 1:
   2.208 +        case 4:
   2.209 +        case 8:
   2.210 +            {
   2.211 +                Uint8 pixel = 0;
   2.212 +                int shift = (8 - ExpandBMP);
   2.213 +                for (i = 0; i < surface->w; ++i) {
   2.214 +                    if (i % (8 / ExpandBMP) == 0) {
   2.215 +                        if (!SDL_RWread(src, &pixel, 1, 1)) {
   2.216 +                            SDL_SetError("Error reading from ICO");
   2.217 +                            was_error = 1;
   2.218 +                            goto done;
   2.219 +                        }
   2.220 +                    }
   2.221 +                    *((Uint32 *) bits + i) = (palette[pixel >> shift]);
   2.222 +                    pixel <<= ExpandBMP;
   2.223 +                }
   2.224 +            }
   2.225 +            break;
   2.226 +
   2.227 +        default:
   2.228 +            if (SDL_RWread(src, bits, 1, surface->pitch)
   2.229 +                != surface->pitch) {
   2.230 +                SDL_Error(SDL_EFREAD);
   2.231 +                was_error = 1;
   2.232 +                goto done;
   2.233 +            }
   2.234 +            break;
   2.235 +        }
   2.236 +        /* Skip padding bytes, ugh */
   2.237 +        if (pad) {
   2.238 +            Uint8 padbyte;
   2.239 +            for (i = 0; i < pad; ++i) {
   2.240 +                SDL_RWread(src, &padbyte, 1, 1);
   2.241 +            }
   2.242 +        }
   2.243 +    }
   2.244 +    /* Read the mask pixels.  Note that the bmp image is upside down */
   2.245 +    bits = (Uint8 *) surface->pixels + (surface->h * surface->pitch);
   2.246 +    ExpandBMP = 1;
   2.247 +    bmpPitch = (biWidth + 7) >> 3;
   2.248 +    pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
   2.249 +    while (bits > (Uint8 *) surface->pixels) {
   2.250 +        Uint8 pixel = 0;
   2.251 +        int shift = (8 - ExpandBMP);
   2.252 +
   2.253 +        bits -= surface->pitch;
   2.254 +        for (i = 0; i < surface->w; ++i) {
   2.255 +            if (i % (8 / ExpandBMP) == 0) {
   2.256 +                if (!SDL_RWread(src, &pixel, 1, 1)) {
   2.257 +                    SDL_SetError("Error reading from ICO");
   2.258 +                    was_error = 1;
   2.259 +                    goto done;
   2.260 +                }
   2.261 +            }
   2.262 +            *((Uint32 *) bits + i) |= ((pixel >> shift) ? 0 : 0xFF000000);
   2.263 +            pixel <<= ExpandBMP;
   2.264 +        }
   2.265 +        /* Skip padding bytes, ugh */
   2.266 +        if (pad) {
   2.267 +            Uint8 padbyte;
   2.268 +            for (i = 0; i < pad; ++i) {
   2.269 +                SDL_RWread(src, &padbyte, 1, 1);
   2.270 +            }
   2.271 +        }
   2.272 +    }
   2.273 +  done:
   2.274 +    if (was_error) {
   2.275 +        if (src) {
   2.276 +            SDL_RWseek(src, fp_offset, RW_SEEK_SET);
   2.277 +        }
   2.278 +        if (surface) {
   2.279 +            SDL_FreeSurface(surface);
   2.280 +        }
   2.281 +        surface = NULL;
   2.282 +    }
   2.283 +    if (freesrc && src) {
   2.284 +        SDL_RWclose(src);
   2.285 +    }
   2.286 +    return (surface);
   2.287 +}
   2.288 +
   2.289  SDL_Surface *
   2.290  SDL_LoadBMP_RW(SDL_RWops * src, int freesrc)
   2.291  {