#!perl -w ######################### We start with some black magic to print on failure. # this used to do the check for the load of Imager, but I want to be able # to count tests, which means I need to load Imager first # since many of the early tests already do this, we don't really need to use strict; use Imager; use IO::Seekable; my $buggy_giflib_file = "buggy_giflib.txt"; Imager::init("log"=>"testout/t50basicoo.log"); # single image/file types my @types = qw( jpeg png raw ppm gif tiff bmp tga ); # multiple image/file formats my @mtypes = qw(tiff gif); my %hsh=%Imager::formats; my $test_num = 0; my $count; for my $type (@types) { $count += 31 if $hsh{$type}; } for my $type (@mtypes) { $count += 7 if $hsh{$type}; } print "1..$count\n"; print "# avaliable formats:\n"; for(keys %hsh) { print "# $_\n"; } #print Dumper(\%hsh); my $img = Imager->new(); my %files; @files{@types} = ({ file => "testout/t101.jpg" }, { file => "testout/t102.png" }, { file => "testout/t103.raw", xsize=>150, ysize=>150, type=>'raw'}, { file => "testout/t104.ppm" }, { file => "testout/t105.gif" }, { file => "testout/t106.tiff" }, { file => "testout/t107_24bit.bmp" }, { file => "testout/t108_24bit.tga" }, ); my %writeopts = ( gif=> { make_colors=>'webmap', translate=>'closest', gifquant=>'gen', gif_delay=>20 }, ); for my $type (@types) { next unless $hsh{$type}; print "# type $type\n"; my %opts = %{$files{$type}}; my @a = map { "$_=>${opts{$_}}" } keys %opts; print "#opening Format: $type, options: @a\n"; ok($img->read( %opts ), "reading from file", $img); #or die "failed: ",$img->errstr,"\n"; my %mopts = %opts; delete $mopts{file}; # read from a file handle my $fh = IO::File->new($opts{file}, "r"); if (ok($fh, "opening $opts{file}")) { binmode $fh; my $fhimg = Imager->new; if (ok($fhimg->read(fh=>$fh, %mopts), "read from fh")) { ok($fh->seek(0, SEEK_SET), "seek after read"); if (ok($fhimg->read(fh=>$fh, %mopts, type=>$type), "read from fh")) { ok(Imager::i_img_diff($img->{IMG}, $fhimg->{IMG}) == 0, "image comparison after fh read"); } else { skip("no image to compare"); } ok($fh->seek(0, SEEK_SET), "seek after read"); } # read from a fd my $fdimg = Imager->new; if (ok($fdimg->read(fd=>fileno($fh), %mopts, type=>$type), "read from fd")) { ok(Imager::i_img_diff($img->{IMG}, $fdimg->{IMG}) == 0, "image comparistion after fd read"); } else { skip("no image to compare"); } ok($fh->seek(0, SEEK_SET), "seek after fd read"); ok($fh->close, "close fh after reads"); } else { skip("couldn't open the damn file: $!", 7); } if ($type ne 'gif' || Imager::i_giflib_version() >= 4) { # read from a memory buffer open DATA, "< $opts{file}" or die "Cannot open $opts{file}: $!"; binmode DATA; my $data = do { local $/; }; close DATA; my $bimg = Imager->new; if (ok($bimg->read(data=>$data, %mopts, type=>$type), "read from buffer", $img)) { ok(Imager::i_img_diff($img->{IMG}, $bimg->{IMG}) == 0, "comparing buffer read image"); } else { skip("nothing to compare"); } # read from callbacks, both with minimum and maximum reads my $buf = $data; my $seekpos = 0; my $reader_min = sub { my ($size, $maxread) = @_; my $out = substr($buf, $seekpos, $size); $seekpos += length $out; $out; }; my $reader_max = sub { my ($size, $maxread) = @_; my $out = substr($buf, $seekpos, $maxread); $seekpos += length $out; $out; }; my $seeker = sub { my ($offset, $whence) = @_; #print "io_seeker($offset, $whence)\n"; if ($whence == SEEK_SET) { $seekpos = $offset; } elsif ($whence == SEEK_CUR) { $seekpos += $offset; } else { # SEEK_END $seekpos = length($buf) + $offset; } #print "-> $seekpos\n"; $seekpos; }; my $cbimg = Imager->new; ok($cbimg->read(callback=>$reader_min, seekcb=>$seeker, type=>$type, %mopts), "read from callback min", $cbimg); ok(Imager::i_img_diff($cbimg->{IMG}, $img->{IMG}) == 0, "comparing mincb image"); $seekpos = 0; ok($cbimg->read(callback=>$reader_max, seekcb=>$seeker, type=>$type, %mopts), "read from callback max", $cbimg); ok(Imager::i_img_diff($cbimg->{IMG}, $img->{IMG}) == 0, "comparing maxcb image"); } else { skip("giflib < 4 doesn't support callbacks", 6); } } for my $type (@types) { next unless $hsh{$type}; print "# write tests for $type\n"; # test writes next unless $hsh{$type}; my $file = "testout/t50out.$type"; my $wimg = Imager->new; # if this doesn't work, we're so screwed up anyway ok($wimg->read(file=>"testout/t104.ppm"), "cannot read base file", $wimg); # first to a file print "# writing $type to a file\n"; my %extraopts; %extraopts = %{$writeopts{$type}} if $writeopts{$type}; ok($wimg->write(file=>$file, %extraopts), "writing $type to a file $file", $wimg); print "# writing $type to a FH\n"; # to a FH my $fh = IO::File->new($file, "w+") or die "Could not create $file: $!"; binmode $fh; ok($wimg->write(fh=>$fh, %extraopts, type=>$type), "writing $type to a FH", $wimg); ok($fh->seek(0, SEEK_END) > 0, "seek after writing $type to a FH"); ok(print($fh "SUFFIX\n"), "write to FH after writing $type"); ok($fh->close, "closing FH after writing $type"); if ($type ne 'gif' || (Imager::i_giflib_version() >= 4 && !-e $buggy_giflib_file)) { if (ok(open(DATA, "< $file"), "opening data source")) { binmode DATA; my $data = do { local $/; }; close DATA; # writing to a buffer print "# writing $type to a buffer\n"; my $buf = ''; ok($wimg->write(data=>\$buf, %extraopts, type=>$type), "writing $type to a buffer", $wimg); $buf .= "SUFFIX\n"; open DATA, "> testout/t50_buf.$type" or die "Cannot create $type buffer file: $!"; binmode DATA; print DATA $buf; close DATA; ok($data eq $buf, "comparing file data to buffer"); $buf = ''; my $seekpos = 0; my $did_close; my $writer = sub { my ($what) = @_; if ($seekpos > length $buf) { $buf .= "\0" x ($seekpos - length $buf); } substr($buf, $seekpos, length $what) = $what; $seekpos += length $what; $did_close = 0; # the close must be last 1; }; my $reader_min = sub { my ($size, $maxread) = @_; my $out = substr($buf, $seekpos, $size); $seekpos += length $out; $out; }; my $reader_max = sub { my ($size, $maxread) = @_; my $out = substr($buf, $seekpos, $maxread); $seekpos += length $out; $out; }; use IO::Seekable; my $seeker = sub { my ($offset, $whence) = @_; #print "io_seeker($offset, $whence)\n"; if ($whence == SEEK_SET) { $seekpos = $offset; } elsif ($whence == SEEK_CUR) { $seekpos += $offset; } else { # SEEK_END $seekpos = length($buf) + $offset; } #print "-> $seekpos\n"; $seekpos; }; my $closer = sub { ++$did_close; }; print "# writing $type via callbacks (mb=1)\n"; ok($wimg->write(writecb=>$writer, seekcb=>$seeker, closecb=>$closer, readcb=>$reader_min, %extraopts, type=>$type, maxbuffer=>1), "writing $type to callback (mb=1)", $wimg); ok($did_close, "checking closecb called"); $buf .= "SUFFIX\n"; ok($data eq $buf, "comparing callback output to file data"); print "# writing $type via callbacks (no mb)\n"; $buf = ''; $did_close = 0; $seekpos = 0; # we don't use the closecb here - used to make sure we don't get # a warning/error on an attempt to call an undef close sub ok($wimg->write(writecb=>$writer, seekcb=>$seeker, readcb=>$reader_min, %extraopts, type=>$type), "writing $type to callback (no mb)", $wimg); $buf .= "SUFFIX\n"; ok($data eq $buf, "comparing callback output to file data"); } else { skip("couldn't open data source", 7); } } else { if (-e $buggy_giflib_file) { skip("see $buggy_giflib_file", 8); } else { skip("giflib < 4 doesn't support callbacks", 8); } } } my $img2 = $img->crop(width=>50, height=>50); $img2 -> write(file=> 'testout/t50.ppm', type=>'pnm'); undef($img); # multi image/file tests print "# multi-image write tests\n"; for my $type (@mtypes) { next unless $hsh{$type}; print "# $type\n"; my $file = "testout/t50out.$type"; my $wimg = Imager->new; # if this doesn't work, we're so screwed up anyway ok($wimg->read(file=>"testout/t50out.$type"), "reading base file", $wimg); ok(my $wimg2 = $wimg->copy, "copying base image", $wimg); ok($wimg2->flip(dir=>'h'), "flipping base image", $wimg2); my @out = ($wimg, $wimg2); my %extraopts; %extraopts = %{$writeopts{$type}} if $writeopts{$type}; ok(Imager->write_multi({ file=>"testout/t50_multi.$type", %extraopts }, @out), "writing multiple to a file", "Imager"); # make sure we get the same back my @images = Imager->read_multi(file=>"testout/t50_multi.$type"); if (ok(@images == @out, "checking read image count")) { for my $i (0 .. $#out) { my $diff = Imager::i_img_diff($out[$i]{IMG}, $images[$i]{IMG}); print "# diff $diff\n"; ok($diff == 0, "comparing image $i"); } } else { skip("wrong number of images read", 2); } } Imager::malloc_state(); #print "ok 2\n"; sub ok { my ($ok, $msg, $img, $why, $skipcount) = @_; ++$test_num; if ($ok) { print "ok $test_num # $msg\n"; Imager::log_entry("ok $test_num # $msg\n", 0); } else { my $err; $err = $img->errstr if $img; # VMS (if we ever support it) wants the whole line in one print my $line = "not ok $test_num # line ".(caller)[2].": $msg"; $line .= ": $err" if $err; print $line, "\n"; Imager::log_entry($line."\n", 0); } skip($why, $skipcount) if defined $why; $ok; } sub skip { my ($why, $skipcount) = @_; $skipcount ||= 1; for (1.. $skipcount) { ++$test_num; print "ok $test_num # skipped $why\n"; } }