adjust formatting of 2, 4 bit tiff load/save

To make it libvipsey. Small fixes as well.
This commit is contained in:
John Cupitt 2020-06-16 18:58:27 +01:00
parent 63b8e162f8
commit 8b469b4516
4 changed files with 103 additions and 100 deletions

View File

@ -31,6 +31,8 @@
- deprecate heifload autorotate -- it's now always on - deprecate heifload autorotate -- it's now always on
- revised resize improves accuracy [kleisauke] - revised resize improves accuracy [kleisauke]
- add --vips-config flag to show configuration info - add --vips-config flag to show configuration info
- add "bitdepth" param to tiff load and save, deprecate "squash" [MathemanFlo]
- tiff load and save now supports 2 and 4 bit data [MathemanFlo]
24/4/20 started 8.9.3 24/4/20 started 8.9.3
- better iiif tile naming [IllyaMoskvin] - better iiif tile naming [IllyaMoskvin]

View File

@ -199,8 +199,8 @@
* - better handling of aligned reads in multipage tiffs * - better handling of aligned reads in multipage tiffs
* 28/5/20 * 28/5/20
* - add subifd * - add subifd
* 06/6/20 * 06/6/20 MathemanFlo
* - add load functionality for 2 and 4 bit greyscale tiffs * - support 2 and 4 bit greyscale load
*/ */
/* /*
@ -1026,14 +1026,13 @@ rtiff_onebit_line( Rtiff *rtiff, VipsPel *q, VipsPel *p, int n, void *flg )
{ {
int photometric_interpretation = int photometric_interpretation =
rtiff->header.photometric_interpretation; rtiff->header.photometric_interpretation;
int x, i, z;
VipsPel bits;
int black = photometric_interpretation == PHOTOMETRIC_MINISBLACK ? int black = photometric_interpretation == PHOTOMETRIC_MINISBLACK ?
0 : 255; 0 : 255;
int white = black ^ 0xff; int white = black ^ 0xff;
int x, i, z;
VipsPel bits;
/* (sigh) how many times have I written this? /* (sigh) how many times have I written this?
*/ */
x = 0; x = 0;
@ -1051,6 +1050,7 @@ rtiff_onebit_line( Rtiff *rtiff, VipsPel *q, VipsPel *p, int n, void *flg )
*/ */
if( n & 7 ) { if( n & 7 ) {
bits = p[i]; bits = p[i];
for( z = 0; z < (n & 7); z++ ) { for( z = 0; z < (n & 7); z++ ) {
q[x + z] = (bits & 128) ? white : black; q[x + z] = (bits & 128) ? white : black;
bits <<= 1; bits <<= 1;
@ -1063,9 +1063,11 @@ 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 photometric_interpretation =
rtiff->header.photometric_interpretation;
int minisblack = photometric_interpretation == PHOTOMETRIC_MINISBLACK;
int x, i, z; int x, i, z;
int minisblack =
rtiff->header.photometric_interpretation == PHOTOMETRIC_MINISBLACK;
VipsPel twobits, fourbits, bits; VipsPel twobits, fourbits, bits;
x = 0; x = 0;
@ -1073,7 +1075,8 @@ rtiff_twobit_line( Rtiff *rtiff, VipsPel *q, VipsPel *p, int n, void *flg )
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.
*/
twobits = bits >> 6; twobits = bits >> 6;
fourbits = twobits | (twobits << 2); fourbits = twobits | (twobits << 2);
q[x] = fourbits | (fourbits << 4); q[x] = fourbits | (fourbits << 4);
@ -1086,7 +1089,8 @@ rtiff_twobit_line( Rtiff *rtiff, VipsPel *q, VipsPel *p, int n, void *flg )
*/ */
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++ ) {
twobits = bits >> 6; twobits = bits >> 6;
fourbits = twobits | (twobits << 2); fourbits = twobits | (twobits << 2);
q[x + z] = fourbits | (fourbits << 4); q[x + z] = fourbits | (fourbits << 4);
@ -1100,18 +1104,20 @@ 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 photometric_interpretation =
rtiff->header.photometric_interpretation;
int minisblack = photometric_interpretation == PHOTOMETRIC_MINISBLACK;
int x, i, z; int x, i, z;
int 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;
@ -1119,10 +1125,10 @@ rtiff_fourbit_line( Rtiff *rtiff, VipsPel *q, VipsPel *p, int n, void *flg )
} }
/* 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

@ -25,6 +25,7 @@
* - add "subifd" to create pyr layers as sub-directories * - add "subifd" to create pyr layers as sub-directories
* 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
* - deprecate "squash"
*/ */
/* /*
@ -263,20 +264,6 @@ vips_foreign_save_tiff_class_init( VipsForeignSaveTiffClass *class )
G_STRUCT_OFFSET( VipsForeignSaveTiff, pyramid ), G_STRUCT_OFFSET( VipsForeignSaveTiff, pyramid ),
FALSE ); FALSE );
VIPS_ARG_BOOL( class, "squash", 14,
_( "Squash" ),
_( "Squash images down to 1 bit" ),
VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED,
G_STRUCT_OFFSET( VipsForeignSaveTiff, squash ),
FALSE );
VIPS_ARG_INT( class, "bitdepth", 14,
_( "bitdepth" ),
_( "Change greyscale image bit depth to 1,2, 4 or 8." ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignSaveTiff, bitdepth ),
1,8,8 );
VIPS_ARG_BOOL( class, "miniswhite", 14, VIPS_ARG_BOOL( class, "miniswhite", 14,
_( "Miniswhite" ), _( "Miniswhite" ),
_( "Use 0 for white in 1-bit images" ), _( "Use 0 for white in 1-bit images" ),
@ -284,41 +271,41 @@ vips_foreign_save_tiff_class_init( VipsForeignSaveTiffClass *class )
G_STRUCT_OFFSET( VipsForeignSaveTiff, miniswhite ), G_STRUCT_OFFSET( VipsForeignSaveTiff, miniswhite ),
FALSE ); FALSE );
VIPS_ARG_ENUM( class, "resunit", 15, VIPS_ARG_INT( class, "bitdepth", 15,
_( "bitdepth" ),
_( "Write as a 1, 2, 4 or 8 bit image" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignSaveTiff, bitdepth ),
0, 8, 0 );
VIPS_ARG_ENUM( class, "resunit", 16,
_( "Resolution unit" ), _( "Resolution unit" ),
_( "Resolution unit" ), _( "Resolution unit" ),
VIPS_ARGUMENT_OPTIONAL_INPUT, VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignSaveTiff, resunit ), G_STRUCT_OFFSET( VipsForeignSaveTiff, resunit ),
VIPS_TYPE_FOREIGN_TIFF_RESUNIT, VIPS_FOREIGN_TIFF_RESUNIT_CM ); VIPS_TYPE_FOREIGN_TIFF_RESUNIT, VIPS_FOREIGN_TIFF_RESUNIT_CM );
VIPS_ARG_DOUBLE( class, "xres", 16, VIPS_ARG_DOUBLE( class, "xres", 17,
_( "Xres" ), _( "Xres" ),
_( "Horizontal resolution in pixels/mm" ), _( "Horizontal resolution in pixels/mm" ),
VIPS_ARGUMENT_OPTIONAL_INPUT, VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignSaveTiff, xres ), G_STRUCT_OFFSET( VipsForeignSaveTiff, xres ),
0.001, 1000000, 1 ); 0.001, 1000000, 1 );
VIPS_ARG_DOUBLE( class, "yres", 17, VIPS_ARG_DOUBLE( class, "yres", 18,
_( "Yres" ), _( "Yres" ),
_( "Vertical resolution in pixels/mm" ), _( "Vertical resolution in pixels/mm" ),
VIPS_ARGUMENT_OPTIONAL_INPUT, VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignSaveTiff, yres ), G_STRUCT_OFFSET( VipsForeignSaveTiff, yres ),
0.001, 1000000, 1 ); 0.001, 1000000, 1 );
VIPS_ARG_BOOL( class, "bigtiff", 18, VIPS_ARG_BOOL( class, "bigtiff", 19,
_( "Bigtiff" ), _( "Bigtiff" ),
_( "Write a bigtiff image" ), _( "Write a bigtiff image" ),
VIPS_ARGUMENT_OPTIONAL_INPUT, VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignSaveTiff, bigtiff ), G_STRUCT_OFFSET( VipsForeignSaveTiff, bigtiff ),
FALSE ); FALSE );
VIPS_ARG_BOOL( class, "rgbjpeg", 20,
_( "RGB JPEG" ),
_( "Output RGB JPEG rather than YCbCr" ),
VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED,
G_STRUCT_OFFSET( VipsForeignSaveTiff, rgbjpeg ),
FALSE );
VIPS_ARG_BOOL( class, "properties", 21, VIPS_ARG_BOOL( class, "properties", 21,
_( "Properties" ), _( "Properties" ),
_( "Write a properties document to IMAGEDESCRIPTION" ), _( "Write a properties document to IMAGEDESCRIPTION" ),
@ -361,6 +348,20 @@ vips_foreign_save_tiff_class_init( VipsForeignSaveTiffClass *class )
G_STRUCT_OFFSET( VipsForeignSaveTiff, subifd ), G_STRUCT_OFFSET( VipsForeignSaveTiff, subifd ),
FALSE ); FALSE );
VIPS_ARG_BOOL( class, "rgbjpeg", 20,
_( "RGB JPEG" ),
_( "Output RGB JPEG rather than YCbCr" ),
VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED,
G_STRUCT_OFFSET( VipsForeignSaveTiff, rgbjpeg ),
FALSE );
VIPS_ARG_BOOL( class, "squash", 14,
_( "Squash" ),
_( "Squash images down to 1 bit" ),
VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED,
G_STRUCT_OFFSET( VipsForeignSaveTiff, squash ),
FALSE );
} }
static void static void
@ -403,10 +404,12 @@ vips_foreign_save_tiff_file_build( VipsObject *object )
build( object ) ) build( object ) )
return( -1 ); return( -1 );
/* handle the deprecated squash parameter */ /* Handle the deprecated squash parameter.
if( vips_object_argument_isset(object,"squash") ) { */
tiff->bitdepth = 1; /*we set that even in the case of LAB to LABQ */ if( vips_object_argument_isset( object, "squash" ) )
} /* We set that even in the case of LAB to LABQ.
*/
tiff->bitdepth = 1;
if( vips__tiff_write( save->ready, file->filename, if( vips__tiff_write( save->ready, file->filename,
tiff->compression, tiff->Q, tiff->predictor, tiff->compression, tiff->Q, tiff->predictor,
@ -555,7 +558,6 @@ vips_foreign_save_tiff_buffer_init( VipsForeignSaveTiffBuffer *buffer )
* * @tile_width: %gint for tile size * * @tile_width: %gint for tile size
* * @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
* * @bitdepth: %int, change bit depth to 1,2, or 4 bit * * @bitdepth: %int, change bit depth to 1,2, or 4 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
@ -583,7 +585,7 @@ vips_foreign_save_tiff_buffer_init( VipsForeignSaveTiffBuffer *buffer )
* can do. * can do.
* *
* XYZ images are automatically saved as libtiff LOGLUV with SGILOG compression. * XYZ images are automatically saved as libtiff LOGLUV with SGILOG compression.
* Float LAB images are saved as float CIELAB. Set @squash to save as 8-bit * Float LAB images are saved as float CIELAB. Set @bitdepth to save as 8-bit
* CIELAB. * CIELAB.
* *
* Use @Q to set the JPEG compression factor. Default 75. * Use @Q to set the JPEG compression factor. Default 75.
@ -617,16 +619,7 @@ vips_foreign_save_tiff_buffer_init( VipsForeignSaveTiffBuffer *buffer )
* tile. Use @depth to stop when the image fits in one pixel, or to only write * tile. Use @depth to stop when the image fits in one pixel, or to only write
* a single layer. * a single layer.
* *
* Set @squash to make 8-bit uchar images write as 1-bit TIFFs. Values >128 * Set @bitdepth to save 8-bit uchar images as 1, 2 or 4-bit TIFFs.
* are written as white, values <=128 as black. Normally vips will write
* MINISBLACK TIFFs where black is a 0 bit, but if you set @miniswhite, it
* will use 0 for a white bit. Many pre-press applications only work with
* images which use this sense. @miniswhite only affects one-bit images, it
* does nothing for greyscale images. Consider @bitdepth for depths 1, 2 and 4.
*
* Set @squash to squash 3-band float CIELAB images down to 8-bit CIELAB.
*
* Set @bitdepth to make 8-bit uchar images write as 1,2 or 4-bit TIFFs.
* In case of depth 1: Values >128 are written as white, values <=128 as black. * In case of depth 1: Values >128 are written as white, values <=128 as black.
* Normally vips will write MINISBLACK TIFFs where black is a 0 bit, but if you * Normally vips will write MINISBLACK TIFFs where black is a 0 bit, but if you
* set @miniswhite, it will use 0 for a white bit. Many pre-press applications * set @miniswhite, it will use 0 for a white bit. Many pre-press applications
@ -639,8 +632,6 @@ vips_foreign_save_tiff_buffer_init( VipsForeignSaveTiffBuffer *buffer )
* 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
* resolution unit is taken from the header field * resolution unit is taken from the header field
@ -704,8 +695,7 @@ vips_tiffsave( VipsImage *in, const char *filename, ... )
* * @tile_width: %gint for tile size * * @tile_width: %gint for tile size
* * @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 * * @bitdepth: %int, set write bit depth to 1, 2, 4 or 8
* * @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

@ -195,9 +195,10 @@
* - add PAGENUMBER support * - add PAGENUMBER support
* 23/5/20 * 23/5/20
* - add support for subifd pyramid layers * - add support for subifd pyramid layers
* 8/6/20 * 06/6/20 MathemanFlo
* - 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.
@ -1190,30 +1191,34 @@ wtiff_new( VipsImage *input, const char *filename,
} }
} }
if( wtiff->bitdepth && !(wtiff->bitdepth == 1 || wtiff->bitdepth == 2 /* Depth 8 is handled above.
|| wtiff->bitdepth == 4) ) {
g_warning( "%s",
_( "allows only bitdepth values 1,2 or 4. "
"-- disabling bitdepth") );
wtiff->bitdepth = 0;
}
/* Can only have byte fractional bit depths for 8 bit mono.
* 3-band float should have been packed above.
*/ */
if( wtiff->bitdepth && !(wtiff->ready->Coding == VIPS_CODING_NONE && if( wtiff->bitdepth &&
wtiff->ready->BandFmt == VIPS_FORMAT_UCHAR && !(wtiff->bitdepth == 1 ||
wtiff->ready->Bands == 1) ) { wtiff->bitdepth == 2 ||
wtiff->bitdepth == 4) ) {
g_warning( "%s", g_warning( "%s",
( "can only set bitdepth for 1-band uchar and " _( "bitdepth 1, 2 or 4 only -- disabling bitdepth") );
"3-band float lab -- disabling bitdepth" ) ); wtiff->bitdepth = 0;
wtiff->bitdepth = 0;
} }
if( wtiff->bitdepth && /* Can only have byte fractional bit depths for 8 bit mono.
* 3-band float should have been packed above.
*/
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" ) );
wtiff->bitdepth = 0;
}
if( wtiff->bitdepth &&
wtiff->compression == COMPRESSION_JPEG ) { wtiff->compression == COMPRESSION_JPEG ) {
g_warning( "%s", g_warning( "%s",
_( "can't have 1,2 or 4-bit JPEG -- disabling JPEG" ) ); _( "can't have <8 bit JPEG -- disabling JPEG" ) );
wtiff->compression = COMPRESSION_NONE; wtiff->compression = COMPRESSION_NONE;
} }
@ -1285,14 +1290,14 @@ LabQ2LabC( VipsPel *q, VipsPel *p, int n )
static void static void
eightbit2onebit( Wtiff *wtiff, VipsPel *q, VipsPel *p, int n ) eightbit2onebit( Wtiff *wtiff, VipsPel *q, VipsPel *p, int n )
{ {
int x;
VipsPel bits;
/* Invert in miniswhite mode. /* Invert in miniswhite mode.
*/ */
int white = wtiff->miniswhite ? 0 : 1; int white = wtiff->miniswhite ? 0 : 1;
int black = white ^ 1; int black = white ^ 1;
int x;
VipsPel bits;
bits = 0; bits = 0;
for( x = 0; x < n; x++ ) { for( x = 0; x < n; x++ ) {
bits <<= 1; bits <<= 1;
@ -1318,12 +1323,12 @@ eightbit2onebit( Wtiff *wtiff, VipsPel *q, VipsPel *p, int n )
static void static void
eightbit2twobit( Wtiff *wtiff, VipsPel *q, VipsPel *p, int n ) eightbit2twobit( Wtiff *wtiff, VipsPel *q, VipsPel *p, int n )
{ {
int x;
VipsPel bits;
VipsPel mask = wtiff->miniswhite ? 3 : 0; VipsPel mask = wtiff->miniswhite ? 3 : 0;
int x;
VipsPel bits;
bits = 0; bits = 0;
for( x = 0; x < n; x++ ) { for( x = 0; x < n; x++ ) {
bits <<= 2; bits <<= 2;
bits |= (p[x] >> 6) ^ mask; bits |= (p[x] >> 6) ^ mask;
@ -1335,9 +1340,9 @@ eightbit2twobit( Wtiff *wtiff, VipsPel *q, VipsPel *p, int n )
} }
/* Any left-over bits? Need to be left-aligned. /* Any left-over bits? Need to be left-aligned.
*/ */
if( (x & 0x3) != 0 ) if( (x & 0x3) != 0 )
*q++ = (wtiff->miniswhite ? ~bits : bits) << (8 - ((x & 0x3) << 1)); *q++ = bits << (8 - ((x & 0x3) << 1));
} }
/* Pack 8 bit VIPS to 4 bit TIFF. /* Pack 8 bit VIPS to 4 bit TIFF.
@ -1345,26 +1350,26 @@ eightbit2twobit( Wtiff *wtiff, VipsPel *q, VipsPel *p, int n )
static void static void
eightbit2fourbit( Wtiff *wtiff, VipsPel *q, VipsPel *p, int n ) eightbit2fourbit( Wtiff *wtiff, VipsPel *q, VipsPel *p, int n )
{ {
int x; VipsPel mask = wtiff->miniswhite ? 0xf : 0;
VipsPel bits;
VipsPel mask = wtiff->miniswhite ? 15 : 0; VipsPel bits;
bits = 0; int x;
bits = 0;
for( x = 0; x < n; x++ ) { for( x = 0; x < n; x++ ) {
bits <<= 4; bits <<= 4;
bits |= (p[x] >> 4) ^ mask; bits |= (p[x] >> 4) ^ mask;
if( (x & 0x1) == 0x1 ) { if( (x & 0x1) == 0x1 ) {
*q++ = bits; *q++ = bits;
bits = 0; 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 )
*q++ = ((VipsPel)(wtiff->miniswhite ? ~bits : bits)) *q++ = bits << (8 - ((x & 0x1) << 2));
<< (8 - ((x & 0x1) << 2));
} }
/* Swap the sense of the first channel, if necessary. /* Swap the sense of the first channel, if necessary.