improve fail-on handling for GIF load

fail-on truncated and warning now works for GIF load
This commit is contained in:
John Cupitt 2022-11-05 12:04:47 +00:00
parent b32bc70de7
commit 3ebb21491d
5 changed files with 60 additions and 8 deletions

View File

@ -18,6 +18,7 @@ master
- threadpools size dynamically with load
- operations can hint threadpool size
- support for N-colour ICC profiles
- GIF load supports truncated frames [tlsa]
11/10/22 started 8.13.3
- improve rules for 16-bit heifsave [johntrunc]

View File

@ -359,19 +359,44 @@ vips_foreign_load_nsgif_header( VipsForeignLoad *load )
return( -1 );
vips_source_minimise( gif->source );
/* Treat errors from _scan() as warnings. If libnsgif really can't do
* something it'll fail gracefully later when we try to read out
* frame data.
*/
result = nsgif_data_scan( gif->anim, size, (void *) data );
VIPS_DEBUG_MSG( "nsgif_data_scan() = %s\n", nsgif_strerror( result ) );
switch( result ) {
case NSGIF_ERR_END_OF_DATA:
if( load->fail_on >= VIPS_FAIL_ON_TRUNCATED ) {
vips_foreign_load_nsgif_error( gif, result );
return( -1 );
}
else
g_warning( "%s", nsgif_strerror( result ) );
break;
case NSGIF_OK:
break;
default:
if( load->fail_on >= VIPS_FAIL_ON_WARNING ) {
vips_foreign_load_nsgif_error( gif, result );
return( -1 );
}
else
g_warning( "%s", nsgif_strerror( result ) );
break;
}
/* Tell libnsgif that that's all the data we have. This will let us
* read out any truncated final frames.
*/
nsgif_data_complete( gif->anim );
gif->info = nsgif_get_info( gif->anim );
#ifdef VERBOSE
print_animation( gif->anim, gif->info );
#endif /*VERBOSE*/
if( result != NSGIF_OK &&
load->fail_on >= VIPS_FAIL_ON_WARNING ) {
vips_foreign_load_nsgif_error( gif, result );
return( -1 );
}
if( !gif->info->frame_count ) {
vips_error( class->nickname, "%s", _( "no frames in GIF" ) );
return( -1 );

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -7,7 +7,7 @@ import pytest
import pyvips
from helpers import \
JPEG_FILE, SRGB_FILE, MATLAB_FILE, PNG_FILE, TIF_FILE, OME_FILE, \
IMAGES, JPEG_FILE, SRGB_FILE, MATLAB_FILE, PNG_FILE, TIF_FILE, OME_FILE, \
ANALYZE_FILE, GIF_FILE, WEBP_FILE, EXR_FILE, FITS_FILE, OPENSLIDE_FILE, \
PDF_FILE, SVG_FILE, SVGZ_FILE, SVG_GZ_FILE, GIF_ANIM_FILE, DICOM_FILE, \
BMP_FILE, NIFTI_FILE, ICO_FILE, TGA_FILE, SGI_FILE, AVIF_FILE, \
@ -1012,6 +1012,32 @@ class TestForeign:
x2 = pyvips.Image.new_from_file(GIF_ANIM_DISPOSE_PREVIOUS_EXPECTED_PNG_FILE)
assert (x1 - x2).abs().max() == 0
@skip_if_no("gifload")
def test_gifload_truncated(self):
# should load with just a warning
truncated_gif = os.path.join(IMAGES, "truncated.gif")
im = pyvips.Image.new_from_file(truncated_gif)
assert im.width == 575
# should fail on truncation and warning
with pytest.raises(Exception):
im = pyvips.Image.new_from_file(truncated_gif, fail_on="warning")
with pytest.raises(Exception):
im = pyvips.Image.new_from_file(truncated_gif, fail_on="truncated")
@skip_if_no("gifload")
def test_gifload_frame_error(self):
# should load with just a warning
truncated_gif = os.path.join(IMAGES, "garden.gif")
im = pyvips.Image.new_from_file(truncated_gif)
assert im.width == 800
# should fail on warning only
im = pyvips.Image.new_from_file(truncated_gif, fail_on="truncated")
assert im.width == 800
with pytest.raises(Exception):
im = pyvips.Image.new_from_file(truncated_gif, fail_on="warning")
@skip_if_no("svgload")
def test_svgload(self):
def svg_valid(im):