]> git.imager.perl.org - imager.git/blob - bmp.c
- added many bad BMP files to test various code paths in bmp.c, and
[imager.git] / bmp.c
1 #include "image.h"
2 #include <stdarg.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);
49 static i_img *read_4bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used, 
50                             int compression);
51 static i_img *read_8bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used, 
52                             int compression);
53 static 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
59 Writes the image as a BMP file.  Uses 1-bit, 4-bit, 8-bit or 24-bit
60 formats depending on the image.
61
62 Never compresses the image.
63
64 =cut
65 */
66 int
67 i_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
95 Reads a Windows format bitmap from the given file.
96
97 Handles BI_RLE4 and BI_RLE8 compressed images.  Attempts to handle
98 BI_BITFIELDS images too, but I need a test image.
99
100 =cut
101 */
102
103 i_img *
104 i_readbmp_wiol(io_glue *ig) {
105   int b_magic, m_magic, filesize, res1, res2, 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   mm_log((1, "i_readbmp_wiol(ig %p)\n", ig));
111   
112   io_glue_commit_types(ig);
113   i_clear_error();
114
115   if (!read_packed(ig, "CCVvvVVVVvvVVVVVV", &b_magic, &m_magic, &filesize, 
116                    &res1, &res2, &offbits, &infohead_size, 
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   }
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));
134   
135   switch (bit_count) {
136   case 1:
137     im = read_1bit_bmp(ig, xsize, ysize, clr_used, compression);
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;
153
154   default:
155     i_push_errorf(0, "unknown bit count for BMP file (%d)", bit_count);
156     return NULL;
157   }
158
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);
175   }
176
177   return im;
178 }
179
180 /*
181 =back
182
183 =head1 IMPLEMENTATION FUNCTIONS
184
185 Internal functions used in the implementation.
186
187 =over
188
189 =item read_packed(ig, format, ...)
190
191 Reads from the specified "file" the specified sizes.  The format codes
192 match those used by perl's pack() function, though only a few are
193 implemented.  In all cases the vararg arguement is an int *.
194
195 Returns non-zero if all of the arguments were read.
196
197 =cut
198 */
199 static
200 int 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':
212       if (ig->readcb(ig, buf, 2) != 2)
213         return 0;
214       *p = buf[0] + (buf[1] << 8);
215       break;
216
217     case 'V':
218       if (ig->readcb(ig, buf, 4) != 4)
219         return 0;
220       *p = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24);
221       break;
222
223     case 'C':
224       if (ig->readcb(ig, buf, 1) != 1)
225         return 0;
226       *p = buf[0];
227       break;
228
229     case 'c':
230       if (ig->readcb(ig, buf, 1) != 1)
231         return 0;
232       *p = (char)buf[0];
233       break;
234       
235     case '3': /* extension - 24-bit number */
236       if (ig->readcb(ig, buf, 3) != 3)
237         return 0;
238       *p = buf[0] + (buf[1] << 8) + (buf[2] << 16);
239       break;
240       
241     default:
242       m_fatal(1, "Unknown read_packed format code 0x%02x", *format);
243     }
244     ++format;
245   }
246   return 1;
247 }
248
249 /*
250 =item write_packed(ig, format, ...)
251
252 Writes packed data to the specified io_glue.
253
254 Returns non-zero on success.
255
256 =cut
257 */
258
259 static int
260 write_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:
295       m_fatal(1, "Unknown write_packed format code 0x%02x", *format);
296     }
297     ++format;
298   }
299   va_end(ap);
300
301   return 1;
302 }
303
304 /*
305 =item write_bmphead(ig, im, bit_count, data_size)
306
307 Writes a Windows BMP header to the file.
308
309 Returns non-zero on success.
310
311 =cut
312 */
313
314 static
315 int 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, 
360                     bit_count, BI_RGB, 0, (int)(xres+0.5), (int)(yres+0.5), 
361                     colors_used, colors_used)){
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
391 /*
392 =item write_1bit_data(ig, im)
393
394 Writes the image data as a 1-bit/pixel image.
395
396 Returns non-zero on success.
397
398 =cut
399 */
400 static int
401 write_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
449   ig->closecb(ig);
450
451   return 1;
452 }
453
454 /*
455 =item write_4bit_data(ig, im)
456
457 Writes the image data as a 4-bit/pixel image.
458
459 Returns non-zero on success.
460
461 =cut
462 */
463 static int
464 write_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
499   ig->closecb(ig);
500
501   return 1;
502 }
503
504 /*
505 =item write_8bit_data(ig, im)
506
507 Writes the image data as a 8-bit/pixel image.
508
509 Returns non-zero on success.
510
511 =cut
512 */
513 static int
514 write_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
538   ig->closecb(ig);
539
540   return 1;
541 }
542
543 static int bgr_chans[] = { 2, 1, 0, };
544 static int grey_chans[] = { 0, 0, 0, };
545
546 /*
547 =item write_24bit_data(ig, im)
548
549 Writes the image data as a 24-bit/pixel image.
550
551 Returns non-zero on success.
552
553 =cut
554 */
555 static int
556 write_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);
568   memset(samples, 0, line_size);
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
579   ig->closecb(ig);
580
581   return 1;
582 }
583
584 /*
585 =item read_bmp_pal(ig, im, count)
586
587 Reads count palette entries from the file and add them to the image.
588
589 Returns non-zero on success.
590
591 =cut
592 */
593 static int
594 read_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;
607     if (i_addcolors(im, &c, 1) < 0) {
608       i_push_error(0, "out of space in image palette");
609       return 0;
610     }
611   }
612   
613   return 1;
614 }
615
616 /*
617 =item read_1bit_bmp(ig, xsize, ysize, clr_used)
618
619 Reads in the palette and image data for a 1-bit/pixel image.
620
621 Returns the image or NULL.
622
623 =cut
624 */
625 static i_img *
626 read_1bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used, 
627               int compression) {
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
636   if (compression != BI_RGB) {
637     i_push_errorf(0, "unknown 1-bit BMP compression (%d)", compression);
638     return NULL;
639   }
640
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   }
655   if (!clr_used)
656     clr_used = 2;
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;
664   if (!read_bmp_pal(ig, im, clr_used)) {
665     i_img_destroy(im);
666     return NULL;
667   }
668   
669   i_tags_add(&im->tags, "bmp_compression_name", 0, "BI_RGB", -1, 0);
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);
677       i_push_error(0, "failed reading 1-bit bmp data");
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
696   myfree(packed);
697   myfree(line);
698   return im;
699 }
700
701 /*
702 =item read_4bit_bmp(ig, xsize, ysize, clr_used, compression)
703
704 Reads in the palette and image data for a 4-bit/pixel image.
705
706 Returns the image or NULL.
707
708 Hopefully this will be combined with the following function at some
709 point.
710
711 =cut
712 */
713 static i_img *
714 read_4bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used, 
715               int compression) {
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;
722   int size, i;
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   }
738   if (!clr_used)
739     clr_used = 16;
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;
749   if (!read_bmp_pal(ig, im, clr_used)) {
750     i_img_destroy(im);
751     return NULL;
752   }
753
754   if (line_size < 260)
755     packed = mymalloc(260);
756   else
757     packed = mymalloc(line_size);
758   line = mymalloc(xsize+1);
759   if (compression == BI_RGB) {
760     i_tags_add(&im->tags, "bmp_compression_name", 0, "BI_RGB", -1, 0);
761     while (y != lasty) {
762       if (ig->readcb(ig, packed, line_size) != line_size) {
763         myfree(packed);
764         myfree(line);
765         i_push_error(0, "failed reading 4-bit bmp data");
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     }
779     myfree(packed);
780     myfree(line);
781   }
782   else if (compression == BI_RLE4) {
783     int read_size;
784     int want_high;
785     int count;
786
787     i_tags_add(&im->tags, "bmp_compression_name", 0, "BI_RLE4", -1, 0);
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:
816           myfree(packed);
817           myfree(line);
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);
857     i_push_errorf(0, "unknown 4-bit BMP compression (%d)", compression);
858     i_img_destroy(im);
859     return NULL;
860   }
861
862   return im;
863 }
864
865 /*
866 =item read_8bit_bmp(ig, xsize, ysize, clr_used, compression)
867
868 Reads in the palette and image data for a 8-bit/pixel image.
869
870 Returns the image or NULL.
871
872 =cut
873 */
874 static i_img *
875 read_8bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used, 
876               int compression) {
877   i_img *im;
878   int x, y, lasty, yinc;
879   i_palidx *line, *p;
880   int line_size = xsize;
881   unsigned char *in;
882
883   line_size = (line_size+3) / 4 * 4;
884
885   if (ysize > 0) {
886     y = ysize-1;
887     lasty = -1;
888     yinc = -1;
889   }
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;
896   }
897   if (!clr_used)
898     clr_used = 256;
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;
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) {
914     i_tags_add(&im->tags, "bmp_compression_name", 0, "BI_RGB", -1, 0);
915     while (y != lasty) {
916       if (ig->readcb(ig, line, line_size) != line_size) {
917         myfree(line);
918         i_push_error(0, "failed reading 8-bit bmp data");
919         i_img_destroy(im);
920         return NULL;
921       }
922       i_ppal(im, 0, xsize, y, line);
923       y += yinc;
924     }
925     myfree(line);
926   }
927   else if (compression == BI_RLE8) {
928     int read_size;
929     int want_high;
930     int count;
931     unsigned char packed[2];
932
933     i_tags_add(&im->tags, "bmp_compression_name", 0, "BI_RLE8", -1, 0);
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:
955           myfree(line);
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);
987     i_push_errorf(0, "unknown 8-bit BMP compression (%d)", compression);
988     i_img_destroy(im);
989     return NULL;
990   }
991
992   return im;
993 }
994
995 struct bm_masks {
996   unsigned masks[3];
997   int shifts[3];
998 };
999 static 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
1018 Skips the palette and reads in the image data for a direct colour image.
1019
1020 Returns the image or NULL.
1021
1022 =cut
1023 */
1024 static i_img *
1025 read_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];
1038   const char *compression_name;
1039   int bytes;
1040   
1041   unpack_code[0] = *("v3V"+pix_size-2);
1042   unpack_code[1] = '\0';
1043
1044   line_size = (line_size+3) / 4 * 4;
1045   extras = line_size - xsize * pix_size;
1046
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   }
1059   if (compression == BI_RGB) {
1060     compression_name = "BI_RGB";
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;
1074     compression_name = "BI_BITFIELDS";
1075
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   }
1091   else {
1092     i_push_errorf(0, "unknown 24-bit BMP compression (%d)", compression);
1093     return NULL;
1094   }
1095
1096   im = i_img_empty(NULL, xsize, ysize);
1097   if (!im)
1098     return NULL;
1099
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);
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)) {
1116         i_push_error(0, "failed reading image data");
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;
1133   }
1134   myfree(line);
1135
1136   return im;
1137 }
1138
1139 /*
1140 =head1 SEE ALSO
1141
1142 Imager(3)
1143
1144 =head1 AUTHOR
1145
1146 Tony Cook <tony@develop-help.com>
1147
1148 =head1 RESTRICTIONS
1149
1150 Cannot save as compressed BMP.
1151
1152 =head1 BUGS
1153
1154 Doesn't handle OS/2 bitmaps.
1155
1156 16-bit/pixel images haven't been tested.  (I need an image).
1157
1158 BI_BITFIELDS compression hasn't been tested (I need an image).
1159
1160 =cut
1161 */