1 /*
2 gd_bmp.c
3
4 Bitmap format support for libgd
5
6 * Written 2007, Scott MacVicar
7 ---------------------------------------------------------------------------
8
9 Todo:
10
11 Bitfield encoding
12
13 ----------------------------------------------------------------------------
14 */
15
16 /**
17 * File: BMP IO
18 *
19 * Read and write BMP images.
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <stdio.h>
27 #include <limits.h>
28 #include <math.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include "gd.h"
32 #include "gdhelpers.h"
33 #include "bmp.h"
34
35 static int compress_row(unsigned char *uncompressed_row, int length);
36 static int build_rle_packet(unsigned char *row, int packet_type, int length, unsigned char *data);
37
38 static int bmp_read_header(gdIOCtxPtr infile, bmp_hdr_t *hdr);
39 static int bmp_read_info(gdIOCtxPtr infile, bmp_info_t *info);
40 static int bmp_read_windows_v3_info(gdIOCtxPtr infile, bmp_info_t *info);
41 static int bmp_read_os2_v1_info(gdIOCtxPtr infile, bmp_info_t *info);
42 static int bmp_read_os2_v2_info(gdIOCtxPtr infile, bmp_info_t *info);
43
44 static int bmp_read_direct(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
45 static int bmp_read_1bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
46 static int bmp_read_4bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
47 static int bmp_read_8bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
48 static int bmp_read_rle(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info);
49
50 static int _gdImageBmpCtx(gdImagePtr im, gdIOCtxPtr out, int compression);
51
52 #define BMP_DEBUG(s)
53
gdBMPPutWord(gdIOCtx * out,int w)54 static int gdBMPPutWord(gdIOCtx *out, int w)
55 {
56 /* Byte order is little-endian */
57 gdPutC(w & 0xFF, out);
58 gdPutC((w >> 8) & 0xFF, out);
59 return 0;
60 }
61
gdBMPPutInt(gdIOCtx * out,int w)62 static int gdBMPPutInt(gdIOCtx *out, int w)
63 {
64 /* Byte order is little-endian */
65 gdPutC(w & 0xFF, out);
66 gdPutC((w >> 8) & 0xFF, out);
67 gdPutC((w >> 16) & 0xFF, out);
68 gdPutC((w >> 24) & 0xFF, out);
69 return 0;
70 }
71
72 /*
73 Function: gdImageBmpPtr
74
75 Outputs the given image as BMP data, but using a <gdIOCtx> instead
76 of a file. See <gdImageBmp>.
77
78 Parameters:
79 im - the image to save.
80 size - Output: size in bytes of the result.
81 compression - whether to apply RLE or not.
82
83 Returns:
84
85 A pointer to memory containing the image data or NULL on error.
86 */
gdImageBmpPtr(gdImagePtr im,int * size,int compression)87 BGD_DECLARE(void *) gdImageBmpPtr(gdImagePtr im, int *size, int compression)
88 {
89 void *rv;
90 gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
91 if (out == NULL) return NULL;
92 if (!_gdImageBmpCtx(im, out, compression))
93 rv = gdDPExtractData(out, size);
94 else
95 rv = NULL;
96 out->gd_free(out);
97 return rv;
98 }
99
100 /*
101 Function: gdImageBmp
102
103 <gdImageBmp> outputs the specified image to the specified file in
104 BMP format. The file must be open for writing. Under MSDOS and all
105 versions of Windows, it is important to use "wb" as opposed to
106 simply "w" as the mode when opening the file, and under Unix there
107 is no penalty for doing so. <gdImageBmp> does not close the file;
108 your code must do so.
109
110 In addition, <gdImageBmp> allows to specify whether RLE compression
111 should be applied.
112
113 Variants:
114
115 <gdImageBmpCtx> write via a <gdIOCtx> instead of a file handle.
116
117 <gdImageBmpPtr> store the image file to memory.
118
119 Parameters:
120
121 im - the image to save.
122 outFile - the output FILE* object.
123 compression - whether to apply RLE or not.
124
125 Returns:
126 nothing
127 */
gdImageBmp(gdImagePtr im,FILE * outFile,int compression)128 BGD_DECLARE(void) gdImageBmp(gdImagePtr im, FILE *outFile, int compression)
129 {
130 gdIOCtx *out = gdNewFileCtx(outFile);
131 if (out == NULL) return;
132 gdImageBmpCtx(im, out, compression);
133 out->gd_free(out);
134 }
135
136 /*
137 Function: gdImageBmpCtx
138
139 Outputs the given image as BMP data, but using a <gdIOCtx> instead
140 of a file. See <gdImageBmp>.
141
142 Parameters:
143 im - the image to save.
144 out - the <gdIOCtx> to write to.
145 compression - whether to apply RLE or not.
146 */
gdImageBmpCtx(gdImagePtr im,gdIOCtxPtr out,int compression)147 BGD_DECLARE(void) gdImageBmpCtx(gdImagePtr im, gdIOCtxPtr out, int compression)
148 {
149 _gdImageBmpCtx(im, out, compression);
150 }
151
_gdImageBmpCtx(gdImagePtr im,gdIOCtxPtr out,int compression)152 static int _gdImageBmpCtx(gdImagePtr im, gdIOCtxPtr out, int compression)
153 {
154 int bitmap_size = 0, info_size, total_size, padding;
155 int i, row, xpos, pixel;
156 int error = 0;
157 unsigned char *uncompressed_row = NULL, *uncompressed_row_start = NULL;
158 FILE *tmpfile_for_compression = NULL;
159 gdIOCtxPtr out_original = NULL;
160 int ret = 1;
161
162 /* No compression if its true colour or we don't support seek */
163 if (im->trueColor) {
164 compression = 0;
165 }
166
167 if (compression && !out->seek) {
168 /* Try to create a temp file where we can seek */
169 if ((tmpfile_for_compression = tmpfile()) == NULL) {
170 compression = 0;
171 } else {
172 out_original = out;
173 if ((out = (gdIOCtxPtr)gdNewFileCtx(tmpfile_for_compression)) == NULL) {
174 out = out_original;
175 out_original = NULL;
176 compression = 0;
177 }
178 }
179 }
180
181 bitmap_size = ((im->sx * (im->trueColor ? 24 : 8)) / 8) * im->sy;
182
183 /* 40 byte Windows v3 header */
184 info_size = BMP_WINDOWS_V3;
185
186 /* data for the palette */
187 if (!im->trueColor) {
188 info_size += im->colorsTotal * 4;
189 if (compression) {
190 bitmap_size = 0;
191 }
192 }
193
194 /* bitmap header + info header + data */
195 total_size = 14 + info_size + bitmap_size;
196
197 /* write bmp header info */
198 gdPutBuf("BM", 2, out);
199 gdBMPPutInt(out, total_size);
200 gdBMPPutWord(out, 0);
201 gdBMPPutWord(out, 0);
202 gdBMPPutInt(out, 14 + info_size);
203
204 /* write Windows v3 headers */
205 gdBMPPutInt(out, BMP_WINDOWS_V3); /* header size */
206 gdBMPPutInt(out, im->sx); /* width */
207 gdBMPPutInt(out, im->sy); /* height */
208 gdBMPPutWord(out, 1); /* colour planes */
209 gdBMPPutWord(out, (im->trueColor ? 24 : 8)); /* bit count */
210 gdBMPPutInt(out, (compression ? BMP_BI_RLE8 : BMP_BI_RGB)); /* compression */
211 gdBMPPutInt(out, bitmap_size); /* image size */
212 gdBMPPutInt(out, 0); /* H resolution */
213 gdBMPPutInt(out, 0); /* V ressolution */
214 gdBMPPutInt(out, im->colorsTotal); /* colours used */
215 gdBMPPutInt(out, 0); /* important colours */
216
217 /* The line must be divisible by 4, else its padded with NULLs */
218 padding = ((int)(im->trueColor ? 3 : 1) * im->sx) % 4;
219 if (padding) {
220 padding = 4 - padding;
221 }
222
223 /* 8-bit colours */
224 if (!im->trueColor) {
225 for(i = 0; i< im->colorsTotal; ++i) {
226 gdPutC(gdImageBlue(im, i), out);
227 gdPutC(gdImageGreen(im, i), out);
228 gdPutC(gdImageRed(im, i), out);
229 gdPutC(0, out);
230 }
231
232 if (compression) {
233 /* Can potentially change this to X + ((X / 128) * 3) */
234 uncompressed_row = uncompressed_row_start = (unsigned char *) gdCalloc(gdImageSX(im) * 2, sizeof(char));
235 if (!uncompressed_row) {
236 /* malloc failed */
237 goto cleanup;
238 }
239 }
240
241 for (row = (im->sy - 1); row >= 0; row--) {
242 if (compression) {
243 memset (uncompressed_row, 0, gdImageSX(im));
244 }
245
246 for (xpos = 0; xpos < im->sx; xpos++) {
247 if (compression) {
248 *uncompressed_row++ = (unsigned char)gdImageGetPixel(im, xpos, row);
249 } else {
250 gdPutC(gdImageGetPixel(im, xpos, row), out);
251 }
252 }
253
254 if (!compression) {
255 /* Add padding to make sure we have n mod 4 == 0 bytes per row */
256 for (xpos = padding; xpos > 0; --xpos) {
257 gdPutC('\0', out);
258 }
259 } else {
260 int compressed_size = 0;
261 uncompressed_row = uncompressed_row_start;
262 if ((compressed_size = compress_row(uncompressed_row, gdImageSX(im))) < 0) {
263 error = 1;
264 break;
265 }
266 bitmap_size += compressed_size;
267
268
269 gdPutBuf(uncompressed_row, compressed_size, out);
270 gdPutC(BMP_RLE_COMMAND, out);
271 gdPutC(BMP_RLE_ENDOFLINE, out);
272 bitmap_size += 2;
273 }
274 }
275
276 if (compression && uncompressed_row) {
277 gdFree(uncompressed_row);
278 if (error != 0) {
279 goto cleanup;
280 }
281 /* Update filesize based on new values and set compression flag */
282 gdPutC(BMP_RLE_COMMAND, out);
283 gdPutC(BMP_RLE_ENDOFBITMAP, out);
284 bitmap_size += 2;
285
286 /* Write new total bitmap size */
287 gdSeek(out, 2);
288 gdBMPPutInt(out, total_size + bitmap_size);
289
290 /* Total length of image data */
291 gdSeek(out, 34);
292 gdBMPPutInt(out, bitmap_size);
293 }
294
295 } else {
296 for (row = (im->sy - 1); row >= 0; row--) {
297 for (xpos = 0; xpos < im->sx; xpos++) {
298 pixel = gdImageGetPixel(im, xpos, row);
299
300 gdPutC(gdTrueColorGetBlue(pixel), out);
301 gdPutC(gdTrueColorGetGreen(pixel), out);
302 gdPutC(gdTrueColorGetRed(pixel), out);
303 }
304
305 /* Add padding to make sure we have n mod 4 == 0 bytes per row */
306 for (xpos = padding; xpos > 0; --xpos) {
307 gdPutC('\0', out);
308 }
309 }
310 }
311
312
313 /* If we needed a tmpfile for compression copy it over to out_original */
314 if (tmpfile_for_compression) {
315 unsigned char* copy_buffer = NULL;
316 int buffer_size = 0;
317
318 gdSeek(out, 0);
319 copy_buffer = (unsigned char *) gdMalloc(1024 * sizeof(unsigned char));
320 if (copy_buffer == NULL) {
321 goto cleanup;
322 }
323
324 while ((buffer_size = gdGetBuf(copy_buffer, 1024, out)) != EOF) {
325 if (buffer_size == 0) {
326 break;
327 }
328 gdPutBuf(copy_buffer , buffer_size, out_original);
329 }
330 gdFree(copy_buffer);
331
332 /* Replace the temp with the original which now has data */
333 out->gd_free(out);
334 out = out_original;
335 out_original = NULL;
336 }
337
338 ret = 0;
339 cleanup:
340 if (tmpfile_for_compression) {
341 #ifdef _WIN32
342 _rmtmp();
343 #else
344 fclose(tmpfile_for_compression);
345 #endif
346 tmpfile_for_compression = NULL;
347 }
348
349 if (out_original) {
350 out_original->gd_free(out_original);
351 }
352 return ret;
353 }
354
compress_row(unsigned char * row,int length)355 static int compress_row(unsigned char *row, int length)
356 {
357 int rle_type = 0;
358 int compressed_length = 0;
359 int pixel = 0, compressed_run = 0, rle_compression = 0;
360 unsigned char *uncompressed_row = NULL, *uncompressed_rowp = NULL, *uncompressed_start = NULL;
361
362 uncompressed_row = (unsigned char *) gdMalloc(length);
363 if (!uncompressed_row) {
364 return -1;
365 }
366
367 memcpy(uncompressed_row, row, length);
368 uncompressed_start = uncompressed_rowp = uncompressed_row;
369
370 for (pixel = 0; pixel < length; pixel++) {
371 if (compressed_run == 0) {
372 uncompressed_row = uncompressed_rowp;
373 compressed_run++;
374 uncompressed_rowp++;
375 rle_type = BMP_RLE_TYPE_RAW;
376 continue;
377 }
378
379 if (compressed_run == 1) {
380 /* Compare next byte */
381 if (memcmp(uncompressed_rowp, uncompressed_rowp - 1, 1) == 0) {
382 rle_type = BMP_RLE_TYPE_RLE;
383 }
384 }
385
386 if (rle_type == BMP_RLE_TYPE_RLE) {
387 if (compressed_run >= 128 || memcmp(uncompressed_rowp, uncompressed_rowp - 1, 1) != 0) {
388 /* more than what we can store in a single run or run is over due to non match, force write */
389 rle_compression = build_rle_packet(row, rle_type, compressed_run, uncompressed_row);
390 row += rle_compression;
391 compressed_length += rle_compression;
392 compressed_run = 0;
393 pixel--;
394 } else {
395 compressed_run++;
396 uncompressed_rowp++;
397 }
398 } else {
399 if (compressed_run >= 128 || memcmp(uncompressed_rowp, uncompressed_rowp - 1, 1) == 0) {
400 /* more than what we can store in a single run or run is over due to match, force write */
401 rle_compression = build_rle_packet(row, rle_type, compressed_run, uncompressed_row);
402 row += rle_compression;
403 compressed_length += rle_compression;
404 compressed_run = 0;
405 pixel--;
406 } else {
407 /* add this pixel to the row */
408 compressed_run++;
409 uncompressed_rowp++;
410 }
411
412 }
413 }
414
415 if (compressed_run) {
416 compressed_length += build_rle_packet(row, rle_type, compressed_run, uncompressed_row);
417 }
418
419 gdFree(uncompressed_start);
420
421 return compressed_length;
422 }
423
build_rle_packet(unsigned char * row,int packet_type,int length,unsigned char * data)424 static int build_rle_packet(unsigned char *row, int packet_type, int length, unsigned char *data)
425 {
426 int compressed_size = 0;
427 if (length < 1 || length > 128) {
428 return 0;
429 }
430
431 /* Bitmap specific cases is that we can't have uncompressed rows of length 1 or 2 */
432 if (packet_type == BMP_RLE_TYPE_RAW && length < 3) {
433 int i = 0;
434 for (i = 0; i < length; i++) {
435 compressed_size += 2;
436 memset(row, 1, 1);
437 row++;
438
439 memcpy(row, data++, 1);
440 row++;
441 }
442 } else if (packet_type == BMP_RLE_TYPE_RLE) {
443 compressed_size = 2;
444 memset(row, length, 1);
445 row++;
446
447 memcpy(row, data, 1);
448 row++;
449 } else {
450 compressed_size = 2 + length;
451 memset(row, BMP_RLE_COMMAND, 1);
452 row++;
453
454 memset(row, length, 1);
455 row++;
456
457 memcpy(row, data, length);
458 row += length;
459
460 /* Must be an even number for an uncompressed run */
461 if (length % 2) {
462 memset(row, 0, 1);
463 row++;
464 compressed_size++;
465 }
466 }
467 return compressed_size;
468 }
469
470 /*
471 Function: gdImageCreateFromBmp
472 */
gdImageCreateFromBmp(FILE * inFile)473 BGD_DECLARE(gdImagePtr) gdImageCreateFromBmp(FILE * inFile)
474 {
475 gdImagePtr im = 0;
476 gdIOCtx *in = gdNewFileCtx(inFile);
477 if (in == NULL) return NULL;
478 im = gdImageCreateFromBmpCtx(in);
479 in->gd_free(in);
480 return im;
481 }
482
483 /*
484 Function: gdImageCreateFromBmpPtr
485 */
gdImageCreateFromBmpPtr(int size,void * data)486 BGD_DECLARE(gdImagePtr) gdImageCreateFromBmpPtr(int size, void *data)
487 {
488 gdImagePtr im;
489 gdIOCtx *in = gdNewDynamicCtxEx(size, data, 0);
490 if (in == NULL) return NULL;
491 im = gdImageCreateFromBmpCtx(in);
492 in->gd_free(in);
493 return im;
494 }
495
496 /*
497 Function: gdImageCreateFromBmpCtx
498 */
gdImageCreateFromBmpCtx(gdIOCtxPtr infile)499 BGD_DECLARE(gdImagePtr) gdImageCreateFromBmpCtx(gdIOCtxPtr infile)
500 {
501 bmp_hdr_t *hdr;
502 bmp_info_t *info;
503 gdImagePtr im = NULL;
504 int error = 0;
505
506 if (!(hdr= (bmp_hdr_t *)gdCalloc(1, sizeof(bmp_hdr_t)))) {
507 return NULL;
508 }
509
510 if (bmp_read_header(infile, hdr)) {
511 gdFree(hdr);
512 return NULL;
513 }
514
515 if (hdr->magic != 0x4d42) {
516 gdFree(hdr);
517 return NULL;
518 }
519
520 if (!(info = (bmp_info_t *)gdCalloc(1, sizeof(bmp_info_t)))) {
521 gdFree(hdr);
522 return NULL;
523 }
524
525 if (bmp_read_info(infile, info)) {
526 gdFree(hdr);
527 gdFree(info);
528 return NULL;
529 }
530
531 BMP_DEBUG(printf("Numcolours: %d\n", info->numcolors));
532 BMP_DEBUG(printf("Width: %d\n", info->width));
533 BMP_DEBUG(printf("Height: %d\n", info->height));
534 BMP_DEBUG(printf("Planes: %d\n", info->numplanes));
535 BMP_DEBUG(printf("Depth: %d\n", info->depth));
536 BMP_DEBUG(printf("Offset: %d\n", hdr->off));
537
538 if (info->depth >= 16) {
539 im = gdImageCreateTrueColor(info->width, info->height);
540 } else {
541 im = gdImageCreate(info->width, info->height);
542 }
543
544 if (!im) {
545 gdFree(hdr);
546 gdFree(info);
547 return NULL;
548 }
549
550 switch (info->depth) {
551 case 1:
552 BMP_DEBUG(printf("1-bit image\n"));
553 error = bmp_read_1bit(im, infile, info, hdr);
554 break;
555 case 4:
556 BMP_DEBUG(printf("4-bit image\n"));
557 error = bmp_read_4bit(im, infile, info, hdr);
558 break;
559 case 8:
560 BMP_DEBUG(printf("8-bit image\n"));
561 error = bmp_read_8bit(im, infile, info, hdr);
562 break;
563 case 16:
564 case 24:
565 case 32:
566 BMP_DEBUG(printf("Direct BMP image\n"));
567 error = bmp_read_direct(im, infile, info, hdr);
568 break;
569 default:
570 BMP_DEBUG(printf("Unknown bit count\n"));
571 error = 1;
572 }
573
574 gdFree(hdr);
575 gdFree(info);
576
577 if (error) {
578 gdImageDestroy(im);
579 return NULL;
580 }
581
582 return im;
583 }
584
bmp_read_header(gdIOCtx * infile,bmp_hdr_t * hdr)585 static int bmp_read_header(gdIOCtx *infile, bmp_hdr_t *hdr)
586 {
587 if(
588 !gdGetWordLSB(&hdr->magic, infile) ||
589 !gdGetIntLSB(&hdr->size, infile) ||
590 !gdGetWordLSB(&hdr->reserved1, infile) ||
591 !gdGetWordLSB(&hdr->reserved2 , infile) ||
592 !gdGetIntLSB(&hdr->off , infile)
593 ) {
594 return 1;
595 }
596 return 0;
597 }
598
bmp_read_info(gdIOCtx * infile,bmp_info_t * info)599 static int bmp_read_info(gdIOCtx *infile, bmp_info_t *info)
600 {
601 /* read BMP length so we can work out the version */
602 if (!gdGetIntLSB(&info->len, infile)) {
603 return 1;
604 }
605
606 switch (info->len) {
607 /* For now treat Windows v4 + v5 as v3 */
608 case BMP_WINDOWS_V3:
609 case BMP_WINDOWS_V4:
610 case BMP_WINDOWS_V5:
611 BMP_DEBUG(printf("Reading Windows Header\n"));
612 if (bmp_read_windows_v3_info(infile, info)) {
613 return 1;
614 }
615 break;
616 case BMP_OS2_V1:
617 if (bmp_read_os2_v1_info(infile, info)) {
618 return 1;
619 }
620 break;
621 case BMP_OS2_V2:
622 if (bmp_read_os2_v2_info(infile, info)) {
623 return 1;
624 }
625 break;
626 default:
627 BMP_DEBUG(printf("Unhandled bitmap\n"));
628 return 1;
629 }
630 return 0;
631 }
632
bmp_read_windows_v3_info(gdIOCtxPtr infile,bmp_info_t * info)633 static int bmp_read_windows_v3_info(gdIOCtxPtr infile, bmp_info_t *info)
634 {
635 if (
636 !gdGetIntLSB(&info->width, infile) ||
637 !gdGetIntLSB(&info->height, infile) ||
638 !gdGetWordLSB(&info->numplanes, infile) ||
639 !gdGetWordLSB(&info->depth, infile) ||
640 !gdGetIntLSB(&info->enctype, infile) ||
641 !gdGetIntLSB(&info->size, infile) ||
642 !gdGetIntLSB(&info->hres, infile) ||
643 !gdGetIntLSB(&info->vres, infile) ||
644 !gdGetIntLSB(&info->numcolors, infile) ||
645 !gdGetIntLSB(&info->mincolors, infile)
646 ) {
647 return 1;
648 }
649
650 /* Unlikely, but possible -- largest signed value won't fit in unsigned. */
651 if (info->height == 0 || info->height == INT_MIN)
652 return 1;
653 if (info->height < 0) {
654 info->topdown = 1;
655 info->height = -info->height;
656 } else {
657 info->topdown = 0;
658 }
659
660 info->type = BMP_PALETTE_4;
661
662 /* Height was checked above. */
663 if (info->width <= 0 || info->numplanes <= 0 || info->depth <= 0 ||
664 info->numcolors < 0 || info->mincolors < 0) {
665 return 1;
666 }
667
668 return 0;
669 }
670
bmp_read_os2_v1_info(gdIOCtxPtr infile,bmp_info_t * info)671 static int bmp_read_os2_v1_info(gdIOCtxPtr infile, bmp_info_t *info)
672 {
673 if (
674 !gdGetWordLSB((signed short int *)&info->width, infile) ||
675 !gdGetWordLSB((signed short int *)&info->height, infile) ||
676 !gdGetWordLSB(&info->numplanes, infile) ||
677 !gdGetWordLSB(&info->depth, infile)
678 ) {
679 return 1;
680 }
681
682 /* OS2 v1 doesn't support topdown */
683 info->topdown = 0;
684
685 /* The spec says the depth can only be a few value values. */
686 if (info->depth != 1 && info->depth != 4 && info->depth != 8 &&
687 info->depth != 16 && info->depth != 24) {
688 return 1;
689 }
690
691 info->numcolors = 1 << info->depth;
692 info->type = BMP_PALETTE_3;
693
694 if (info->width <= 0 || info->height <= 0 || info->numplanes <= 0) {
695 return 1;
696 }
697
698 return 0;
699 }
700
bmp_read_os2_v2_info(gdIOCtxPtr infile,bmp_info_t * info)701 static int bmp_read_os2_v2_info(gdIOCtxPtr infile, bmp_info_t *info)
702 {
703 char useless_bytes[24];
704 if (
705 !gdGetIntLSB(&info->width, infile) ||
706 !gdGetIntLSB(&info->height, infile) ||
707 !gdGetWordLSB(&info->numplanes, infile) ||
708 !gdGetWordLSB(&info->depth, infile) ||
709 !gdGetIntLSB(&info->enctype, infile) ||
710 !gdGetIntLSB(&info->size, infile) ||
711 !gdGetIntLSB(&info->hres, infile) ||
712 !gdGetIntLSB(&info->vres, infile) ||
713 !gdGetIntLSB(&info->numcolors, infile) ||
714 !gdGetIntLSB(&info->mincolors, infile)
715 ) {
716 return 1;
717 }
718
719 /* Lets seek the next 24 pointless bytes, we don't care too much about it */
720 if (!gdGetBuf(useless_bytes, 24, infile)) {
721 return 1;
722 }
723
724 /* Unlikely, but possible -- largest signed value won't fit in unsigned. */
725 if (info->height == 0 || info->height == INT_MIN)
726 return 1;
727 if (info->height < 0) {
728 info->topdown = 1;
729 info->height = -info->height;
730 } else {
731 info->topdown = 0;
732 }
733
734 info->type = BMP_PALETTE_4;
735
736 /* Height was checked above. */
737 if (info->width <= 0 || info->numplanes <= 0 || info->depth <= 0 ||
738 info->numcolors < 0 || info->mincolors < 0) {
739 return 1;
740 }
741
742 return 0;
743 }
744
bmp_read_direct(gdImagePtr im,gdIOCtxPtr infile,bmp_info_t * info,bmp_hdr_t * header)745 static int bmp_read_direct(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
746 {
747 int ypos = 0, xpos = 0, row = 0;
748 int padding = 0, alpha = 0, red = 0, green = 0, blue = 0;
749 signed short int data = 0;
750
751 switch(info->enctype) {
752 case BMP_BI_RGB:
753 /* no-op */
754 break;
755
756 case BMP_BI_BITFIELDS:
757 if (info->depth == 24) {
758 BMP_DEBUG(printf("Bitfield compression isn't supported for 24-bit\n"));
759 return 1;
760 }
761 BMP_DEBUG(printf("Currently no bitfield support\n"));
762 return 1;
763 break;
764
765 case BMP_BI_RLE8:
766 if (info->depth != 8) {
767 BMP_DEBUG(printf("RLE is only valid for 8-bit images\n"));
768 return 1;
769 }
770 break;
771 case BMP_BI_RLE4:
772 if (info->depth != 4) {
773 BMP_DEBUG(printf("RLE is only valid for 4-bit images\n"));
774 return 1;
775 }
776 break;
777 case BMP_BI_JPEG:
778 case BMP_BI_PNG:
779 default:
780 BMP_DEBUG(printf("Unsupported BMP compression format\n"));
781 return 1;
782 }
783
784 /* There is a chance the data isn't until later, would be weird but it is possible */
785 if (gdTell(infile) != header->off) {
786 /* Should make sure we don't seek past the file size */
787 if (!gdSeek(infile, header->off)) {
788 return 1;
789 }
790 }
791
792 /* The line must be divisible by 4, else its padded with NULLs */
793 padding = ((int)(info->depth / 8) * info->width) % 4;
794 if (padding) {
795 padding = 4 - padding;
796 }
797
798
799 for (ypos = 0; ypos < info->height; ++ypos) {
800 if (info->topdown) {
801 row = ypos;
802 } else {
803 row = info->height - ypos - 1;
804 }
805
806 for (xpos = 0; xpos < info->width; xpos++) {
807 if (info->depth == 16) {
808 if (!gdGetWordLSB(&data, infile)) {
809 return 1;
810 }
811 BMP_DEBUG(printf("Data: %X\n", data));
812 red = ((data & 0x7C00) >> 10) << 3;
813 green = ((data & 0x3E0) >> 5) << 3;
814 blue = (data & 0x1F) << 3;
815 BMP_DEBUG(printf("R: %d, G: %d, B: %d\n", red, green, blue));
816 } else if (info->depth == 24) {
817 if (!gdGetByte(&blue, infile) || !gdGetByte(&green, infile) || !gdGetByte(&red, infile)) {
818 return 1;
819 }
820 } else {
821 if (!gdGetByte(&blue, infile) || !gdGetByte(&green, infile) || !gdGetByte(&red, infile) || !gdGetByte(&alpha, infile)) {
822 return 1;
823 }
824 }
825 /*alpha = gdAlphaMax - (alpha >> 1);*/
826 gdImageSetPixel(im, xpos, row, gdTrueColor(red, green, blue));
827 }
828 for (xpos = padding; xpos > 0; --xpos) {
829 if (!gdGetByte(&red, infile)) {
830 return 1;
831 }
832 }
833 }
834
835 return 0;
836 }
837
bmp_read_palette(gdImagePtr im,gdIOCtxPtr infile,int count,int read_four)838 static int bmp_read_palette(gdImagePtr im, gdIOCtxPtr infile, int count, int read_four)
839 {
840 int i;
841 int r, g, b, z;
842
843 for (i = 0; i < count; i++) {
844 if (
845 !gdGetByte(&b, infile) ||
846 !gdGetByte(&g, infile) ||
847 !gdGetByte(&r, infile) ||
848 (read_four && !gdGetByte(&z, infile))
849 ) {
850 return 1;
851 }
852 im->red[i] = r;
853 im->green[i] = g;
854 im->blue[i] = b;
855 im->open[i] = 1;
856 }
857 return 0;
858 }
859
bmp_read_1bit(gdImagePtr im,gdIOCtxPtr infile,bmp_info_t * info,bmp_hdr_t * header)860 static int bmp_read_1bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
861 {
862 int ypos = 0, xpos = 0, row = 0, index = 0;
863 int padding = 0, current_byte = 0, bit = 0;
864
865 if (info->enctype != BMP_BI_RGB) {
866 return 1;
867 }
868
869 if (!info->numcolors) {
870 info->numcolors = 2;
871 } else if (info->numcolors < 0 || info->numcolors > 2) {
872 return 1;
873 }
874
875 if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) {
876 return 1;
877 }
878
879 im->colorsTotal = info->numcolors;
880
881 /* There is a chance the data isn't until later, would be weird but it is possible */
882 if (gdTell(infile) != header->off) {
883 /* Should make sure we don't seek past the file size */
884 if (!gdSeek(infile, header->off)) {
885 return 1;
886 }
887 }
888
889 /* The line must be aligned on a 32 bits word, else it is padded with zeros */
890 padding = (info->width + 7) / 8 % 4;
891 if (padding) {
892 padding = 4 - padding;
893 }
894
895 for (ypos = 0; ypos < info->height; ++ypos) {
896 if (info->topdown) {
897 row = ypos;
898 } else {
899 row = info->height - ypos - 1;
900 }
901
902 for (xpos = 0; xpos < info->width; xpos += 8) {
903 /* Bitmaps are always aligned in bytes so we'll never overflow */
904 if (!gdGetByte(¤t_byte, infile)) {
905 return 1;
906 }
907
908 for (bit = 0; bit < 8; bit++) {
909 index = ((current_byte & (0x80 >> bit)) != 0 ? 0x01 : 0x00);
910 if (im->open[index]) {
911 im->open[index] = 0;
912 }
913 gdImageSetPixel(im, xpos + bit, row, index);
914 /* No need to read anything extra */
915 if ((xpos + bit) >= info->width) {
916 break;
917 }
918 }
919 }
920
921 for (xpos = padding; xpos > 0; --xpos) {
922 if (!gdGetByte(&index, infile)) {
923 return 1;
924 }
925 }
926 }
927 return 0;
928 }
929
bmp_read_4bit(gdImagePtr im,gdIOCtxPtr infile,bmp_info_t * info,bmp_hdr_t * header)930 static int bmp_read_4bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
931 {
932 int ypos = 0, xpos = 0, row = 0, index = 0;
933 int padding = 0, current_byte = 0;
934
935 if (info->enctype != BMP_BI_RGB && info->enctype != BMP_BI_RLE4) {
936 return 1;
937 }
938
939 if (!info->numcolors) {
940 info->numcolors = 16;
941 } else if (info->numcolors < 0 || info->numcolors > 16) {
942 return 1;
943 }
944
945 if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) {
946 return 1;
947 }
948
949 im->colorsTotal = info->numcolors;
950
951 /* There is a chance the data isn't until later, would be weird but it is possible */
952 if (gdTell(infile) != header->off) {
953 /* Should make sure we don't seek past the file size */
954 if (!gdSeek(infile, header->off)) {
955 return 1;
956 }
957 }
958
959 /* The line must be divisible by 4, else its padded with NULLs */
960 padding = ((int)ceil(0.5 * info->width)) % 4;
961 if (padding) {
962 padding = 4 - padding;
963 }
964
965 switch (info->enctype) {
966 case BMP_BI_RGB:
967 for (ypos = 0; ypos < info->height; ++ypos) {
968 if (info->topdown) {
969 row = ypos;
970 } else {
971 row = info->height - ypos - 1;
972 }
973
974 for (xpos = 0; xpos < info->width; xpos += 2) {
975 if (!gdGetByte(¤t_byte, infile)) {
976 return 1;
977 }
978
979 index = (current_byte >> 4) & 0x0f;
980 if (im->open[index]) {
981 im->open[index] = 0;
982 }
983 gdImageSetPixel(im, xpos, row, index);
984
985 /* This condition may get called often, potential optimsations */
986 if (xpos >= info->width) {
987 break;
988 }
989
990 index = current_byte & 0x0f;
991 if (im->open[index]) {
992 im->open[index] = 0;
993 }
994 gdImageSetPixel(im, xpos + 1, row, index);
995 }
996
997 for (xpos = padding; xpos > 0; --xpos) {
998 if (!gdGetByte(&index, infile)) {
999 return 1;
1000 }
1001 }
1002 }
1003 break;
1004
1005 case BMP_BI_RLE4:
1006 if (bmp_read_rle(im, infile, info)) {
1007 return 1;
1008 }
1009 break;
1010
1011 default:
1012 return 1;
1013 }
1014 return 0;
1015 }
1016
bmp_read_8bit(gdImagePtr im,gdIOCtxPtr infile,bmp_info_t * info,bmp_hdr_t * header)1017 static int bmp_read_8bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
1018 {
1019 int ypos = 0, xpos = 0, row = 0, index = 0;
1020 int padding = 0;
1021
1022 if (info->enctype != BMP_BI_RGB && info->enctype != BMP_BI_RLE8) {
1023 return 1;
1024 }
1025
1026 if (!info->numcolors) {
1027 info->numcolors = 256;
1028 } else if (info->numcolors < 0 || info->numcolors > 256) {
1029 return 1;
1030 }
1031
1032 if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) {
1033 return 1;
1034 }
1035
1036 im->colorsTotal = info->numcolors;
1037
1038 /* There is a chance the data isn't until later, would be weird but it is possible */
1039 if (gdTell(infile) != header->off) {
1040 /* Should make sure we don't seek past the file size */
1041 if (!gdSeek(infile, header->off)) {
1042 return 1;
1043 }
1044 }
1045
1046 /* The line must be divisible by 4, else its padded with NULLs */
1047 padding = (1 * info->width) % 4;
1048 if (padding) {
1049 padding = 4 - padding;
1050 }
1051
1052 switch (info->enctype) {
1053 case BMP_BI_RGB:
1054 for (ypos = 0; ypos < info->height; ++ypos) {
1055 if (info->topdown) {
1056 row = ypos;
1057 } else {
1058 row = info->height - ypos - 1;
1059 }
1060
1061 for (xpos = 0; xpos < info->width; ++xpos) {
1062 if (!gdGetByte(&index, infile)) {
1063 return 1;
1064 }
1065
1066 if (im->open[index]) {
1067 im->open[index] = 0;
1068 }
1069 gdImageSetPixel(im, xpos, row, index);
1070 }
1071 /* Could create a new variable, but it isn't really worth it */
1072 for (xpos = padding; xpos > 0; --xpos) {
1073 if (!gdGetByte(&index, infile)) {
1074 return 1;
1075 }
1076 }
1077 }
1078 break;
1079
1080 case BMP_BI_RLE8:
1081 if (bmp_read_rle(im, infile, info)) {
1082 return 1;
1083 }
1084 break;
1085
1086 default:
1087 return 1;
1088 }
1089 return 0;
1090 }
1091
bmp_read_rle(gdImagePtr im,gdIOCtxPtr infile,bmp_info_t * info)1092 static int bmp_read_rle(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info)
1093 {
1094 int ypos = 0, xpos = 0, row = 0, index = 0;
1095 int rle_length = 0, rle_data = 0;
1096 int padding = 0;
1097 int i = 0, j = 0;
1098 int pixels_per_byte = 8 / info->depth;
1099
1100 for (ypos = 0; ypos < info->height && xpos <= info->width;) {
1101 if (!gdGetByte(&rle_length, infile) || !gdGetByte(&rle_data, infile)) {
1102 return 1;
1103 }
1104 row = info->height - ypos - 1;
1105
1106 if (rle_length != BMP_RLE_COMMAND) {
1107 if (im->open[rle_data]) {
1108 im->open[rle_data] = 0;
1109 }
1110
1111 for (i = 0; (i < rle_length) && (xpos < info->width);) {
1112 for (j = 1; (j <= pixels_per_byte) && (xpos < info->width) && (i < rle_length); j++, xpos++, i++) {
1113 index = (rle_data & (((1 << info->depth) - 1) << (8 - (j * info->depth)))) >> (8 - (j * info->depth));
1114 if (im->open[index]) {
1115 im->open[index] = 0;
1116 }
1117 gdImageSetPixel(im, xpos, row, index);
1118 }
1119 }
1120 } else if (rle_length == BMP_RLE_COMMAND && rle_data > 2) {
1121 /* Uncompressed RLE needs to be even */
1122 padding = 0;
1123 for (i = 0; (i < rle_data) && (xpos < info->width); i += pixels_per_byte) {
1124 int max_pixels = pixels_per_byte;
1125
1126 if (!gdGetByte(&index, infile)) {
1127 return 1;
1128 }
1129 padding++;
1130
1131 if (rle_data - i < max_pixels) {
1132 max_pixels = rle_data - i;
1133 }
1134
1135 for (j = 1; (j <= max_pixels) && (xpos < info->width); j++, xpos++) {
1136 int temp = (index >> (8 - (j * info->depth))) & ((1 << info->depth) - 1);
1137 if (im->open[temp]) {
1138 im->open[temp] = 0;
1139 }
1140 gdImageSetPixel(im, xpos, row, temp);
1141 }
1142 }
1143
1144 /* Make sure the bytes read are even */
1145 if (padding % 2 && !gdGetByte(&index, infile)) {
1146 return 1;
1147 }
1148 } else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_ENDOFLINE) {
1149 /* Next Line */
1150 xpos = 0;
1151 ypos++;
1152 } else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_DELTA) {
1153 /* Delta Record, used for bmp files that contain other data*/
1154 if (!gdGetByte(&rle_length, infile) || !gdGetByte(&rle_data, infile)) {
1155 return 1;
1156 }
1157 xpos += rle_length;
1158 ypos += rle_data;
1159 } else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_ENDOFBITMAP) {
1160 /* End of bitmap */
1161 break;
1162 }
1163 }
1164 return 0;
1165 }
1166