comparison src/video/SDL_bmp.c @ 3024:1a08749aebce

Add SDL_LoadICO_RW to SDL. Loads best quality icon from *.ico file.
author Couriersud <couriersud@arcor.de>
date Sun, 11 Jan 2009 23:56:19 +0000
parents 502adab079a4
children 69ab1117dd3b
comparison
equal deleted inserted replaced
3023:d72a0dd80e8b 3024:1a08749aebce
43 #define BI_RLE8 1 43 #define BI_RLE8 1
44 #define BI_RLE4 2 44 #define BI_RLE4 2
45 #define BI_BITFIELDS 3 45 #define BI_BITFIELDS 3
46 #endif 46 #endif
47 47
48
49 static Uint8
50 SDL_Read8(SDL_RWops * src)
51 {
52 Uint8 value;
53
54 SDL_RWread(src, &value, 1, 1);
55 return (value);
56 }
57
58 SDL_Surface *
59 SDL_LoadICO_RW(SDL_RWops * src, int freesrc)
60 {
61 int was_error;
62 long fp_offset;
63 int bmpPitch;
64 int i, pad;
65 SDL_Surface *surface;
66 Uint32 Rmask;
67 Uint32 Gmask;
68 Uint32 Bmask;
69 Uint8 *bits;
70 int ExpandBMP;
71 int maxCol = 0;
72 int icoOfs = 0;
73 Uint32 palette[256];
74
75 /* The Win32 ICO file header (14 bytes) */
76 Uint16 bfReserved;
77 Uint16 bfType;
78 Uint16 bfCount;
79
80 /* The Win32 BITMAPINFOHEADER struct (40 bytes) */
81 Uint32 biSize;
82 Sint32 biWidth;
83 Sint32 biHeight;
84 Uint16 biPlanes;
85 Uint16 biBitCount;
86 Uint32 biCompression;
87 Uint32 biSizeImage;
88 Sint32 biXPelsPerMeter;
89 Sint32 biYPelsPerMeter;
90 Uint32 biClrUsed;
91 Uint32 biClrImportant;
92
93 /* Make sure we are passed a valid data source */
94 surface = NULL;
95 was_error = 0;
96 if (src == NULL) {
97 was_error = 1;
98 goto done;
99 }
100
101 /* Read in the ICO file header */
102 fp_offset = SDL_RWtell(src);
103 SDL_ClearError();
104
105 bfReserved = SDL_ReadLE16(src);
106 bfType = SDL_ReadLE16(src);
107 bfCount = SDL_ReadLE16(src);
108 if ((bfType != 1 && bfType != 2) || (bfCount == 0)) {
109 SDL_SetError("File is not a Windows ICO file");
110 was_error = 1;
111 goto done;
112 }
113
114 /* Read the Win32 Icon Directory */
115 for (i = 0; i < bfCount; i++) {
116 /* Icon Directory Entries */
117 int bWidth = SDL_Read8(src); /* Uint8, but 0 = 256 ! */
118 int bHeight = SDL_Read8(src); /* Uint8, but 0 = 256 ! */
119 int bColorCount = SDL_Read8(src); /* Uint8, but 0 = 256 ! */
120 Uint8 bReserved = SDL_Read8(src);
121 Uint16 wPlanes = SDL_ReadLE16(src);
122 Uint16 wBitCount = SDL_ReadLE16(src);
123 Uint32 dwBytesInRes = SDL_ReadLE32(src);
124 Uint32 dwImageOffset = SDL_ReadLE32(src);
125
126 if (!bWidth)
127 bWidth = 256;
128 if (!bHeight)
129 bHeight = 256;
130 if (!bColorCount)
131 bColorCount = 256;
132
133 //printf("%dx%d@%d - %08x\n", bWidth, bHeight, bColorCount, dwImageOffset);
134 if (bColorCount > maxCol) {
135 maxCol = bColorCount;
136 icoOfs = dwImageOffset;
137 //printf("marked\n");
138 }
139 }
140
141 /* Advance to the DIB Data */
142 if (SDL_RWseek(src, icoOfs, RW_SEEK_SET) < 0) {
143 SDL_Error(SDL_EFSEEK);
144 was_error = 1;
145 goto done;
146 }
147
148 /* Read the Win32 BITMAPINFOHEADER */
149 biSize = SDL_ReadLE32(src);
150 if (biSize == 40) {
151 biWidth = SDL_ReadLE32(src);
152 biHeight = SDL_ReadLE32(src);
153 biPlanes = SDL_ReadLE16(src);
154 biBitCount = SDL_ReadLE16(src);
155 biCompression = SDL_ReadLE32(src);
156 biSizeImage = SDL_ReadLE32(src);
157 biXPelsPerMeter = SDL_ReadLE32(src);
158 biYPelsPerMeter = SDL_ReadLE32(src);
159 biClrUsed = SDL_ReadLE32(src);
160 biClrImportant = SDL_ReadLE32(src);
161 } else {
162 SDL_SetError("Unsupported ICO bitmap format");
163 was_error = 1;
164 goto done;
165 }
166
167 /* Check for read error */
168 if (SDL_strcmp(SDL_GetError(), "") != 0) {
169 was_error = 1;
170 goto done;
171 }
172
173 /* We don't support any BMP compression right now */
174 switch (biCompression) {
175 case BI_RGB:
176 /* Default values for the BMP format */
177 switch (biBitCount) {
178 case 1:
179 case 4:
180 ExpandBMP = biBitCount;
181 biBitCount = 8;
182 break;
183 case 8:
184 ExpandBMP = 8;
185 break;
186 case 32:
187 Rmask = 0x00FF0000;
188 Gmask = 0x0000FF00;
189 Bmask = 0x000000FF;
190 ExpandBMP = 0;
191 break;
192 default:
193 SDL_SetError("ICO file with unsupported bit count");
194 was_error = 1;
195 goto done;
196 }
197 break;
198 default:
199 SDL_SetError("Compressed ICO files not supported");
200 was_error = 1;
201 goto done;
202 }
203
204 /* Create a RGBA surface */
205 biHeight = biHeight >> 1;
206 //printf("%d x %d\n", biWidth, biHeight);
207 surface =
208 SDL_CreateRGBSurface(0, biWidth, biHeight, 32, 0x00FF0000,
209 0x0000FF00, 0x000000FF, 0xFF000000);
210 if (surface == NULL) {
211 was_error = 1;
212 goto done;
213 }
214
215 /* Load the palette, if any */
216 //printf("bc %d bused %d\n", biBitCount, biClrUsed);
217 if (biBitCount <= 8) {
218 if (biClrUsed == 0) {
219 biClrUsed = 1 << biBitCount;
220 }
221 for (i = 0; i < (int) biClrUsed; ++i) {
222 SDL_RWread(src, &palette[i], 4, 1);
223 }
224 }
225
226 /* Read the surface pixels. Note that the bmp image is upside down */
227 bits = (Uint8 *) surface->pixels + (surface->h * surface->pitch);
228 switch (ExpandBMP) {
229 case 1:
230 bmpPitch = (biWidth + 7) >> 3;
231 pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
232 break;
233 case 4:
234 bmpPitch = (biWidth + 1) >> 1;
235 pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
236 break;
237 case 8:
238 bmpPitch = biWidth;
239 pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
240 break;
241 default:
242 bmpPitch = biWidth * 4;
243 pad = 0;
244 break;
245 }
246 while (bits > (Uint8 *) surface->pixels) {
247 bits -= surface->pitch;
248 switch (ExpandBMP) {
249 case 1:
250 case 4:
251 case 8:
252 {
253 Uint8 pixel = 0;
254 int shift = (8 - ExpandBMP);
255 for (i = 0; i < surface->w; ++i) {
256 if (i % (8 / ExpandBMP) == 0) {
257 if (!SDL_RWread(src, &pixel, 1, 1)) {
258 SDL_SetError("Error reading from ICO");
259 was_error = 1;
260 goto done;
261 }
262 }
263 *((Uint32 *) bits + i) = (palette[pixel >> shift]);
264 pixel <<= ExpandBMP;
265 }
266 }
267 break;
268
269 default:
270 if (SDL_RWread(src, bits, 1, surface->pitch)
271 != surface->pitch) {
272 SDL_Error(SDL_EFREAD);
273 was_error = 1;
274 goto done;
275 }
276 break;
277 }
278 /* Skip padding bytes, ugh */
279 if (pad) {
280 Uint8 padbyte;
281 for (i = 0; i < pad; ++i) {
282 SDL_RWread(src, &padbyte, 1, 1);
283 }
284 }
285 }
286 /* Read the mask pixels. Note that the bmp image is upside down */
287 bits = (Uint8 *) surface->pixels + (surface->h * surface->pitch);
288 ExpandBMP = 1;
289 bmpPitch = (biWidth + 7) >> 3;
290 pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
291 while (bits > (Uint8 *) surface->pixels) {
292 Uint8 pixel = 0;
293 int shift = (8 - ExpandBMP);
294
295 bits -= surface->pitch;
296 for (i = 0; i < surface->w; ++i) {
297 if (i % (8 / ExpandBMP) == 0) {
298 if (!SDL_RWread(src, &pixel, 1, 1)) {
299 SDL_SetError("Error reading from ICO");
300 was_error = 1;
301 goto done;
302 }
303 }
304 *((Uint32 *) bits + i) |= ((pixel >> shift) ? 0 : 0xFF000000);
305 pixel <<= ExpandBMP;
306 }
307 /* Skip padding bytes, ugh */
308 if (pad) {
309 Uint8 padbyte;
310 for (i = 0; i < pad; ++i) {
311 SDL_RWread(src, &padbyte, 1, 1);
312 }
313 }
314 }
315 done:
316 if (was_error) {
317 if (src) {
318 SDL_RWseek(src, fp_offset, RW_SEEK_SET);
319 }
320 if (surface) {
321 SDL_FreeSurface(surface);
322 }
323 surface = NULL;
324 }
325 if (freesrc && src) {
326 SDL_RWclose(src);
327 }
328 return (surface);
329 }
48 330
49 SDL_Surface * 331 SDL_Surface *
50 SDL_LoadBMP_RW(SDL_RWops * src, int freesrc) 332 SDL_LoadBMP_RW(SDL_RWops * src, int freesrc)
51 { 333 {
52 int was_error; 334 int was_error;