static int write_24bit_data(io_glue *ig, i_img *im);
static int read_bmp_pal(io_glue *ig, i_img *im, int count);
static i_img *read_1bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used,
- int compression);
+ int compression, long offbits);
static i_img *read_4bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used,
- int compression);
+ int compression, long offbits);
static i_img *read_8bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used,
- int compression);
+ int compression, long offbits);
static i_img *read_direct_bmp(io_glue *ig, int xsize, int ysize,
- int bit_count, int clr_used, int compression);
+ int bit_count, int clr_used, int compression,
+ long offbits);
/*
=item i_writebmp_wiol(im, io_glue)
switch (bit_count) {
case 1:
- im = read_1bit_bmp(ig, xsize, ysize, clr_used, compression);
+ im = read_1bit_bmp(ig, xsize, ysize, clr_used, compression, offbits);
break;
case 4:
- im = read_4bit_bmp(ig, xsize, ysize, clr_used, compression);
+ im = read_4bit_bmp(ig, xsize, ysize, clr_used, compression, offbits);
break;
case 8:
- im = read_8bit_bmp(ig, xsize, ysize, clr_used, compression);
+ im = read_8bit_bmp(ig, xsize, ysize, clr_used, compression, offbits);
break;
case 32:
case 24:
case 16:
- im = read_direct_bmp(ig, xsize, ysize, bit_count, clr_used, compression);
+ im = read_direct_bmp(ig, xsize, ysize, bit_count, clr_used, compression,
+ offbits);
break;
default:
}
/*
-=item read_1bit_bmp(ig, xsize, ysize, clr_used)
+=item read_1bit_bmp(ig, xsize, ysize, clr_used, compression, offbits)
Reads in the palette and image data for a 1-bit/pixel image.
*/
static i_img *
read_1bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used,
- int compression) {
+ int compression, long offbits) {
i_img *im;
int x, y, lasty, yinc;
i_palidx *line, *p;
int line_size = (xsize + 7)/8;
int byte, bit;
unsigned char *in;
+ long base_offset;
if (compression != BI_RGB) {
i_push_errorf(0, "unknown 1-bit BMP compression (%d)", compression);
i_push_errorf(0, "out of range colors used (%d)", clr_used);
return NULL;
}
+
+ base_offset = FILEHEAD_SIZE + INFOHEAD_SIZE + clr_used * 4;
+ if (offbits < base_offset) {
+ i_push_errorf(0, "image data offset too small (%ld)", offbits);
+ return NULL;
+ }
+
im = i_img_pal_new(xsize, ysize, 3, 256);
if (!im)
return NULL;
i_img_destroy(im);
return NULL;
}
+
+ if (offbits > base_offset) {
+ /* this will be slow if the offset is large, but that should be
+ rare */
+ char buffer;
+ while (base_offset < offbits) {
+ if (ig->readcb(ig, &buffer, 1) != 1) {
+ i_img_destroy(im);
+ i_push_error(0, "failed skipping to image data offset");
+ return NULL;
+ }
+ ++base_offset;
+ }
+ }
i_tags_add(&im->tags, "bmp_compression_name", 0, "BI_RGB", -1, 0);
*/
static i_img *
read_4bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used,
- int compression) {
+ int compression, long offbits) {
i_img *im;
int x, y, lasty, yinc;
i_palidx *line, *p;
int line_size = (xsize + 1)/2;
unsigned char *in;
int size, i;
+ long base_offset;
line_size = (line_size+3) / 4 * 4;
return NULL;
}
+ base_offset = FILEHEAD_SIZE + INFOHEAD_SIZE + clr_used * 4;
+ if (offbits < base_offset) {
+ i_push_errorf(0, "image data offset too small (%ld)", offbits);
+ return NULL;
+ }
+
im = i_img_pal_new(xsize, ysize, 3, 256);
if (!im) /* error should have been pushed already */
return NULL;
return NULL;
}
+ if (offbits > base_offset) {
+ /* this will be slow if the offset is large, but that should be
+ rare */
+ char buffer;
+ while (base_offset < offbits) {
+ if (ig->readcb(ig, &buffer, 1) != 1) {
+ i_img_destroy(im);
+ i_push_error(0, "failed skipping to image data offset");
+ return NULL;
+ }
+ ++base_offset;
+ }
+ }
+
if (line_size < 260)
packed = mymalloc(260);
else
*/
static i_img *
read_8bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used,
- int compression) {
+ int compression, long offbits) {
i_img *im;
int x, y, lasty, yinc;
i_palidx *line, *p;
int line_size = xsize;
unsigned char *in;
+ long base_offset;
line_size = (line_size+3) / 4 * 4;
return NULL;
}
+ base_offset = FILEHEAD_SIZE + INFOHEAD_SIZE + clr_used * 4;
+ if (offbits < base_offset) {
+ i_push_errorf(0, "image data offset too small (%ld)", offbits);
+ return NULL;
+ }
+
im = i_img_pal_new(xsize, ysize, 3, 256);
if (!im)
return NULL;
return NULL;
}
+ if (offbits > base_offset) {
+ /* this will be slow if the offset is large, but that should be
+ rare */
+ char buffer;
+ while (base_offset < offbits) {
+ if (ig->readcb(ig, &buffer, 1) != 1) {
+ i_img_destroy(im);
+ i_push_error(0, "failed skipping to image data offset");
+ return NULL;
+ }
+ ++base_offset;
+ }
+ }
+
line = mymalloc(line_size);
if (compression == BI_RGB) {
i_tags_add(&im->tags, "bmp_compression_name", 0, "BI_RGB", -1, 0);
*/
static i_img *
read_direct_bmp(io_glue *ig, int xsize, int ysize, int bit_count,
- int clr_used, int compression) {
+ int clr_used, int compression, long offbits) {
i_img *im;
int x, y, lasty, yinc;
i_color *line, *p;
char junk[4];
const char *compression_name;
int bytes;
+ long base_offset = FILEHEAD_SIZE + INFOHEAD_SIZE;
unpack_code[0] = *("v3V"+pix_size-2);
unpack_code[1] = '\0';
i_push_error(0, "skipping colors");
return 0;
}
+ base_offset += 4;
}
}
else if (compression == BI_BITFIELDS) {
}
masks.shifts[i] = pos - 8;
}
+ base_offset += 4 * 4;
}
else {
i_push_errorf(0, "unknown 24-bit BMP compression (%d)", compression);
return NULL;
}
+ if (offbits > base_offset) {
+ /* this will be slow if the offset is large, but that should be
+ rare */
+ char buffer;
+ while (base_offset < offbits) {
+ if (ig->readcb(ig, &buffer, 1) != 1) {
+ i_img_destroy(im);
+ i_push_error(0, "failed skipping to image data offset");
+ return NULL;
+ }
+ ++base_offset;
+ }
+ }
+
im = i_img_empty(NULL, xsize, ysize);
if (!im)
return NULL;
BI_BITFIELDS compression hasn't been tested (I need an image).
+The header handling for paletted images needs to be refactored
+
=cut
*/
#!perl -w
-print "1..62\n";
+print "1..74\n";
use Imager qw(:all);
use strict;
init_log("testout/t107bmp.log",1);
-require 't/testtools.pl';
+BEGIN { require 't/testtools.pl'; } # BEGIN to apply prototypes
my $base_diff = 0;
# if you change this make sure you generate new compressed versions
$test_num += 2;
}
}
+
+# previously we didn't seek to the offbits position before reading
+# the image data, check we handle it correctly
+# in each case the first is an original image with a given number of
+# bits and the second is the same file with data inserted before the
+# image bits and the offset modified to suit
+my @comp =
+ (
+ [ 'winrgb2.bmp', 'winrgb2off.bmp', 1 ],
+ [ 'winrgb4.bmp', 'winrgb4off.bmp', 4 ],
+ [ 'winrgb8.bmp', 'winrgb8off.bmp', 8 ],
+ [ 'winrgb24.bmp', 'winrgb24off.bmp', 24 ],
+ );
+
+for my $comp (@comp) {
+ my ($base_file, $off_file, $bits) = @$comp;
+
+ my $base_im = Imager->new;
+ my $got_base =
+ okn($test_num++, $base_im->read(file=>"testimg/$base_file"),
+ "read original")
+ or print "# ",$base_im->errstr,"\n";
+ my $off_im = Imager->new;
+ my $got_off =
+ okn($test_num++, $off_im->read(file=>"testimg/$off_file"),
+ "read offset file")
+ or print "# ",$off_im->errstr,"\n";
+ if ($got_base && $got_off) {
+ okn($test_num++, !i_img_diff($base_im->{IMG}, $off_im->{IMG}),
+ "compare base and offset image ($bits bits)");
+ }
+ else {
+ skipn($test_num++, 1, "missed one file");
+ }
+}
sub write_test {
my ($test_num, $im, $filename) = @_;