rgd 0.4.1a-x86-mingw32

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