diff --git a/libvips/foreign/webp2vips.c b/libvips/foreign/webp2vips.c index a620c25c..36164d5e 100644 --- a/libvips/foreign/webp2vips.c +++ b/libvips/foreign/webp2vips.c @@ -287,11 +287,6 @@ vips_image_paint_image( VipsImage *frame, g_assert( VIPS_IMAGE_SIZEOF_PEL( sub ) == ps ); - /* Disable blend if we are not RGBA. - */ - if( frame->Bands != 4 ) - blend = FALSE; - vips_rect_intersectrect( &frame_rect, &sub_rect, &ovl ); if( !vips_rect_isempty( &ovl ) ) { VipsPel *p, *q; @@ -455,10 +450,11 @@ read_header( Read *read, VipsImage *out ) flags = WebPDemuxGetI( read->demux, WEBP_FF_FORMAT_FLAGS ); read->alpha = flags & ALPHA_FLAG; - if( read->alpha ) - read->config.output.colorspace = MODE_RGBA; - else - read->config.output.colorspace = MODE_RGB; + + /* We do everything as RGBA and then, if we can, drop the alpha on + * save. + */ + read->config.output.colorspace = MODE_RGBA; if( flags & ANIMATION_FLAG ) { int loop_count; @@ -553,10 +549,12 @@ read_header( Read *read, VipsImage *out ) } } + /* The canvas is always RGBA, we drop alpha to RGB on output if we + * can. + */ read->frame = vips_image_new_memory(); vips_image_init_fields( read->frame, - read->frame_width, read->frame_height, - read->alpha ? 4 : 3, + read->frame_width, read->frame_height, 4, VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, VIPS_INTERPRETATION_sRGB, 1.0, 1.0 ); @@ -619,8 +617,7 @@ read_frame( Read *read, frame = vips_image_new_memory(); vips_image_init_fields( frame, - width, height, - read->alpha ? 4 : 3, + width, height, 4, VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, VIPS_INTERPRETATION_sRGB, 1.0, 1.0 ); @@ -765,9 +762,29 @@ read_webp_generate( VipsRegion *or, read->frame_no += 1; } - memcpy( VIPS_REGION_ADDR( or, 0, r->top ), - VIPS_IMAGE_ADDR( read->frame, 0, line ), - VIPS_IMAGE_SIZEOF_LINE( read->frame ) ); + if( or->im->Bands == 4 ) + memcpy( VIPS_REGION_ADDR( or, 0, r->top ), + VIPS_IMAGE_ADDR( read->frame, 0, line ), + VIPS_IMAGE_SIZEOF_LINE( read->frame ) ); + else { + int x; + VipsPel *p; + VipsPel *q; + + /* We know that alpha is solid, so we can just drop the 4th + * band. + */ + p = VIPS_IMAGE_ADDR( read->frame, 0, line ); + q = VIPS_REGION_ADDR( or, 0, r->top ); + for( x = 0; x < r->width; x++ ) { + q[0] = p[0]; + q[1] = p[1]; + q[2] = p[2]; + + q += 3; + p += 4; + } + } return( 0 ); } diff --git a/test/test-suite/test_foreign.py b/test/test-suite/test_foreign.py index b260705a..cf917bf1 100644 --- a/test/test-suite/test_foreign.py +++ b/test/test-suite/test_foreign.py @@ -463,7 +463,7 @@ class TestForeign: def test_webp(self): def webp_valid(im): a = im(10, 10) - assert_almost_equal_objects(a, [71, 166, 236]) + assert_almost_equal_objects(a, [70, 165, 235]) assert im.width == 550 assert im.height == 368 assert im.bands == 3 @@ -478,7 +478,7 @@ class TestForeign: im = pyvips.Image.new_from_file(WEBP_FILE) buf = im.webpsave_buffer(lossless=True) im2 = pyvips.Image.new_from_buffer(buf, "") - assert im.avg() == im2.avg() + assert abs(im.avg() - im2.avg()) < 1 # higher Q should mean a bigger buffer b1 = im.webpsave_buffer(Q=10)