long delayed renaming of m_fatal() to i_fatal() to match Imager's
[imager.git] / bmp.c
CommitLineData
261f91c5 1#include <stdarg.h>
92bda632 2#include "imageri.h"
261f91c5 3
705fd961
TC
4/*
5=head1 NAME
261f91c5 6
705fd961
TC
7bmp.c - read and write windows BMP files
8
9=head1 SYNOPSIS
10
11 i_img *im;
12 io_glue *ig;
13
14 if (!i_writebmp_wiol(im, ig)) {
15 ... error ...
16 }
17 im = i_readbmp(ig);
18
19=head1 DESCRIPTION
20
21Reads and writes Windows BMP files.
22
23=over
24
25=cut
26*/
27
28#define FILEHEAD_SIZE 14
29#define INFOHEAD_SIZE 40
30#define BI_RGB 0
31#define BI_RLE8 1
32#define BI_RLE4 2
33#define BI_BITFIELDS 3
34#define BMPRLE_ENDOFLINE 0
35#define BMPRLE_ENDOFBMP 1
36#define BMPRLE_DELTA 2
37
38static int read_packed(io_glue *ig, char *format, ...);
39static int write_packed(io_glue *ig, char *format, ...);
40static int write_bmphead(io_glue *ig, i_img *im, int bit_count,
41 int data_size);
42static int write_1bit_data(io_glue *ig, i_img *im);
43static int write_4bit_data(io_glue *ig, i_img *im);
44static int write_8bit_data(io_glue *ig, i_img *im);
45static int write_24bit_data(io_glue *ig, i_img *im);
46static int read_bmp_pal(io_glue *ig, i_img *im, int count);
662e3c02 47static i_img *read_1bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used,
403946c6 48 int compression, long offbits);
705fd961 49static i_img *read_4bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used,
403946c6 50 int compression, long offbits);
705fd961 51static i_img *read_8bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used,
403946c6 52 int compression, long offbits);
705fd961 53static i_img *read_direct_bmp(io_glue *ig, int xsize, int ysize,
403946c6
TC
54 int bit_count, int clr_used, int compression,
55 long offbits);
705fd961
TC
56
57/*
58=item i_writebmp_wiol(im, io_glue)
59
60Writes the image as a BMP file. Uses 1-bit, 4-bit, 8-bit or 24-bit
61formats depending on the image.
62
63Never compresses the image.
64
65=cut
66*/
67int
68i_writebmp_wiol(i_img *im, io_glue *ig) {
69 io_glue_commit_types(ig);
70 i_clear_error();
71
72 /* pick a format */
73 if (im->type == i_direct_type) {
74 return write_24bit_data(ig, im);
75 }
76 else {
77 int pal_size;
78
79 /* must be paletted */
80 pal_size = i_colorcount(im);
81 if (pal_size <= 2) {
82 return write_1bit_data(ig, im);
83 }
84 else if (pal_size <= 16) {
85 return write_4bit_data(ig, im);
86 }
87 else {
88 return write_8bit_data(ig, im);
89 }
90 }
91}
92
93/*
94=item i_readbmp_wiol(ig)
95
96Reads a Windows format bitmap from the given file.
97
98Handles BI_RLE4 and BI_RLE8 compressed images. Attempts to handle
99BI_BITFIELDS images too, but I need a test image.
100
101=cut
102*/
103
104i_img *
105i_readbmp_wiol(io_glue *ig) {
662e3c02 106 int b_magic, m_magic, filesize, res1, res2, infohead_size;
705fd961
TC
107 int xsize, ysize, planes, bit_count, compression, size_image, xres, yres;
108 int clr_used, clr_important, offbits;
109 i_img *im;
662e3c02
TC
110
111 mm_log((1, "i_readbmp_wiol(ig %p)\n", ig));
705fd961
TC
112
113 io_glue_commit_types(ig);
114 i_clear_error();
115
116 if (!read_packed(ig, "CCVvvVVVVvvVVVVVV", &b_magic, &m_magic, &filesize,
662e3c02 117 &res1, &res2, &offbits, &infohead_size,
705fd961
TC
118 &xsize, &ysize, &planes,
119 &bit_count, &compression, &size_image, &xres, &yres,
120 &clr_used, &clr_important)) {
121 i_push_error(0, "file too short");
122 return 0;
123 }
124 if (b_magic != 'B' || m_magic != 'M' || infohead_size != INFOHEAD_SIZE
125 || planes != 1) {
126 i_push_error(0, "not a BMP file");
127 return 0;
128 }
662e3c02
TC
129
130 mm_log((1, " bmp header: filesize %d offbits %d xsize %d ysize %d planes %d "
131 "bit_count %d compression %d size %d xres %d yres %d clr_used %d "
132 "clr_important %d\n", filesize, offbits, xsize, ysize, planes,
133 bit_count, compression, size_image, xres, yres, clr_used,
134 clr_important));
77157728
TC
135
136 if (!i_int_check_image_file_limits(xsize, ysize, 3, sizeof(i_sample_t))) {
137 mm_log((1, "i_readbmp_wiol: image size exceeds limits\n"));
138 return NULL;
139 }
705fd961
TC
140
141 switch (bit_count) {
142 case 1:
403946c6 143 im = read_1bit_bmp(ig, xsize, ysize, clr_used, compression, offbits);
705fd961
TC
144 break;
145
146 case 4:
403946c6 147 im = read_4bit_bmp(ig, xsize, ysize, clr_used, compression, offbits);
705fd961
TC
148 break;
149
150 case 8:
403946c6 151 im = read_8bit_bmp(ig, xsize, ysize, clr_used, compression, offbits);
705fd961
TC
152 break;
153
154 case 32:
155 case 24:
156 case 16:
403946c6
TC
157 im = read_direct_bmp(ig, xsize, ysize, bit_count, clr_used, compression,
158 offbits);
705fd961 159 break;
efdc2568
TC
160
161 default:
162 i_push_errorf(0, "unknown bit count for BMP file (%d)", bit_count);
163 return NULL;
705fd961
TC
164 }
165
662e3c02
TC
166 if (im) {
167 /* store the resolution */
168 if (xres && !yres)
169 yres = xres;
170 else if (yres && !xres)
171 xres = yres;
172 if (xres) {
2e41e30b
TC
173 i_tags_set_float2(&im->tags, "i_xres", 0, xres * 0.0254, 4);
174 i_tags_set_float2(&im->tags, "i_yres", 0, yres * 0.0254, 4);
662e3c02
TC
175 }
176 i_tags_addn(&im->tags, "bmp_compression", 0, compression);
177 i_tags_addn(&im->tags, "bmp_important_colors", 0, clr_important);
178 i_tags_addn(&im->tags, "bmp_used_colors", 0, clr_used);
179 i_tags_addn(&im->tags, "bmp_filesize", 0, filesize);
180 i_tags_addn(&im->tags, "bmp_bit_count", 0, bit_count);
181 i_tags_add(&im->tags, "i_format", 0, "bmp", 3, 0);
705fd961 182 }
705fd961
TC
183
184 return im;
185}
186
187/*
188=back
189
190=head1 IMPLEMENTATION FUNCTIONS
191
192Internal functions used in the implementation.
193
194=over
195
196=item read_packed(ig, format, ...)
197
198Reads from the specified "file" the specified sizes. The format codes
199match those used by perl's pack() function, though only a few are
200implemented. In all cases the vararg arguement is an int *.
201
202Returns non-zero if all of the arguments were read.
203
204=cut
261f91c5
TC
205*/
206static
207int read_packed(io_glue *ig, char *format, ...) {
208 unsigned char buf[4];
209 va_list ap;
210 int *p;
211
212 va_start(ap, format);
213
214 while (*format) {
215 p = va_arg(ap, int *);
216
217 switch (*format) {
218 case 'v':
662e3c02 219 if (ig->readcb(ig, buf, 2) != 2)
261f91c5
TC
220 return 0;
221 *p = buf[0] + (buf[1] << 8);
222 break;
223
224 case 'V':
662e3c02 225 if (ig->readcb(ig, buf, 4) != 4)
261f91c5
TC
226 return 0;
227 *p = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24);
228 break;
229
230 case 'C':
662e3c02 231 if (ig->readcb(ig, buf, 1) != 1)
261f91c5
TC
232 return 0;
233 *p = buf[0];
234 break;
235
236 case 'c':
662e3c02 237 if (ig->readcb(ig, buf, 1) != 1)
261f91c5
TC
238 return 0;
239 *p = (char)buf[0];
240 break;
241
705fd961 242 case '3': /* extension - 24-bit number */
662e3c02 243 if (ig->readcb(ig, buf, 3) != 3)
705fd961
TC
244 return 0;
245 *p = buf[0] + (buf[1] << 8) + (buf[2] << 16);
246 break;
247
261f91c5 248 default:
b1e96952 249 i_fatal(1, "Unknown read_packed format code 0x%02x", *format);
261f91c5
TC
250 }
251 ++format;
252 }
253 return 1;
254}
255
705fd961
TC
256/*
257=item write_packed(ig, format, ...)
258
259Writes packed data to the specified io_glue.
260
261Returns non-zero on success.
262
263=cut
264*/
265
261f91c5
TC
266static int
267write_packed(io_glue *ig, char *format, ...) {
268 unsigned char buf[4];
269 va_list ap;
270 int i;
271
272 va_start(ap, format);
273
274 while (*format) {
275 i = va_arg(ap, unsigned int);
276
277 switch (*format) {
278 case 'v':
279 buf[0] = i & 255;
280 buf[1] = i / 256;
281 if (ig->writecb(ig, buf, 2) == -1)
282 return 0;
283 break;
284
285 case 'V':
286 buf[0] = i & 0xFF;
287 buf[1] = (i >> 8) & 0xFF;
288 buf[2] = (i >> 16) & 0xFF;
289 buf[3] = (i >> 24) & 0xFF;
290 if (ig->writecb(ig, buf, 4) == -1)
291 return 0;
292 break;
293
294 case 'C':
295 case 'c':
296 buf[0] = i & 0xFF;
297 if (ig->writecb(ig, buf, 1) == -1)
298 return 0;
299 break;
300
301 default:
b1e96952 302 i_fatal(1, "Unknown write_packed format code 0x%02x", *format);
261f91c5
TC
303 }
304 ++format;
305 }
306 va_end(ap);
307
308 return 1;
309}
310
705fd961
TC
311/*
312=item write_bmphead(ig, im, bit_count, data_size)
313
314Writes a Windows BMP header to the file.
315
316Returns non-zero on success.
317
318=cut
319*/
261f91c5
TC
320
321static
322int write_bmphead(io_glue *ig, i_img *im, int bit_count, int data_size) {
323 double xres, yres;
324 int got_xres, got_yres, aspect_only;
325 int colors_used = 0;
326 int offset = FILEHEAD_SIZE + INFOHEAD_SIZE;
327
328 got_xres = i_tags_get_float(&im->tags, "i_xres", 0, &xres);
329 got_yres = i_tags_get_float(&im->tags, "i_yres", 0, &yres);
330 if (!i_tags_get_int(&im->tags, "i_aspect_only", 0,&aspect_only))
331 aspect_only = 0;
332 if (!got_xres) {
333 if (!got_yres)
334 xres = yres = 72;
335 else
336 xres = yres;
337 }
338 else {
339 if (!got_yres)
340 yres = xres;
341 }
342 if (xres <= 0 || yres <= 0)
343 xres = yres = 72;
344 if (aspect_only) {
345 /* scale so the smaller value is 72 */
346 double ratio;
347 if (xres < yres) {
348 ratio = 72.0 / xres;
349 }
350 else {
351 ratio = 72.0 / yres;
352 }
353 xres *= ratio;
354 yres *= ratio;
355 }
356 /* now to pels/meter */
357 xres *= 100.0/2.54;
358 yres *= 100.0/2.54;
359
360 if (im->type == i_palette_type) {
361 colors_used = i_colorcount(im);
362 offset += 4 * colors_used;
363 }
364
365 if (!write_packed(ig, "CCVvvVVVVvvVVVVVV", 'B', 'M', data_size+offset,
366 0, 0, offset, INFOHEAD_SIZE, im->xsize, im->ysize, 1,
705fd961
TC
367 bit_count, BI_RGB, 0, (int)(xres+0.5), (int)(yres+0.5),
368 colors_used, colors_used)){
261f91c5
TC
369 i_push_error(0, "cannot write bmp header");
370 return 0;
371 }
372 if (im->type == i_palette_type) {
373 int i;
374 i_color c;
375
376 for (i = 0; i < colors_used; ++i) {
377 i_getcolors(im, i, &c, 1);
378 if (im->channels >= 3) {
379 if (!write_packed(ig, "CCCC", c.channel[2], c.channel[1],
380 c.channel[0], 0)) {
381 i_push_error(0, "cannot write palette entry");
382 return 0;
383 }
384 }
385 else {
386 if (!write_packed(ig, "CCCC", c.channel[0], c.channel[0],
387 c.channel[0], 0)) {
388 i_push_error(0, "cannot write palette entry");
389 return 0;
390 }
391 }
392 }
393 }
394
395 return 1;
396}
397
705fd961
TC
398/*
399=item write_1bit_data(ig, im)
400
401Writes the image data as a 1-bit/pixel image.
402
403Returns non-zero on success.
404
405=cut
406*/
261f91c5
TC
407static int
408write_1bit_data(io_glue *ig, i_img *im) {
409 i_palidx *line;
410 unsigned char *packed;
411 int byte;
412 int mask;
413 unsigned char *out;
414 int line_size = (im->xsize+7) / 8;
415 int x, y;
f0960b14 416 int unpacked_size;
261f91c5
TC
417
418 /* round up to nearest multiple of four */
419 line_size = (line_size + 3) / 4 * 4;
420
421 if (!write_bmphead(ig, im, 1, line_size * im->ysize))
422 return 0;
423
f0960b14
TC
424 /* this shouldn't be an issue, but let's be careful */
425 unpacked_size = im->xsize + 8;
426 if (unpacked_size < im->xsize) {
427 i_push_error(0, "integer overflow during memory allocation");
428 return 0;
429 }
430 line = mymalloc(unpacked_size); /* checked 29jun05 tonyc */
261f91c5 431 memset(line + im->xsize, 0, 8);
f0960b14
TC
432
433 /* size allocated here is always much smaller than xsize, hence
434 can't overflow int */
435 packed = mymalloc(line_size); /* checked 29jun05 tonyc */
261f91c5
TC
436 memset(packed, 0, line_size);
437
438 for (y = im->ysize-1; y >= 0; --y) {
439 i_gpal(im, 0, im->xsize, y, line);
440 mask = 0x80;
441 byte = 0;
442 out = packed;
443 for (x = 0; x < im->xsize; ++x) {
444 if (line[x])
445 byte |= mask;
446 if ((mask >>= 1) == 0) {
447 *out++ = byte;
448 byte = 0;
449 mask = 0x80;
450 }
451 }
452 if (mask != 0x80) {
453 *out++ = byte;
454 }
455 if (ig->writecb(ig, packed, line_size) < 0) {
456 myfree(packed);
457 myfree(line);
458 i_push_error(0, "writing 1 bit/pixel packed data");
459 return 0;
460 }
461 }
462 myfree(packed);
463 myfree(line);
464
10461f9a
TC
465 ig->closecb(ig);
466
261f91c5
TC
467 return 1;
468}
469
705fd961
TC
470/*
471=item write_4bit_data(ig, im)
472
473Writes the image data as a 4-bit/pixel image.
474
475Returns non-zero on success.
476
477=cut
478*/
261f91c5
TC
479static int
480write_4bit_data(io_glue *ig, i_img *im) {
481 i_palidx *line;
482 unsigned char *packed;
483 unsigned char *out;
484 int line_size = (im->xsize+1) / 2;
485 int x, y;
f0960b14 486 int unpacked_size;
261f91c5
TC
487
488 /* round up to nearest multiple of four */
489 line_size = (line_size + 3) / 4 * 4;
490
491 if (!write_bmphead(ig, im, 4, line_size * im->ysize))
492 return 0;
493
f0960b14
TC
494 /* this shouldn't be an issue, but let's be careful */
495 unpacked_size = im->xsize + 2;
496 if (unpacked_size < im->xsize) {
497 i_push_error(0, "integer overflow during memory allocation");
498 return 0;
499 }
500 line = mymalloc(unpacked_size); /* checked 29jun05 tonyc */
261f91c5
TC
501 memset(line + im->xsize, 0, 2);
502
f0960b14
TC
503 /* size allocated here is always much smaller than xsize, hence
504 can't overflow int */
505 packed = mymalloc(line_size); /* checked 29jun05 tonyc */
261f91c5
TC
506 memset(packed, 0, line_size);
507
508 for (y = im->ysize-1; y >= 0; --y) {
509 i_gpal(im, 0, im->xsize, y, line);
510 out = packed;
511 for (x = 0; x < im->xsize; x += 2) {
512 *out++ = (line[x] << 4) + line[x+1];
513 }
514 if (ig->writecb(ig, packed, line_size) < 0) {
515 myfree(packed);
516 myfree(line);
517 i_push_error(0, "writing 4 bit/pixel packed data");
518 return 0;
519 }
520 }
521 myfree(packed);
522 myfree(line);
523
10461f9a
TC
524 ig->closecb(ig);
525
261f91c5
TC
526 return 1;
527}
528
705fd961
TC
529/*
530=item write_8bit_data(ig, im)
531
532Writes the image data as a 8-bit/pixel image.
533
534Returns non-zero on success.
535
536=cut
537*/
261f91c5
TC
538static int
539write_8bit_data(io_glue *ig, i_img *im) {
540 i_palidx *line;
541 int line_size = im->xsize;
a659442a 542 int y;
f0960b14 543 int unpacked_size;
261f91c5
TC
544
545 /* round up to nearest multiple of four */
546 line_size = (line_size + 3) / 4 * 4;
547
548 if (!write_bmphead(ig, im, 8, line_size * im->ysize))
549 return 0;
550
f0960b14
TC
551 /* this shouldn't be an issue, but let's be careful */
552 unpacked_size = im->xsize + 4;
553 if (unpacked_size < im->xsize) {
554 i_push_error(0, "integer overflow during memory allocation");
555 return 0;
556 }
557 line = mymalloc(unpacked_size); /* checked 29jun05 tonyc */
261f91c5
TC
558 memset(line + im->xsize, 0, 4);
559
560 for (y = im->ysize-1; y >= 0; --y) {
561 i_gpal(im, 0, im->xsize, y, line);
562 if (ig->writecb(ig, line, line_size) < 0) {
563 myfree(line);
564 i_push_error(0, "writing 8 bit/pixel packed data");
565 return 0;
566 }
567 }
568 myfree(line);
569
10461f9a
TC
570 ig->closecb(ig);
571
261f91c5
TC
572 return 1;
573}
574
575static int bgr_chans[] = { 2, 1, 0, };
576static int grey_chans[] = { 0, 0, 0, };
577
705fd961
TC
578/*
579=item write_24bit_data(ig, im)
580
581Writes the image data as a 24-bit/pixel image.
582
583Returns non-zero on success.
584
585=cut
586*/
261f91c5
TC
587static int
588write_24bit_data(io_glue *ig, i_img *im) {
589 int *chans;
590 unsigned char *samples;
a659442a 591 int y;
261f91c5 592 int line_size = 3 * im->xsize;
f0960b14
TC
593
594 /* just in case we implement a direct format with 2bytes/pixel
595 (unlikely though) */
596 if (line_size / 3 != im->xsize) {
597 i_push_error(0, "integer overflow during memory allocation");
598 return 0;
599 }
261f91c5
TC
600
601 line_size = (line_size + 3) / 4 * 4;
602
603 if (!write_bmphead(ig, im, 24, line_size * im->ysize))
604 return 0;
605 chans = im->channels >= 3 ? bgr_chans : grey_chans;
f0960b14 606 samples = mymalloc(line_size); /* checked 29jun05 tonyc */
10461f9a 607 memset(samples, 0, line_size);
261f91c5
TC
608 for (y = im->ysize-1; y >= 0; --y) {
609 i_gsamp(im, 0, im->xsize, y, samples, chans, 3);
610 if (ig->writecb(ig, samples, line_size) < 0) {
611 i_push_error(0, "writing image data");
612 myfree(samples);
613 return 0;
614 }
615 }
616 myfree(samples);
617
10461f9a
TC
618 ig->closecb(ig);
619
261f91c5
TC
620 return 1;
621}
622
705fd961
TC
623/*
624=item read_bmp_pal(ig, im, count)
261f91c5 625
705fd961 626Reads count palette entries from the file and add them to the image.
261f91c5 627
705fd961 628Returns non-zero on success.
261f91c5 629
705fd961
TC
630=cut
631*/
261f91c5
TC
632static int
633read_bmp_pal(io_glue *ig, i_img *im, int count) {
634 int i;
635 int r, g, b, x;
636 i_color c;
637
638 for (i = 0; i < count; ++i) {
639 if (!read_packed(ig, "CCCC", &b, &g, &r, &x)) {
640 i_push_error(0, "reading BMP palette");
641 return 0;
642 }
643 c.channel[0] = r;
644 c.channel[1] = g;
645 c.channel[2] = b;
662e3c02
TC
646 if (i_addcolors(im, &c, 1) < 0) {
647 i_push_error(0, "out of space in image palette");
261f91c5 648 return 0;
662e3c02 649 }
261f91c5
TC
650 }
651
652 return 1;
653}
654
705fd961 655/*
403946c6 656=item read_1bit_bmp(ig, xsize, ysize, clr_used, compression, offbits)
705fd961
TC
657
658Reads in the palette and image data for a 1-bit/pixel image.
659
660Returns the image or NULL.
661
662=cut
663*/
261f91c5 664static i_img *
662e3c02 665read_1bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used,
403946c6 666 int compression, long offbits) {
261f91c5
TC
667 i_img *im;
668 int x, y, lasty, yinc;
669 i_palidx *line, *p;
670 unsigned char *packed;
671 int line_size = (xsize + 7)/8;
a659442a 672 int bit;
261f91c5 673 unsigned char *in;
403946c6 674 long base_offset;
261f91c5 675
662e3c02
TC
676 if (compression != BI_RGB) {
677 i_push_errorf(0, "unknown 1-bit BMP compression (%d)", compression);
678 return NULL;
679 }
680
f0960b14
TC
681 if (xsize + 8 < xsize) { /* if there was overflow */
682 /* we check with 8 because we allocate that much for the decoded
683 line buffer */
684 i_push_error(0, "integer overflow during memory allocation");
685 return NULL;
686 }
687
688 /* if xsize+7 is ok then (xsize+7)/8 will be and the minor
689 adjustments below won't make it overflow */
261f91c5
TC
690 line_size = (line_size+3) / 4 * 4;
691
692 if (ysize > 0) {
693 y = ysize-1;
694 lasty = -1;
695 yinc = -1;
696 }
697 else {
698 /* when ysize is -ve it's a top-down image */
699 ysize = -ysize;
700 y = 0;
701 lasty = ysize;
702 yinc = 1;
703 }
705fd961
TC
704 if (!clr_used)
705 clr_used = 2;
662e3c02
TC
706 if (clr_used < 0 || clr_used > 2) {
707 i_push_errorf(0, "out of range colors used (%d)", clr_used);
708 return NULL;
709 }
403946c6
TC
710
711 base_offset = FILEHEAD_SIZE + INFOHEAD_SIZE + clr_used * 4;
712 if (offbits < base_offset) {
713 i_push_errorf(0, "image data offset too small (%ld)", offbits);
714 return NULL;
715 }
716
662e3c02
TC
717 im = i_img_pal_new(xsize, ysize, 3, 256);
718 if (!im)
719 return NULL;
261f91c5
TC
720 if (!read_bmp_pal(ig, im, clr_used)) {
721 i_img_destroy(im);
722 return NULL;
723 }
403946c6
TC
724
725 if (offbits > base_offset) {
726 /* this will be slow if the offset is large, but that should be
727 rare */
728 char buffer;
729 while (base_offset < offbits) {
730 if (ig->readcb(ig, &buffer, 1) != 1) {
731 i_img_destroy(im);
732 i_push_error(0, "failed skipping to image data offset");
733 return NULL;
734 }
735 ++base_offset;
736 }
737 }
662e3c02
TC
738
739 i_tags_add(&im->tags, "bmp_compression_name", 0, "BI_RGB", -1, 0);
261f91c5 740
f0960b14
TC
741 packed = mymalloc(line_size); /* checked 29jun05 tonyc */
742 line = mymalloc(xsize+8); /* checked 29jun05 tonyc */
261f91c5
TC
743 while (y != lasty) {
744 if (ig->readcb(ig, packed, line_size) != line_size) {
745 myfree(packed);
746 myfree(line);
662e3c02 747 i_push_error(0, "failed reading 1-bit bmp data");
261f91c5
TC
748 i_img_destroy(im);
749 return NULL;
750 }
751 in = packed;
752 bit = 0x80;
753 p = line;
754 for (x = 0; x < xsize; ++x) {
755 *p++ = (*in & bit) ? 1 : 0;
756 bit >>= 1;
757 if (!bit) {
758 ++in;
759 bit = 0x80;
760 }
761 }
762 i_ppal(im, 0, xsize, y, line);
763 y += yinc;
764 }
765
4b0f812c
AMH
766 myfree(packed);
767 myfree(line);
261f91c5
TC
768 return im;
769}
261f91c5 770
705fd961
TC
771/*
772=item read_4bit_bmp(ig, xsize, ysize, clr_used, compression)
773
774Reads in the palette and image data for a 4-bit/pixel image.
775
776Returns the image or NULL.
777
778Hopefully this will be combined with the following function at some
779point.
780
781=cut
782*/
261f91c5 783static i_img *
705fd961 784read_4bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used,
403946c6 785 int compression, long offbits) {
261f91c5
TC
786 i_img *im;
787 int x, y, lasty, yinc;
788 i_palidx *line, *p;
789 unsigned char *packed;
790 int line_size = (xsize + 1)/2;
791 unsigned char *in;
705fd961 792 int size, i;
403946c6 793 long base_offset;
261f91c5 794
f0960b14
TC
795 /* line_size is going to be smaller than xsize in most cases (and
796 when it's not, xsize is itself small), and hence not overflow */
261f91c5
TC
797 line_size = (line_size+3) / 4 * 4;
798
799 if (ysize > 0) {
800 y = ysize-1;
801 lasty = -1;
802 yinc = -1;
803 }
804 else {
805 /* when ysize is -ve it's a top-down image */
806 ysize = -ysize;
807 y = 0;
808 lasty = ysize;
809 yinc = 1;
810 }
705fd961
TC
811 if (!clr_used)
812 clr_used = 16;
662e3c02
TC
813
814 if (clr_used > 16 || clr_used < 0) {
815 i_push_errorf(0, "out of range colors used (%d)", clr_used);
816 return NULL;
817 }
818
403946c6
TC
819 base_offset = FILEHEAD_SIZE + INFOHEAD_SIZE + clr_used * 4;
820 if (offbits < base_offset) {
821 i_push_errorf(0, "image data offset too small (%ld)", offbits);
822 return NULL;
823 }
824
662e3c02
TC
825 im = i_img_pal_new(xsize, ysize, 3, 256);
826 if (!im) /* error should have been pushed already */
827 return NULL;
261f91c5
TC
828 if (!read_bmp_pal(ig, im, clr_used)) {
829 i_img_destroy(im);
830 return NULL;
831 }
832
403946c6
TC
833 if (offbits > base_offset) {
834 /* this will be slow if the offset is large, but that should be
835 rare */
836 char buffer;
837 while (base_offset < offbits) {
838 if (ig->readcb(ig, &buffer, 1) != 1) {
839 i_img_destroy(im);
840 i_push_error(0, "failed skipping to image data offset");
841 return NULL;
842 }
843 ++base_offset;
844 }
845 }
846
705fd961 847 if (line_size < 260)
f0960b14 848 packed = mymalloc(260); /* checked 29jun05 tonyc */
705fd961 849 else
f0960b14
TC
850 packed = mymalloc(line_size); /* checked 29jun05 tonyc */
851 /* xsize won't approach MAXINT */
852 line = mymalloc(xsize+1); /* checked 29jun05 tonyc */
261f91c5 853 if (compression == BI_RGB) {
662e3c02 854 i_tags_add(&im->tags, "bmp_compression_name", 0, "BI_RGB", -1, 0);
261f91c5
TC
855 while (y != lasty) {
856 if (ig->readcb(ig, packed, line_size) != line_size) {
857 myfree(packed);
858 myfree(line);
662e3c02 859 i_push_error(0, "failed reading 4-bit bmp data");
261f91c5
TC
860 i_img_destroy(im);
861 return NULL;
862 }
863 in = packed;
864 p = line;
865 for (x = 0; x < xsize; x+=2) {
866 *p++ = *in >> 4;
867 *p++ = *in & 0x0F;
868 ++in;
869 }
870 i_ppal(im, 0, xsize, y, line);
871 y += yinc;
872 }
4b0f812c
AMH
873 myfree(packed);
874 myfree(line);
261f91c5
TC
875 }
876 else if (compression == BI_RLE4) {
705fd961 877 int read_size;
705fd961
TC
878 int count;
879
662e3c02 880 i_tags_add(&im->tags, "bmp_compression_name", 0, "BI_RLE4", -1, 0);
705fd961
TC
881 x = 0;
882 while (1) {
883 /* there's always at least 2 bytes in a sequence */
884 if (ig->readcb(ig, packed, 2) != 2) {
885 myfree(packed);
886 myfree(line);
887 i_push_error(0, "missing data during decompression");
888 i_img_destroy(im);
889 return NULL;
890 }
891 else if (packed[0]) {
892 line[0] = packed[1] >> 4;
893 line[1] = packed[1] & 0x0F;
894 for (i = 0; i < packed[0]; i += 2) {
895 if (i < packed[0]-1)
896 i_ppal(im, x, x+2, y, line);
897 else
898 i_ppal(im, x, x+(packed[0]-i), y, line);
899 x += 2;
900 }
901 } else {
902 switch (packed[1]) {
903 case BMPRLE_ENDOFLINE:
904 x = 0;
905 y += yinc;
906 break;
907
908 case BMPRLE_ENDOFBMP:
4dfa5522
AMH
909 myfree(packed);
910 myfree(line);
705fd961
TC
911 return im;
912
913 case BMPRLE_DELTA:
914 if (ig->readcb(ig, packed, 2) != 2) {
915 myfree(packed);
916 myfree(line);
917 i_push_error(0, "missing data during decompression");
918 i_img_destroy(im);
919 return NULL;
920 }
921 x += packed[0];
922 y += yinc * packed[1];
923 break;
924
925 default:
926 count = packed[1];
927 size = (count + 1) / 2;
928 read_size = (size+1) / 2 * 2;
929 if (ig->readcb(ig, packed, read_size) != read_size) {
930 myfree(packed);
931 myfree(line);
932 i_push_error(0, "missing data during decompression");
933 /*i_img_destroy(im);*/
934 return im;
935 }
936 for (i = 0; i < size; ++i) {
937 line[0] = packed[i] >> 4;
938 line[1] = packed[i] & 0xF;
939 i_ppal(im, x, x+2, y, line);
940 x += 2;
941 }
942 break;
943 }
944 }
945 }
946 }
947 else { /*if (compression == BI_RLE4) {*/
948 myfree(packed);
949 myfree(line);
662e3c02 950 i_push_errorf(0, "unknown 4-bit BMP compression (%d)", compression);
705fd961
TC
951 i_img_destroy(im);
952 return NULL;
261f91c5
TC
953 }
954
955 return im;
956}
957
705fd961
TC
958/*
959=item read_8bit_bmp(ig, xsize, ysize, clr_used, compression)
261f91c5 960
705fd961
TC
961Reads in the palette and image data for a 8-bit/pixel image.
962
963Returns the image or NULL.
964
965=cut
966*/
967static i_img *
968read_8bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used,
403946c6 969 int compression, long offbits) {
261f91c5 970 i_img *im;
705fd961 971 int x, y, lasty, yinc;
a659442a 972 i_palidx *line;
705fd961 973 int line_size = xsize;
403946c6 974 long base_offset;
261f91c5 975
705fd961 976 line_size = (line_size+3) / 4 * 4;
f0960b14
TC
977 if (line_size < xsize) { /* if it overflowed (unlikely, but check) */
978 i_push_error(0, "integer overflow during memory allocation");
979 return NULL;
980 }
705fd961
TC
981
982 if (ysize > 0) {
983 y = ysize-1;
984 lasty = -1;
985 yinc = -1;
261f91c5 986 }
705fd961
TC
987 else {
988 /* when ysize is -ve it's a top-down image */
989 ysize = -ysize;
990 y = 0;
991 lasty = ysize;
992 yinc = 1;
261f91c5 993 }
705fd961
TC
994 if (!clr_used)
995 clr_used = 256;
662e3c02
TC
996 if (clr_used > 256 || clr_used < 0) {
997 i_push_errorf(0, "out of range colors used (%d)", clr_used);
998 return NULL;
999 }
1000
403946c6
TC
1001 base_offset = FILEHEAD_SIZE + INFOHEAD_SIZE + clr_used * 4;
1002 if (offbits < base_offset) {
1003 i_push_errorf(0, "image data offset too small (%ld)", offbits);
1004 return NULL;
1005 }
1006
662e3c02
TC
1007 im = i_img_pal_new(xsize, ysize, 3, 256);
1008 if (!im)
1009 return NULL;
705fd961
TC
1010 if (!read_bmp_pal(ig, im, clr_used)) {
1011 i_img_destroy(im);
1012 return NULL;
1013 }
1014
403946c6
TC
1015 if (offbits > base_offset) {
1016 /* this will be slow if the offset is large, but that should be
1017 rare */
1018 char buffer;
1019 while (base_offset < offbits) {
1020 if (ig->readcb(ig, &buffer, 1) != 1) {
1021 i_img_destroy(im);
1022 i_push_error(0, "failed skipping to image data offset");
1023 return NULL;
1024 }
1025 ++base_offset;
1026 }
1027 }
1028
f0960b14 1029 line = mymalloc(line_size); /* checked 29jun05 tonyc */
705fd961 1030 if (compression == BI_RGB) {
662e3c02 1031 i_tags_add(&im->tags, "bmp_compression_name", 0, "BI_RGB", -1, 0);
705fd961
TC
1032 while (y != lasty) {
1033 if (ig->readcb(ig, line, line_size) != line_size) {
1034 myfree(line);
662e3c02 1035 i_push_error(0, "failed reading 8-bit bmp data");
705fd961
TC
1036 i_img_destroy(im);
1037 return NULL;
1038 }
1039 i_ppal(im, 0, xsize, y, line);
1040 y += yinc;
1041 }
12d25826 1042 myfree(line);
705fd961
TC
1043 }
1044 else if (compression == BI_RLE8) {
1045 int read_size;
705fd961
TC
1046 int count;
1047 unsigned char packed[2];
1048
662e3c02 1049 i_tags_add(&im->tags, "bmp_compression_name", 0, "BI_RLE8", -1, 0);
705fd961
TC
1050 x = 0;
1051 while (1) {
1052 /* there's always at least 2 bytes in a sequence */
1053 if (ig->readcb(ig, packed, 2) != 2) {
1054 myfree(line);
1055 i_push_error(0, "missing data during decompression");
1056 i_img_destroy(im);
1057 return NULL;
1058 }
1059 if (packed[0]) {
1060 memset(line, packed[1], packed[0]);
1061 i_ppal(im, x, x+packed[0], y, line);
1062 x += packed[0];
1063 } else {
1064 switch (packed[1]) {
1065 case BMPRLE_ENDOFLINE:
1066 x = 0;
1067 y += yinc;
1068 break;
1069
1070 case BMPRLE_ENDOFBMP:
4dfa5522 1071 myfree(line);
705fd961
TC
1072 return im;
1073
1074 case BMPRLE_DELTA:
1075 if (ig->readcb(ig, packed, 2) != 2) {
1076 myfree(line);
1077 i_push_error(0, "missing data during decompression");
1078 i_img_destroy(im);
1079 return NULL;
1080 }
1081 x += packed[0];
1082 y += yinc * packed[1];
1083 break;
1084
1085 default:
1086 count = packed[1];
1087 read_size = (count+1) / 2 * 2;
1088 if (ig->readcb(ig, line, read_size) != read_size) {
1089 myfree(line);
1090 i_push_error(0, "missing data during decompression");
1091 i_img_destroy(im);
1092 return NULL;
1093 }
1094 i_ppal(im, x, x+count, y, line);
1095 x += count;
1096 break;
1097 }
1098 }
1099 }
1100 }
1101 else {
1102 myfree(line);
662e3c02 1103 i_push_errorf(0, "unknown 8-bit BMP compression (%d)", compression);
705fd961
TC
1104 i_img_destroy(im);
1105 return NULL;
1106 }
1107
1108 return im;
1109}
1110
1111struct bm_masks {
1112 unsigned masks[3];
1113 int shifts[3];
1114};
1115static struct bm_masks std_masks[] =
1116{
1117 { /* 16-bit */
1118 { 0770000, 00007700, 00000077, },
1119 { 10, 4, -2, },
1120 },
1121 { /* 24-bit */
1122 { 0xFF0000, 0x00FF00, 0x0000FF, },
1123 { 16, 8, 0, },
1124 },
1125 { /* 32-bit */
1126 { 0xFF0000, 0x00FF00, 0x0000FF, },
1127 { 16, 8, 0, },
1128 },
1129};
1130
1131/*
1132=item read_direct_bmp(ig, xsize, ysize, bit_count, clr_used, compression)
1133
1134Skips the palette and reads in the image data for a direct colour image.
1135
1136Returns the image or NULL.
1137
1138=cut
1139*/
1140static i_img *
1141read_direct_bmp(io_glue *ig, int xsize, int ysize, int bit_count,
403946c6 1142 int clr_used, int compression, long offbits) {
705fd961
TC
1143 i_img *im;
1144 int x, y, lasty, yinc;
1145 i_color *line, *p;
705fd961
TC
1146 int pix_size = bit_count / 8;
1147 int line_size = xsize * pix_size;
1148 struct bm_masks masks;
1149 char unpack_code[2] = "";
1150 int i;
1151 int extras;
1152 char junk[4];
662e3c02
TC
1153 const char *compression_name;
1154 int bytes;
403946c6 1155 long base_offset = FILEHEAD_SIZE + INFOHEAD_SIZE;
261f91c5 1156
705fd961
TC
1157 unpack_code[0] = *("v3V"+pix_size-2);
1158 unpack_code[1] = '\0';
261f91c5 1159
705fd961
TC
1160 line_size = (line_size+3) / 4 * 4;
1161 extras = line_size - xsize * pix_size;
261f91c5 1162
705fd961
TC
1163 if (ysize > 0) {
1164 y = ysize-1;
1165 lasty = -1;
1166 yinc = -1;
1167 }
1168 else {
1169 /* when ysize is -ve it's a top-down image */
1170 ysize = -ysize;
1171 y = 0;
1172 lasty = ysize;
1173 yinc = 1;
1174 }
705fd961 1175 if (compression == BI_RGB) {
662e3c02 1176 compression_name = "BI_RGB";
705fd961
TC
1177 masks = std_masks[pix_size-2];
1178
1179 /* there's a potential "palette" after the header */
1180 for (i = 0; i < clr_used; ++clr_used) {
1181 char buf[4];
1182 if (ig->readcb(ig, buf, 4) != 4) {
1183 i_push_error(0, "skipping colors");
1184 return 0;
1185 }
403946c6 1186 base_offset += 4;
705fd961
TC
1187 }
1188 }
1189 else if (compression == BI_BITFIELDS) {
1190 int pos, bit;
662e3c02
TC
1191 compression_name = "BI_BITFIELDS";
1192
705fd961
TC
1193 for (i = 0; i < 3; ++i) {
1194 if (!read_packed(ig, "V", masks.masks+i)) {
1195 i_push_error(0, "reading pixel masks");
1196 return 0;
1197 }
1198 /* work out a shift for the mask */
1199 pos = 0;
1200 bit = masks.masks[i] & -masks.masks[i];
1201 while (bit) {
1202 ++pos;
1203 bit >>= 1;
1204 }
1205 masks.shifts[i] = pos - 8;
1206 }
403946c6 1207 base_offset += 4 * 4;
705fd961 1208 }
662e3c02
TC
1209 else {
1210 i_push_errorf(0, "unknown 24-bit BMP compression (%d)", compression);
1211 return NULL;
1212 }
261f91c5 1213
403946c6
TC
1214 if (offbits > base_offset) {
1215 /* this will be slow if the offset is large, but that should be
1216 rare */
1217 char buffer;
1218 while (base_offset < offbits) {
1219 if (ig->readcb(ig, &buffer, 1) != 1) {
403946c6
TC
1220 i_push_error(0, "failed skipping to image data offset");
1221 return NULL;
1222 }
1223 ++base_offset;
1224 }
1225 }
1226
705fd961 1227 im = i_img_empty(NULL, xsize, ysize);
662e3c02
TC
1228 if (!im)
1229 return NULL;
705fd961 1230
662e3c02
TC
1231 i_tags_add(&im->tags, "bmp_compression_name", 0, compression_name, -1, 0);
1232
1233 /* I wasn't able to make this overflow in testing, but better to be
1234 safe */
1235 bytes = sizeof(i_color) * xsize;
1236 if (bytes / sizeof(i_color) != xsize) {
1237 i_img_destroy(im);
1238 i_push_error(0, "integer overflow calculating buffer size");
1239 return NULL;
1240 }
f0960b14 1241 line = mymalloc(bytes); /* checked 29jun05 tonyc */
705fd961
TC
1242 while (y != lasty) {
1243 p = line;
1244 for (x = 0; x < xsize; ++x) {
1245 unsigned pixel;
1246 if (!read_packed(ig, unpack_code, &pixel)) {
662e3c02 1247 i_push_error(0, "failed reading image data");
705fd961
TC
1248 myfree(line);
1249 i_img_destroy(im);
1250 return NULL;
1251 }
1252 for (i = 0; i < 3; ++i) {
1253 if (masks.shifts[i] > 0)
1254 p->channel[i] = (pixel & masks.masks[i]) >> masks.shifts[i];
1255 else
1256 p->channel[i] = (pixel & masks.masks[i]) << -masks.shifts[i];
1257 }
1258 ++p;
1259 }
1260 i_plin(im, 0, xsize, y, line);
1261 if (extras)
1262 ig->readcb(ig, junk, extras);
1263 y += yinc;
261f91c5 1264 }
705fd961
TC
1265 myfree(line);
1266
1267 return im;
261f91c5 1268}
705fd961
TC
1269
1270/*
1271=head1 SEE ALSO
1272
1273Imager(3)
1274
1275=head1 AUTHOR
1276
1277Tony Cook <tony@develop-help.com>
1278
1279=head1 RESTRICTIONS
1280
1281Cannot save as compressed BMP.
1282
1283=head1 BUGS
1284
1285Doesn't handle OS/2 bitmaps.
1286
128716-bit/pixel images haven't been tested. (I need an image).
1288
1289BI_BITFIELDS compression hasn't been tested (I need an image).
1290
403946c6
TC
1291The header handling for paletted images needs to be refactored
1292
705fd961
TC
1293=cut
1294*/