add n/page support for webp read

This commit is contained in:
John Cupitt 2018-11-05 16:21:21 +00:00
parent b161f4b982
commit 17c9856e38
2 changed files with 61 additions and 27 deletions

View File

@ -4,7 +4,7 @@
- add XMP support to png read/write [jcupitt]
- deprecate thumbnail auto_rotate, add no_rotate [jcupitt]
- implement thumbnail shrink-on-load for openslide images [jcupitt]
- add animated webp write [jcupitt]
- add animated webp support [jcupitt]
23/9/18 started 8.7.1
- update function list in docs [janko-m]

View File

@ -43,8 +43,8 @@
*/
/*
*/
#define DEBUG_VERBOSE
*/
#define DEBUG
#ifdef HAVE_CONFIG_H
@ -100,9 +100,9 @@ typedef struct {
int frame_width;
int frame_height;
/* RGBA background colour.
/* Background colour as an ink we can paint with.
*/
uint32_t background;
guint32 background;
/* TRUE for RGBA.
*/
@ -179,7 +179,7 @@ vips_image_paint_pel( VipsImage *image, const VipsRect *r, const VipsPel *ink )
}
}
/* Blend two uint8s.
/* Blend two guint8.
*/
#define BLEND( X, aX, Y, aY, scale ) \
((X * aX + Y * aY) * scale >> 24)
@ -195,28 +195,27 @@ vips_image_paint_pel( VipsImage *image, const VipsRect *r, const VipsPel *ink )
*/
#define setRGBA( R, G, B, A ) (R | (G << 8) | (B << 16) | (A << 24))
/* OVER blend of two unpremultiplied RGBA uint32_t
/* OVER blend of two unpremultiplied RGBA guint32
*
* We assume little-endian (x86), add a byteswap before this if necessary.
*/
static uint32_t
blend_pixel( uint32_t A, uint32_t B )
static guint32
blend_pixel( guint32 A, guint32 B )
{
uint8_t aA = getA( A );
guint8 aA = getA( A );
if( aA == 0 )
return( B );
uint8_t aB = getA( B );
guint8 aB = getA( B );
uint8_t fac = (aB * (256 - aA)) >> 8;
uint8_t aR = aA + fac;
guint8 fac = (aB * (256 - aA)) >> 8;
guint8 aR = aA + fac;
int scale = (1 << 24) / aR;
uint8_t rR = BLEND( getR( A ), aA, getR( B ), fac, scale );
uint8_t gR = BLEND( getG( A ), aA, getG( B ), fac, scale );
uint8_t bR = BLEND( getB( A ), aA, getB( B ), fac, scale );
guint8 rR = BLEND( getR( A ), aA, getR( B ), fac, scale );
guint8 gR = BLEND( getG( A ), aA, getG( B ), fac, scale );
guint8 bR = BLEND( getB( A ), aA, getB( B ), fac, scale );
return( setRGBA( rR, gR, bR, aR ) );
}
@ -248,8 +247,8 @@ vips_image_paint_image( VipsImage *image,
for( i = 0; i < ovl.height; i++ ) {
if( blend ) {
uint32_t *A = (uint32_t *) p;
uint32_t *B = (uint32_t *) q;
guint32 *A = (guint32 *) p;
guint32 *B = (guint32 *) q;
for( x = 0; x < ovl.width; x++ )
B[x] = blend_pixel( A[x], B[x] );
@ -365,6 +364,21 @@ const VipsWebPNames vips__webp_names[] = {
};
const int vips__n_webp_names = VIPS_NUMBER( vips__webp_names );
/* libwebp supplies things like background as B, G, R, A, but we need RGBA
* order for libvips.
*/
static guint32
bgra2rgba( guint32 x )
{
VipsPel pixel[4];
*((guint32 *) &pixel) = x;
VIPS_SWAP( VipsPel, pixel[0], pixel[2] );
x = *((guint32 *) &pixel);
return( x );
}
static int
read_header( Read *read, VipsImage *out )
{
@ -395,11 +409,11 @@ read_header( Read *read, VipsImage *out )
flags = WebPDemuxGetI( read->demux, WEBP_FF_FORMAT_FLAGS );
/* FIXME ... do we need to byteswap, or can we use &background as the
* ink?
/* background is in B, G, R, A byte order, but we need R, G, B, A for
* libvips.
*/
read->background = WebPDemuxGetI( read->demux,
WEBP_FF_BACKGROUND_COLOR );
read->background = bgra2rgba(
WebPDemuxGetI( read->demux, WEBP_FF_BACKGROUND_COLOR ) );
read->alpha = flags & ALPHA_FLAG;
if( read->alpha )
@ -437,8 +451,24 @@ read_header( Read *read, VipsImage *out )
WebPDemuxReleaseIterator( &iter );
}
if( read->n == -1 )
read->n = read->frame_count - read->page;
if( read->page < 0 ||
read->n <= 0 ||
read->page + read->n > read->frame_count ) {
vips_error( "webp",
"%s", _( "bad page number" ) );
return( -1 );
}
/* Note that n-pages is the number of pages in the original,
* not the number of pages in the image we are writing.
*/
vips_image_set_int( out, "n-pages", read->frame_count );
read->width = read->frame_width;
read->height = read->frame_count * read->frame_height;
read->height = read->n * read->frame_height;
}
else {
read->width = read->frame_width;
@ -535,7 +565,7 @@ vips__webp_read_file_header( const char *filename, VipsImage *out,
static VipsImage *
read_frame( Read *read,
int width, int height, const uint8_t *data, size_t length )
int width, int height, const guint8 *data, size_t length )
{
VipsImage *frame;
@ -578,8 +608,12 @@ read_next_frame( Read *read )
/* We must clear the pixels occupied by this webp frame (not
* the whole of the read frame) to the background colour.
*/
VipsRect area = { read->iter.x_offset, read->iter.y_offset,
read->iter.width, read->iter.height };
VipsRect area = {
read->iter.x_offset,
read->iter.y_offset,
read->iter.width,
read->iter.height
};
vips_image_paint_pel( read->frame,
&area, (VipsPel *) &read->background );
@ -641,7 +675,7 @@ read_webp_generate( VipsRegion *or,
VipsRect *r = &or->valid;
Read *read = (Read *) a;
int frame = r->top / read->frame_height;
int frame = r->top / read->frame_height + read->page;
int line = r->top % read->frame_height;
#ifdef DEBUG_VERBOSE