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