diff --git a/libvips/foreign/tiff2vips.c b/libvips/foreign/tiff2vips.c index e5228d86..546248b6 100644 --- a/libvips/foreign/tiff2vips.c +++ b/libvips/foreign/tiff2vips.c @@ -1063,34 +1063,36 @@ rtiff_onebit_line( Rtiff *rtiff, VipsPel *q, VipsPel *p, int n, void *flg ) static void rtiff_twobit_line( Rtiff *rtiff, VipsPel *q, VipsPel *p, int n, void *flg ) { - int x, i, z; - int minisblack = - rtiff->header.photometric_interpretation == PHOTOMETRIC_MINISBLACK; - VipsPel bits; + int x, i, z; + int minisblack = + rtiff->header.photometric_interpretation == PHOTOMETRIC_MINISBLACK; + VipsPel twobits, fourbits, bits; - x = 0; - for( i = 0; i < (n >> 2); i++ ) { - bits = (VipsPel) minisblack ? p[i] : ~p[i]; + x = 0; + for( i = 0; i < (n >> 2); i++ ) { + bits = (VipsPel) minisblack ? p[i] : ~p[i]; - for( z = 0; z < 4; z++ ) { - /* The grey shade is the value four times concatenated */ - q[x] = (bits & 0xC0) | ((bits & 0xC0) >> 2) - | ((bits & 0xC0) >> 4) | (bits >> 6); - bits <<= 2; - x += 1; - } - } + for( z = 0; z < 4; z++ ) { + /* The grey shade is the value four times concatenated */ + twobits = bits >> 6; + fourbits = twobits | (twobits << 2); + q[x] = fourbits | (fourbits << 4); + bits <<= 2; + x += 1; + } + } - /* Do last byte in line. - */ - if( n & 3 ) { - bits = (VipsPel) minisblack ? p[i] : ~p[i]; - for( z = 0; z < (n & 3) ; z++ ) { - q[x + z] = (bits & 0xC0) | ((bits & 0xC0) >> 2) - | ((bits & 0xC0) >> 4) | (bits >> 6); - bits <<= 2; - } - } + /* Do last byte in line. + */ + if( n & 3 ) { + bits = (VipsPel) minisblack ? p[i] : ~p[i]; + for( z = 0; z < (n & 3) ; z++ ) { + twobits = bits >> 6; + fourbits = twobits | (twobits << 2); + q[x + z] = fourbits | (fourbits << 4); + bits <<= 2; + } + } } /* Per-scanline process function for 4 bit greyscale images. @@ -1098,33 +1100,33 @@ rtiff_twobit_line( Rtiff *rtiff, VipsPel *q, VipsPel *p, int n, void *flg ) static void rtiff_fourbit_line( Rtiff *rtiff, VipsPel *q, VipsPel *p, int n, void *flg ) { - int x, i, z; - int minisblack = - rtiff->header.photometric_interpretation == PHOTOMETRIC_MINISBLACK; - VipsPel bits; + int x, i, z; + int minisblack = + rtiff->header.photometric_interpretation == PHOTOMETRIC_MINISBLACK; + VipsPel bits; - x = 0; + x = 0; - for( i = 0; i < (n >> 1); i++ ) { - bits = (VipsPel) minisblack ? p[i] : ~p[i]; + for( i = 0; i < (n >> 1); i++ ) { + bits = (VipsPel) minisblack ? p[i] : ~p[i]; - for( z = 0; z < 2; z++ ) { - /* The grey shade is the value two times concatenated */ - q[x] = (bits & 0xF0) | (bits >> 4); - bits <<= 4; - x += 1; - } - } + for( z = 0; z < 2; z++ ) { + /* The grey shade is the value two times concatenated */ + q[x] = (bits & 0xF0) | (bits >> 4); + bits <<= 4; + x += 1; + } + } - /* Do last byte in line. - */ - if( n & 1) { - bits = (VipsPel) minisblack ? p[i] : ~p[i]; - for( z = 0; z < (n & 1) ; z++ ) { - q[x + z] = (bits & 0xF0) | (bits >> 4); - bits <<= 4; - } - } + /* Do last byte in line. + */ + if( n & 1) { + bits = (VipsPel) minisblack ? p[i] : ~p[i]; + for( z = 0; z < (n & 1) ; z++ ) { + q[x + z] = (bits & 0xF0) | (bits >> 4); + bits <<= 4; + } + } } diff --git a/libvips/foreign/tiffsave.c b/libvips/foreign/tiffsave.c index e1fce97a..6e7096ad 100644 --- a/libvips/foreign/tiffsave.c +++ b/libvips/foreign/tiffsave.c @@ -638,6 +638,8 @@ vips_foreign_save_tiff_buffer_init( VipsForeignSaveTiffBuffer *buffer ) * In case @miniswhite is set to true this behavior is inverted. * In case of depth 4: values < 16 are written as black, and so on for the * lighter shades. In case @miniswhite is set to true this behavior is inverted. + * + * Set @bitdepth to 8 to squash 3-band float CIELAB images down to 8-bit CIELAB. * * Use @resunit to override the default resolution unit. * The default @@ -703,7 +705,7 @@ vips_tiffsave( VipsImage *in, const char *filename, ... ) * * @tile_height: %gint for tile size * * @pyramid: %gboolean, write an image pyramid * * @squash: %gboolean, squash 8-bit images down to 1 bit - * * @bitdepth: %int, change bit depth to 1,2 or 4-bit + * * @bitdepth: %int, change bit depth to 1,2 or 4-bit or squash float to 8 bit * * @miniswhite: %gboolean, write 1-bit images as MINISWHITE * * @resunit: #VipsForeignTiffResunit for resolution unit * * @xres: %gdouble horizontal resolution in pixels/mm diff --git a/libvips/foreign/vips2tiff.c b/libvips/foreign/vips2tiff.c index 1bf6d5cb..191fdf41 100644 --- a/libvips/foreign/vips2tiff.c +++ b/libvips/foreign/vips2tiff.c @@ -197,7 +197,7 @@ * - add support for subifd pyramid layers * 8/6/20 * - add bitdepth support for 2 and 4 bit greyscale images - + */ /* This file is part of VIPS. @@ -1041,7 +1041,7 @@ ready_to_write( Wtiff *wtiff ) /* "squash" float LAB down to LABQ. */ - if( wtiff->bitdepth == 1 && + if( (wtiff->bitdepth && wtiff->input->Bands == 3 && wtiff->input->BandFmt == VIPS_FORMAT_FLOAT && wtiff->input->Type == VIPS_INTERPRETATION_LAB ) { @@ -1201,11 +1201,9 @@ wtiff_new( VipsImage *input, const char *filename, /* Can only have byte fractional bit depths for 8 bit mono. * 3-band float should have been packed above. */ - if( wtiff->bitdepth && (wtiff->bitdepth == 1 || wtiff->bitdepth == 2 - || wtiff->bitdepth == 4 ) - && !(wtiff->ready->Coding == VIPS_CODING_NONE && - wtiff->ready->BandFmt == VIPS_FORMAT_UCHAR && - wtiff->ready->Bands == 1) ) { + if( wtiff->bitdepth && !(wtiff->ready->Coding == VIPS_CODING_NONE && + wtiff->ready->BandFmt == VIPS_FORMAT_UCHAR && + wtiff->ready->Bands == 1) ) { g_warning( "%s", ( "can only set bitdepth for 1-band uchar and " "3-band float lab -- disabling bitdepth" ) ); @@ -1250,11 +1248,11 @@ wtiff_new( VipsImage *input, const char *filename, */ if( wtiff->ready->Coding == VIPS_CODING_LABQ ) wtiff->tls = wtiff->tilew * 3; - else if( wtiff->bitdepth == 1) + else if( wtiff->bitdepth == 1 ) wtiff->tls = VIPS_ROUND_UP( wtiff->tilew, 8 ) / 8; - else if( wtiff->bitdepth == 2) + else if( wtiff->bitdepth == 2 ) wtiff->tls = VIPS_ROUND_UP( wtiff->tilew, 4 ) / 4; - else if( wtiff->bitdepth == 4) + else if( wtiff->bitdepth == 4 ) wtiff->tls = VIPS_ROUND_UP( wtiff->tilew, 2 ) / 2; else wtiff->tls = VIPS_IMAGE_SIZEOF_PEL( wtiff->ready ) * @@ -1322,28 +1320,17 @@ eightbit2twobit( Wtiff *wtiff, VipsPel *q, VipsPel *p, int n ) { int x; VipsPel bits; + VipsPel mask = wtiff->miniswhite ? 3 : 0; bits = 0; - if( !wtiff->miniswhite ) { //avoid unnecessary branches - for( x = 0; x < n; x++ ) { - bits <<= 2; - bits |= p[x] >> 6; + + for( x = 0; x < n; x++ ) { + bits <<= 2; + bits |= (p[x] >> 6) ^ mask; - if( (x & 0x3) == 0x3 ) { - *q++ = bits; - bits = 0; - } - } - } - else { - for( x = 0; x < n; x++ ) { - bits <<= 2; - bits |= p[x] >> 6; - - if( (x & 0x3) == 0x3 ) { - *q++ = ~bits; - bits = 0; - } + if( (x & 0x3) == 0x3 ) { + *q++ = bits; + bits = 0; } } @@ -1360,30 +1347,19 @@ eightbit2fourbit( Wtiff *wtiff, VipsPel *q, VipsPel *p, int n ) { int x; VipsPel bits; - + VipsPel mask = wtiff->miniswhite ? 15 : 0; bits = 0; - if( !wtiff->miniswhite ) { //avoid unnecessary branches - for( x = 0; x < n; x++ ) { - bits <<= 4; - bits |= p[x] >> 4; + + for( x = 0; x < n; x++ ) { + bits <<= 4; + bits |= (p[x] >> 4) ^ mask; - if( (x & 0x1) == 0x1 ) { - *q++ = bits; - bits = 0; - } + if( (x & 0x1) == 0x1 ) { + *q++ = bits; + bits = 0; } } - else { - for( x = 0; x < n; x++ ) { - bits <<= 4; - bits |= p[x] >> 4; - if( (x & 0x1) == 0x1 ) { - *q++ = ~bits; - bits = 0; - } - } - } /* Any left-over bits? Need to be left-aligned. */ if( (x & 0x1) != 0 ) @@ -1642,11 +1618,11 @@ wtiff_layer_write_strip( Wtiff *wtiff, Layer *layer, VipsRegion *strip ) eightbit2onebit( wtiff, wtiff->tbuf, p, im->Xsize ); p = wtiff->tbuf; } - else if( wtiff->bitdepth == 2) { + else if( wtiff->bitdepth == 2 ) { eightbit2twobit( wtiff, wtiff->tbuf, p, im->Xsize ); p = wtiff->tbuf; } - else if( wtiff->bitdepth == 4) { + else if( wtiff->bitdepth == 4 ) { eightbit2fourbit( wtiff, wtiff->tbuf, p, im->Xsize ); p = wtiff->tbuf; }