Fixed issues with bitdepth

This commit is contained in:
Florian Heinrich 2020-06-16 16:21:52 +02:00
parent 17a9bf393f
commit 00bd91a3c4
3 changed files with 79 additions and 99 deletions

View File

@ -1063,34 +1063,36 @@ rtiff_onebit_line( Rtiff *rtiff, VipsPel *q, VipsPel *p, int n, void *flg )
static void static void
rtiff_twobit_line( Rtiff *rtiff, VipsPel *q, VipsPel *p, int n, void *flg ) rtiff_twobit_line( Rtiff *rtiff, VipsPel *q, VipsPel *p, int n, void *flg )
{ {
int x, i, z; int x, i, z;
int minisblack = int minisblack =
rtiff->header.photometric_interpretation == PHOTOMETRIC_MINISBLACK; rtiff->header.photometric_interpretation == PHOTOMETRIC_MINISBLACK;
VipsPel bits; VipsPel twobits, fourbits, bits;
x = 0; x = 0;
for( i = 0; i < (n >> 2); i++ ) { for( i = 0; i < (n >> 2); i++ ) {
bits = (VipsPel) minisblack ? p[i] : ~p[i]; bits = (VipsPel) minisblack ? p[i] : ~p[i];
for( z = 0; z < 4; z++ ) { for( z = 0; z < 4; z++ ) {
/* The grey shade is the value four times concatenated */ /* The grey shade is the value four times concatenated */
q[x] = (bits & 0xC0) | ((bits & 0xC0) >> 2) twobits = bits >> 6;
| ((bits & 0xC0) >> 4) | (bits >> 6); fourbits = twobits | (twobits << 2);
bits <<= 2; q[x] = fourbits | (fourbits << 4);
x += 1; bits <<= 2;
} x += 1;
} }
}
/* Do last byte in line. /* Do last byte in line.
*/ */
if( n & 3 ) { if( n & 3 ) {
bits = (VipsPel) minisblack ? p[i] : ~p[i]; bits = (VipsPel) minisblack ? p[i] : ~p[i];
for( z = 0; z < (n & 3) ; z++ ) { for( z = 0; z < (n & 3) ; z++ ) {
q[x + z] = (bits & 0xC0) | ((bits & 0xC0) >> 2) twobits = bits >> 6;
| ((bits & 0xC0) >> 4) | (bits >> 6); fourbits = twobits | (twobits << 2);
bits <<= 2; q[x + z] = fourbits | (fourbits << 4);
} bits <<= 2;
} }
}
} }
/* Per-scanline process function for 4 bit greyscale images. /* 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 static void
rtiff_fourbit_line( Rtiff *rtiff, VipsPel *q, VipsPel *p, int n, void *flg ) rtiff_fourbit_line( Rtiff *rtiff, VipsPel *q, VipsPel *p, int n, void *flg )
{ {
int x, i, z; int x, i, z;
int minisblack = int minisblack =
rtiff->header.photometric_interpretation == PHOTOMETRIC_MINISBLACK; rtiff->header.photometric_interpretation == PHOTOMETRIC_MINISBLACK;
VipsPel bits; VipsPel bits;
x = 0; x = 0;
for( i = 0; i < (n >> 1); i++ ) { for( i = 0; i < (n >> 1); i++ ) {
bits = (VipsPel) minisblack ? p[i] : ~p[i]; bits = (VipsPel) minisblack ? p[i] : ~p[i];
for( z = 0; z < 2; z++ ) { for( z = 0; z < 2; z++ ) {
/* The grey shade is the value two times concatenated */ /* The grey shade is the value two times concatenated */
q[x] = (bits & 0xF0) | (bits >> 4); q[x] = (bits & 0xF0) | (bits >> 4);
bits <<= 4; bits <<= 4;
x += 1; x += 1;
} }
} }
/* Do last byte in line. /* Do last byte in line.
*/ */
if( n & 1) { if( n & 1) {
bits = (VipsPel) minisblack ? p[i] : ~p[i]; bits = (VipsPel) minisblack ? p[i] : ~p[i];
for( z = 0; z < (n & 1) ; z++ ) { for( z = 0; z < (n & 1) ; z++ ) {
q[x + z] = (bits & 0xF0) | (bits >> 4); q[x + z] = (bits & 0xF0) | (bits >> 4);
bits <<= 4; bits <<= 4;
} }
} }
} }

View File

@ -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 @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 * 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. * 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. * Use @resunit to override the default resolution unit.
* The default * The default
@ -703,7 +705,7 @@ vips_tiffsave( VipsImage *in, const char *filename, ... )
* * @tile_height: %gint for tile size * * @tile_height: %gint for tile size
* * @pyramid: %gboolean, write an image pyramid * * @pyramid: %gboolean, write an image pyramid
* * @squash: %gboolean, squash 8-bit images down to 1 bit * * @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 * * @miniswhite: %gboolean, write 1-bit images as MINISWHITE
* * @resunit: #VipsForeignTiffResunit for resolution unit * * @resunit: #VipsForeignTiffResunit for resolution unit
* * @xres: %gdouble horizontal resolution in pixels/mm * * @xres: %gdouble horizontal resolution in pixels/mm

View File

@ -197,7 +197,7 @@
* - add support for subifd pyramid layers * - add support for subifd pyramid layers
* 8/6/20 * 8/6/20
* - add bitdepth support for 2 and 4 bit greyscale images * - add bitdepth support for 2 and 4 bit greyscale images
*/
/* /*
This file is part of VIPS. This file is part of VIPS.
@ -1041,7 +1041,7 @@ ready_to_write( Wtiff *wtiff )
/* "squash" float LAB down to LABQ. /* "squash" float LAB down to LABQ.
*/ */
if( wtiff->bitdepth == 1 && if( (wtiff->bitdepth &&
wtiff->input->Bands == 3 && wtiff->input->Bands == 3 &&
wtiff->input->BandFmt == VIPS_FORMAT_FLOAT && wtiff->input->BandFmt == VIPS_FORMAT_FLOAT &&
wtiff->input->Type == VIPS_INTERPRETATION_LAB ) { 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. /* Can only have byte fractional bit depths for 8 bit mono.
* 3-band float should have been packed above. * 3-band float should have been packed above.
*/ */
if( wtiff->bitdepth && (wtiff->bitdepth == 1 || wtiff->bitdepth == 2 if( wtiff->bitdepth && !(wtiff->ready->Coding == VIPS_CODING_NONE &&
|| wtiff->bitdepth == 4 ) wtiff->ready->BandFmt == VIPS_FORMAT_UCHAR &&
&& !(wtiff->ready->Coding == VIPS_CODING_NONE && wtiff->ready->Bands == 1) ) {
wtiff->ready->BandFmt == VIPS_FORMAT_UCHAR &&
wtiff->ready->Bands == 1) ) {
g_warning( "%s", g_warning( "%s",
( "can only set bitdepth for 1-band uchar and " ( "can only set bitdepth for 1-band uchar and "
"3-band float lab -- disabling bitdepth" ) ); "3-band float lab -- disabling bitdepth" ) );
@ -1250,11 +1248,11 @@ wtiff_new( VipsImage *input, const char *filename,
*/ */
if( wtiff->ready->Coding == VIPS_CODING_LABQ ) if( wtiff->ready->Coding == VIPS_CODING_LABQ )
wtiff->tls = wtiff->tilew * 3; wtiff->tls = wtiff->tilew * 3;
else if( wtiff->bitdepth == 1) else if( wtiff->bitdepth == 1 )
wtiff->tls = VIPS_ROUND_UP( wtiff->tilew, 8 ) / 8; 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; 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; wtiff->tls = VIPS_ROUND_UP( wtiff->tilew, 2 ) / 2;
else else
wtiff->tls = VIPS_IMAGE_SIZEOF_PEL( wtiff->ready ) * wtiff->tls = VIPS_IMAGE_SIZEOF_PEL( wtiff->ready ) *
@ -1322,28 +1320,17 @@ eightbit2twobit( Wtiff *wtiff, VipsPel *q, VipsPel *p, int n )
{ {
int x; int x;
VipsPel bits; VipsPel bits;
VipsPel mask = wtiff->miniswhite ? 3 : 0;
bits = 0; bits = 0;
if( !wtiff->miniswhite ) { //avoid unnecessary branches
for( x = 0; x < n; x++ ) { for( x = 0; x < n; x++ ) {
bits <<= 2; bits <<= 2;
bits |= p[x] >> 6; bits |= (p[x] >> 6) ^ mask;
if( (x & 0x3) == 0x3 ) { if( (x & 0x3) == 0x3 ) {
*q++ = bits; *q++ = bits;
bits = 0; bits = 0;
}
}
}
else {
for( x = 0; x < n; x++ ) {
bits <<= 2;
bits |= p[x] >> 6;
if( (x & 0x3) == 0x3 ) {
*q++ = ~bits;
bits = 0;
}
} }
} }
@ -1360,30 +1347,19 @@ eightbit2fourbit( Wtiff *wtiff, VipsPel *q, VipsPel *p, int n )
{ {
int x; int x;
VipsPel bits; VipsPel bits;
VipsPel mask = wtiff->miniswhite ? 15 : 0;
bits = 0; bits = 0;
if( !wtiff->miniswhite ) { //avoid unnecessary branches
for( x = 0; x < n; x++ ) { for( x = 0; x < n; x++ ) {
bits <<= 4; bits <<= 4;
bits |= p[x] >> 4; bits |= (p[x] >> 4) ^ mask;
if( (x & 0x1) == 0x1 ) { if( (x & 0x1) == 0x1 ) {
*q++ = bits; *q++ = bits;
bits = 0; 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. /* Any left-over bits? Need to be left-aligned.
*/ */
if( (x & 0x1) != 0 ) 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 ); eightbit2onebit( wtiff, wtiff->tbuf, p, im->Xsize );
p = wtiff->tbuf; p = wtiff->tbuf;
} }
else if( wtiff->bitdepth == 2) { else if( wtiff->bitdepth == 2 ) {
eightbit2twobit( wtiff, wtiff->tbuf, p, im->Xsize ); eightbit2twobit( wtiff, wtiff->tbuf, p, im->Xsize );
p = wtiff->tbuf; p = wtiff->tbuf;
} }
else if( wtiff->bitdepth == 4) { else if( wtiff->bitdepth == 4 ) {
eightbit2fourbit( wtiff, wtiff->tbuf, p, im->Xsize ); eightbit2fourbit( wtiff, wtiff->tbuf, p, im->Xsize );
p = wtiff->tbuf; p = wtiff->tbuf;
} }