]> git.imager.perl.org - imager.git/blob - bmp.c
add support for file write plugins
[imager.git] / bmp.c
1 #include <stdarg.h>
2 #include "imageri.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   int unpacked_size;
417
418   /* round up to nearest multiple of four */
419   line_size = (line_size + 3) / 4 * 4;
420
421   if (!write_bmphead(ig, im, 1, line_size * im->ysize))
422     return 0;
423
424   /* this shouldn't be an issue, but let's be careful */
425   unpacked_size = im->xsize + 8;
426   if (unpacked_size < im->xsize) {
427     i_push_error(0, "integer overflow during memory allocation");
428     return 0;
429   }
430   line = mymalloc(unpacked_size); /* checked 29jun05 tonyc */
431   memset(line + im->xsize, 0, 8);
432
433   /* size allocated here is always much smaller than xsize, hence
434      can't overflow int */
435   packed = mymalloc(line_size); /* checked 29jun05 tonyc */
436   memset(packed, 0, line_size);
437   
438   for (y = im->ysize-1; y >= 0; --y) {
439     i_gpal(im, 0, im->xsize, y, line);
440     mask = 0x80;
441     byte = 0;
442     out = packed;
443     for (x = 0; x < im->xsize; ++x) {
444       if (line[x])
445         byte |= mask;
446       if ((mask >>= 1) == 0) {
447         *out++ = byte;
448         byte = 0;
449         mask = 0x80;
450       }
451     }
452     if (mask != 0x80) {
453       *out++ = byte;
454     }
455     if (ig->writecb(ig, packed, line_size) < 0) {
456       myfree(packed);
457       myfree(line);
458       i_push_error(0, "writing 1 bit/pixel packed data");
459       return 0;
460     }
461   }
462   myfree(packed);
463   myfree(line);
464
465   ig->closecb(ig);
466
467   return 1;
468 }
469
470 /*
471 =item write_4bit_data(ig, im)
472
473 Writes the image data as a 4-bit/pixel image.
474
475 Returns non-zero on success.
476
477 =cut
478 */
479 static int
480 write_4bit_data(io_glue *ig, i_img *im) {
481   i_palidx *line;
482   unsigned char *packed;
483   unsigned char *out;
484   int line_size = (im->xsize+1) / 2;
485   int x, y;
486   int unpacked_size;
487
488   /* round up to nearest multiple of four */
489   line_size = (line_size + 3) / 4 * 4;
490
491   if (!write_bmphead(ig, im, 4, line_size * im->ysize))
492     return 0;
493
494   /* this shouldn't be an issue, but let's be careful */
495   unpacked_size = im->xsize + 2;
496   if (unpacked_size < im->xsize) {
497     i_push_error(0, "integer overflow during memory allocation");
498     return 0;
499   }
500   line = mymalloc(unpacked_size); /* checked 29jun05 tonyc */
501   memset(line + im->xsize, 0, 2);
502   
503   /* size allocated here is always much smaller than xsize, hence
504      can't overflow int */
505   packed = mymalloc(line_size); /* checked 29jun05 tonyc */
506   memset(packed, 0, line_size);
507   
508   for (y = im->ysize-1; y >= 0; --y) {
509     i_gpal(im, 0, im->xsize, y, line);
510     out = packed;
511     for (x = 0; x < im->xsize; x += 2) {
512       *out++ = (line[x] << 4) + line[x+1];
513     }
514     if (ig->writecb(ig, packed, line_size) < 0) {
515       myfree(packed);
516       myfree(line);
517       i_push_error(0, "writing 4 bit/pixel packed data");
518       return 0;
519     }
520   }
521   myfree(packed);
522   myfree(line);
523
524   ig->closecb(ig);
525
526   return 1;
527 }
528
529 /*
530 =item write_8bit_data(ig, im)
531
532 Writes the image data as a 8-bit/pixel image.
533
534 Returns non-zero on success.
535
536 =cut
537 */
538 static int
539 write_8bit_data(io_glue *ig, i_img *im) {
540   i_palidx *line;
541   int line_size = im->xsize;
542   int y;
543   int unpacked_size;
544
545   /* round up to nearest multiple of four */
546   line_size = (line_size + 3) / 4 * 4;
547
548   if (!write_bmphead(ig, im, 8, line_size * im->ysize))
549     return 0;
550
551   /* this shouldn't be an issue, but let's be careful */
552   unpacked_size = im->xsize + 4;
553   if (unpacked_size < im->xsize) {
554     i_push_error(0, "integer overflow during memory allocation");
555     return 0;
556   }
557   line = mymalloc(unpacked_size); /* checked 29jun05 tonyc */
558   memset(line + im->xsize, 0, 4);
559   
560   for (y = im->ysize-1; y >= 0; --y) {
561     i_gpal(im, 0, im->xsize, y, line);
562     if (ig->writecb(ig, line, line_size) < 0) {
563       myfree(line);
564       i_push_error(0, "writing 8 bit/pixel packed data");
565       return 0;
566     }
567   }
568   myfree(line);
569
570   ig->closecb(ig);
571
572   return 1;
573 }
574
575 static int bgr_chans[] = { 2, 1, 0, };
576 static int grey_chans[] = { 0, 0, 0, };
577
578 /*
579 =item write_24bit_data(ig, im)
580
581 Writes the image data as a 24-bit/pixel image.
582
583 Returns non-zero on success.
584
585 =cut
586 */
587 static int
588 write_24bit_data(io_glue *ig, i_img *im) {
589   int *chans;
590   unsigned char *samples;
591   int y;
592   int line_size = 3 * im->xsize;
593
594   /* just in case we implement a direct format with 2bytes/pixel
595      (unlikely though) */
596   if (line_size / 3 != im->xsize) {
597     i_push_error(0, "integer overflow during memory allocation");
598     return 0;
599   }
600   
601   line_size = (line_size + 3) / 4 * 4;
602   
603   if (!write_bmphead(ig, im, 24, line_size * im->ysize))
604     return 0;
605   chans = im->channels >= 3 ? bgr_chans : grey_chans;
606   samples = mymalloc(line_size); /* checked 29jun05 tonyc */
607   memset(samples, 0, line_size);
608   for (y = im->ysize-1; y >= 0; --y) {
609     i_gsamp(im, 0, im->xsize, y, samples, chans, 3);
610     if (ig->writecb(ig, samples, line_size) < 0) {
611       i_push_error(0, "writing image data");
612       myfree(samples);
613       return 0;
614     }
615   }
616   myfree(samples);
617
618   ig->closecb(ig);
619
620   return 1;
621 }
622
623 /*
624 =item read_bmp_pal(ig, im, count)
625
626 Reads count palette entries from the file and add them to the image.
627
628 Returns non-zero on success.
629
630 =cut
631 */
632 static int
633 read_bmp_pal(io_glue *ig, i_img *im, int count) {
634   int i;
635   int r, g, b, x;
636   i_color c;
637   
638   for (i = 0; i < count; ++i) {
639     if (!read_packed(ig, "CCCC", &b, &g, &r, &x)) {
640       i_push_error(0, "reading BMP palette");
641       return 0;
642     }
643     c.channel[0] = r;
644     c.channel[1] = g;
645     c.channel[2] = b;
646     if (i_addcolors(im, &c, 1) < 0) {
647       i_push_error(0, "out of space in image palette");
648       return 0;
649     }
650   }
651   
652   return 1;
653 }
654
655 /*
656 =item read_1bit_bmp(ig, xsize, ysize, clr_used, compression, offbits)
657
658 Reads in the palette and image data for a 1-bit/pixel image.
659
660 Returns the image or NULL.
661
662 =cut
663 */
664 static i_img *
665 read_1bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used, 
666               int compression, long offbits) {
667   i_img *im;
668   int x, y, lasty, yinc;
669   i_palidx *line, *p;
670   unsigned char *packed;
671   int line_size = (xsize + 7)/8;
672   int bit;
673   unsigned char *in;
674   long base_offset;
675
676   if (compression != BI_RGB) {
677     i_push_errorf(0, "unknown 1-bit BMP compression (%d)", compression);
678     return NULL;
679   }
680
681   if (xsize + 8 < xsize) { /* if there was overflow */
682     /* we check with 8 because we allocate that much for the decoded 
683        line buffer */
684     i_push_error(0, "integer overflow during memory allocation");
685     return NULL;
686   }
687
688   /* if xsize+7 is ok then (xsize+7)/8 will be and the minor
689      adjustments below won't make it overflow */
690   line_size = (line_size+3) / 4 * 4;
691
692   if (ysize > 0) {
693     y = ysize-1;
694     lasty = -1;
695     yinc = -1;
696   }
697   else {
698     /* when ysize is -ve it's a top-down image */
699     ysize = -ysize;
700     y = 0;
701     lasty = ysize;
702     yinc = 1;
703   }
704   if (!clr_used)
705     clr_used = 2;
706   if (clr_used < 0 || clr_used > 2) {
707     i_push_errorf(0, "out of range colors used (%d)", clr_used);
708     return NULL;
709   }
710
711   base_offset = FILEHEAD_SIZE + INFOHEAD_SIZE + clr_used * 4;
712   if (offbits < base_offset) {
713     i_push_errorf(0, "image data offset too small (%ld)", offbits);
714     return NULL;
715   }
716
717   im = i_img_pal_new(xsize, ysize, 3, 256);
718   if (!im)
719     return NULL;
720   if (!read_bmp_pal(ig, im, clr_used)) {
721     i_img_destroy(im);
722     return NULL;
723   }
724
725   if (offbits > base_offset) {
726     /* this will be slow if the offset is large, but that should be
727        rare */
728     char buffer;
729     while (base_offset < offbits) {
730       if (ig->readcb(ig, &buffer, 1) != 1) {
731         i_img_destroy(im);
732         i_push_error(0, "failed skipping to image data offset");
733         return NULL;
734       }
735       ++base_offset;
736     }
737   }
738   
739   i_tags_add(&im->tags, "bmp_compression_name", 0, "BI_RGB", -1, 0);
740
741   packed = mymalloc(line_size); /* checked 29jun05 tonyc */
742   line = mymalloc(xsize+8); /* checked 29jun05 tonyc */
743   while (y != lasty) {
744     if (ig->readcb(ig, packed, line_size) != line_size) {
745       myfree(packed);
746       myfree(line);
747       i_push_error(0, "failed reading 1-bit bmp data");
748       i_img_destroy(im);
749       return NULL;
750     }
751     in = packed;
752     bit = 0x80;
753     p = line;
754     for (x = 0; x < xsize; ++x) {
755       *p++ = (*in & bit) ? 1 : 0;
756       bit >>= 1;
757       if (!bit) {
758         ++in;
759         bit = 0x80;
760       }
761     }
762     i_ppal(im, 0, xsize, y, line);
763     y += yinc;
764   }
765
766   myfree(packed);
767   myfree(line);
768   return im;
769 }
770
771 /*
772 =item read_4bit_bmp(ig, xsize, ysize, clr_used, compression)
773
774 Reads in the palette and image data for a 4-bit/pixel image.
775
776 Returns the image or NULL.
777
778 Hopefully this will be combined with the following function at some
779 point.
780
781 =cut
782 */
783 static i_img *
784 read_4bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used, 
785               int compression, long offbits) {
786   i_img *im;
787   int x, y, lasty, yinc;
788   i_palidx *line, *p;
789   unsigned char *packed;
790   int line_size = (xsize + 1)/2;
791   unsigned char *in;
792   int size, i;
793   long base_offset;
794
795   /* line_size is going to be smaller than xsize in most cases (and
796      when it's not, xsize is itself small), and hence not overflow */
797   line_size = (line_size+3) / 4 * 4;
798
799   if (ysize > 0) {
800     y = ysize-1;
801     lasty = -1;
802     yinc = -1;
803   }
804   else {
805     /* when ysize is -ve it's a top-down image */
806     ysize = -ysize;
807     y = 0;
808     lasty = ysize;
809     yinc = 1;
810   }
811   if (!clr_used)
812     clr_used = 16;
813
814   if (clr_used > 16 || clr_used < 0) {
815     i_push_errorf(0, "out of range colors used (%d)", clr_used);
816     return NULL;
817   }
818
819   base_offset = FILEHEAD_SIZE + INFOHEAD_SIZE + clr_used * 4;
820   if (offbits < base_offset) {
821     i_push_errorf(0, "image data offset too small (%ld)", offbits);
822     return NULL;
823   }
824
825   im = i_img_pal_new(xsize, ysize, 3, 256);
826   if (!im) /* error should have been pushed already */
827     return NULL;
828   if (!read_bmp_pal(ig, im, clr_used)) {
829     i_img_destroy(im);
830     return NULL;
831   }
832
833   if (offbits > base_offset) {
834     /* this will be slow if the offset is large, but that should be
835        rare */
836     char buffer;
837     while (base_offset < offbits) {
838       if (ig->readcb(ig, &buffer, 1) != 1) {
839         i_img_destroy(im);
840         i_push_error(0, "failed skipping to image data offset");
841         return NULL;
842       }
843       ++base_offset;
844     }
845   }
846   
847   if (line_size < 260)
848     packed = mymalloc(260); /* checked 29jun05 tonyc */
849   else
850     packed = mymalloc(line_size); /* checked 29jun05 tonyc */
851   /* xsize won't approach MAXINT */
852   line = mymalloc(xsize+1); /* checked 29jun05 tonyc */
853   if (compression == BI_RGB) {
854     i_tags_add(&im->tags, "bmp_compression_name", 0, "BI_RGB", -1, 0);
855     while (y != lasty) {
856       if (ig->readcb(ig, packed, line_size) != line_size) {
857         myfree(packed);
858         myfree(line);
859         i_push_error(0, "failed reading 4-bit bmp data");
860         i_img_destroy(im);
861         return NULL;
862       }
863       in = packed;
864       p = line;
865       for (x = 0; x < xsize; x+=2) {
866         *p++ = *in >> 4;
867         *p++ = *in & 0x0F;
868         ++in;
869       }
870       i_ppal(im, 0, xsize, y, line);
871       y += yinc;
872     }
873     myfree(packed);
874     myfree(line);
875   }
876   else if (compression == BI_RLE4) {
877     int read_size;
878     int count;
879
880     i_tags_add(&im->tags, "bmp_compression_name", 0, "BI_RLE4", -1, 0);
881     x = 0;
882     while (1) {
883       /* there's always at least 2 bytes in a sequence */
884       if (ig->readcb(ig, packed, 2) != 2) {
885         myfree(packed);
886         myfree(line);
887         i_push_error(0, "missing data during decompression");
888         i_img_destroy(im);
889         return NULL;
890       }
891       else if (packed[0]) {
892         line[0] = packed[1] >> 4;
893         line[1] = packed[1] & 0x0F;
894         for (i = 0; i < packed[0]; i += 2) {
895           if (i < packed[0]-1) 
896             i_ppal(im, x, x+2, y, line);
897           else
898             i_ppal(im, x, x+(packed[0]-i), y, line);
899           x += 2;
900         }
901       } else {
902         switch (packed[1]) {
903         case BMPRLE_ENDOFLINE:
904           x = 0;
905           y += yinc;
906           break;
907
908         case BMPRLE_ENDOFBMP:
909           myfree(packed);
910           myfree(line);
911           return im;
912
913         case BMPRLE_DELTA:
914           if (ig->readcb(ig, packed, 2) != 2) {
915             myfree(packed);
916             myfree(line);
917             i_push_error(0, "missing data during decompression");
918             i_img_destroy(im);
919             return NULL;
920           }
921           x += packed[0];
922           y += yinc * packed[1];
923           break;
924
925         default:
926           count = packed[1];
927           size = (count + 1) / 2;
928           read_size = (size+1) / 2 * 2;
929           if (ig->readcb(ig, packed, read_size) != read_size) {
930             myfree(packed);
931             myfree(line);
932             i_push_error(0, "missing data during decompression");
933             /*i_img_destroy(im);*/
934             return im;
935           }
936           for (i = 0; i < size; ++i) {
937             line[0] = packed[i] >> 4;
938             line[1] = packed[i] & 0xF;
939             i_ppal(im, x, x+2, y, line);
940             x += 2;
941           }
942           break;
943         }
944       }
945     }
946   }
947   else { /*if (compression == BI_RLE4) {*/
948     myfree(packed);
949     myfree(line);
950     i_push_errorf(0, "unknown 4-bit BMP compression (%d)", compression);
951     i_img_destroy(im);
952     return NULL;
953   }
954
955   return im;
956 }
957
958 /*
959 =item read_8bit_bmp(ig, xsize, ysize, clr_used, compression)
960
961 Reads in the palette and image data for a 8-bit/pixel image.
962
963 Returns the image or NULL.
964
965 =cut
966 */
967 static i_img *
968 read_8bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used, 
969               int compression, long offbits) {
970   i_img *im;
971   int x, y, lasty, yinc;
972   i_palidx *line;
973   int line_size = xsize;
974   long base_offset;
975
976   line_size = (line_size+3) / 4 * 4;
977   if (line_size < xsize) { /* if it overflowed (unlikely, but check) */
978     i_push_error(0, "integer overflow during memory allocation");
979     return NULL;
980   }
981
982   if (ysize > 0) {
983     y = ysize-1;
984     lasty = -1;
985     yinc = -1;
986   }
987   else {
988     /* when ysize is -ve it's a top-down image */
989     ysize = -ysize;
990     y = 0;
991     lasty = ysize;
992     yinc = 1;
993   }
994   if (!clr_used)
995     clr_used = 256;
996   if (clr_used > 256 || clr_used < 0) {
997     i_push_errorf(0, "out of range colors used (%d)", clr_used);
998     return NULL;
999   }
1000
1001   base_offset = FILEHEAD_SIZE + INFOHEAD_SIZE + clr_used * 4;
1002   if (offbits < base_offset) {
1003     i_push_errorf(0, "image data offset too small (%ld)", offbits);
1004     return NULL;
1005   }
1006
1007   im = i_img_pal_new(xsize, ysize, 3, 256);
1008   if (!im)
1009     return NULL;
1010   if (!read_bmp_pal(ig, im, clr_used)) {
1011     i_img_destroy(im);
1012     return NULL;
1013   }
1014
1015   if (offbits > base_offset) {
1016     /* this will be slow if the offset is large, but that should be
1017        rare */
1018     char buffer;
1019     while (base_offset < offbits) {
1020       if (ig->readcb(ig, &buffer, 1) != 1) {
1021         i_img_destroy(im);
1022         i_push_error(0, "failed skipping to image data offset");
1023         return NULL;
1024       }
1025       ++base_offset;
1026     }
1027   }
1028   
1029   line = mymalloc(line_size); /* checked 29jun05 tonyc */
1030   if (compression == BI_RGB) {
1031     i_tags_add(&im->tags, "bmp_compression_name", 0, "BI_RGB", -1, 0);
1032     while (y != lasty) {
1033       if (ig->readcb(ig, line, line_size) != line_size) {
1034         myfree(line);
1035         i_push_error(0, "failed reading 8-bit bmp data");
1036         i_img_destroy(im);
1037         return NULL;
1038       }
1039       i_ppal(im, 0, xsize, y, line);
1040       y += yinc;
1041     }
1042     myfree(line);
1043   }
1044   else if (compression == BI_RLE8) {
1045     int read_size;
1046     int count;
1047     unsigned char packed[2];
1048
1049     i_tags_add(&im->tags, "bmp_compression_name", 0, "BI_RLE8", -1, 0);
1050     x = 0;
1051     while (1) {
1052       /* there's always at least 2 bytes in a sequence */
1053       if (ig->readcb(ig, packed, 2) != 2) {
1054         myfree(line);
1055         i_push_error(0, "missing data during decompression");
1056         i_img_destroy(im);
1057         return NULL;
1058       }
1059       if (packed[0]) {
1060         memset(line, packed[1], packed[0]);
1061         i_ppal(im, x, x+packed[0], y, line);
1062         x += packed[0];
1063       } else {
1064         switch (packed[1]) {
1065         case BMPRLE_ENDOFLINE:
1066           x = 0;
1067           y += yinc;
1068           break;
1069
1070         case BMPRLE_ENDOFBMP:
1071           myfree(line);
1072           return im;
1073
1074         case BMPRLE_DELTA:
1075           if (ig->readcb(ig, packed, 2) != 2) {
1076             myfree(line);
1077             i_push_error(0, "missing data during decompression");
1078             i_img_destroy(im);
1079             return NULL;
1080           }
1081           x += packed[0];
1082           y += yinc * packed[1];
1083           break;
1084
1085         default:
1086           count = packed[1];
1087           read_size = (count+1) / 2 * 2;
1088           if (ig->readcb(ig, line, read_size) != read_size) {
1089             myfree(line);
1090             i_push_error(0, "missing data during decompression");
1091             i_img_destroy(im);
1092             return NULL;
1093           }
1094           i_ppal(im, x, x+count, y, line);
1095           x += count;
1096           break;
1097         }
1098       }
1099     }
1100   }
1101   else { 
1102     myfree(line);
1103     i_push_errorf(0, "unknown 8-bit BMP compression (%d)", compression);
1104     i_img_destroy(im);
1105     return NULL;
1106   }
1107
1108   return im;
1109 }
1110
1111 struct bm_masks {
1112   unsigned masks[3];
1113   int shifts[3];
1114 };
1115 static struct bm_masks std_masks[] =
1116 {
1117   { /* 16-bit */
1118     { 0770000, 00007700, 00000077, },
1119     { 10, 4, -2, },
1120   },
1121   { /* 24-bit */
1122     { 0xFF0000, 0x00FF00, 0x0000FF, },
1123     {       16,        8,        0, },
1124   },
1125   { /* 32-bit */
1126     { 0xFF0000, 0x00FF00, 0x0000FF, },
1127     {       16,        8,        0, },
1128   },
1129 };
1130
1131 /*
1132 =item read_direct_bmp(ig, xsize, ysize, bit_count, clr_used, compression)
1133
1134 Skips the palette and reads in the image data for a direct colour image.
1135
1136 Returns the image or NULL.
1137
1138 =cut
1139 */
1140 static i_img *
1141 read_direct_bmp(io_glue *ig, int xsize, int ysize, int bit_count, 
1142                 int clr_used, int compression, long offbits) {
1143   i_img *im;
1144   int x, y, lasty, yinc;
1145   i_color *line, *p;
1146   int pix_size = bit_count / 8;
1147   int line_size = xsize * pix_size;
1148   struct bm_masks masks;
1149   char unpack_code[2] = "";
1150   int i;
1151   int extras;
1152   char junk[4];
1153   const char *compression_name;
1154   int bytes;
1155   long base_offset = FILEHEAD_SIZE + INFOHEAD_SIZE;
1156   
1157   unpack_code[0] = *("v3V"+pix_size-2);
1158   unpack_code[1] = '\0';
1159
1160   line_size = (line_size+3) / 4 * 4;
1161   extras = line_size - xsize * pix_size;
1162
1163   if (ysize > 0) {
1164     y = ysize-1;
1165     lasty = -1;
1166     yinc = -1;
1167   }
1168   else {
1169     /* when ysize is -ve it's a top-down image */
1170     ysize = -ysize;
1171     y = 0;
1172     lasty = ysize;
1173     yinc = 1;
1174   }
1175   if (compression == BI_RGB) {
1176     compression_name = "BI_RGB";
1177     masks = std_masks[pix_size-2];
1178     
1179     /* there's a potential "palette" after the header */
1180     for (i = 0; i < clr_used; ++clr_used) {
1181       char buf[4];
1182       if (ig->readcb(ig, buf, 4) != 4) {
1183         i_push_error(0, "skipping colors");
1184         return 0;
1185       }
1186       base_offset += 4;
1187     }
1188   }
1189   else if (compression == BI_BITFIELDS) {
1190     int pos, bit;
1191     compression_name = "BI_BITFIELDS";
1192
1193     for (i = 0; i < 3; ++i) {
1194       if (!read_packed(ig, "V", masks.masks+i)) {
1195         i_push_error(0, "reading pixel masks");
1196         return 0;
1197       }
1198       /* work out a shift for the mask */
1199       pos = 0;
1200       bit = masks.masks[i] & -masks.masks[i];
1201       while (bit) {
1202         ++pos;
1203         bit >>= 1;
1204       }
1205       masks.shifts[i] = pos - 8;
1206     }
1207     base_offset += 4 * 4;
1208   }
1209   else {
1210     i_push_errorf(0, "unknown 24-bit BMP compression (%d)", compression);
1211     return NULL;
1212   }
1213
1214   if (offbits > base_offset) {
1215     /* this will be slow if the offset is large, but that should be
1216        rare */
1217     char buffer;
1218     while (base_offset < offbits) {
1219       if (ig->readcb(ig, &buffer, 1) != 1) {
1220         i_push_error(0, "failed skipping to image data offset");
1221         return NULL;
1222       }
1223       ++base_offset;
1224     }
1225   }
1226   
1227   im = i_img_empty(NULL, xsize, ysize);
1228   if (!im)
1229     return NULL;
1230
1231   i_tags_add(&im->tags, "bmp_compression_name", 0, compression_name, -1, 0);
1232
1233   /* I wasn't able to make this overflow in testing, but better to be
1234      safe */
1235   bytes = sizeof(i_color) * xsize;
1236   if (bytes / sizeof(i_color) != xsize) {
1237     i_img_destroy(im);
1238     i_push_error(0, "integer overflow calculating buffer size");
1239     return NULL;
1240   }
1241   line = mymalloc(bytes); /* checked 29jun05 tonyc */
1242   while (y != lasty) {
1243     p = line;
1244     for (x = 0; x < xsize; ++x) {
1245       unsigned pixel;
1246       if (!read_packed(ig, unpack_code, &pixel)) {
1247         i_push_error(0, "failed reading image data");
1248         myfree(line);
1249         i_img_destroy(im);
1250         return NULL;
1251       }
1252       for (i = 0; i < 3; ++i) {
1253         if (masks.shifts[i] > 0)
1254           p->channel[i] = (pixel & masks.masks[i]) >> masks.shifts[i];
1255         else 
1256           p->channel[i] = (pixel & masks.masks[i]) << -masks.shifts[i];
1257       }
1258       ++p;
1259     }
1260     i_plin(im, 0, xsize, y, line);
1261     if (extras)
1262       ig->readcb(ig, junk, extras);
1263     y += yinc;
1264   }
1265   myfree(line);
1266
1267   return im;
1268 }
1269
1270 /*
1271 =head1 SEE ALSO
1272
1273 Imager(3)
1274
1275 =head1 AUTHOR
1276
1277 Tony Cook <tony@develop-help.com>
1278
1279 =head1 RESTRICTIONS
1280
1281 Cannot save as compressed BMP.
1282
1283 =head1 BUGS
1284
1285 Doesn't handle OS/2 bitmaps.
1286
1287 16-bit/pixel images haven't been tested.  (I need an image).
1288
1289 BI_BITFIELDS compression hasn't been tested (I need an image).
1290
1291 The header handling for paletted images needs to be refactored
1292
1293 =cut
1294 */