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
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;
}
}
}

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 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

View File

@ -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;
}