php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
gd_bmp.c
Go to the documentation of this file.
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
28static int compress_row(unsigned char *uncompressed_row, int length);
29static int build_rle_packet(unsigned char *row, int packet_type, int length, unsigned char *data);
30
31static int bmp_read_header(gdIOCtxPtr infile, bmp_hdr_t *hdr);
32static int bmp_read_info(gdIOCtxPtr infile, bmp_info_t *info);
33static int bmp_read_windows_v3_info(gdIOCtxPtr infile, bmp_info_t *info);
34static int bmp_read_os2_v1_info(gdIOCtxPtr infile, bmp_info_t *info);
35static int bmp_read_os2_v2_info(gdIOCtxPtr infile, bmp_info_t *info);
36
37static int bmp_read_direct(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
38static int bmp_read_1bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
39static int bmp_read_4bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
40static int bmp_read_8bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
41static int bmp_read_rle(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info);
42
43#define BMP_DEBUG(s)
44
45static 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
53static 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*/
66void * gdImageBmpPtr(gdImagePtr im, int *size, int compression)
67{
68 void *rv;
70 if (out == NULL) return NULL;
71 gdImageBmpCtx(im, out, compression);
73 out->gd_free(out);
74 return rv;
75}
76
77/*
78 Function: gdImageBmp
79*/
80void 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*/
91void 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 it's 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);
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 */
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
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
276cleanup:
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
292static 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 compressed_length += build_rle_packet(row, rle_type, compressed_run, uncompressed_row);
354 }
355
356 gdFree(uncompressed_start);
357
358 return compressed_length;
359}
360
361static int build_rle_packet(unsigned char *row, int packet_type, int length, unsigned char *data)
362{
363 int compressed_size = 0;
364 if (length < 1 || length > 128) {
365 return 0;
366 }
367
368 /* Bitmap specific cases is that we can't have uncompressed rows of length 1 or 2 */
369 if (packet_type == BMP_RLE_TYPE_RAW && length < 3) {
370 int i = 0;
371 for (i = 0; i < length; i++) {
372 compressed_size += 2;
373 memset(row, 1, 1);
374 row++;
375
376 memcpy(row, data++, 1);
377 row++;
378 }
379 } else if (packet_type == BMP_RLE_TYPE_RLE) {
380 compressed_size = 2;
381 memset(row, length, 1);
382 row++;
383
384 memcpy(row, data, 1);
385 row++;
386 } else {
387 compressed_size = 2 + length;
388 memset(row, BMP_RLE_COMMAND, 1);
389 row++;
390
391 memset(row, length, 1);
392 row++;
393
394 memcpy(row, data, length);
395 row += length;
396
397 /* Must be an even number for an uncompressed run */
398 if (length % 2) {
399 memset(row, 0, 1);
400 row++;
401 compressed_size++;
402 }
403 }
404 return compressed_size;
405}
406
407/*
408 Function: gdImageCreateFromBmp
409*/
411{
412 gdImagePtr im = 0;
413 gdIOCtx *in = gdNewFileCtx(inFile);
414 if (in == NULL) return NULL;
416 in->gd_free(in);
417 return im;
418}
419
420/*
421 Function: gdImageCreateFromBmpPtr
422*/
424{
425 gdImagePtr im;
427 if (in == NULL) return NULL;
429 in->gd_free(in);
430 return im;
431}
432
433/*
434 Function: gdImageCreateFromBmpCtx
435*/
437{
438 bmp_hdr_t *hdr;
439 bmp_info_t *info;
440 gdImagePtr im = NULL;
441 int error = 0;
442
443 if (!(hdr= (bmp_hdr_t *)gdCalloc(1, sizeof(bmp_hdr_t)))) {
444 return NULL;
445 }
446
447 if (bmp_read_header(infile, hdr)) {
448 gdFree(hdr);
449 return NULL;
450 }
451
452 if (hdr->magic != 0x4d42) {
453 gdFree(hdr);
454 return NULL;
455 }
456
457 if (!(info = (bmp_info_t *)gdCalloc(1, sizeof(bmp_info_t)))) {
458 gdFree(hdr);
459 return NULL;
460 }
461
462 if (bmp_read_info(infile, info)) {
463 gdFree(hdr);
464 gdFree(info);
465 return NULL;
466 }
467
468 BMP_DEBUG(printf("Numcolours: %d\n", info->numcolors));
469 BMP_DEBUG(printf("Width: %d\n", info->width));
470 BMP_DEBUG(printf("Height: %d\n", info->height));
471 BMP_DEBUG(printf("Planes: %d\n", info->numplanes));
472 BMP_DEBUG(printf("Depth: %d\n", info->depth));
473 BMP_DEBUG(printf("Offset: %d\n", hdr->off));
474
475 if (info->depth >= 16) {
476 im = gdImageCreateTrueColor(info->width, info->height);
477 } else {
478 im = gdImageCreate(info->width, info->height);
479 }
480
481 if (!im) {
482 gdFree(hdr);
483 gdFree(info);
484 return NULL;
485 }
486
487 switch (info->depth) {
488 case 1:
489 BMP_DEBUG(printf("1-bit image\n"));
490 error = bmp_read_1bit(im, infile, info, hdr);
491 break;
492 case 4:
493 BMP_DEBUG(printf("4-bit image\n"));
494 error = bmp_read_4bit(im, infile, info, hdr);
495 break;
496 case 8:
497 BMP_DEBUG(printf("8-bit image\n"));
498 error = bmp_read_8bit(im, infile, info, hdr);
499 break;
500 case 16:
501 case 24:
502 case 32:
503 BMP_DEBUG(printf("Direct BMP image\n"));
504 error = bmp_read_direct(im, infile, info, hdr);
505 break;
506 default:
507 BMP_DEBUG(printf("Unknown bit count\n"));
508 error = 1;
509 }
510
511 gdFree(hdr);
512 gdFree(info);
513
514 if (error) {
515 gdImageDestroy(im);
516 return NULL;
517 }
518
519 return im;
520}
521
522static int bmp_read_header(gdIOCtx *infile, bmp_hdr_t *hdr)
523{
524 if(
525 !gdGetWordLSB(&hdr->magic, infile) ||
526 !gdGetIntLSB(&hdr->size, infile) ||
527 !gdGetWordLSB(&hdr->reserved1, infile) ||
528 !gdGetWordLSB(&hdr->reserved2 , infile) ||
529 !gdGetIntLSB(&hdr->off , infile)
530 ) {
531 return 1;
532 }
533 return 0;
534}
535
536static int bmp_read_info(gdIOCtx *infile, bmp_info_t *info)
537{
538 /* read BMP length so we can work out the version */
539 if (!gdGetIntLSB(&info->len, infile)) {
540 return 1;
541 }
542
543 switch (info->len) {
544 /* For now treat Windows v4 + v5 as v3 */
545 case BMP_WINDOWS_V3:
546 case BMP_WINDOWS_V4:
547 case BMP_WINDOWS_V5:
548 BMP_DEBUG(printf("Reading Windows Header\n"));
549 if (bmp_read_windows_v3_info(infile, info)) {
550 return 1;
551 }
552 break;
553 case BMP_OS2_V1:
554 if (bmp_read_os2_v1_info(infile, info)) {
555 return 1;
556 }
557 break;
558 case BMP_OS2_V2:
559 if (bmp_read_os2_v2_info(infile, info)) {
560 return 1;
561 }
562 break;
563 default:
564 BMP_DEBUG(printf("Unhandled bitmap\n"));
565 return 1;
566 }
567 return 0;
568}
569
570static int bmp_read_windows_v3_info(gdIOCtxPtr infile, bmp_info_t *info)
571{
572 if (
573 !gdGetIntLSB(&info->width, infile) ||
574 !gdGetIntLSB(&info->height, infile) ||
575 !gdGetWordLSB(&info->numplanes, infile) ||
576 !gdGetWordLSB(&info->depth, infile) ||
577 !gdGetIntLSB(&info->enctype, infile) ||
578 !gdGetIntLSB(&info->size, infile) ||
579 !gdGetIntLSB(&info->hres, infile) ||
580 !gdGetIntLSB(&info->vres, infile) ||
581 !gdGetIntLSB(&info->numcolors, infile) ||
582 !gdGetIntLSB(&info->mincolors, infile)
583 ) {
584 return 1;
585 }
586
587 if (info->height < 0) {
588 info->topdown = 1;
589 info->height = -info->height;
590 } else {
591 info->topdown = 0;
592 }
593
594 info->type = BMP_PALETTE_4;
595
596 if (info->width <= 0 || info->height <= 0 || info->numplanes <= 0 ||
597 info->depth <= 0 || info->numcolors < 0 || info->mincolors < 0) {
598 return 1;
599 }
600
601 return 0;
602}
603
604static int bmp_read_os2_v1_info(gdIOCtxPtr infile, bmp_info_t *info)
605{
606 if (
607 !gdGetWordLSB((signed short int *)&info->width, infile) ||
608 !gdGetWordLSB((signed short int *)&info->height, infile) ||
609 !gdGetWordLSB(&info->numplanes, infile) ||
610 !gdGetWordLSB(&info->depth, infile)
611 ) {
612 return 1;
613 }
614
615 /* OS2 v1 doesn't support topdown */
616 info->topdown = 0;
617
618 info->numcolors = 1 << info->depth;
619 info->type = BMP_PALETTE_3;
620
621 if (info->width <= 0 || info->height <= 0 || info->numplanes <= 0 ||
622 info->depth <= 0 || info->numcolors < 0) {
623 return 1;
624 }
625
626 return 0;
627}
628
629static int bmp_read_os2_v2_info(gdIOCtxPtr infile, bmp_info_t *info)
630{
631 char useless_bytes[24];
632 if (
633 !gdGetIntLSB(&info->width, infile) ||
634 !gdGetIntLSB(&info->height, infile) ||
635 !gdGetWordLSB(&info->numplanes, infile) ||
636 !gdGetWordLSB(&info->depth, infile) ||
637 !gdGetIntLSB(&info->enctype, infile) ||
638 !gdGetIntLSB(&info->size, infile) ||
639 !gdGetIntLSB(&info->hres, infile) ||
640 !gdGetIntLSB(&info->vres, infile) ||
641 !gdGetIntLSB(&info->numcolors, infile) ||
642 !gdGetIntLSB(&info->mincolors, infile)
643 ) {
644 return 1;
645 }
646
647 /* Let's seek the next 24 pointless bytes, we don't care too much about it */
648 if (!gdGetBuf(useless_bytes, 24, infile)) {
649 return 1;
650 }
651
652 if (info->height < 0) {
653 info->topdown = 1;
654 info->height = -info->height;
655 } else {
656 info->topdown = 0;
657 }
658
659 info->type = BMP_PALETTE_4;
660
661 if (info->width <= 0 || info->height <= 0 || info->numplanes <= 0 ||
662 info->depth <= 0 || info->numcolors < 0 || info->mincolors < 0) {
663 return 1;
664 }
665
666
667 return 0;
668}
669
670static int bmp_read_direct(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
671{
672 int ypos = 0, xpos = 0, row = 0;
673 int padding = 0, alpha = 0, red = 0, green = 0, blue = 0;
674 signed short int data = 0;
675
676 switch(info->enctype) {
677 case BMP_BI_RGB:
678 /* no-op */
679 break;
680
681 case BMP_BI_BITFIELDS:
682 if (info->depth == 24) {
683 BMP_DEBUG(printf("Bitfield compression isn't supported for 24-bit\n"));
684 return 1;
685 }
686 BMP_DEBUG(printf("Currently no bitfield support\n"));
687 return 1;
688 break;
689
690 case BMP_BI_RLE8:
691 if (info->depth != 8) {
692 BMP_DEBUG(printf("RLE is only valid for 8-bit images\n"));
693 return 1;
694 }
695 break;
696 case BMP_BI_RLE4:
697 if (info->depth != 4) {
698 BMP_DEBUG(printf("RLE is only valid for 4-bit images\n"));
699 return 1;
700 }
701 break;
702 case BMP_BI_JPEG:
703 case BMP_BI_PNG:
704 default:
705 BMP_DEBUG(printf("Unsupported BMP compression format\n"));
706 return 1;
707 }
708
709 /* There is a chance the data isn't until later, would be weird but it is possible */
710 if (gdTell(infile) != header->off) {
711 /* Should make sure we don't seek past the file size */
712 if (!gdSeek(infile, header->off)) {
713 return 1;
714 }
715 }
716
717 /* The line must be divisible by 4, else it's padded with NULLs */
718 padding = ((int)(info->depth / 8) * info->width) % 4;
719 if (padding) {
720 padding = 4 - padding;
721 }
722
723
724 for (ypos = 0; ypos < info->height; ++ypos) {
725 if (info->topdown) {
726 row = ypos;
727 } else {
728 row = info->height - ypos - 1;
729 }
730
731 for (xpos = 0; xpos < info->width; xpos++) {
732 if (info->depth == 16) {
733 if (!gdGetWordLSB(&data, infile)) {
734 return 1;
735 }
736 BMP_DEBUG(printf("Data: %X\n", data));
737 red = ((data & 0x7C00) >> 10) << 3;
738 green = ((data & 0x3E0) >> 5) << 3;
739 blue = (data & 0x1F) << 3;
740 BMP_DEBUG(printf("R: %d, G: %d, B: %d\n", red, green, blue));
741 } else if (info->depth == 24) {
742 if (!gdGetByte(&blue, infile) || !gdGetByte(&green, infile) || !gdGetByte(&red, infile)) {
743 return 1;
744 }
745 } else {
746 if (!gdGetByte(&blue, infile) || !gdGetByte(&green, infile) || !gdGetByte(&red, infile) || !gdGetByte(&alpha, infile)) {
747 return 1;
748 }
749 }
750 /*alpha = gdAlphaMax - (alpha >> 1);*/
751 gdImageSetPixel(im, xpos, row, gdTrueColor(red, green, blue));
752 }
753 for (xpos = padding; xpos > 0; --xpos) {
754 if (!gdGetByte(&red, infile)) {
755 return 1;
756 }
757 }
758 }
759
760 return 0;
761}
762
763static int bmp_read_palette(gdImagePtr im, gdIOCtxPtr infile, int count, int read_four)
764{
765 int i;
766 int r, g, b, z;
767
768 for (i = 0; i < count; i++) {
769 if (
770 !gdGetByte(&b, infile) ||
771 !gdGetByte(&g, infile) ||
772 !gdGetByte(&r, infile) ||
773 (read_four && !gdGetByte(&z, infile))
774 ) {
775 return 1;
776 }
777 im->red[i] = r;
778 im->green[i] = g;
779 im->blue[i] = b;
780 im->open[i] = 1;
781 }
782 return 0;
783}
784
785static int bmp_read_1bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
786{
787 int ypos = 0, xpos = 0, row = 0, index = 0;
788 int padding = 0, current_byte = 0, bit = 0;
789
790 if (info->enctype != BMP_BI_RGB) {
791 return 1;
792 }
793
794 if (!info->numcolors) {
795 info->numcolors = 2;
796 } else if (info->numcolors < 0 || info->numcolors > 2) {
797 return 1;
798 }
799
800 if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) {
801 return 1;
802 }
803
804 im->colorsTotal = info->numcolors;
805
806 /* There is a chance the data isn't until later, would be weird but it is possible */
807 if (gdTell(infile) != header->off) {
808 /* Should make sure we don't seek past the file size */
809 if (!gdSeek(infile, header->off)) {
810 return 1;
811 }
812 }
813
814 /* The line must be aligned on a 32 bits word, else it is padded with zeros */
815 padding = (info->width + 7) / 8 % 4;
816 if (padding) {
817 padding = 4 - padding;
818 }
819
820 for (ypos = 0; ypos < info->height; ++ypos) {
821 if (info->topdown) {
822 row = ypos;
823 } else {
824 row = info->height - ypos - 1;
825 }
826
827 for (xpos = 0; xpos < info->width; xpos += 8) {
828 /* Bitmaps are always aligned in bytes so we'll never overflow */
829 if (!gdGetByte(&current_byte, infile)) {
830 return 1;
831 }
832
833 for (bit = 0; bit < 8; bit++) {
834 index = ((current_byte & (0x80 >> bit)) != 0 ? 0x01 : 0x00);
835 if (im->open[index]) {
836 im->open[index] = 0;
837 }
838 gdImageSetPixel(im, xpos + bit, row, index);
839 /* No need to read anything extra */
840 if ((xpos + bit) >= info->width) {
841 break;
842 }
843 }
844 }
845
846 for (xpos = padding; xpos > 0; --xpos) {
847 if (!gdGetByte(&index, infile)) {
848 return 1;
849 }
850 }
851 }
852 return 0;
853}
854
855static int bmp_read_4bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
856{
857 int ypos = 0, xpos = 0, row = 0, index = 0;
858 int padding = 0, current_byte = 0;
859
860 if (info->enctype != BMP_BI_RGB && info->enctype != BMP_BI_RLE4) {
861 return 1;
862 }
863
864 if (!info->numcolors) {
865 info->numcolors = 16;
866 } else if (info->numcolors < 0 || info->numcolors > 16) {
867 return 1;
868 }
869
870 if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) {
871 return 1;
872 }
873
874 im->colorsTotal = info->numcolors;
875
876 /* There is a chance the data isn't until later, would be weird but it is possible */
877 if (gdTell(infile) != header->off) {
878 /* Should make sure we don't seek past the file size */
879 if (!gdSeek(infile, header->off)) {
880 return 1;
881 }
882 }
883
884 /* The line must be divisible by 4, else it's padded with NULLs */
885 padding = ((int)ceil(0.5 * info->width)) % 4;
886 if (padding) {
887 padding = 4 - padding;
888 }
889
890 switch (info->enctype) {
891 case BMP_BI_RGB:
892 for (ypos = 0; ypos < info->height; ++ypos) {
893 if (info->topdown) {
894 row = ypos;
895 } else {
896 row = info->height - ypos - 1;
897 }
898
899 for (xpos = 0; xpos < info->width; xpos += 2) {
900 if (!gdGetByte(&current_byte, infile)) {
901 return 1;
902 }
903
904 index = (current_byte >> 4) & 0x0f;
905 if (im->open[index]) {
906 im->open[index] = 0;
907 }
908 gdImageSetPixel(im, xpos, row, index);
909
910 /* This condition may get called often, potential optimsations */
911 if (xpos >= info->width) {
912 break;
913 }
914
915 index = current_byte & 0x0f;
916 if (im->open[index]) {
917 im->open[index] = 0;
918 }
919 gdImageSetPixel(im, xpos + 1, row, index);
920 }
921
922 for (xpos = padding; xpos > 0; --xpos) {
923 if (!gdGetByte(&index, infile)) {
924 return 1;
925 }
926 }
927 }
928 break;
929
930 case BMP_BI_RLE4:
931 if (bmp_read_rle(im, infile, info)) {
932 return 1;
933 }
934 break;
935
936 default:
937 return 1;
938 }
939 return 0;
940}
941
942static int bmp_read_8bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
943{
944 int ypos = 0, xpos = 0, row = 0, index = 0;
945 int padding = 0;
946
947 if (info->enctype != BMP_BI_RGB && info->enctype != BMP_BI_RLE8) {
948 return 1;
949 }
950
951 if (!info->numcolors) {
952 info->numcolors = 256;
953 } else if (info->numcolors < 0 || info->numcolors > 256) {
954 return 1;
955 }
956
957 if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) {
958 return 1;
959 }
960
961 im->colorsTotal = info->numcolors;
962
963 /* There is a chance the data isn't until later, would be weird but it is possible */
964 if (gdTell(infile) != header->off) {
965 /* Should make sure we don't seek past the file size */
966 if (!gdSeek(infile, header->off)) {
967 return 1;
968 }
969 }
970
971 /* The line must be divisible by 4, else it's padded with NULLs */
972 padding = (1 * info->width) % 4;
973 if (padding) {
974 padding = 4 - padding;
975 }
976
977 switch (info->enctype) {
978 case BMP_BI_RGB:
979 for (ypos = 0; ypos < info->height; ++ypos) {
980 if (info->topdown) {
981 row = ypos;
982 } else {
983 row = info->height - ypos - 1;
984 }
985
986 for (xpos = 0; xpos < info->width; ++xpos) {
987 if (!gdGetByte(&index, infile)) {
988 return 1;
989 }
990
991 if (im->open[index]) {
992 im->open[index] = 0;
993 }
994 gdImageSetPixel(im, xpos, row, index);
995 }
996 /* Could create a new variable, but it isn't really worth it */
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_RLE8:
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
1017static int bmp_read_rle(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info)
1018{
1019 int ypos = 0, xpos = 0, row = 0, index = 0;
1020 int rle_length = 0, rle_data = 0;
1021 int padding = 0;
1022 int i = 0, j = 0;
1023 int pixels_per_byte = 8 / info->depth;
1024
1025 for (ypos = 0; ypos < info->height && xpos <= info->width;) {
1026 if (!gdGetByte(&rle_length, infile) || !gdGetByte(&rle_data, infile)) {
1027 return 1;
1028 }
1029 row = info->height - ypos - 1;
1030
1031 if (rle_length != BMP_RLE_COMMAND) {
1032 if (im->open[rle_data]) {
1033 im->open[rle_data] = 0;
1034 }
1035
1036 for (i = 0; (i < rle_length) && (xpos < info->width);) {
1037 for (j = 1; (j <= pixels_per_byte) && (xpos < info->width) && (i < rle_length); j++, xpos++, i++) {
1038 index = (rle_data & (((1 << info->depth) - 1) << (8 - (j * info->depth)))) >> (8 - (j * info->depth));
1039 if (im->open[index]) {
1040 im->open[index] = 0;
1041 }
1042 gdImageSetPixel(im, xpos, row, index);
1043 }
1044 }
1045 } else if (rle_length == BMP_RLE_COMMAND && rle_data > 2) {
1046 /* Uncompressed RLE needs to be even */
1047 padding = 0;
1048 for (i = 0; (i < rle_data) && (xpos < info->width); i += pixels_per_byte) {
1049 int max_pixels = pixels_per_byte;
1050
1051 if (!gdGetByte(&index, infile)) {
1052 return 1;
1053 }
1054 padding++;
1055
1056 if (rle_data - i < max_pixels) {
1057 max_pixels = rle_data - i;
1058 }
1059
1060 for (j = 1; (j <= max_pixels) && (xpos < info->width); j++, xpos++) {
1061 int temp = (index >> (8 - (j * info->depth))) & ((1 << info->depth) - 1);
1062 if (im->open[temp]) {
1063 im->open[temp] = 0;
1064 }
1065 gdImageSetPixel(im, xpos, row, temp);
1066 }
1067 }
1068
1069 /* Make sure the bytes read are even */
1070 if (padding % 2 && !gdGetByte(&index, infile)) {
1071 return 1;
1072 }
1073 } else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_ENDOFLINE) {
1074 /* Next Line */
1075 xpos = 0;
1076 ypos++;
1077 } else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_DELTA) {
1078 /* Delta Record, used for bmp files that contain other data*/
1079 if (!gdGetByte(&rle_length, infile) || !gdGetByte(&rle_data, infile)) {
1080 return 1;
1081 }
1082 xpos += rle_length;
1083 ypos += rle_data;
1084 } else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_ENDOFBITMAP) {
1085 /* End of bitmap */
1086 break;
1087 }
1088 }
1089 return 0;
1090}
printf(string $format, mixed ... $values)
fclose($stream)
header(string $header, bool $replace=true, int $response_code=0)
count(Countable|array $value, int $mode=COUNT_NORMAL)
ceil(int|float $num)
#define BMP_RLE_ENDOFBITMAP
Definition bmp.h:43
#define BMP_RLE_TYPE_RAW
Definition bmp.h:46
#define BMP_RLE_TYPE_RLE
Definition bmp.h:47
#define BMP_BI_PNG
Definition bmp.h:39
#define BMP_RLE_DELTA
Definition bmp.h:44
#define BMP_BI_BITFIELDS
Definition bmp.h:37
#define BMP_OS2_V1
Definition bmp.h:29
#define BMP_RLE_COMMAND
Definition bmp.h:41
#define BMP_WINDOWS_V4
Definition bmp.h:31
#define BMP_PALETTE_4
Definition bmp.h:26
#define BMP_PALETTE_3
Definition bmp.h:25
#define BMP_BI_RLE8
Definition bmp.h:35
#define BMP_BI_RLE4
Definition bmp.h:36
#define BMP_BI_JPEG
Definition bmp.h:38
#define BMP_RLE_ENDOFLINE
Definition bmp.h:42
#define BMP_BI_RGB
Definition bmp.h:34
#define BMP_WINDOWS_V5
Definition bmp.h:32
#define BMP_WINDOWS_V3
Definition bmp.h:28
#define BMP_OS2_V2
Definition bmp.h:30
error($message)
Definition ext_skel.php:22
new_type size
Definition ffi.c:4365
memcpy(ptr1, ptr2, size)
memset(ptr, 0, type->size)
#define gdImageBlue(im, c)
Definition gd.h:775
#define gdTrueColorGetBlue(c)
Definition gd.h:88
void * gdDPExtractData(struct gdIOCtx *ctx, int *size)
Definition gd_io_dp.c:95
#define gdTrueColorGetGreen(c)
Definition gd.h:87
#define gdTrueColorGetRed(c)
Definition gd.h:86
#define gdImageSX(im)
Definition gd.h:768
gdIOCtx * gdNewFileCtx(FILE *)
Definition gd_io_file.c:49
#define gdImageGreen(im, c)
Definition gd.h:773
gdIOCtx * gdNewDynamicCtx(int, void *)
Definition gd_io_dp.c:65
#define gdTrueColor(r, g, b)
Definition gd.h:537
gdIOCtx * gdNewDynamicCtxEx(int size, void *data, int freeFlag)
Definition gd_io_dp.c:70
#define gdImageRed(im, c)
Definition gd.h:771
gdImage * gdImagePtr
Definition gd.h:248
void * gdImageBmpPtr(gdImagePtr im, int *size, int compression)
Definition gd_bmp.c:66
void gdImageBmp(gdImagePtr im, FILE *outFile, int compression)
Definition gd_bmp.c:80
gdImagePtr gdImageCreateFromBmpCtx(gdIOCtxPtr infile)
Definition gd_bmp.c:436
gdImagePtr gdImageCreateFromBmpPtr(int size, void *data)
Definition gd_bmp.c:423
gdImagePtr gdImageCreateFromBmp(FILE *inFile)
Definition gd_bmp.c:410
void gdImageBmpCtx(gdImagePtr im, gdIOCtxPtr out, int compression)
Definition gd_bmp.c:91
#define BMP_DEBUG(s)
Definition gd_bmp.c:43
int gdGetIntLSB(signed int *result, gdIOCtx *ctx)
Definition gd_io.c:142
long gdTell(gdIOCtx *ctx)
Definition gd_io.c:200
int gdGetBuf(void *buf, int size, gdIOCtx *ctx)
Definition gd_io.c:188
int gdSeek(gdIOCtx *ctx, const int pos)
Definition gd_io.c:193
void Putchar(int c, gdIOCtx *ctx)
Definition gd_io.c:43
int gdGetByte(int *result, gdIOCtx *ctx)
Definition gd_io.c:76
int gdPutBuf(const void *buf, int size, gdIOCtx *ctx)
Definition gd_io.c:181
void gdPutC(const unsigned char c, gdIOCtx *ctx)
Definition gd_io.c:48
int gdGetWordLSB(signed short int *result, gdIOCtx *ctx)
Definition gd_io.c:98
struct gdIOCtx * gdIOCtxPtr
Definition gd_io.h:25
#define NULL
Definition gdcache.h:45
#define gdFree(ptr)
Definition gdhelpers.h:19
#define gdCalloc(nmemb, size)
Definition gdhelpers.h:15
#define gdMalloc(size)
Definition gdhelpers.h:16
again j
gdImagePtr gdImageCreate(int sx, int sy)
Definition gd.c:141
int gdImageGetPixel(gdImagePtr im, int x, int y)
Definition gd.c:953
void gdImageDestroy(gdImagePtr im)
Definition gd.c:247
gdImagePtr gdImageCreateTrueColor(int sx, int sy)
Definition gd.c:195
void gdImageSetPixel(gdImagePtr im, int x, int y, int color)
Definition gd.c:733
zend_constant * data
zval rv
Definition session.c:1024
signed short int reserved2
Definition bmp.h:59
signed int off
Definition bmp.h:62
int size
Definition bmp.h:55
signed short int magic
Definition bmp.h:52
signed short int reserved1
Definition bmp.h:58
signed int hres
Definition bmp.h:95
signed int vres
Definition bmp.h:98
signed short int numplanes
Definition bmp.h:83
signed int mincolors
Definition bmp.h:104
signed short int depth
Definition bmp.h:86
signed char topdown
Definition bmp.h:80
signed int width
Definition bmp.h:74
signed int height
Definition bmp.h:77
signed int size
Definition bmp.h:92
signed short int type
Definition bmp.h:69
signed int numcolors
Definition bmp.h:101
signed int enctype
Definition bmp.h:89
signed int len
Definition bmp.h:71
void(* gd_free)(struct gdIOCtx *)
Definition gd_io.h:20
int trueColor
Definition gd.h:217
int red[gdMaxColors]
Definition gd.h:179
int blue[gdMaxColors]
Definition gd.h:181
int open[gdMaxColors]
Definition gd.h:182
int sy
Definition gd.h:174
int sx
Definition gd.h:173
int green[gdMaxColors]
Definition gd.h:180
int colorsTotal
Definition gd.h:178
out($f, $s)