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