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