diff --git a/ChangeLog b/ChangeLog index 9c542653..d28743c8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -13,6 +13,7 @@ - vipsthumbnail uses embedded jpg thumbnails if it can - rename vips_diag() as vips_info(), add --vips-info flag - deprecate im_hsp() +- support alpha for 8, 16 and 32-bit greyscale tiff images, thanks Robert 3/7/13 started 7.34.2 - lower priority for Matlab load to reduce segvs from Mat_Open(), thanks diff --git a/TODO b/TODO index 3fcae8fc..b06fe2f1 100644 --- a/TODO +++ b/TODO @@ -8,19 +8,8 @@ - support planar config in tiff reader -- support GA (greyscale with alpha) in tiff reader - - $ vips extract_band shark.jpg x.tif 0 -n 2 - $ header x.tif - header: tiff2vips: required field 277 = 2, not 1 - - is vips_hist_local() correct? it seems to leave white dots everywhere -- use VipsInterpolate to generate intermediate values in buildlut etc. - - need to pull out columns of input matrix into separate image and expand each - one - - use g_log() instead of vips_info() - do we always call copy_fields and demand_hint with ALL input images? what diff --git a/libvips/foreign/tiff2vips.c b/libvips/foreign/tiff2vips.c index 85b70094..845b60b9 100644 --- a/libvips/foreign/tiff2vips.c +++ b/libvips/foreign/tiff2vips.c @@ -135,6 +135,8 @@ * - clip rows_per_strip down to image height to avoid overflows for huge * values (thanks Nicolas) * - better error msg for not PLANARCONFIG_CONTIG images + * 16/9/13 + * - support alpha for 8, 16 and 32-bit greyscale images, thanks Robert */ /* @@ -224,6 +226,10 @@ typedef struct { tsize_t scanline_size; tsize_t strip_size; int number_of_strips; + + /* EOR greyscale images with this on read. + */ + int mask; } ReadTiff; /* Handle TIFF errors here. Shared with vips2tiff.c. These can be called from @@ -464,17 +470,26 @@ parse_onebit( ReadTiff *rtiff, int pm, VipsImage *out ) /* Per-scanline process function for 8-bit greyscale images. */ static void -greyscale8_line( VipsPel *q, VipsPel *p, int n, void *flg ) +greyscale8_line( VipsPel *q, VipsPel *p, int n, void *client ) { - /* Extract swap mask. - */ - VipsPel mask = *((VipsPel *) flg); + ReadTiff *rtiff = (ReadTiff *) client; + int bands = rtiff->out->Bands; + int x; /* Read bytes, swapping sense if necessary. */ - for( x = 0; x < n; x++ ) - q[x] = p[x] ^ mask; + for( x = 0; x < n; x++ ) { + q[0] = p[0] ^ rtiff->mask; + + /* Process alpha, if any. Don't swap this. + */ + if( bands == 2 ) + q[1] = p[1]; + + q += bands; + p += bands; + } } /* Read a 8-bit grey-scale TIFF image. @@ -482,25 +497,31 @@ greyscale8_line( VipsPel *q, VipsPel *p, int n, void *flg ) static int parse_greyscale8( ReadTiff *rtiff, int pm, VipsImage *out ) { - VipsPel *mask; + int bands; - if( !tfequals( rtiff->tiff, TIFFTAG_SAMPLESPERPIXEL, 1 ) || - !tfequals( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, 8 ) ) + /* Can have an extra alpha band. + */ + if( !tfequals( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, 8 ) || + !tfget16( rtiff->tiff, TIFFTAG_SAMPLESPERPIXEL, &bands ) ) return( -1 ); + if( bands != 1 && + bands != 2 ) { + vips_error( "tiff2vips", + "%s", _( "1 or 2 bands greyscale TIFF only" ) ); + return( -1 ); + } /* Eor each pel with this later. */ - if( !(mask = VIPS_ARRAY( out, 1, VipsPel )) ) - return( -1 ); - *mask = (pm == PHOTOMETRIC_MINISBLACK) ? 0 : 255; + rtiff->mask = (pm == PHOTOMETRIC_MINISBLACK) ? 0 : -1; - out->Bands = 1; + out->Bands = bands; out->BandFmt = VIPS_FORMAT_UCHAR; out->Coding = VIPS_CODING_NONE; out->Type = VIPS_INTERPRETATION_B_W; rtiff->sfn = greyscale8_line; - rtiff->client = mask; + rtiff->client = rtiff; return( 0 ); } @@ -508,19 +529,30 @@ parse_greyscale8( ReadTiff *rtiff, int pm, VipsImage *out ) /* Per-scanline process function for 16-bit greyscale images. */ static void -greyscale16_line( VipsPel *q, VipsPel *p, int n, void *flg ) +greyscale16_line( VipsPel *q, VipsPel *p, int n, void *client ) { - /* Extract swap mask. - */ - unsigned short mask = *((unsigned short *) flg); - unsigned short *p1 = (unsigned short *) p; - unsigned short *q1 = (unsigned short *) q; + ReadTiff *rtiff = (ReadTiff *) client; + int bands = rtiff->out->Bands; + + unsigned short *p1; + unsigned short *q1; int x; /* Read bytes, swapping sense if necessary. */ - for( x = 0; x < n; x++ ) - q1[x] = p1[x] ^ mask; + p1 = (unsigned short *) p; + q1 = (unsigned short *) q; + for( x = 0; x < n; x++ ) { + q1[0] = p1[0] ^ rtiff->mask; + + /* Process alpha, if any. Don't swap this. + */ + if( bands == 2 ) + q1[1] = p1[1]; + + q1 += bands; + p1 += bands; + } } /* Read a 16-bit grey-scale TIFF image. @@ -528,25 +560,29 @@ greyscale16_line( VipsPel *q, VipsPel *p, int n, void *flg ) static int parse_greyscale16( ReadTiff *rtiff, int pm, VipsImage *out ) { - unsigned short *mask; + int bands; - if( !tfequals( rtiff->tiff, TIFFTAG_SAMPLESPERPIXEL, 1 ) || - !tfequals( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, 16 ) ) - return( -1 ); - - /* Eor each pel with this later. + /* Can have an extra alpha band. */ - if( !(mask = VIPS_ARRAY( out, 1, unsigned short )) ) + if( !tfequals( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, 16 ) || + !tfget16( rtiff->tiff, TIFFTAG_SAMPLESPERPIXEL, &bands ) ) return( -1 ); - mask[0] = (pm == PHOTOMETRIC_MINISBLACK) ? 0 : 65535; + if( bands != 1 && + bands != 2 ) { + vips_error( "tiff2vips", + "%s", _( "1 or 2 bands greyscale TIFF only" ) ); + return( -1 ); + } - out->Bands = 1; + rtiff->mask = (pm == PHOTOMETRIC_MINISBLACK) ? 0 : -1; + + out->Bands = bands; out->BandFmt = VIPS_FORMAT_USHORT; out->Coding = VIPS_CODING_NONE; out->Type = VIPS_INTERPRETATION_GREY16; rtiff->sfn = greyscale16_line; - rtiff->client = mask; + rtiff->client = rtiff; return( 0 ); } @@ -568,11 +604,21 @@ memcpy_line( VipsPel *q, VipsPel *p, int n, void *client ) static int parse_greyscale32f( ReadTiff *rtiff, int pm, VipsImage *out ) { - if( !tfequals( rtiff->tiff, TIFFTAG_SAMPLESPERPIXEL, 1 ) || - !tfequals( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, 32 ) ) - return( -1 ); + int bands; - out->Bands = 1; + /* Can have an extra alpha band. + */ + if( !tfequals( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, 32 ) || + !tfget16( rtiff->tiff, TIFFTAG_SAMPLESPERPIXEL, &bands ) ) + return( -1 ); + if( bands != 1 && + bands != 2 ) { + vips_error( "tiff2vips", + "%s", _( "1 or 2 bands greyscale TIFF only" ) ); + return( -1 ); + } + + out->Bands = bands; out->BandFmt = VIPS_FORMAT_FLOAT; out->Coding = VIPS_CODING_NONE; out->Type = VIPS_INTERPRETATION_B_W;