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