diff --git a/MANIFEST b/MANIFEST index e5d11c7e6..59e7bd782 100644 --- a/MANIFEST +++ b/MANIFEST @@ -415,6 +415,7 @@ t/Image/Conversion.t t/Image/Extract.t t/Image/FloodFill.t t/Image/Import.t +t/Image/Loader.t t/Image/Path.t t/Image/ROP.t t/Image/Stream.t diff --git a/Prima/Classes.pm b/Prima/Classes.pm index 227fda475..d6b3845cb 100644 --- a/Prima/Classes.pm +++ b/Prima/Classes.pm @@ -983,6 +983,15 @@ sub save_stream return $ok; } +sub has_codec +{ + my $what = $_[1]; + for ( map { $_->{fileShortType} } @{ Prima::Image->codecs }) { + return 1 if m/$what/; + } + return 0; +} + package Prima::Icon; use vars qw( @ISA); @ISA = qw(Prima::Image); diff --git a/img/load.c b/img/load.c index 6303ddc4a..6892f9ff2 100644 --- a/img/load.c +++ b/img/load.c @@ -335,7 +335,7 @@ apc_img_open_load( char * fileName, Bool is_utf8, PImgIORequest ioreq, HV * pro char dummy_error_buf[256]; PImgCodec c; PImgLoadFileInstance fi; - long pos = 0; + long pos1 = 0, pos2 = 0; CHK; if ( !( fi = malloc(sizeof(ImgLoadFileInstance)))) { @@ -357,9 +357,6 @@ apc_img_open_load( char * fileName, Bool is_utf8, PImgIORequest ioreq, HV * pro fi-> fileProperties = newHV(); fi-> frameCount = -1; - if ( ioreq != NULL) - pos = req_tell( ioreq ); - if ( pexist( loadExtras) && pget_B( loadExtras)) fi-> loadExtras = true; @@ -394,9 +391,13 @@ apc_img_open_load( char * fileName, Bool is_utf8, PImgIORequest ioreq, HV * pro fi-> baseClassName = duplicate_string("Prima::Image"); /* find codec */ + if ( ioreq != NULL) + pos1 = req_tell( ioreq ); if (( err = !img_find_codec( fi))) goto EXIT_NOW; c = fi->codec; + if ( ioreq != NULL) + pos2 = req_tell( ioreq ); /* use common profile */ fi-> cached_defaults = c-> vmt-> load_defaults( c); @@ -408,10 +409,10 @@ apc_img_open_load( char * fileName, Bool is_utf8, PImgIORequest ioreq, HV * pro if ( fi-> frameCount < 0 && fi-> wantFrames) { if ( ioreq != NULL) - req_seek( ioreq, pos, SEEK_SET); + req_seek( ioreq, pos1, SEEK_SET); fi-> frameCount = apc_img_frame_count( fileName, is_utf8, ioreq); if ( ioreq != NULL) - req_seek( ioreq, pos, SEEK_SET); + req_seek( ioreq, pos2, SEEK_SET); } if ( fi-> loadExtras ) { @@ -690,9 +691,7 @@ apc_img_load( Handle self, char * fileName, Bool is_utf8, PImgIORequest ioreq, Bool eof_is_not_an_error = false; if ( incrementalLoad ) { - if ( fi->frameCount < 0 ) - fi->frame++; - else if ( i >= fi->frameCount) + if ( fi->frameCount >= 0 && i >= fi->frameCount) break; } else { if ( fi->frameCount < 0 ) @@ -714,6 +713,9 @@ apc_img_load( Handle self, char * fileName, Bool is_utf8, PImgIORequest ioreq, img = apc_img_load_next_frame( self, fi, frame_profile, error ); + if ( incrementalLoad ) + fi->frame++; + if ( img == NULL_HANDLE && incrementalLoad ) { /* if it is EOF? report no error then */ if ( fi-> frameCount < 0) { @@ -1086,6 +1088,7 @@ apc_img_save_next_frame( Handle source, PImgSaveFileInstance fi, HV * profile, c /* saving image */ if ( !c-> vmt-> save( c, fi)) { c-> vmt-> close_save( c, fi); + fi->instance = NULL; err = true; } diff --git a/t/Image/Loader.t b/t/Image/Loader.t new file mode 100644 index 000000000..a4f3be1fc --- /dev/null +++ b/t/Image/Loader.t @@ -0,0 +1,118 @@ +use strict; +use warnings; + +use Prima::sys::Test qw(noX11); +use Test::More; +use Prima::Image::Loader; + +my @codecs; +my @names; + +for ( @{ Prima::Image->codecs }) { + next unless $_->{canLoad} && $_->{canSave} && $_->{canSaveMultiple} && $_->{canLoadMultiple} && $_->{canSaveStream} && $_->{canLoadStream}; + push @codecs, $_->{codecID}; + push @names, $_->{fileShortType}; +} +plan skip_all => 'No multiframe-capable codecs' unless @codecs; + +sub ix($) { + Prima::Image->new( + type => im::Byte, + size => [1,1], + data => $_[0], + ) +} +my @ix = map { ix chr } 0..2; + +sub test_codec +{ + my ($codecID, $name) = @_; + + my $buf1 = ''; + open F, "+>", \ $buf1 or die $!; + + my $ok = Prima::Image->save( \*F, images => \@ix, codecID => $codecID); + ok( $ok, "$name: traditional save".( $ok ? '' : ":$@")); + + my $buf2 = ''; + open G, "+>", \ $buf2 or die $!; + + my ($s,$err) = Prima::Image::Saver->new( \*G, codecID => $codecID, frames => scalar(@ix) ) ; + ok( $s, "$name: open_save".($s ? '' : ":$err")); + + for (0..2) { + ($ok,$err) = $s->save($ix[$_]); + ok($ok, "$name: save frame $_".($ok ? '' : ":$err")); + } + undef $s; + close G; + ok( $buf1 eq $buf2, "$name: traditional and framed saves produce identical results"); + + + seek(F,0,0); + my @nx = Prima::Image->load(\*F, loadAll => 1, loadExtras => 1 ); + is( scalar(@nx), 3, "$name: traditional load returned 3 frames"); + is( $nx[0] && $nx[0]->{extras} && $nx[0]->{extras}->{frames}, 3, "$name: extras.frames is okay"); + for my $n ( 0..2 ) { + is($nx[$n]->pixel(0,0), $n, "$name/loadAll: image $n is loaded correctly") if $nx[$n]; + } + + for my $n (0..2) { + seek(F,0,0); + @nx = Prima::Image->load(\*F, index => $n); + is( scalar(@nx), 1, "$name/index: index $n loaded ok"); + is($nx[0]->pixel(0,0), $n, "$name/index: image $n is loaded correctly") if $nx[0]; + + my $i = Prima::Image->new; + seek(F,0,0); + ($ok,$err) = $i->load(\*F, index => $n); + ok( $ok, "$name/inplace: index $n loaded ok"); + is($i->pixel(0,0), $n, "$name/inplace: image $n is loaded correctly"); + + seek(F,0,0); + @nx = Prima::Image->load(\*F, map => [$n]); + is( scalar(@nx), 1, "$name/map: index $n loaded ok"); + is($nx[0]->pixel(0,0), $n, "$name/map: image $n is loaded correctly") if $nx[0]; + + my $m = ($n < 2) ? $n + 1 : 0; + seek(F,0,0); + @nx = Prima::Image->load(\*F, map => [$n, $m]); + is( scalar(@nx), 2, "$name/map($n,$m): images $n and $m loaded ok"); + is($nx[0]->pixel(0,0), $n, "$name/map($n,$m): image $n is loaded correctly") if $nx[0]; + is($nx[1]->pixel(0,0), $m, "$name/map($n,$m): image $m is loaded correctly") if $nx[1]; + } + + my ($lx,$i); + $i = Prima::Image->new; + seek(F,0,0); + @nx = $i->load(\*F, map => [], loadExtras => 1, wantFrames => 1); + is(scalar(@nx), 0, "$name: traditional null load request is ok"); + is($i->{extras}->{frames}, 3, "$name: traditional null load request says 3 frames"); + + seek(F,0,0); + ($lx,$err) = Prima::Image::Loader->new(\*F); + ok( $lx, "$name: loader created".($ok?'':":$err")); + + is($lx->frames, 3, "$name/loader: null load request says 3 frames"); + + for my $n (0..2) { + ok(!$lx->eof, "$name/loader: lx($n) is not eof"); + ($i,$err) = $lx->next; + ok( $i, "$name/loader: image $n loaded".($i?'':":$err")); + is($i->pixel(0,0), $n, "$name/loader: image $n is loaded correctly") + if $i; + } + ok($lx->eof,"$name/loader: lx(3) is eof"); + ($i,$err) = $lx->next; + ok(!$i, "$name/loader: image(3) is null"); + + close F; +} + +for ( my $i = 0; $i < @codecs; $i++) { + test_codec($codecs[$i], $names[$i]); +# last; # XXX +} + + +done_testing;