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