better support for TIFFs with many alphas
The premultiplied alpha can be in any position, and it checks if there is more than one ASSOCALPHA. See https://github.com/libvips/libvips/issues/1471
This commit is contained in:
parent
cb7bc24b2a
commit
712157cd16
|
@ -20,6 +20,7 @@
|
|||
- add iiif layout to dzsave
|
||||
- fix use of resolution-unit metadata on tiff save [kayarre]
|
||||
- support TIFF CIELAB images with alpha [angelmixu]
|
||||
- support TIFF with premultiplied alpha in any band
|
||||
|
||||
17/9/19 started 8.8.4
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ typedef struct _VipsUnpremultiply {
|
|||
VipsImage *in;
|
||||
|
||||
double max_alpha;
|
||||
int alpha_band;
|
||||
|
||||
} VipsUnpremultiply;
|
||||
|
||||
|
@ -76,17 +77,21 @@ G_DEFINE_TYPE( VipsUnpremultiply, vips_unpremultiply, VIPS_TYPE_CONVERSION );
|
|||
OUT * restrict q = (OUT *) out; \
|
||||
\
|
||||
for( x = 0; x < width; x++ ) { \
|
||||
IN alpha = p[bands - 1]; \
|
||||
IN alpha = p[alpha_band]; \
|
||||
IN clip_alpha = VIPS_CLIP( 0, alpha, max_alpha ); \
|
||||
OUT nalpha = (OUT) clip_alpha / max_alpha; \
|
||||
\
|
||||
if( nalpha == 0 ) \
|
||||
for( i = 0; i < bands - 1; i++ ) \
|
||||
for( i = 0; i < alpha_band + 1; i++ ) \
|
||||
q[i] = 0; \
|
||||
else \
|
||||
for( i = 0; i < bands - 1; i++ ) \
|
||||
else { \
|
||||
for( i = 0; i < alpha_band; i++ ) \
|
||||
q[i] = p[i] / nalpha; \
|
||||
q[i] = clip_alpha; \
|
||||
q[alpha_band] = clip_alpha; \
|
||||
} \
|
||||
\
|
||||
for( i = alpha_band + 1; i < bands; i++ ) \
|
||||
q[i] = p[i]; \
|
||||
\
|
||||
p += bands; \
|
||||
q += bands; \
|
||||
|
@ -108,13 +113,14 @@ G_DEFINE_TYPE( VipsUnpremultiply, vips_unpremultiply, VIPS_TYPE_CONVERSION );
|
|||
q[0] = 0; \
|
||||
q[1] = 0; \
|
||||
q[2] = 0; \
|
||||
q[3] = 0; \
|
||||
} \
|
||||
else { \
|
||||
q[0] = p[0] / nalpha; \
|
||||
q[1] = p[1] / nalpha; \
|
||||
q[2] = p[2] / nalpha; \
|
||||
q[3] = clip_alpha; \
|
||||
} \
|
||||
q[3] = clip_alpha; \
|
||||
\
|
||||
p += 4; \
|
||||
q += 4; \
|
||||
|
@ -141,6 +147,7 @@ vips_unpremultiply_gen( VipsRegion *or, void *vseq, void *a, void *b,
|
|||
int width = r->width;
|
||||
int bands = im->Bands;
|
||||
double max_alpha = unpremultiply->max_alpha;
|
||||
int alpha_band = unpremultiply->alpha_band;
|
||||
|
||||
int x, y, i;
|
||||
|
||||
|
@ -235,6 +242,11 @@ vips_unpremultiply_build( VipsObject *object )
|
|||
in->Type == VIPS_INTERPRETATION_RGB16 )
|
||||
unpremultiply->max_alpha = 65535;
|
||||
|
||||
/* Is alpha-band unset? Default to the final band for this image.
|
||||
*/
|
||||
if( !vips_object_argument_isset( object, "alpha_band" ) )
|
||||
unpremultiply->alpha_band = in->Bands - 1;
|
||||
|
||||
if( in->BandFmt == VIPS_FORMAT_DOUBLE )
|
||||
conversion->out->BandFmt = VIPS_FORMAT_DOUBLE;
|
||||
else
|
||||
|
@ -279,6 +291,13 @@ vips_unpremultiply_class_init( VipsUnpremultiplyClass *class )
|
|||
G_STRUCT_OFFSET( VipsUnpremultiply, max_alpha ),
|
||||
0, 100000000, 255 );
|
||||
|
||||
VIPS_ARG_INT( class, "alpha_band", 116,
|
||||
_( "Alpha band" ),
|
||||
_( "Unpremultiply with this alpha" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsUnpremultiply, alpha_band ),
|
||||
0, 100000000, 3 );
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -296,10 +315,11 @@ vips_unpremultiply_init( VipsUnpremultiply *unpremultiply )
|
|||
* Optional arguments:
|
||||
*
|
||||
* * @max_alpha: %gdouble, maximum value for alpha
|
||||
* * @alpha_band: %gint, band containing alpha data
|
||||
*
|
||||
* Unpremultiplies any alpha channel.
|
||||
* The final band is taken to be the alpha
|
||||
* and the bands are transformed as:
|
||||
* Band @alpha_band (by default the final band) contains the alpha and all
|
||||
* other bands are transformed as:
|
||||
*
|
||||
* |[
|
||||
* alpha = (int) clip( 0, in[in.bands - 1], @max_alpha );
|
||||
|
@ -312,8 +332,7 @@ vips_unpremultiply_init( VipsUnpremultiply *unpremultiply )
|
|||
*
|
||||
* So for an N-band image, the first N - 1 bands are divided by the clipped
|
||||
* and normalised final band, the final band is clipped.
|
||||
* If there is only a single band,
|
||||
* the image is passed through unaltered.
|
||||
* If there is only a single band, the image is passed through unaltered.
|
||||
*
|
||||
* The result is
|
||||
* #VIPS_FORMAT_FLOAT unless the input format is #VIPS_FORMAT_DOUBLE, in which
|
||||
|
|
|
@ -189,6 +189,8 @@
|
|||
* 7/6/19
|
||||
* - istiff reads the first directory rather than just testing the magic
|
||||
* number, so it ignores more TIFF-like, but not TIFF images
|
||||
* 18/11/19
|
||||
* - support ASSOCALPHA in any alpha band
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -219,6 +221,7 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
#define DEBUG_VERBOSE
|
||||
#define DEBUG
|
||||
*/
|
||||
|
||||
|
@ -253,7 +256,10 @@ typedef struct _RtiffHeader {
|
|||
int sample_format;
|
||||
gboolean separate;
|
||||
int orientation;
|
||||
gboolean premultiplied;
|
||||
/* If there's a premultiplied alpha, the band we need to
|
||||
* unpremultiply with. -1 for no unpremultiplication.
|
||||
*/
|
||||
int alpha_band;
|
||||
uint16 compression;
|
||||
|
||||
/* Result of TIFFIsTiled().
|
||||
|
@ -549,9 +555,9 @@ rtiff_strip_read( Rtiff *rtiff, int strip, tdata_t buf )
|
|||
{
|
||||
tsize_t length;
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_VERBOSE
|
||||
printf( "rtiff_strip_read: reading strip %d\n", strip );
|
||||
#endif /*DEBUG*/
|
||||
#endif /*DEBUG_VERBOSE*/
|
||||
|
||||
if( rtiff->header.read_scanlinewise )
|
||||
length = TIFFReadScanline( rtiff->tiff,
|
||||
|
@ -1542,10 +1548,10 @@ rtiff_fill_region_aligned( VipsRegion *out, void *seq, void *a, void *b )
|
|||
g_assert( r->height == rtiff->header.tile_height );
|
||||
g_assert( VIPS_REGION_LSKIP( out ) == VIPS_REGION_SIZEOF_LINE( out ) );
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_VERBOSE
|
||||
printf( "rtiff_fill_region_aligned: left = %d, top = %d\n",
|
||||
r->left, r->top );
|
||||
#endif /*DEBUG*/
|
||||
#endif /*DEBUG_VERBOSE*/
|
||||
|
||||
VIPS_GATE_START( "rtiff_fill_region_aligned: work" );
|
||||
|
||||
|
@ -1729,10 +1735,13 @@ rtiff_autorotate( Rtiff *rtiff, VipsImage *in, VipsImage **out )
|
|||
static int
|
||||
rtiff_unpremultiply( Rtiff *rtiff, VipsImage *in, VipsImage **out )
|
||||
{
|
||||
if( rtiff->header.premultiplied ) {
|
||||
if( rtiff->header.alpha_band != -1 ) {
|
||||
VipsImage *x;
|
||||
|
||||
if( vips_unpremultiply( in, &x, NULL ) ||
|
||||
if(
|
||||
vips_unpremultiply( in, &x,
|
||||
"alpha_band", rtiff->header.alpha_band,
|
||||
NULL ) ||
|
||||
vips_cast( x, out, in->BandFmt, NULL ) ) {
|
||||
g_object_unref( x );
|
||||
return( -1 );
|
||||
|
@ -1881,11 +1890,11 @@ rtiff_stripwise_generate( VipsRegion *or,
|
|||
|
||||
int y;
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_VERBOSE
|
||||
printf( "rtiff_stripwise_generate: top = %d, height = %d\n",
|
||||
r->top, r->height );
|
||||
printf( "rtiff_stripwise_generate: y_top = %d\n", rtiff->y_pos );
|
||||
#endif /*DEBUG*/
|
||||
#endif /*DEBUG_VERBOSE*/
|
||||
|
||||
/* We're inside a tilecache where tiles are the full image width, so
|
||||
* this should always be true.
|
||||
|
@ -2315,8 +2324,25 @@ rtiff_header_read( Rtiff *rtiff, RtiffHeader *header )
|
|||
|
||||
TIFFGetFieldDefaulted( rtiff->tiff, TIFFTAG_EXTRASAMPLES,
|
||||
&extra_samples_count, &extra_samples_types );
|
||||
header->premultiplied = extra_samples_count > 0 &&
|
||||
extra_samples_types[0] == EXTRASAMPLE_ASSOCALPHA;
|
||||
|
||||
header->alpha_band = -1;
|
||||
if( extra_samples_count > 0 ) {
|
||||
/* There must be exactly one band which is
|
||||
* EXTRASAMPLE_ASSOCALPHA. Note which one it is so we can
|
||||
* unpremultiply with the right channel.
|
||||
*/
|
||||
int i;
|
||||
|
||||
for( i = 0; i < extra_samples_count; i++ )
|
||||
if( extra_samples_types[i] == EXTRASAMPLE_ASSOCALPHA ) {
|
||||
if( header->alpha_band != -1 )
|
||||
g_warning( "%s", _( "more than one "
|
||||
"alpha -- ignoring" ) );
|
||||
|
||||
header->alpha_band = header->samples_per_pixel -
|
||||
extra_samples_count + i;
|
||||
}
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue