more animated webp load fixes
webpload scale on load works for animated images
This commit is contained in:
parent
37865e34f8
commit
b1c995b2d9
|
@ -153,6 +153,39 @@ typedef struct {
|
||||||
VipsRect dispose_rect;
|
VipsRect dispose_rect;
|
||||||
} Read;
|
} Read;
|
||||||
|
|
||||||
|
const char *
|
||||||
|
vips__error_webp( VP8StatusCode code )
|
||||||
|
{
|
||||||
|
switch( code ) {
|
||||||
|
case VP8_STATUS_OK:
|
||||||
|
return( "VP8_STATUS_OK" );
|
||||||
|
|
||||||
|
case VP8_STATUS_OUT_OF_MEMORY:
|
||||||
|
return( "VP8_STATUS_OUT_OF_MEMORY" );
|
||||||
|
|
||||||
|
case VP8_STATUS_INVALID_PARAM:
|
||||||
|
return( "VP8_STATUS_INVALID_PARAM" );
|
||||||
|
|
||||||
|
case VP8_STATUS_BITSTREAM_ERROR:
|
||||||
|
return( "VP8_STATUS_BITSTREAM_ERROR" );
|
||||||
|
|
||||||
|
case VP8_STATUS_UNSUPPORTED_FEATURE:
|
||||||
|
return( "VP8_STATUS_UNSUPPORTED_FEATURE" );
|
||||||
|
|
||||||
|
case VP8_STATUS_SUSPENDED:
|
||||||
|
return( "VP8_STATUS_SUSPENDED" );
|
||||||
|
|
||||||
|
case VP8_STATUS_USER_ABORT:
|
||||||
|
return( "VP8_STATUS_USER_ABORT" );
|
||||||
|
|
||||||
|
case VP8_STATUS_NOT_ENOUGH_DATA:
|
||||||
|
return( "VP8_STATUS_NOT_ENOUGH_DATA" );
|
||||||
|
|
||||||
|
default:
|
||||||
|
return( "<unkown>" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
vips_image_paint_area( VipsImage *image, const VipsRect *r, const VipsPel *ink )
|
vips_image_paint_area( VipsImage *image, const VipsRect *r, const VipsPel *ink )
|
||||||
{
|
{
|
||||||
|
@ -233,32 +266,34 @@ blend_pixel( guint32 A, guint32 B )
|
||||||
return( setRGBA( rR, gR, bR, aR ) );
|
return( setRGBA( rR, gR, bR, aR ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Blend sub into frame at left, top.
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
vips_image_paint_image( VipsImage *image,
|
vips_image_paint_image( VipsImage *frame,
|
||||||
VipsImage *ink, int x, int y, gboolean blend )
|
VipsImage *sub, int left, int top, gboolean blend )
|
||||||
{
|
{
|
||||||
VipsRect valid = { 0, 0, image->Xsize, image->Ysize };
|
VipsRect frame_rect = { 0, 0, frame->Xsize, frame->Ysize };
|
||||||
VipsRect sub = { x, y, ink->Xsize, ink->Ysize };
|
VipsRect sub_rect = { left, top, sub->Xsize, sub->Ysize };
|
||||||
int ps = VIPS_IMAGE_SIZEOF_PEL( image );
|
int ps = VIPS_IMAGE_SIZEOF_PEL( frame );
|
||||||
|
|
||||||
VipsRect ovl;
|
VipsRect ovl;
|
||||||
|
|
||||||
g_assert( VIPS_IMAGE_SIZEOF_PEL( ink ) == ps );
|
g_assert( VIPS_IMAGE_SIZEOF_PEL( sub ) == ps );
|
||||||
|
|
||||||
/* Disable blend if we are not RGBA.
|
/* Disable blend if we are not RGBA.
|
||||||
*/
|
*/
|
||||||
if( image->Bands != 4 )
|
if( frame->Bands != 4 )
|
||||||
blend = FALSE;
|
blend = FALSE;
|
||||||
|
|
||||||
vips_rect_intersectrect( &valid, &sub, &ovl );
|
vips_rect_intersectrect( &frame_rect, &sub_rect, &ovl );
|
||||||
if( !vips_rect_isempty( &ovl ) ) {
|
if( !vips_rect_isempty( &ovl ) ) {
|
||||||
VipsPel *p, *q;
|
VipsPel *p, *q;
|
||||||
int i;
|
int x, y;
|
||||||
|
|
||||||
p = VIPS_IMAGE_ADDR( ink, ovl.left - x, ovl.top - y );
|
p = VIPS_IMAGE_ADDR( sub, ovl.left - left, ovl.top - top );
|
||||||
q = VIPS_IMAGE_ADDR( image, ovl.left, ovl.top );
|
q = VIPS_IMAGE_ADDR( frame, ovl.left, ovl.top );
|
||||||
|
|
||||||
for( i = 0; i < ovl.height; i++ ) {
|
for( y = 0; y < ovl.height; y++ ) {
|
||||||
if( blend ) {
|
if( blend ) {
|
||||||
guint32 *A = (guint32 *) p;
|
guint32 *A = (guint32 *) p;
|
||||||
guint32 *B = (guint32 *) q;
|
guint32 *B = (guint32 *) q;
|
||||||
|
@ -270,8 +305,8 @@ vips_image_paint_image( VipsImage *image,
|
||||||
memcpy( (char *) q, (char *) p,
|
memcpy( (char *) q, (char *) p,
|
||||||
ovl.width * ps );
|
ovl.width * ps );
|
||||||
|
|
||||||
p += VIPS_IMAGE_SIZEOF_LINE( ink );
|
p += VIPS_IMAGE_SIZEOF_LINE( sub );
|
||||||
q += VIPS_IMAGE_SIZEOF_LINE( image );
|
q += VIPS_IMAGE_SIZEOF_LINE( frame );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -402,11 +437,12 @@ read_header( Read *read, VipsImage *out )
|
||||||
read->frame_width = VIPS_RINT( canvas_width * read->scale );
|
read->frame_width = VIPS_RINT( canvas_width * read->scale );
|
||||||
read->frame_height = VIPS_RINT( canvas_height * read->scale );
|
read->frame_height = VIPS_RINT( canvas_height * read->scale );
|
||||||
|
|
||||||
if( read->scale != 1.0 ) {
|
#ifdef DEBUG
|
||||||
read->config.options.use_scaling = 1;
|
printf( "webp2vips: canvas_width = %d\n", canvas_width );
|
||||||
read->config.options.scaled_width = read->frame_width;
|
printf( "webp2vips: canvas_height = %d\n", canvas_height );
|
||||||
read->config.options.scaled_height = read->frame_height;
|
printf( "webp2vips: frame_width = %d\n", read->frame_width );
|
||||||
}
|
printf( "webp2vips: frame_height = %d\n", read->frame_height );
|
||||||
|
#endif /*DEBUG*/
|
||||||
|
|
||||||
flags = WebPDemuxGetI( read->demux, WEBP_FF_FORMAT_FLAGS );
|
flags = WebPDemuxGetI( read->demux, WEBP_FF_FORMAT_FLAGS );
|
||||||
|
|
||||||
|
@ -546,6 +582,9 @@ vips__webp_read_file_header( const char *filename, VipsImage *out,
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Read a single frame -- a width * height block of pixels. This will get
|
||||||
|
* blended into the accumulator at some offset.
|
||||||
|
*/
|
||||||
static VipsImage *
|
static VipsImage *
|
||||||
read_frame( Read *read,
|
read_frame( Read *read,
|
||||||
int width, int height, const guint8 *data, size_t length )
|
int width, int height, const guint8 *data, size_t length )
|
||||||
|
@ -573,6 +612,11 @@ read_frame( Read *read,
|
||||||
read->config.output.u.RGBA.rgba = VIPS_IMAGE_ADDR( frame, 0, 0 );
|
read->config.output.u.RGBA.rgba = VIPS_IMAGE_ADDR( frame, 0, 0 );
|
||||||
read->config.output.u.RGBA.stride = VIPS_IMAGE_SIZEOF_LINE( frame );
|
read->config.output.u.RGBA.stride = VIPS_IMAGE_SIZEOF_LINE( frame );
|
||||||
read->config.output.u.RGBA.size = VIPS_IMAGE_SIZEOF_IMAGE( frame );
|
read->config.output.u.RGBA.size = VIPS_IMAGE_SIZEOF_IMAGE( frame );
|
||||||
|
if( read->scale != 1.0 ) {
|
||||||
|
read->config.options.use_scaling = 1;
|
||||||
|
read->config.options.scaled_width = width;
|
||||||
|
read->config.options.scaled_height = height;
|
||||||
|
}
|
||||||
|
|
||||||
if( WebPDecode( data, length, &read->config ) != VP8_STATUS_OK ) {
|
if( WebPDecode( data, length, &read->config ) != VP8_STATUS_OK ) {
|
||||||
g_object_unref( frame );
|
g_object_unref( frame );
|
||||||
|
@ -587,16 +631,24 @@ static int
|
||||||
read_next_frame( Read *read )
|
read_next_frame( Read *read )
|
||||||
{
|
{
|
||||||
VipsImage *frame;
|
VipsImage *frame;
|
||||||
|
VipsRect area;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
printf( "read_next_frame:\n" );
|
printf( "read_next_frame:\n" );
|
||||||
#endif /*DEBUG*/
|
#endif /*DEBUG*/
|
||||||
|
|
||||||
|
/* Area of this frame, in output image coordinates.
|
||||||
|
*/
|
||||||
|
area.left = read->iter.x_offset * read->scale;
|
||||||
|
area.top = read->iter.y_offset * read->scale;
|
||||||
|
area.width = read->iter.width * read->scale;
|
||||||
|
area.height = read->iter.height * read->scale;
|
||||||
|
|
||||||
/* Dispose from the previous frame.
|
/* Dispose from the previous frame.
|
||||||
*/
|
*/
|
||||||
if( read->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND ) {
|
if( read->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND ) {
|
||||||
/* We must clear the pixels occupied by this webp frame (not
|
/* We must clear the pixels occupied by the previous webp
|
||||||
* the whole of the read frame) to 0 (transparent).
|
* frame (not the whole of the read frame) to 0 (transparent).
|
||||||
*
|
*
|
||||||
* We do not clear to WEBP_FF_BACKGROUND_COLOR. That's only
|
* We do not clear to WEBP_FF_BACKGROUND_COLOR. That's only
|
||||||
* used to composite down to RGB. Perhaps we
|
* used to composite down to RGB. Perhaps we
|
||||||
|
@ -611,17 +663,14 @@ read_next_frame( Read *read )
|
||||||
/* Note this frame's dispose for next time.
|
/* Note this frame's dispose for next time.
|
||||||
*/
|
*/
|
||||||
read->dispose_method = read->iter.dispose_method;
|
read->dispose_method = read->iter.dispose_method;
|
||||||
read->dispose_rect.left = read->iter.x_offset * read->scale;
|
read->dispose_rect = area;
|
||||||
read->dispose_rect.top = read->iter.y_offset * read->scale;
|
|
||||||
read->dispose_rect.width = read->iter.width * read->scale;
|
|
||||||
read->dispose_rect.height = read->iter.height * read->scale;
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
printf( "webp2vips: frame_num = %d\n", read->iter.frame_num );
|
printf( "webp2vips: frame_num = %d\n", read->iter.frame_num );
|
||||||
printf( " x_offset = %d\n", read->iter.x_offset );
|
printf( " left = %d\n", area.left );
|
||||||
printf( " y_offset = %d\n", read->iter.y_offset );
|
printf( " top = %d\n", area.top );
|
||||||
printf( " width = %d\n", read->iter.width );
|
printf( " width = %d\n", area.width );
|
||||||
printf( " height = %d\n", read->iter.height );
|
printf( " height = %d\n", area.height );
|
||||||
printf( " duration = %d\n", read->iter.duration );
|
printf( " duration = %d\n", read->iter.duration );
|
||||||
printf( " dispose = " );
|
printf( " dispose = " );
|
||||||
if( read->iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND )
|
if( read->iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND )
|
||||||
|
@ -642,14 +691,14 @@ read_next_frame( Read *read )
|
||||||
"not all frames have equal duration" );
|
"not all frames have equal duration" );
|
||||||
|
|
||||||
if( !(frame = read_frame( read,
|
if( !(frame = read_frame( read,
|
||||||
read->iter.width, read->iter.height,
|
area.width, area.height,
|
||||||
read->iter.fragment.bytes, read->iter.fragment.size )) )
|
read->iter.fragment.bytes, read->iter.fragment.size )) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
/* Now blend or copy the new pixels into our accumulator.
|
/* Now blend or copy the new pixels into our accumulator.
|
||||||
*/
|
*/
|
||||||
vips_image_paint_image( read->frame, frame,
|
vips_image_paint_image( read->frame, frame,
|
||||||
read->iter.x_offset, read->iter.y_offset,
|
area.left, area.top,
|
||||||
read->iter.blend_method == WEBP_MUX_BLEND );
|
read->iter.blend_method == WEBP_MUX_BLEND );
|
||||||
|
|
||||||
g_object_unref( frame );
|
g_object_unref( frame );
|
||||||
|
|
Loading…
Reference in New Issue