diff options
Diffstat (limited to 'utils/wpseditor/screenshot/gd_bmp.c')
-rw-r--r-- | utils/wpseditor/screenshot/gd_bmp.c | 778 |
1 files changed, 778 insertions, 0 deletions
diff --git a/utils/wpseditor/screenshot/gd_bmp.c b/utils/wpseditor/screenshot/gd_bmp.c new file mode 100644 index 0000000000..8fe737da03 --- /dev/null +++ b/utils/wpseditor/screenshot/gd_bmp.c | |||
@@ -0,0 +1,778 @@ | |||
1 | /* | ||
2 | Stolen from http://cvs.php.net/viewcvs.cgi/gd/playground/gdbmp/ | ||
3 | */ | ||
4 | |||
5 | /* | ||
6 | gd_bmp.c | ||
7 | |||
8 | Bitmap format support for libgd | ||
9 | |||
10 | * Written 2007, Scott MacVicar | ||
11 | --------------------------------------------------------------------------- | ||
12 | |||
13 | Todo: | ||
14 | |||
15 | Bitfield encoding | ||
16 | |||
17 | ---------------------------------------------------------------------------- | ||
18 | */ | ||
19 | /* $Id$ */ | ||
20 | #ifdef HAVE_CONFIG_H | ||
21 | #include "config.h" | ||
22 | #endif | ||
23 | |||
24 | #include <stdio.h> | ||
25 | #include <math.h> | ||
26 | #include <string.h> | ||
27 | #include <stdlib.h> | ||
28 | #include "gd.h" | ||
29 | #include "bmp.h" | ||
30 | |||
31 | extern void* gdCalloc (size_t nmemb, size_t size); | ||
32 | |||
33 | static int bmp_read_header(gdIOCtxPtr infile, bmp_hdr_t *hdr); | ||
34 | static int bmp_read_info(gdIOCtxPtr infile, bmp_info_t *info); | ||
35 | static int bmp_read_windows_v3_info(gdIOCtxPtr infile, bmp_info_t *info); | ||
36 | static int bmp_read_os2_v1_info(gdIOCtxPtr infile, bmp_info_t *info); | ||
37 | static int bmp_read_os2_v2_info(gdIOCtxPtr infile, bmp_info_t *info); | ||
38 | |||
39 | static int bmp_read_direct(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header); | ||
40 | static int bmp_read_1bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header); | ||
41 | static int bmp_read_4bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header); | ||
42 | static int bmp_read_8bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header); | ||
43 | static int bmp_read_rle(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info); | ||
44 | |||
45 | #if GD_MAJOR_VERSION == 2 && GD_MINOR_VERSION < 1 | ||
46 | /* Byte helper functions, since added to GD 2.1 */ | ||
47 | static int gdGetIntLSB(signed int *result, gdIOCtx * ctx); | ||
48 | static int gdGetWordLSB(signed short int *result, gdIOCtx * ctx); | ||
49 | #endif | ||
50 | |||
51 | #define BMP_DEBUG(s) | ||
52 | |||
53 | gdImagePtr gdImageCreateFromBmpCtx(gdIOCtxPtr infile); | ||
54 | |||
55 | gdImagePtr gdImageCreateFromBmp(FILE * inFile) | ||
56 | { | ||
57 | gdImagePtr im = 0; | ||
58 | gdIOCtx *in = gdNewFileCtx(inFile); | ||
59 | im = gdImageCreateFromBmpCtx(in); | ||
60 | in->gd_free(in); | ||
61 | return im; | ||
62 | } | ||
63 | |||
64 | gdImagePtr gdImageCreateFromBmpPtr(int size, void *data) | ||
65 | { | ||
66 | gdImagePtr im; | ||
67 | gdIOCtx *in = gdNewDynamicCtxEx(size, data, 0); | ||
68 | im = gdImageCreateFromBmpCtx(in); | ||
69 | in->gd_free(in); | ||
70 | return im; | ||
71 | } | ||
72 | |||
73 | gdImagePtr gdImageCreateFromBmpCtx(gdIOCtxPtr infile) | ||
74 | { | ||
75 | bmp_hdr_t *hdr; | ||
76 | bmp_info_t *info; | ||
77 | gdImagePtr im = NULL; | ||
78 | int error = 0; | ||
79 | |||
80 | if (!(hdr= (bmp_hdr_t *)gdCalloc(1, sizeof(bmp_hdr_t)))) { | ||
81 | return NULL; | ||
82 | } | ||
83 | |||
84 | if (bmp_read_header(infile, hdr)) { | ||
85 | gdFree(hdr); | ||
86 | return NULL; | ||
87 | } | ||
88 | |||
89 | if (hdr->magic != 0x4d42) { | ||
90 | gdFree(hdr); | ||
91 | return NULL; | ||
92 | } | ||
93 | |||
94 | if (!(info = (bmp_info_t *)gdCalloc(1, sizeof(bmp_info_t)))) { | ||
95 | gdFree(hdr); | ||
96 | return NULL; | ||
97 | } | ||
98 | |||
99 | if (bmp_read_info(infile, info)) { | ||
100 | gdFree(hdr); | ||
101 | gdFree(info); | ||
102 | return NULL; | ||
103 | } | ||
104 | |||
105 | BMP_DEBUG(printf("Numcolours: %d\n", info->numcolors)); | ||
106 | BMP_DEBUG(printf("Width: %d\n", info->width)); | ||
107 | BMP_DEBUG(printf("Height: %d\n", info->height)); | ||
108 | BMP_DEBUG(printf("Planes: %d\n", info->numplanes)); | ||
109 | BMP_DEBUG(printf("Depth: %d\n", info->depth)); | ||
110 | BMP_DEBUG(printf("Offset: %d\n", hdr->off)); | ||
111 | |||
112 | if (info->depth >= 16) { | ||
113 | im = gdImageCreateTrueColor(info->width, info->height); | ||
114 | } else { | ||
115 | im = gdImageCreate(info->width, info->height); | ||
116 | } | ||
117 | |||
118 | if (!im) { | ||
119 | gdFree(hdr); | ||
120 | gdFree(info); | ||
121 | return NULL; | ||
122 | } | ||
123 | |||
124 | switch (info->depth) { | ||
125 | case 1: | ||
126 | BMP_DEBUG(printf("1-bit image\n")); | ||
127 | error = bmp_read_1bit(im, infile, info, hdr); | ||
128 | break; | ||
129 | case 4: | ||
130 | BMP_DEBUG(printf("4-bit image\n")); | ||
131 | error = bmp_read_4bit(im, infile, info, hdr); | ||
132 | break; | ||
133 | case 8: | ||
134 | BMP_DEBUG(printf("8-bit image\n")); | ||
135 | error = bmp_read_8bit(im, infile, info, hdr); | ||
136 | break; | ||
137 | case 16: | ||
138 | case 24: | ||
139 | case 32: | ||
140 | BMP_DEBUG(printf("Direct BMP image\n")); | ||
141 | error = bmp_read_direct(im, infile, info, hdr); | ||
142 | break; | ||
143 | default: | ||
144 | BMP_DEBUG(printf("Unknown bit count\n")); | ||
145 | error = 1; | ||
146 | } | ||
147 | |||
148 | gdFree(hdr); | ||
149 | gdFree(info); | ||
150 | |||
151 | if (error) { | ||
152 | gdImageDestroy(im); | ||
153 | return NULL; | ||
154 | } | ||
155 | |||
156 | return im; | ||
157 | } | ||
158 | |||
159 | static int bmp_read_header(gdIOCtx *infile, bmp_hdr_t *hdr) | ||
160 | { | ||
161 | if( | ||
162 | !gdGetWordLSB(&hdr->magic, infile) || | ||
163 | !gdGetIntLSB(&hdr->size, infile) || | ||
164 | !gdGetWordLSB(&hdr->reserved1, infile) || | ||
165 | !gdGetWordLSB(&hdr->reserved2 , infile) || | ||
166 | !gdGetIntLSB(&hdr->off , infile) | ||
167 | ) { | ||
168 | return 1; | ||
169 | } | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | static int bmp_read_info(gdIOCtx *infile, bmp_info_t *info) | ||
174 | { | ||
175 | /* read BMP length so we can work out the version */ | ||
176 | if (!gdGetIntLSB(&info->len, infile)) { | ||
177 | return 1; | ||
178 | } | ||
179 | |||
180 | switch (info->len) { | ||
181 | /* For now treat Windows v4 + v5 as v3 */ | ||
182 | case BMP_WINDOWS_V3: | ||
183 | case BMP_WINDOWS_V4: | ||
184 | case BMP_WINDOWS_V5: | ||
185 | BMP_DEBUG(printf("Reading Windows Header\n")); | ||
186 | if (bmp_read_windows_v3_info(infile, info)) { | ||
187 | return 1; | ||
188 | } | ||
189 | break; | ||
190 | case BMP_OS2_V1: | ||
191 | if (bmp_read_os2_v1_info(infile, info)) { | ||
192 | return 1; | ||
193 | } | ||
194 | break; | ||
195 | case BMP_OS2_V2: | ||
196 | if (bmp_read_os2_v2_info(infile, info)) { | ||
197 | return 1; | ||
198 | } | ||
199 | break; | ||
200 | default: | ||
201 | BMP_DEBUG(printf("Unhandled bitmap\n")); | ||
202 | return 1; | ||
203 | } | ||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | static int bmp_read_windows_v3_info(gdIOCtxPtr infile, bmp_info_t *info) | ||
208 | { | ||
209 | if ( | ||
210 | !gdGetIntLSB(&info->width, infile) || | ||
211 | !gdGetIntLSB(&info->height, infile) || | ||
212 | !gdGetWordLSB(&info->numplanes, infile) || | ||
213 | !gdGetWordLSB(&info->depth, infile) || | ||
214 | !gdGetIntLSB(&info->enctype, infile) || | ||
215 | !gdGetIntLSB(&info->size, infile) || | ||
216 | !gdGetIntLSB(&info->hres, infile) || | ||
217 | !gdGetIntLSB(&info->vres, infile) || | ||
218 | !gdGetIntLSB(&info->numcolors, infile) || | ||
219 | !gdGetIntLSB(&info->mincolors, infile) | ||
220 | ) { | ||
221 | return 1; | ||
222 | } | ||
223 | |||
224 | if (info->height < 0) { | ||
225 | info->topdown = 1; | ||
226 | info->height = -info->height; | ||
227 | } else { | ||
228 | info->topdown = 0; | ||
229 | } | ||
230 | |||
231 | info->type = BMP_PALETTE_4; | ||
232 | |||
233 | if (info->width <= 0 || info->height <= 0 || info->numplanes <= 0 || | ||
234 | info->depth <= 0 || info->numcolors < 0 || info->mincolors < 0) { | ||
235 | return 1; | ||
236 | } | ||
237 | |||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | static int bmp_read_os2_v1_info(gdIOCtxPtr infile, bmp_info_t *info) | ||
242 | { | ||
243 | if ( | ||
244 | !gdGetWordLSB((signed short int *)&info->width, infile) || | ||
245 | !gdGetWordLSB((signed short int *)&info->height, infile) || | ||
246 | !gdGetWordLSB(&info->numplanes, infile) || | ||
247 | !gdGetWordLSB(&info->depth, infile) | ||
248 | ) { | ||
249 | return 1; | ||
250 | } | ||
251 | |||
252 | /* OS2 v1 doesn't support topdown */ | ||
253 | info->topdown = 0; | ||
254 | |||
255 | info->numcolors = 1 << info->depth; | ||
256 | info->type = BMP_PALETTE_3; | ||
257 | |||
258 | if (info->width <= 0 || info->height <= 0 || info->numplanes <= 0 || | ||
259 | info->depth <= 0 || info->numcolors < 0) { | ||
260 | return 1; | ||
261 | } | ||
262 | |||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | static int bmp_read_os2_v2_info(gdIOCtxPtr infile, bmp_info_t *info) | ||
267 | { | ||
268 | char useless_bytes[24]; | ||
269 | if ( | ||
270 | !gdGetIntLSB(&info->width, infile) || | ||
271 | !gdGetIntLSB(&info->height, infile) || | ||
272 | !gdGetWordLSB(&info->numplanes, infile) || | ||
273 | !gdGetWordLSB(&info->depth, infile) || | ||
274 | !gdGetIntLSB(&info->enctype, infile) || | ||
275 | !gdGetIntLSB(&info->size, infile) || | ||
276 | !gdGetIntLSB(&info->hres, infile) || | ||
277 | !gdGetIntLSB(&info->vres, infile) || | ||
278 | !gdGetIntLSB(&info->numcolors, infile) || | ||
279 | !gdGetIntLSB(&info->mincolors, infile) | ||
280 | ) { | ||
281 | return 1; | ||
282 | } | ||
283 | |||
284 | /* Lets seek the next 24 pointless bytes, we don't care too much about it */ | ||
285 | if (!gdGetBuf(useless_bytes, 24, infile)) { | ||
286 | return 1; | ||
287 | } | ||
288 | |||
289 | if (info->height < 0) { | ||
290 | info->topdown = 1; | ||
291 | info->height = -info->height; | ||
292 | } else { | ||
293 | info->topdown = 0; | ||
294 | } | ||
295 | |||
296 | info->type = BMP_PALETTE_4; | ||
297 | |||
298 | if (info->width <= 0 || info->height <= 0 || info->numplanes <= 0 || | ||
299 | info->depth <= 0 || info->numcolors < 0 || info->mincolors < 0) { | ||
300 | return 1; | ||
301 | } | ||
302 | |||
303 | |||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | static int bmp_read_direct(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header) | ||
308 | { | ||
309 | int ypos = 0, xpos = 0, row = 0; | ||
310 | int padding = 0, alpha = 0, red = 0, green = 0, blue = 0; | ||
311 | signed short int data = 0; | ||
312 | |||
313 | switch(info->enctype) { | ||
314 | case BMP_BI_RGB: | ||
315 | /* no-op */ | ||
316 | break; | ||
317 | |||
318 | case BMP_BI_BITFIELDS: | ||
319 | if (info->depth == 24) { | ||
320 | BMP_DEBUG(printf("Bitfield compression isn't supported for 24-bit\n")); | ||
321 | return 1; | ||
322 | } | ||
323 | BMP_DEBUG(printf("Currently no bitfield support\n")); | ||
324 | return 1; | ||
325 | break; | ||
326 | |||
327 | case BMP_BI_RLE8: | ||
328 | if (info->depth != 8) { | ||
329 | BMP_DEBUG(printf("RLE is only valid for 8-bit images\n")); | ||
330 | return 1; | ||
331 | } | ||
332 | case BMP_BI_RLE4: | ||
333 | if (info->depth != 4) { | ||
334 | BMP_DEBUG(printf("RLE is only valid for 4-bit images\n")); | ||
335 | return 1; | ||
336 | } | ||
337 | case BMP_BI_JPEG: | ||
338 | case BMP_BI_PNG: | ||
339 | default: | ||
340 | BMP_DEBUG(printf("Unsupported BMP compression format\n")); | ||
341 | return 1; | ||
342 | } | ||
343 | |||
344 | /* There is a chance the data isn't until later, would be wierd but it is possible */ | ||
345 | if (gdTell(infile) != header->off) { | ||
346 | /* Should make sure we don't seek past the file size */ | ||
347 | gdSeek(infile, header->off); | ||
348 | } | ||
349 | |||
350 | /* The line must be divisible by 4, else its padded with NULLs */ | ||
351 | padding = ((int)(info->depth / 8) * info->width) % 4; | ||
352 | if (padding) { | ||
353 | padding = 4 - padding; | ||
354 | } | ||
355 | |||
356 | |||
357 | for (ypos = 0; ypos < info->height; ++ypos) { | ||
358 | if (info->topdown) { | ||
359 | row = ypos; | ||
360 | } else { | ||
361 | row = info->height - ypos - 1; | ||
362 | } | ||
363 | |||
364 | for (xpos = 0; xpos < info->width; xpos++) { | ||
365 | if (info->depth == 16) { | ||
366 | if (!gdGetWordLSB(&data, infile)) { | ||
367 | return 1; | ||
368 | } | ||
369 | BMP_DEBUG(printf("Data: %X\n", data)); | ||
370 | red = ((data & 0x7C00) >> 10) << 3; | ||
371 | green = ((data & 0x3E0) >> 5) << 3; | ||
372 | blue = (data & 0x1F) << 3; | ||
373 | BMP_DEBUG(printf("R: %d, G: %d, B: %d\n", red, green, blue)); | ||
374 | } else if (info->depth == 24) { | ||
375 | if (!gdGetByte(&blue, infile) || !gdGetByte(&green, infile) || !gdGetByte(&red, infile)) { | ||
376 | return 1; | ||
377 | } | ||
378 | } else { | ||
379 | if (!gdGetByte(&blue, infile) || !gdGetByte(&green, infile) || !gdGetByte(&red, infile) || !gdGetByte(&alpha, infile)) { | ||
380 | return 1; | ||
381 | } | ||
382 | } | ||
383 | /*alpha = gdAlphaMax - (alpha >> 1);*/ | ||
384 | gdImageSetPixel(im, xpos, row, gdTrueColor(red, green, blue)); | ||
385 | } | ||
386 | for (xpos = padding; xpos > 0; --xpos) { | ||
387 | if (!gdGetByte(&red, infile)) { | ||
388 | return 1; | ||
389 | } | ||
390 | } | ||
391 | } | ||
392 | |||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | static int bmp_read_palette(gdImagePtr im, gdIOCtxPtr infile, int count, int read_four) | ||
397 | { | ||
398 | int i; | ||
399 | int r, g, b, z; | ||
400 | |||
401 | for (i = 0; i < count; i++) { | ||
402 | if ( | ||
403 | !gdGetByte(&r, infile) || | ||
404 | !gdGetByte(&g, infile) || | ||
405 | !gdGetByte(&b, infile) || | ||
406 | (read_four && !gdGetByte(&z, infile)) | ||
407 | ) { | ||
408 | return 1; | ||
409 | } | ||
410 | im->red[i] = r; | ||
411 | im->green[i] = g; | ||
412 | im->blue[i] = b; | ||
413 | im->open[i] = 1; | ||
414 | } | ||
415 | return 0; | ||
416 | } | ||
417 | |||
418 | static int bmp_read_1bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header) | ||
419 | { | ||
420 | int ypos = 0, xpos = 0, row = 0, index = 0; | ||
421 | int padding = 0, current_byte = 0, bit = 0; | ||
422 | |||
423 | if (info->enctype != BMP_BI_RGB) { | ||
424 | return 1; | ||
425 | } | ||
426 | |||
427 | if (!info->numcolors) { | ||
428 | info->numcolors = 2; | ||
429 | } else if (info->numcolors < 0 || info->numcolors > 2) { | ||
430 | return 1; | ||
431 | } | ||
432 | |||
433 | if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) { | ||
434 | return 1; | ||
435 | } | ||
436 | |||
437 | im->colorsTotal = info->numcolors; | ||
438 | |||
439 | /* There is a chance the data isn't until later, would be wierd but it is possible */ | ||
440 | if (gdTell(infile) != header->off) { | ||
441 | /* Should make sure we don't seek past the file size */ | ||
442 | gdSeek(infile, header->off); | ||
443 | } | ||
444 | |||
445 | /* The line must be divisible by 4, else its padded with NULLs */ | ||
446 | padding = ((int)ceill(0.1 * info->width)) % 4; | ||
447 | if (padding) { | ||
448 | padding = 4 - padding; | ||
449 | } | ||
450 | |||
451 | for (ypos = 0; ypos < info->height; ++ypos) { | ||
452 | if (info->topdown) { | ||
453 | row = ypos; | ||
454 | } else { | ||
455 | row = info->height - ypos - 1; | ||
456 | } | ||
457 | |||
458 | for (xpos = 0; xpos < info->width; xpos += 8) { | ||
459 | /* Bitmaps are always aligned in bytes so we'll never overflow */ | ||
460 | if (!gdGetByte(¤t_byte, infile)) { | ||
461 | return 1; | ||
462 | } | ||
463 | |||
464 | for (bit = 0; bit < 8; bit++) { | ||
465 | index = ((current_byte & (0x80 >> bit)) != 0 ? 0x01 : 0x00); | ||
466 | if (im->open[index]) { | ||
467 | im->open[index] = 0; | ||
468 | } | ||
469 | gdImageSetPixel(im, xpos + bit, row, index); | ||
470 | /* No need to read anything extra */ | ||
471 | if ((xpos + bit) >= info->width) { | ||
472 | break; | ||
473 | } | ||
474 | } | ||
475 | } | ||
476 | |||
477 | for (xpos = padding; xpos > 0; --xpos) { | ||
478 | if (!gdGetByte(&index, infile)) { | ||
479 | return 1; | ||
480 | } | ||
481 | } | ||
482 | } | ||
483 | return 0; | ||
484 | } | ||
485 | |||
486 | static int bmp_read_4bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header) | ||
487 | { | ||
488 | int ypos = 0, xpos = 0, row = 0, index = 0; | ||
489 | int padding = 0, current_byte = 0; | ||
490 | |||
491 | if (info->enctype != BMP_BI_RGB && info->enctype != BMP_BI_RLE4) { | ||
492 | return 1; | ||
493 | } | ||
494 | |||
495 | if (!info->numcolors) { | ||
496 | info->numcolors = 16; | ||
497 | } else if (info->numcolors < 0 || info->numcolors > 16) { | ||
498 | return 1; | ||
499 | } | ||
500 | |||
501 | if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) { | ||
502 | return 1; | ||
503 | } | ||
504 | |||
505 | im->colorsTotal = info->numcolors; | ||
506 | |||
507 | /* There is a chance the data isn't until later, would be wierd but it is possible */ | ||
508 | if (gdTell(infile) != header->off) { | ||
509 | /* Should make sure we don't seek past the file size */ | ||
510 | gdSeek(infile, header->off); | ||
511 | } | ||
512 | |||
513 | /* The line must be divisible by 4, else its padded with NULLs */ | ||
514 | padding = ((int)ceil(0.5 * info->width)) % 4; | ||
515 | if (padding) { | ||
516 | padding = 4 - padding; | ||
517 | } | ||
518 | |||
519 | switch (info->enctype) { | ||
520 | case BMP_BI_RGB: | ||
521 | for (ypos = 0; ypos < info->height; ++ypos) { | ||
522 | if (info->topdown) { | ||
523 | row = ypos; | ||
524 | } else { | ||
525 | row = info->height - ypos - 1; | ||
526 | } | ||
527 | |||
528 | for (xpos = 0; xpos < info->width; xpos += 2) { | ||
529 | if (!gdGetByte(¤t_byte, infile)) { | ||
530 | return 1; | ||
531 | } | ||
532 | |||
533 | index = (current_byte >> 4) & 0x0f; | ||
534 | if (im->open[index]) { | ||
535 | im->open[index] = 0; | ||
536 | } | ||
537 | gdImageSetPixel(im, xpos, row, index); | ||
538 | |||
539 | /* This condition may get called often, potential optimsations */ | ||
540 | if (xpos >= info->width) { | ||
541 | break; | ||
542 | } | ||
543 | |||
544 | index = current_byte & 0x0f; | ||
545 | if (im->open[index]) { | ||
546 | im->open[index] = 0; | ||
547 | } | ||
548 | gdImageSetPixel(im, xpos + 1, row, index); | ||
549 | } | ||
550 | |||
551 | for (xpos = padding; xpos > 0; --xpos) { | ||
552 | if (!gdGetByte(&index, infile)) { | ||
553 | return 1; | ||
554 | } | ||
555 | } | ||
556 | } | ||
557 | break; | ||
558 | |||
559 | case BMP_BI_RLE4: | ||
560 | if (bmp_read_rle(im, infile, info)) { | ||
561 | return 1; | ||
562 | } | ||
563 | break; | ||
564 | |||
565 | default: | ||
566 | return 1; | ||
567 | } | ||
568 | return 0; | ||
569 | } | ||
570 | |||
571 | static int bmp_read_8bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header) | ||
572 | { | ||
573 | int ypos = 0, xpos = 0, row = 0, index = 0; | ||
574 | int padding = 0; | ||
575 | |||
576 | if (info->enctype != BMP_BI_RGB && info->enctype != BMP_BI_RLE8) { | ||
577 | return 1; | ||
578 | } | ||
579 | |||
580 | if (!info->numcolors) { | ||
581 | info->numcolors = 256; | ||
582 | } else if (info->numcolors < 0 || info->numcolors > 256) { | ||
583 | return 1; | ||
584 | } | ||
585 | |||
586 | if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) { | ||
587 | return 1; | ||
588 | } | ||
589 | |||
590 | im->colorsTotal = info->numcolors; | ||
591 | |||
592 | /* There is a chance the data isn't until later, would be wierd but it is possible */ | ||
593 | if (gdTell(infile) != header->off) { | ||
594 | /* Should make sure we don't seek past the file size */ | ||
595 | gdSeek(infile, header->off); | ||
596 | } | ||
597 | |||
598 | /* The line must be divisible by 4, else its padded with NULLs */ | ||
599 | padding = (1 * info->width) % 4; | ||
600 | if (padding) { | ||
601 | padding = 4 - padding; | ||
602 | } | ||
603 | |||
604 | switch (info->enctype) { | ||
605 | case BMP_BI_RGB: | ||
606 | for (ypos = 0; ypos < info->height; ++ypos) { | ||
607 | if (info->topdown) { | ||
608 | row = ypos; | ||
609 | } else { | ||
610 | row = info->height - ypos - 1; | ||
611 | } | ||
612 | |||
613 | for (xpos = 0; xpos < info->width; ++xpos) { | ||
614 | if (!gdGetByte(&index, infile)) { | ||
615 | return 1; | ||
616 | } | ||
617 | |||
618 | if (im->open[index]) { | ||
619 | im->open[index] = 0; | ||
620 | } | ||
621 | gdImageSetPixel(im, xpos, row, index); | ||
622 | } | ||
623 | /* Could create a new variable, but it isn't really worth it */ | ||
624 | for (xpos = padding; xpos > 0; --xpos) { | ||
625 | if (!gdGetByte(&index, infile)) { | ||
626 | return 1; | ||
627 | } | ||
628 | } | ||
629 | } | ||
630 | break; | ||
631 | |||
632 | case BMP_BI_RLE8: | ||
633 | if (bmp_read_rle(im, infile, info)) { | ||
634 | return 1; | ||
635 | } | ||
636 | break; | ||
637 | |||
638 | default: | ||
639 | return 1; | ||
640 | } | ||
641 | return 0; | ||
642 | } | ||
643 | |||
644 | static int bmp_read_rle(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info) | ||
645 | { | ||
646 | int ypos = 0, xpos = 0, row = 0, index = 0; | ||
647 | int rle_length = 0, rle_data = 0; | ||
648 | int padding = 0; | ||
649 | int i = 0, j = 0; | ||
650 | int pixels_per_byte = 8 / info->depth; | ||
651 | |||
652 | for (ypos = 0; ypos < info->height && xpos <= info->width;) { | ||
653 | if (!gdGetByte(&rle_length, infile) || !gdGetByte(&rle_data, infile)) { | ||
654 | return 1; | ||
655 | } | ||
656 | row = info->height - ypos - 1; | ||
657 | |||
658 | if (rle_length != BMP_RLE_COMMAND) { | ||
659 | if (im->open[rle_data]) { | ||
660 | im->open[rle_data] = 0; | ||
661 | } | ||
662 | |||
663 | for (i = 0; (i < rle_length) && (xpos < info->width);) { | ||
664 | for (j = 1; (j <= pixels_per_byte) && (xpos < info->width) && (i < rle_length); j++, xpos++, i++) { | ||
665 | index = (rle_data & (((1 << info->depth) - 1) << (8 - (j * info->depth)))) >> (8 - (j * info->depth)); | ||
666 | if (im->open[index]) { | ||
667 | im->open[index] = 0; | ||
668 | } | ||
669 | gdImageSetPixel(im, xpos, row, index); | ||
670 | } | ||
671 | } | ||
672 | } else if (rle_length == BMP_RLE_COMMAND && rle_data > 2) { | ||
673 | /* Uncompressed RLE needs to be even */ | ||
674 | padding = 0; | ||
675 | for (i = 0; (i < rle_data) && (xpos < info->width); i += pixels_per_byte) { | ||
676 | int max_pixels = pixels_per_byte; | ||
677 | |||
678 | if (!gdGetByte(&index, infile)) { | ||
679 | return 1; | ||
680 | } | ||
681 | padding++; | ||
682 | |||
683 | if (rle_data - i < max_pixels) { | ||
684 | max_pixels = rle_data - i; | ||
685 | } | ||
686 | |||
687 | for (j = 1; (j <= max_pixels) && (xpos < info->width); j++, xpos++) { | ||
688 | int temp = (index >> (8 - (j * info->depth))) & ((1 << info->depth) - 1); | ||
689 | if (im->open[temp]) { | ||
690 | im->open[temp] = 0; | ||
691 | } | ||
692 | gdImageSetPixel(im, xpos, row, temp); | ||
693 | } | ||
694 | } | ||
695 | |||
696 | /* Make sure the bytes read are even */ | ||
697 | if (padding % 2 && !gdGetByte(&index, infile)) { | ||
698 | return 1; | ||
699 | } | ||
700 | } else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_ENDOFLINE) { | ||
701 | /* Next Line */ | ||
702 | xpos = 0; | ||
703 | ypos++; | ||
704 | } else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_DELTA) { | ||
705 | /* Delta Record, used for bmp files that contain other data*/ | ||
706 | if (!gdGetByte(&rle_length, infile) || !gdGetByte(&rle_data, infile)) { | ||
707 | return 1; | ||
708 | } | ||
709 | xpos += rle_length; | ||
710 | ypos += rle_data; | ||
711 | } else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_ENDOFBITMAP) { | ||
712 | /* End of bitmap */ | ||
713 | break; | ||
714 | } | ||
715 | } | ||
716 | return 0; | ||
717 | } | ||
718 | |||
719 | #if GD_MAJOR_VERSION == 2 && GD_MINOR_VERSION < 1 | ||
720 | static int gdGetWordLSB(signed short int *result, gdIOCtx * ctx) | ||
721 | { | ||
722 | unsigned int high = 0, low = 0; | ||
723 | low = (ctx->getC) (ctx); | ||
724 | if (low == EOF) { | ||
725 | return 0; | ||
726 | } | ||
727 | |||
728 | high = (ctx->getC) (ctx); | ||
729 | if (high == EOF) { | ||
730 | return 0; | ||
731 | } | ||
732 | |||
733 | if (result) { | ||
734 | *result = (high << 8) | low; | ||
735 | } | ||
736 | |||
737 | return 1; | ||
738 | } | ||
739 | |||
740 | static int gdGetIntLSB(signed int *result, gdIOCtx * ctx) | ||
741 | { | ||
742 | int c = 0; | ||
743 | unsigned int r = 0; | ||
744 | |||
745 | c = (ctx->getC) (ctx); | ||
746 | if (c == EOF) { | ||
747 | return 0; | ||
748 | } | ||
749 | r |= (c << 24); | ||
750 | r >>= 8; | ||
751 | |||
752 | c = (ctx->getC) (ctx); | ||
753 | if (c == EOF) { | ||
754 | return 0; | ||
755 | } | ||
756 | r |= (c << 24); | ||
757 | r >>= 8; | ||
758 | |||
759 | c = (ctx->getC) (ctx); | ||
760 | if (c == EOF) { | ||
761 | return 0; | ||
762 | } | ||
763 | r |= (c << 24); | ||
764 | r >>= 8; | ||
765 | |||
766 | c = (ctx->getC) (ctx); | ||
767 | if (c == EOF) { | ||
768 | return 0; | ||
769 | } | ||
770 | r |= (c << 24); | ||
771 | |||
772 | if (result) { | ||
773 | *result = (signed int)r; | ||
774 | } | ||
775 | |||
776 | return 1; | ||
777 | } | ||
778 | #endif | ||