"squash" to tiffsave now does lab as well

The "squash" option to tiffsave now also squashes 32-bit 3-band float
CIELAB images down to 8 bits.

See https://github.com/libvips/libvips/issues/1499
This commit is contained in:
John Cupitt 2019-12-18 17:29:34 +00:00
parent 6c038f5ca8
commit e1baf66f19
6 changed files with 145 additions and 107 deletions

View File

@ -571,6 +571,8 @@ vips_foreign_save_tiff_buffer_init( VipsForeignSaveTiffBuffer *buffer )
* images which use this sense. @miniswhite only affects one-bit images, it * images which use this sense. @miniswhite only affects one-bit images, it
* does nothing for greyscale images. * does nothing for greyscale images.
* *
* Set @squash to squash 3-band float CIELAB images down to 8-bit CIELAB.
*
* Use @resunit to override the default resolution unit. * Use @resunit to override the default resolution unit.
* The default * The default
* resolution unit is taken from the header field * resolution unit is taken from the header field

View File

@ -185,6 +185,8 @@
* 8/7/19 * 8/7/19
* - add webp and zstd support * - add webp and zstd support
* - add @level and @lossless * - add @level and @lossless
* 18/12/19
* - "squash" now squashes 3-band float LAB down to LABQ
*/ */
/* /*
@ -287,7 +289,11 @@ struct _Layer {
/* A TIFF image in the process of being written. /* A TIFF image in the process of being written.
*/ */
struct _Wtiff { struct _Wtiff {
VipsImage *im; /* Original input image */ VipsImage *input; /* Original input image */
/* Image transformed ready for write.
*/
VipsImage *ready;
/* File to write to, or NULL. /* File to write to, or NULL.
*/ */
@ -308,7 +314,7 @@ struct _Wtiff {
int tile; /* Tile or not */ int tile; /* Tile or not */
int tilew, tileh; /* Tile size */ int tilew, tileh; /* Tile size */
int pyramid; /* Wtiff pyramid */ int pyramid; /* Wtiff pyramid */
int onebit; /* Wtiff as 1-bit TIFF */ int squash; /* Write as small format */
int miniswhite; /* Wtiff as 0 == white */ int miniswhite; /* Wtiff as 0 == white */
int resunit; /* Resolution unit (inches or cm) */ int resunit; /* Resolution unit (inches or cm) */
double xres; /* Resolution in X */ double xres; /* Resolution in X */
@ -384,7 +390,7 @@ wtiff_layer_new( Wtiff *wtiff, Layer *above, int width, int height )
{ {
Layer *layer; Layer *layer;
layer = VIPS_NEW( wtiff->im, Layer ); layer = VIPS_NEW( wtiff->ready, Layer );
layer->wtiff = wtiff; layer->wtiff = wtiff;
layer->width = width; layer->width = width;
layer->height = height; layer->height = height;
@ -435,14 +441,14 @@ wtiff_layer_new( Wtiff *wtiff, Layer *above, int width, int height )
*/ */
if( wtiff->filename ) { if( wtiff->filename ) {
if( !above ) if( !above )
layer->lname = vips_strdup( VIPS_OBJECT( wtiff->im ), layer->lname = vips_strdup( VIPS_OBJECT( wtiff->ready ),
wtiff->filename ); wtiff->filename );
else { else {
char *lname; char *lname;
lname = vips__temp_name( "%s.tif" ); lname = vips__temp_name( "%s.tif" );
layer->lname = layer->lname = vips_strdup( VIPS_OBJECT( wtiff->ready ),
vips_strdup( VIPS_OBJECT( wtiff->im ), lname ); lname );
g_free( lname ); g_free( lname );
} }
} }
@ -458,8 +464,8 @@ wtiff_embed_profile( Wtiff *wtiff, TIFF *tif )
return( -1 ); return( -1 );
if( !wtiff->icc_profile && if( !wtiff->icc_profile &&
vips_image_get_typeof( wtiff->im, VIPS_META_ICC_NAME ) && vips_image_get_typeof( wtiff->ready, VIPS_META_ICC_NAME ) &&
embed_profile_meta( tif, wtiff->im ) ) embed_profile_meta( tif, wtiff->ready ) )
return( -1 ); return( -1 );
return( 0 ); return( 0 );
@ -471,9 +477,10 @@ wtiff_embed_xmp( Wtiff *wtiff, TIFF *tif )
const void *data; const void *data;
size_t size; size_t size;
if( !vips_image_get_typeof( wtiff->im, VIPS_META_XMP_NAME ) ) if( !vips_image_get_typeof( wtiff->ready, VIPS_META_XMP_NAME ) )
return( 0 ); return( 0 );
if( vips_image_get_blob( wtiff->im, VIPS_META_XMP_NAME, &data, &size ) ) if( vips_image_get_blob( wtiff->ready, VIPS_META_XMP_NAME,
&data, &size ) )
return( -1 ); return( -1 );
TIFFSetField( tif, TIFFTAG_XMLPACKET, size, data ); TIFFSetField( tif, TIFFTAG_XMLPACKET, size, data );
@ -490,9 +497,9 @@ wtiff_embed_iptc( Wtiff *wtiff, TIFF *tif )
const void *data; const void *data;
size_t size; size_t size;
if( !vips_image_get_typeof( wtiff->im, VIPS_META_IPTC_NAME ) ) if( !vips_image_get_typeof( wtiff->ready, VIPS_META_IPTC_NAME ) )
return( 0 ); return( 0 );
if( vips_image_get_blob( wtiff->im, VIPS_META_IPTC_NAME, if( vips_image_get_blob( wtiff->ready, VIPS_META_IPTC_NAME,
&data, &size ) ) &data, &size ) )
return( -1 ); return( -1 );
@ -522,10 +529,10 @@ wtiff_embed_photoshop( Wtiff *wtiff, TIFF *tif )
const void *data; const void *data;
size_t size; size_t size;
if( !vips_image_get_typeof( wtiff->im, VIPS_META_PHOTOSHOP_NAME ) ) if( !vips_image_get_typeof( wtiff->ready, VIPS_META_PHOTOSHOP_NAME ) )
return( 0 ); return( 0 );
if( vips_image_get_blob( wtiff->im, if( vips_image_get_blob( wtiff->ready, VIPS_META_PHOTOSHOP_NAME,
VIPS_META_PHOTOSHOP_NAME, &data, &size ) ) &data, &size ) )
return( -1 ); return( -1 );
TIFFSetField( tif, TIFFTAG_PHOTOSHOP, size, data ); TIFFSetField( tif, TIFFTAG_PHOTOSHOP, size, data );
@ -545,7 +552,7 @@ wtiff_embed_imagedescription( Wtiff *wtiff, TIFF *tif )
if( wtiff->properties ) { if( wtiff->properties ) {
char *doc; char *doc;
if( !(doc = vips__xml_properties( wtiff->im )) ) if( !(doc = vips__xml_properties( wtiff->ready )) )
return( -1 ); return( -1 );
TIFFSetField( tif, TIFFTAG_IMAGEDESCRIPTION, doc ); TIFFSetField( tif, TIFFTAG_IMAGEDESCRIPTION, doc );
g_free( doc ); g_free( doc );
@ -553,10 +560,10 @@ wtiff_embed_imagedescription( Wtiff *wtiff, TIFF *tif )
else { else {
const char *imagedescription; const char *imagedescription;
if( !vips_image_get_typeof( wtiff->im, if( !vips_image_get_typeof( wtiff->ready,
VIPS_META_IMAGEDESCRIPTION ) ) VIPS_META_IMAGEDESCRIPTION ) )
return( 0 ); return( 0 );
if( vips_image_get_string( wtiff->im, if( vips_image_get_string( wtiff->ready,
VIPS_META_IMAGEDESCRIPTION, &imagedescription ) ) VIPS_META_IMAGEDESCRIPTION, &imagedescription ) )
return( -1 ); return( -1 );
TIFFSetField( tif, TIFFTAG_IMAGEDESCRIPTION, imagedescription ); TIFFSetField( tif, TIFFTAG_IMAGEDESCRIPTION, imagedescription );
@ -620,19 +627,19 @@ wtiff_write_header( Wtiff *wtiff, Layer *layer )
wtiff_embed_imagedescription( wtiff, tif ) ) wtiff_embed_imagedescription( wtiff, tif ) )
return( -1 ); return( -1 );
if( vips_image_get_typeof( wtiff->im, VIPS_META_ORIENTATION ) && if( vips_image_get_typeof( wtiff->ready, VIPS_META_ORIENTATION ) &&
!vips_image_get_int( wtiff->im, !vips_image_get_int( wtiff->ready,
VIPS_META_ORIENTATION, &orientation ) ) VIPS_META_ORIENTATION, &orientation ) )
TIFFSetField( tif, TIFFTAG_ORIENTATION, orientation ); TIFFSetField( tif, TIFFTAG_ORIENTATION, orientation );
/* And colour fields. /* And colour fields.
*/ */
if( wtiff->im->Coding == VIPS_CODING_LABQ ) { if( wtiff->ready->Coding == VIPS_CODING_LABQ ) {
TIFFSetField( tif, TIFFTAG_SAMPLESPERPIXEL, 3 ); TIFFSetField( tif, TIFFTAG_SAMPLESPERPIXEL, 3 );
TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE, 8 ); TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE, 8 );
TIFFSetField( tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_CIELAB ); TIFFSetField( tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_CIELAB );
} }
else if( wtiff->onebit ) { else if( wtiff->squash ) {
TIFFSetField( tif, TIFFTAG_SAMPLESPERPIXEL, 1 ); TIFFSetField( tif, TIFFTAG_SAMPLESPERPIXEL, 1 );
TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE, 1 ); TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE, 1 );
TIFFSetField( tif, TIFFTAG_PHOTOMETRIC, TIFFSetField( tif, TIFFTAG_PHOTOMETRIC,
@ -650,13 +657,14 @@ wtiff_write_header( Wtiff *wtiff, Layer *layer )
int alpha_bands; int alpha_bands;
TIFFSetField( tif, TIFFTAG_SAMPLESPERPIXEL, wtiff->im->Bands ); TIFFSetField( tif, TIFFTAG_SAMPLESPERPIXEL,
wtiff->ready->Bands );
TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE, TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE,
vips_format_sizeof( wtiff->im->BandFmt ) << 3 ); vips_format_sizeof( wtiff->ready->BandFmt ) << 3 );
if( wtiff->im->Type == VIPS_INTERPRETATION_B_W || if( wtiff->ready->Type == VIPS_INTERPRETATION_B_W ||
wtiff->im->Type == VIPS_INTERPRETATION_GREY16 || wtiff->ready->Type == VIPS_INTERPRETATION_GREY16 ||
wtiff->im->Bands < 3 ) { wtiff->ready->Bands < 3 ) {
/* Mono or mono + alpha. /* Mono or mono + alpha.
*/ */
photometric = wtiff->miniswhite ? photometric = wtiff->miniswhite ?
@ -664,20 +672,20 @@ wtiff_write_header( Wtiff *wtiff, Layer *layer )
PHOTOMETRIC_MINISBLACK; PHOTOMETRIC_MINISBLACK;
colour_bands = 1; colour_bands = 1;
} }
else if( wtiff->im->Type == VIPS_INTERPRETATION_LAB || else if( wtiff->ready->Type == VIPS_INTERPRETATION_LAB ||
wtiff->im->Type == VIPS_INTERPRETATION_LABS ) { wtiff->ready->Type == VIPS_INTERPRETATION_LABS ) {
photometric = PHOTOMETRIC_CIELAB; photometric = PHOTOMETRIC_CIELAB;
colour_bands = 3; colour_bands = 3;
} }
else if( wtiff->im->Type == VIPS_INTERPRETATION_CMYK && else if( wtiff->ready->Type == VIPS_INTERPRETATION_CMYK &&
wtiff->im->Bands >= 4 ) { wtiff->ready->Bands >= 4 ) {
photometric = PHOTOMETRIC_SEPARATED; photometric = PHOTOMETRIC_SEPARATED;
TIFFSetField( tif, TIFFTAG_INKSET, INKSET_CMYK ); TIFFSetField( tif, TIFFTAG_INKSET, INKSET_CMYK );
colour_bands = 4; colour_bands = 4;
} }
else if( wtiff->compression == COMPRESSION_JPEG && else if( wtiff->compression == COMPRESSION_JPEG &&
wtiff->im->Bands == 3 && wtiff->ready->Bands == 3 &&
wtiff->im->BandFmt == VIPS_FORMAT_UCHAR && wtiff->ready->BandFmt == VIPS_FORMAT_UCHAR &&
(!wtiff->rgbjpeg && wtiff->Q < 90) ) { (!wtiff->rgbjpeg && wtiff->Q < 90) ) {
/* This signals to libjpeg that it can do /* This signals to libjpeg that it can do
* YCbCr chrominance subsampling from RGB, not * YCbCr chrominance subsampling from RGB, not
@ -698,7 +706,7 @@ wtiff_write_header( Wtiff *wtiff, Layer *layer )
} }
alpha_bands = VIPS_CLIP( 0, alpha_bands = VIPS_CLIP( 0,
wtiff->im->Bands - colour_bands, MAX_ALPHA ); wtiff->ready->Bands - colour_bands, MAX_ALPHA );
if( alpha_bands > 0 ) { if( alpha_bands > 0 ) {
uint16 v[MAX_ALPHA]; uint16 v[MAX_ALPHA];
int i; int i;
@ -733,13 +741,13 @@ wtiff_write_header( Wtiff *wtiff, Layer *layer )
/* Sample format. /* Sample format.
*/ */
format = SAMPLEFORMAT_UINT; format = SAMPLEFORMAT_UINT;
if( vips_band_format_isuint( wtiff->im->BandFmt ) ) if( vips_band_format_isuint( wtiff->ready->BandFmt ) )
format = SAMPLEFORMAT_UINT; format = SAMPLEFORMAT_UINT;
else if( vips_band_format_isint( wtiff->im->BandFmt ) ) else if( vips_band_format_isint( wtiff->ready->BandFmt ) )
format = SAMPLEFORMAT_INT; format = SAMPLEFORMAT_INT;
else if( vips_band_format_isfloat( wtiff->im->BandFmt ) ) else if( vips_band_format_isfloat( wtiff->ready->BandFmt ) )
format = SAMPLEFORMAT_IEEEFP; format = SAMPLEFORMAT_IEEEFP;
else if( vips_band_format_iscomplex( wtiff->im->BandFmt ) ) else if( vips_band_format_iscomplex( wtiff->ready->BandFmt ) )
format = SAMPLEFORMAT_COMPLEXIEEEFP; format = SAMPLEFORMAT_COMPLEXIEEEFP;
TIFFSetField( tif, TIFFTAG_SAMPLEFORMAT, format ); TIFFSetField( tif, TIFFTAG_SAMPLEFORMAT, format );
@ -779,7 +787,7 @@ wtiff_allocate_layers( Wtiff *wtiff )
for( layer = wtiff->layer; layer; layer = layer->below ) { for( layer = wtiff->layer; layer; layer = layer->below ) {
layer->image = vips_image_new(); layer->image = vips_image_new();
if( vips_image_pipelinev( layer->image, if( vips_image_pipelinev( layer->image,
VIPS_DEMAND_STYLE_ANY, wtiff->im, NULL ) ) VIPS_DEMAND_STYLE_ANY, wtiff->ready, NULL ) )
return( -1 ); return( -1 );
layer->image->Xsize = layer->width; layer->image->Xsize = layer->width;
layer->image->Ysize = layer->height; layer->image->Ysize = layer->height;
@ -800,7 +808,7 @@ wtiff_allocate_layers( Wtiff *wtiff )
layer->tif = vips__tiff_openout( layer->tif = vips__tiff_openout(
layer->lname, wtiff->bigtiff ); layer->lname, wtiff->bigtiff );
else { else {
layer->tif = vips__tiff_openout_buffer( wtiff->im, layer->tif = vips__tiff_openout_buffer( wtiff->ready,
wtiff->bigtiff, &layer->buf, &layer->len ); wtiff->bigtiff, &layer->buf, &layer->len );
} }
if( !layer->tif ) if( !layer->tif )
@ -866,9 +874,12 @@ wtiff_free( Wtiff *wtiff )
{ {
wtiff_delete_temps( wtiff ); wtiff_delete_temps( wtiff );
VIPS_UNREF( wtiff->ready );
VIPS_FREEF( vips_free, wtiff->tbuf ); VIPS_FREEF( vips_free, wtiff->tbuf );
VIPS_FREEF( layer_free_all, wtiff->layer ); VIPS_FREEF( layer_free_all, wtiff->layer );
VIPS_FREEF( vips_free, wtiff->icc_profile ); VIPS_FREEF( vips_free, wtiff->icc_profile );
VIPS_FREE( wtiff->filename );
VIPS_FREE( wtiff );
} }
static int static int
@ -917,8 +928,34 @@ get_resunit( VipsForeignTiffResunit resunit )
return( -1 ); return( -1 );
} }
/* Get the image ready to be written.
*/
static int
ready_to_write( Wtiff *wtiff )
{
if( vips_check_coding_known( "vips2tiff", wtiff->input ) )
return( -1 );
/* "squash" float LAB down to LABQ.
*/
if( wtiff->squash &&
wtiff->input->Bands == 3 &&
wtiff->input->BandFmt == VIPS_FORMAT_FLOAT &&
wtiff->input->Type == VIPS_INTERPRETATION_LAB ) {
if( vips_Lab2LabQ( wtiff->input, &wtiff->ready, NULL ) )
return( -1 );
wtiff->squash = 0;
}
else {
wtiff->ready = wtiff->input;
g_object_ref( wtiff->ready );
}
return( 0 );
}
static Wtiff * static Wtiff *
wtiff_new( VipsImage *im, const char *filename, wtiff_new( VipsImage *input, const char *filename,
VipsForeignTiffCompression compression, int Q, VipsForeignTiffCompression compression, int Q,
VipsForeignTiffPredictor predictor, VipsForeignTiffPredictor predictor,
char *profile, char *profile,
@ -936,11 +973,11 @@ wtiff_new( VipsImage *im, const char *filename,
{ {
Wtiff *wtiff; Wtiff *wtiff;
if( !(wtiff = VIPS_NEW( im, Wtiff )) ) if( !(wtiff = VIPS_NEW( NULL, Wtiff )) )
return( NULL ); return( NULL );
wtiff->im = im; wtiff->input = input;
wtiff->filename = filename ? wtiff->ready = NULL;
vips_strdup( VIPS_OBJECT( im ), filename ) : NULL; wtiff->filename = filename ? vips_strdup( NULL, filename ) : NULL;
wtiff->layer = NULL; wtiff->layer = NULL;
wtiff->tbuf = NULL; wtiff->tbuf = NULL;
wtiff->compression = get_compression( compression ); wtiff->compression = get_compression( compression );
@ -950,7 +987,7 @@ wtiff_new( VipsImage *im, const char *filename,
wtiff->tilew = tile_width; wtiff->tilew = tile_width;
wtiff->tileh = tile_height; wtiff->tileh = tile_height;
wtiff->pyramid = pyramid; wtiff->pyramid = pyramid;
wtiff->onebit = squash; wtiff->squash = squash;
wtiff->miniswhite = miniswhite; wtiff->miniswhite = miniswhite;
wtiff->resunit = get_resunit( resunit ); wtiff->resunit = get_resunit( resunit );
wtiff->xres = xres; wtiff->xres = xres;
@ -964,18 +1001,25 @@ wtiff_new( VipsImage *im, const char *filename,
wtiff->level = level; wtiff->level = level;
wtiff->lossless = lossless; wtiff->lossless = lossless;
wtiff->toilet_roll = FALSE; wtiff->toilet_roll = FALSE;
wtiff->page_height = vips_image_get_page_height( im ); wtiff->page_height = vips_image_get_page_height( input );
wtiff->image_height = im->Ysize; wtiff->image_height = input->Ysize;
/* Any pre-processing on the image.
*/
if( ready_to_write( wtiff ) ) {
wtiff_free( wtiff );
return( NULL );
}
/* Multipage image? /* Multipage image?
*/ */
if( wtiff->page_height < im->Ysize ) { if( wtiff->page_height < wtiff->ready->Ysize ) {
#ifdef DEBUG #ifdef DEBUG
printf( "wtiff_new: detected toilet roll image, " printf( "wtiff_new: detected toilet roll image, "
"page-height=%d\n", "page-height=%d\n",
wtiff->page_height ); wtiff->page_height );
printf( "wtiff_new: pages=%d\n", printf( "wtiff_new: pages=%d\n",
im->Ysize / wtiff->page_height ); wtiff->ready->Ysize / wtiff->page_height );
#endif/*DEBUG*/ #endif/*DEBUG*/
wtiff->toilet_roll = TRUE; wtiff->toilet_roll = TRUE;
@ -997,6 +1041,7 @@ wtiff_new( VipsImage *im, const char *filename,
if( tile ) { if( tile ) {
if( (wtiff->tilew & 0xf) != 0 || if( (wtiff->tilew & 0xf) != 0 ||
(wtiff->tileh & 0xf) != 0 ) { (wtiff->tileh & 0xf) != 0 ) {
wtiff_free( wtiff );
vips_error( "vips2tiff", vips_error( "vips2tiff",
"%s", _( "tile size not a multiple of 16" ) ); "%s", _( "tile size not a multiple of 16" ) );
return( NULL ); return( NULL );
@ -1006,8 +1051,9 @@ wtiff_new( VipsImage *im, const char *filename,
/* We can only pyramid LABQ and non-complex images. /* We can only pyramid LABQ and non-complex images.
*/ */
if( wtiff->pyramid ) { if( wtiff->pyramid ) {
if( im->Coding == VIPS_CODING_NONE && if( wtiff->ready->Coding == VIPS_CODING_NONE &&
vips_band_format_iscomplex( im->BandFmt ) ) { vips_band_format_iscomplex( wtiff->ready->BandFmt ) ) {
wtiff_free( wtiff );
vips_error( "vips2tiff", vips_error( "vips2tiff",
"%s", _( "can only pyramid LABQ and " "%s", _( "can only pyramid LABQ and "
"non-complex images" ) ); "non-complex images" ) );
@ -1015,19 +1061,20 @@ wtiff_new( VipsImage *im, const char *filename,
} }
} }
/* Only 1-bit-ize 8 bit mono images. /* Can only squash 8 bit mono. 3-band float should have been squashed
* above.
*/ */
if( wtiff->onebit && if( wtiff->squash &&
(im->Coding != VIPS_CODING_NONE || !(wtiff->ready->Coding == VIPS_CODING_NONE &&
im->BandFmt != VIPS_FORMAT_UCHAR || wtiff->ready->BandFmt == VIPS_FORMAT_UCHAR &&
im->Bands != 1) ) { wtiff->ready->Bands == 1) ) {
g_warning( "%s", g_warning( "%s",
_( "can only squash 1 band uchar images -- " _( "can only squash 1-band uchar and "
"disabling squash" ) ); "3-band float lab -- disabling squash" ) );
wtiff->onebit = 0; wtiff->squash = 0;
} }
if( wtiff->onebit && if( wtiff->squash &&
wtiff->compression == COMPRESSION_JPEG ) { wtiff->compression == COMPRESSION_JPEG ) {
g_warning( "%s", g_warning( "%s",
_( "can't have 1-bit JPEG -- disabling JPEG" ) ); _( "can't have 1-bit JPEG -- disabling JPEG" ) );
@ -1037,9 +1084,9 @@ wtiff_new( VipsImage *im, const char *filename,
/* We can only MINISWHITE non-complex images of 1 or 2 bands. /* We can only MINISWHITE non-complex images of 1 or 2 bands.
*/ */
if( wtiff->miniswhite && if( wtiff->miniswhite &&
(im->Coding != VIPS_CODING_NONE || (wtiff->ready->Coding != VIPS_CODING_NONE ||
vips_band_format_iscomplex( im->BandFmt ) || vips_band_format_iscomplex( wtiff->ready->BandFmt ) ||
im->Bands > 2) ) { wtiff->ready->Bands > 2) ) {
g_warning( "%s", g_warning( "%s",
_( "can only save non-complex greyscale images " _( "can only save non-complex greyscale images "
"as miniswhite -- disabling miniswhite" ) ); "as miniswhite -- disabling miniswhite" ) );
@ -1063,12 +1110,13 @@ wtiff_new( VipsImage *im, const char *filename,
/* Sizeof a line of bytes in the TIFF tile. /* Sizeof a line of bytes in the TIFF tile.
*/ */
if( im->Coding == VIPS_CODING_LABQ ) if( wtiff->ready->Coding == VIPS_CODING_LABQ )
wtiff->tls = wtiff->tilew * 3; wtiff->tls = wtiff->tilew * 3;
else if( wtiff->onebit ) else if( wtiff->squash )
wtiff->tls = VIPS_ROUND_UP( wtiff->tilew, 8 ) / 8; wtiff->tls = VIPS_ROUND_UP( wtiff->tilew, 8 ) / 8;
else else
wtiff->tls = VIPS_IMAGE_SIZEOF_PEL( im ) * wtiff->tilew; wtiff->tls = VIPS_IMAGE_SIZEOF_PEL( wtiff->ready ) *
wtiff->tilew;
/* If compression is off and we're writing a >4gb image, automatically /* If compression is off and we're writing a >4gb image, automatically
* enable bigtiff. * enable bigtiff.
@ -1077,7 +1125,7 @@ wtiff_new( VipsImage *im, const char *filename,
* there's a lot of metadata, we could be pushed over the 4gb limit. * there's a lot of metadata, we could be pushed over the 4gb limit.
*/ */
if( wtiff->compression == COMPRESSION_NONE && if( wtiff->compression == COMPRESSION_NONE &&
VIPS_IMAGE_SIZEOF_IMAGE( wtiff->im ) > UINT_MAX && VIPS_IMAGE_SIZEOF_IMAGE( wtiff->ready ) > UINT_MAX &&
!wtiff->bigtiff ) { !wtiff->bigtiff ) {
g_warning( "%s", _( "image over 4gb, enabling bigtiff" ) ); g_warning( "%s", _( "image over 4gb, enabling bigtiff" ) );
wtiff->bigtiff = TRUE; wtiff->bigtiff = TRUE;
@ -1086,7 +1134,7 @@ wtiff_new( VipsImage *im, const char *filename,
/* Build the pyramid framework. /* Build the pyramid framework.
*/ */
wtiff->layer = wtiff_layer_new( wtiff, NULL, wtiff->layer = wtiff_layer_new( wtiff, NULL,
im->Xsize, wtiff->image_height ); wtiff->ready->Xsize, wtiff->image_height );
/* Fill all the layers. /* Fill all the layers.
*/ */
@ -1190,7 +1238,7 @@ eightbit2onebit( Wtiff *wtiff, VipsPel *q, VipsPel *p, int n )
static void static void
invert_band0( Wtiff *wtiff, VipsPel *q, VipsPel *p, int n ) invert_band0( Wtiff *wtiff, VipsPel *q, VipsPel *p, int n )
{ {
VipsImage *im = wtiff->im; VipsImage *im = wtiff->ready;
gboolean invert = wtiff->miniswhite; gboolean invert = wtiff->miniswhite;
int x, i; int x, i;
@ -1278,20 +1326,20 @@ wtiff_pack2tiff( Wtiff *wtiff, Layer *layer,
for( y = area->top; y < VIPS_RECT_BOTTOM( area ); y++ ) { for( y = area->top; y < VIPS_RECT_BOTTOM( area ); y++ ) {
VipsPel *p = (VipsPel *) VIPS_REGION_ADDR( in, area->left, y ); VipsPel *p = (VipsPel *) VIPS_REGION_ADDR( in, area->left, y );
if( wtiff->im->Coding == VIPS_CODING_LABQ ) if( wtiff->ready->Coding == VIPS_CODING_LABQ )
LabQ2LabC( q, p, area->width ); LabQ2LabC( q, p, area->width );
else if( wtiff->onebit ) else if( wtiff->squash )
eightbit2onebit( wtiff, q, p, area->width ); eightbit2onebit( wtiff, q, p, area->width );
else if( (in->im->Bands == 1 || in->im->Bands == 2) && else if( (in->im->Bands == 1 || in->im->Bands == 2) &&
wtiff->miniswhite ) wtiff->miniswhite )
invert_band0( wtiff, q, p, area->width ); invert_band0( wtiff, q, p, area->width );
else if( wtiff->im->BandFmt == VIPS_FORMAT_SHORT && else if( wtiff->ready->BandFmt == VIPS_FORMAT_SHORT &&
wtiff->im->Type == VIPS_INTERPRETATION_LABS ) wtiff->ready->Type == VIPS_INTERPRETATION_LABS )
LabS2Lab16( q, p, area->width, in->im->Bands ); LabS2Lab16( q, p, area->width, in->im->Bands );
else else
memcpy( q, p, memcpy( q, p,
area->width * area->width *
VIPS_IMAGE_SIZEOF_PEL( wtiff->im ) ); VIPS_IMAGE_SIZEOF_PEL( wtiff->ready ) );
q += wtiff->tls; q += wtiff->tls;
} }
@ -1373,7 +1421,7 @@ wtiff_layer_write_strip( Wtiff *wtiff, Layer *layer, VipsRegion *strip )
LabS2Lab16( wtiff->tbuf, p, im->Xsize, im->Bands ); LabS2Lab16( wtiff->tbuf, p, im->Xsize, im->Bands );
p = wtiff->tbuf; p = wtiff->tbuf;
} }
else if( wtiff->onebit ) { else if( wtiff->squash ) {
eightbit2onebit( wtiff, wtiff->tbuf, p, im->Xsize ); eightbit2onebit( wtiff, wtiff->tbuf, p, im->Xsize );
p = wtiff->tbuf; p = wtiff->tbuf;
} }
@ -1642,8 +1690,8 @@ wtiff_copy_tiff( Wtiff *wtiff, TIFF *out, TIFF *in )
/* Only for three-band, 8-bit images. /* Only for three-band, 8-bit images.
*/ */
if( wtiff->im->Bands == 3 && if( wtiff->ready->Bands == 3 &&
wtiff->im->BandFmt == VIPS_FORMAT_UCHAR ) { wtiff->ready->BandFmt == VIPS_FORMAT_UCHAR ) {
/* Enable rgb->ycbcr conversion in the jpeg write. /* Enable rgb->ycbcr conversion in the jpeg write.
*/ */
if( !wtiff->rgbjpeg && if( !wtiff->rgbjpeg &&
@ -1768,8 +1816,8 @@ wtiff_write_image( Wtiff *wtiff )
for(;;) { for(;;) {
VipsImage *page; VipsImage *page;
if( vips_crop( wtiff->im, &page, if( vips_crop( wtiff->ready, &page,
0, y, wtiff->im->Xsize, wtiff->page_height, 0, y, wtiff->ready->Xsize, wtiff->page_height,
NULL ) ) NULL ) )
return( -1 ); return( -1 );
if( vips_sink_disc( page, write_strip, wtiff ) ) { if( vips_sink_disc( page, write_strip, wtiff ) ) {
@ -1779,7 +1827,7 @@ wtiff_write_image( Wtiff *wtiff )
g_object_unref( page ); g_object_unref( page );
y += wtiff->page_height; y += wtiff->page_height;
if( y >= wtiff->im->Ysize ) if( y >= wtiff->ready->Ysize )
break; break;
if( !TIFFWriteDirectory( wtiff->layer->tif ) || if( !TIFFWriteDirectory( wtiff->layer->tif ) ||
@ -1795,7 +1843,7 @@ wtiff_write_image( Wtiff *wtiff )
printf( "wtiff_write_image: pyramid mode\n" ); printf( "wtiff_write_image: pyramid mode\n" );
#endif /*DEBUG*/ #endif /*DEBUG*/
if( vips_sink_disc( wtiff->im, write_strip, wtiff ) ) if( vips_sink_disc( wtiff->ready, write_strip, wtiff ) )
return( -1 ); return( -1 );
if( !TIFFWriteDirectory( wtiff->layer->tif ) ) if( !TIFFWriteDirectory( wtiff->layer->tif ) )
@ -1820,7 +1868,7 @@ wtiff_write_image( Wtiff *wtiff )
printf( "wtiff_write_image: single-image mode\n" ); printf( "wtiff_write_image: single-image mode\n" );
#endif /*DEBUG*/ #endif /*DEBUG*/
if( vips_sink_disc( wtiff->im, write_strip, wtiff ) ) if( vips_sink_disc( wtiff->ready, write_strip, wtiff ) )
return( -1 ); return( -1 );
} }
@ -1828,7 +1876,7 @@ wtiff_write_image( Wtiff *wtiff )
} }
int int
vips__tiff_write( VipsImage *in, const char *filename, vips__tiff_write( VipsImage *input, const char *filename,
VipsForeignTiffCompression compression, int Q, VipsForeignTiffCompression compression, int Q,
VipsForeignTiffPredictor predictor, VipsForeignTiffPredictor predictor,
char *profile, char *profile,
@ -1851,10 +1899,7 @@ vips__tiff_write( VipsImage *in, const char *filename,
vips__tiff_init(); vips__tiff_init();
if( vips_check_coding_known( "vips2tiff", in ) ) if( !(wtiff = wtiff_new( input, filename,
return( -1 );
if( !(wtiff = wtiff_new( in, filename,
compression, Q, predictor, profile, compression, Q, predictor, profile,
tile, tile_width, tile_height, pyramid, squash, tile, tile_width, tile_height, pyramid, squash,
miniswhite, resunit, xres, yres, bigtiff, rgbjpeg, miniswhite, resunit, xres, yres, bigtiff, rgbjpeg,
@ -1872,7 +1917,7 @@ vips__tiff_write( VipsImage *in, const char *filename,
} }
int int
vips__tiff_write_buf( VipsImage *in, vips__tiff_write_buf( VipsImage *input,
void **obuf, size_t *olen, void **obuf, size_t *olen,
VipsForeignTiffCompression compression, int Q, VipsForeignTiffCompression compression, int Q,
VipsForeignTiffPredictor predictor, VipsForeignTiffPredictor predictor,
@ -1892,10 +1937,7 @@ vips__tiff_write_buf( VipsImage *in,
vips__tiff_init(); vips__tiff_init();
if( vips_check_coding_known( "vips2tiff", in ) ) if( !(wtiff = wtiff_new( input, NULL,
return( -1 );
if( !(wtiff = wtiff_new( in, NULL,
compression, Q, predictor, profile, compression, Q, predictor, profile,
tile, tile_width, tile_height, pyramid, squash, tile, tile_width, tile_height, pyramid, squash,
miniswhite, resunit, xres, yres, bigtiff, rgbjpeg, miniswhite, resunit, xres, yres, bigtiff, rgbjpeg,

View File

@ -197,6 +197,12 @@ vips_resize_build( VipsObject *object )
int_hshrink = vips_resize_int_shrink( resize, hscale ); int_hshrink = vips_resize_int_shrink( resize, hscale );
int_vshrink = vips_resize_int_shrink( resize, vscale ); int_vshrink = vips_resize_int_shrink( resize, vscale );
/* Unpack for processing.
*/
if( vips_image_decode( in, &t[5] ) )
return( -1 );
in = t[5];
if( int_vshrink > 1 ) { if( int_vshrink > 1 ) {
g_info( "shrinkv by %d", int_vshrink ); g_info( "shrinkv by %d", int_vshrink );
if( vips_shrinkv( in, &t[0], int_vshrink, NULL ) ) if( vips_shrinkv( in, &t[0], int_vshrink, NULL ) )

View File

@ -252,12 +252,6 @@ vips_shrinkh_build( VipsObject *object )
if( shrink->hshrink == 1 ) if( shrink->hshrink == 1 )
return( vips_image_write( in, resample->out ) ); return( vips_image_write( in, resample->out ) );
/* Unpack for processing.
*/
if( vips_image_decode( in, &t[0] ) )
return( -1 );
in = t[0];
/* We need new pixels at the right so that we don't have small chunks /* We need new pixels at the right so that we don't have small chunks
* to average down the right edge. * to average down the right edge.
*/ */

View File

@ -345,12 +345,6 @@ vips_shrinkv_build( VipsObject *object )
if( shrink->vshrink == 1 ) if( shrink->vshrink == 1 )
return( vips_image_write( in, resample->out ) ); return( vips_image_write( in, resample->out ) );
/* Unpack for processing.
*/
if( vips_image_decode( in, &t[0] ) )
return( -1 );
in = t[0];
/* Make the height a multiple of the shrink factor so we don't need to /* Make the height a multiple of the shrink factor so we don't need to
* average half pixels. * average half pixels.
*/ */

View File

@ -6,12 +6,12 @@ set -e
. ./variables.sh . ./variables.sh
if test_supported tiffload; then if test_supported tiffload; then
VIPS_STALL=1 vips copy $image $tmp/x.tif VIPS_STALL=1 $vips copy $image $tmp/x.tif
cat > $tmp/mask.con <<EOF cat > $tmp/mask.con <<EOF
3 3 8 0 3 3 8 0
-1 -1 -1 -1 -1 -1
-1 16 -1 -1 16 -1
-1 -1 -1 -1 -1 -1
EOF EOF
VIPS_STALL=1 vips conv $tmp/x.tif $tmp/x2.tif $tmp/mask.con VIPS_STALL=1 $vips conv $tmp/x.tif $tmp/x2.tif $tmp/mask.con
fi fi