tiff reader allows many more formats

eg. 32-bit ints, signed and unsigned, complex, extra alpha, etc.
This commit is contained in:
John Cupitt 2013-09-23 14:55:05 +01:00
parent 326365ab6c
commit a11e5352f2
2 changed files with 228 additions and 354 deletions

View File

@ -18,6 +18,7 @@
- added vips_webpload(), vips_webpload_buffer(), vips_webpsave(), - added vips_webpload(), vips_webpload_buffer(), vips_webpsave(),
vips_webpsave_buffer(), vips_webpsave_mime() vips_webpsave_buffer(), vips_webpsave_mime()
- tiff reader allows separate planes for strip read - tiff reader allows separate planes for strip read
- tiff reader allows many more formats, eg. 32-bit int, complex, etc.
- added vips_image_new_matrixv() - added vips_image_new_matrixv()
3/7/13 started 7.34.2 3/7/13 started 7.34.2

View File

@ -140,6 +140,7 @@
* 17/9/13 * 17/9/13
* - support separate planes for strip read * - support separate planes for strip read
* - big cleanup * - big cleanup
* - support for many more formats, eg. 32-bit int etc.
*/ */
/* /*
@ -170,8 +171,8 @@
*/ */
/* /*
#define DEBUG
*/ */
#define DEBUG
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> #include <config.h>
@ -233,6 +234,7 @@ typedef struct _ReadTiff {
int samples_per_pixel; int samples_per_pixel;
int bits_per_sample; int bits_per_sample;
int photometric_interpretation; int photometric_interpretation;
int sample_format;
/* Turn on separate plane reading. /* Turn on separate plane reading.
*/ */
@ -326,24 +328,6 @@ tfget16( TIFF *tif, ttag_t tag, int *out )
return( 1 ); return( 1 );
} }
/* Test a uint16 field. Field must be defined and equal to the value.
*/
static int
tfequals( TIFF *tif, ttag_t tag, uint16 val )
{
int v;
if( !tfget16( tif, tag, &v ) )
return( 0 );
if( v != val ) {
vips_error( "tiff2vips",
_( "required field %d = %d, not %d" ), tag, v, val );
return( 0 );
}
return( 1 );
}
static int static int
check_samples( ReadTiff *rtiff, int samples_per_pixel ) check_samples( ReadTiff *rtiff, int samples_per_pixel )
{ {
@ -359,13 +343,25 @@ check_samples( ReadTiff *rtiff, int samples_per_pixel )
/* Check n and n+1 so we can have an alpha. /* Check n and n+1 so we can have an alpha.
*/ */
static int static int
check_samples_alpha( ReadTiff *rtiff, int samples_per_pixel ) check_min_samples( ReadTiff *rtiff, int samples_per_pixel )
{ {
if( rtiff->samples_per_pixel != samples_per_pixel && if( rtiff->samples_per_pixel < samples_per_pixel ) {
rtiff->samples_per_pixel != samples_per_pixel + 1 ) {
vips_error( "tiff2vips", vips_error( "tiff2vips",
_( "not %d or %d bands" ), _( "not at least %d samples per pixel" ),
samples_per_pixel, samples_per_pixel + 1 ); samples_per_pixel );
return( -1 );
}
return( 0 );
}
static int
check_interpretation( ReadTiff *rtiff, int photometric_interpretation )
{
if( rtiff->photometric_interpretation != photometric_interpretation ) {
vips_error( "tiff2vips",
_( "not photometric interpretation %d" ),
photometric_interpretation );
return( -1 ); return( -1 );
} }
@ -400,20 +396,55 @@ check_bits_palette( ReadTiff *rtiff )
return( 0 ); return( 0 );
} }
static int static VipsBandFormat
check_float( ReadTiff *rtiff ) guess_format( ReadTiff *rtiff )
{ {
int format; switch( rtiff->bits_per_sample ) {
case 1:
case 2:
case 4:
case 8:
if( rtiff->sample_format == SAMPLEFORMAT_INT )
return( VIPS_FORMAT_CHAR );
if( rtiff->sample_format == SAMPLEFORMAT_UINT )
return( VIPS_FORMAT_UCHAR );
break;
if( !tfget16( rtiff->tiff, TIFFTAG_SAMPLEFORMAT, &format ) ) case 16:
return( -1 ); if( rtiff->sample_format == SAMPLEFORMAT_INT )
if( format != SAMPLEFORMAT_IEEEFP ) { return( VIPS_FORMAT_SHORT );
vips_error( "tiff2vips", if( rtiff->sample_format == SAMPLEFORMAT_UINT )
"%s", _( "not a floating-point image" ) ); return( VIPS_FORMAT_USHORT );
return( -1 ); break;
case 32:
if( rtiff->sample_format == SAMPLEFORMAT_INT )
return( VIPS_FORMAT_INT );
if( rtiff->sample_format == SAMPLEFORMAT_UINT )
return( VIPS_FORMAT_UINT );
if( rtiff->sample_format == SAMPLEFORMAT_IEEEFP )
return( VIPS_FORMAT_FLOAT );
break;
case 64:
if( rtiff->sample_format == SAMPLEFORMAT_IEEEFP )
return( VIPS_FORMAT_DOUBLE );
if( rtiff->sample_format == SAMPLEFORMAT_COMPLEXIEEEFP )
return( VIPS_FORMAT_COMPLEX );
break;
case 128:
if( rtiff->sample_format == SAMPLEFORMAT_COMPLEXIEEEFP )
return( VIPS_FORMAT_DPCOMPLEX );
break;
default:
break;
} }
return( 0 ); vips_error( "tiff2vips", "%s", _( "unsupported image format\n" ) );
return( VIPS_FORMAT_NOTSET );
} }
/* Per-scanline process function for VIPS_CODING_LABQ. /* Per-scanline process function for VIPS_CODING_LABQ.
@ -439,8 +470,9 @@ labpack_line( ReadTiff *rtiff, VipsPel *q, VipsPel *p, int n, void *dummy )
static int static int
parse_labpack( ReadTiff *rtiff, VipsImage *out ) parse_labpack( ReadTiff *rtiff, VipsImage *out )
{ {
if( check_samples_alpha( rtiff, 3 ) || if( check_min_samples( rtiff, 3 ) ||
check_bits( rtiff, 8 ) ) check_bits( rtiff, 8 ) ||
check_interpretation( rtiff, PHOTOMETRIC_CIELAB ) )
return( -1 ); return( -1 );
out->Bands = 4; out->Bands = 4;
@ -461,13 +493,17 @@ labs_line( ReadTiff *rtiff, VipsPel *q, VipsPel *p, int n, void *dummy )
int x; int x;
unsigned short *p1 = (unsigned short *) p; unsigned short *p1 = (unsigned short *) p;
short *q1 = (short *) q; short *q1 = (short *) q;
int i;
for( x = 0; x < n; x++ ) { for( x = 0; x < n; x++ ) {
/* We use a signed int16 for L.
*/
q1[0] = p1[0] >> 1; q1[0] = p1[0] >> 1;
q1[1] = p1[1];
q1[2] = p1[2];
q1 += 3; for( i = 1; i < rtiff->samples_per_pixel; i++ )
q1[i] = p1[i];
q1 += rtiff->samples_per_pixel;
p1 += rtiff->samples_per_pixel; p1 += rtiff->samples_per_pixel;
} }
} }
@ -477,11 +513,12 @@ labs_line( ReadTiff *rtiff, VipsPel *q, VipsPel *p, int n, void *dummy )
static int static int
parse_labs( ReadTiff *rtiff, VipsImage *out ) parse_labs( ReadTiff *rtiff, VipsImage *out )
{ {
if( check_samples_alpha( rtiff, 3 ) || if( check_min_samples( rtiff, 3 ) ||
check_bits( rtiff, 16 ) ) check_bits( rtiff, 16 ) ||
check_interpretation( rtiff, PHOTOMETRIC_CIELAB ) )
return( -1 ); return( -1 );
out->Bands = 3; out->Bands = rtiff->samples_per_pixel;
out->BandFmt = VIPS_FORMAT_SHORT; out->BandFmt = VIPS_FORMAT_SHORT;
out->Coding = VIPS_CODING_NONE; out->Coding = VIPS_CODING_NONE;
out->Type = VIPS_INTERPRETATION_LABS; out->Type = VIPS_INTERPRETATION_LABS;
@ -526,7 +563,7 @@ onebit_line( ReadTiff *rtiff, VipsPel *q, VipsPel *p, int n, void *flg )
} }
} }
/* Read a 1-bit TIFF image. Pass in pixel values to use for black and white. /* Read a 1-bit TIFF image.
*/ */
static int static int
parse_onebit( ReadTiff *rtiff, VipsImage *out ) parse_onebit( ReadTiff *rtiff, VipsImage *out )
@ -545,129 +582,98 @@ parse_onebit( ReadTiff *rtiff, VipsImage *out )
return( 0 ); return( 0 );
} }
/* Per-scanline process function for 8-bit greyscale images. /* Swap the sense of the first channel, if necessary.
*/
#define GREY_LOOP( TYPE, MAX ) { \
TYPE *p1; \
TYPE *q1; \
\
p1 = (TYPE *) p; \
q1 = (TYPE *) q; \
for( x = 0; x < n; x++ ) { \
if( invert ) \
q1[0] = MAX - p1[0]; \
else \
q1[0] = p1[0]; \
\
for( i = 1; i < rtiff->samples_per_pixel; i++ ) \
q1[i] = p1[i]; \
\
q1 += rtiff->samples_per_pixel; \
p1 += rtiff->samples_per_pixel; \
} \
}
/* Per-scanline process function for greyscale images.
*/ */
static void static void
greyscale8_line( ReadTiff *rtiff, VipsPel *q, VipsPel *p, int n, void *client ) greyscale_line( ReadTiff *rtiff, VipsPel *q, VipsPel *p, int n, void *client )
{ {
int mask = gboolean invert =
rtiff->photometric_interpretation == PHOTOMETRIC_MINISBLACK ? rtiff->photometric_interpretation == PHOTOMETRIC_MINISWHITE;
0 : -1; VipsBandFormat format = guess_format( rtiff );
int x; int x, i;
/* Read bytes, swapping sense if necessary. switch( format ) {
*/ case VIPS_FORMAT_UCHAR:
for( x = 0; x < n; x++ ) { case VIPS_FORMAT_CHAR:
q[0] = p[0] ^ mask; GREY_LOOP( guchar, UCHAR_MAX );
break;
/* Process alpha, if any. Don't swap this. case VIPS_FORMAT_SHORT:
*/ GREY_LOOP( gshort, SHRT_MAX );
if( rtiff->samples_per_pixel == 2 ) break;
q[1] = p[1];
q += rtiff->samples_per_pixel; case VIPS_FORMAT_USHORT:
p += rtiff->samples_per_pixel; GREY_LOOP( gushort, USHRT_MAX );
break;
case VIPS_FORMAT_INT:
GREY_LOOP( gint, INT_MAX );
break;
case VIPS_FORMAT_UINT:
GREY_LOOP( guint, UINT_MAX );
break;
case VIPS_FORMAT_FLOAT:
GREY_LOOP( float, 1.0 );
break;
case VIPS_FORMAT_DOUBLE:
GREY_LOOP( double, 1.0 );
break;
default:
g_assert( 0 );
} }
} }
/* Read a 8-bit grey-scale TIFF image. /* Read a grey-scale TIFF image. We have to invert the first band if
* PHOTOMETRIC_MINISBLACK is set.
*/ */
static int static int
parse_greyscale8( ReadTiff *rtiff, VipsImage *out ) parse_greyscale( ReadTiff *rtiff, VipsImage *out )
{ {
if( check_samples_alpha( rtiff, 1 ) || if( check_min_samples( rtiff, 1 ) )
check_bits( rtiff, 8 ) )
return( -1 ); return( -1 );
out->Bands = rtiff->samples_per_pixel; out->Bands = rtiff->samples_per_pixel;
out->BandFmt = VIPS_FORMAT_UCHAR; out->BandFmt = guess_format( rtiff );
out->Coding = VIPS_CODING_NONE; out->Coding = VIPS_CODING_NONE;
out->Type = VIPS_INTERPRETATION_B_W;
rtiff->sfn = greyscale8_line; if( rtiff->bits_per_sample == 16 )
return( 0 );
}
/* Per-scanline process function for 16-bit greyscale images.
*/
static void
greyscale16_line( ReadTiff *rtiff, VipsPel *q, VipsPel *p, int n, void *client )
{
int mask =
rtiff->photometric_interpretation == PHOTOMETRIC_MINISBLACK ?
0 : -1;
unsigned short *p1;
unsigned short *q1;
int x;
/* Read bytes, swapping sense if necessary.
*/
p1 = (unsigned short *) p;
q1 = (unsigned short *) q;
for( x = 0; x < n; x++ ) {
q1[0] = p1[0] ^ mask;
/* Process alpha, if any. Don't swap this.
*/
if( rtiff->samples_per_pixel == 2 )
q1[1] = p1[1];
q1 += rtiff->samples_per_pixel;
p1 += rtiff->samples_per_pixel;
}
}
/* Read a 16-bit grey-scale TIFF image.
*/
static int
parse_greyscale16( ReadTiff *rtiff, VipsImage *out )
{
if( check_samples_alpha( rtiff, 1 ) ||
check_bits( rtiff, 16 ) )
return( -1 );
out->Bands = rtiff->samples_per_pixel;
out->BandFmt = VIPS_FORMAT_USHORT;
out->Coding = VIPS_CODING_NONE;
out->Type = VIPS_INTERPRETATION_GREY16; out->Type = VIPS_INTERPRETATION_GREY16;
else
rtiff->sfn = greyscale16_line;
return( 0 );
}
/* Per-scanline process function when we just need to copy.
*/
static void
memcpy_line( ReadTiff *rtiff, VipsPel *q, VipsPel *p, int n, void *client )
{
VipsImage *im = (VipsImage *) client;
size_t len = n * VIPS_IMAGE_SIZEOF_PEL( im );
memcpy( q, p, len );
}
/* Read a 32-bit floating point greyscale TIFF image. What do we do about
* MINISWHITE/MINISBLACK (pm)? Not sure ... just ignore it.
*/
static int
parse_greyscale32f( ReadTiff *rtiff, VipsImage *out )
{
if( check_samples_alpha( rtiff, 1 ) ||
check_bits( rtiff, 32 ) )
return( -1 );
out->Bands = rtiff->samples_per_pixel;
out->BandFmt = VIPS_FORMAT_FLOAT;
out->Coding = VIPS_CODING_NONE;
out->Type = VIPS_INTERPRETATION_B_W; out->Type = VIPS_INTERPRETATION_B_W;
rtiff->sfn = memcpy_line; /* greyscale_line() doesn't do complex.
rtiff->client = out; */
rtiff->memcpy = TRUE; if( vips_check_noncomplex( "tiff2vips", out ) )
return( -1 );
rtiff->sfn = greyscale_line;
return( 0 ); return( 0 );
} }
@ -787,95 +793,42 @@ parse_palette( ReadTiff *rtiff, VipsImage *out )
return( 0 ); return( 0 );
} }
/* Read an 8-bit RGB/RGBA image. /* Per-scanline process function when we just need to copy.
*/ */
static int static void
parse_rgb8( ReadTiff *rtiff, VipsImage *out ) memcpy_line( ReadTiff *rtiff, VipsPel *q, VipsPel *p, int n, void *client )
{ {
if( check_samples_alpha( rtiff, 3 ) || VipsImage *im = (VipsImage *) client;
check_bits( rtiff, 8 ) ) size_t len = n * VIPS_IMAGE_SIZEOF_PEL( im );
return( -1 );
out->Bands = rtiff->samples_per_pixel; memcpy( q, p, len );
out->BandFmt = VIPS_FORMAT_UCHAR;
out->Coding = VIPS_CODING_NONE;
out->Type = VIPS_INTERPRETATION_sRGB;
rtiff->sfn = memcpy_line;
rtiff->client = out;
rtiff->memcpy = TRUE;
return( 0 );
} }
/* Read a 16-bit RGB/RGBA image. /* Read a regular multiband image where we can just copy pixels from the tiff
* buffer.
*/ */
static int static int
parse_rgb16( ReadTiff *rtiff, VipsImage *out ) parse_copy( ReadTiff *rtiff, VipsImage *out )
{ {
if( check_samples_alpha( rtiff, 3 ) ||
check_bits( rtiff, 16 ) )
return( -1 );
out->Bands = rtiff->samples_per_pixel; out->Bands = rtiff->samples_per_pixel;
out->BandFmt = VIPS_FORMAT_USHORT; out->BandFmt = guess_format( rtiff );
out->Coding = VIPS_CODING_NONE; out->Coding = VIPS_CODING_NONE;
if( rtiff->samples_per_pixel >= 3 &&
(rtiff->photometric_interpretation == PHOTOMETRIC_RGB ||
rtiff->photometric_interpretation == PHOTOMETRIC_YCBCR) ) {
if( rtiff->bits_per_sample == 16 )
out->Type = VIPS_INTERPRETATION_RGB16; out->Type = VIPS_INTERPRETATION_RGB16;
else
rtiff->sfn = memcpy_line;
rtiff->client = out;
rtiff->memcpy = TRUE;
return( 0 );
}
/* Read a 32-bit float image. RGB or LAB, with or without alpha.
*/
static int
parse_32f( ReadTiff *rtiff, VipsImage *out )
{
if( check_samples_alpha( rtiff, 3 ) ||
check_bits( rtiff, 32 ) ||
check_float( rtiff ) )
return( -1 );
out->Bands = rtiff->samples_per_pixel;
out->BandFmt = VIPS_FORMAT_FLOAT;
out->Coding = VIPS_CODING_NONE;
switch( rtiff->photometric_interpretation ) {
case PHOTOMETRIC_CIELAB:
out->Type = VIPS_INTERPRETATION_LAB;
break;
case PHOTOMETRIC_RGB:
out->Type = VIPS_INTERPRETATION_sRGB; out->Type = VIPS_INTERPRETATION_sRGB;
break;
default:
g_assert( 0 );
} }
rtiff->sfn = memcpy_line; if( rtiff->samples_per_pixel >= 3 &&
rtiff->client = out; rtiff->photometric_interpretation == PHOTOMETRIC_CIELAB )
rtiff->memcpy = TRUE; out->Type = VIPS_INTERPRETATION_LAB;
return( 0 ); if( rtiff->samples_per_pixel >= 4 &&
} rtiff->photometric_interpretation == PHOTOMETRIC_SEPARATED )
/* Read a CMYK image.
*/
static int
parse_cmyk( ReadTiff *rtiff, VipsImage *out )
{
if( check_samples_alpha( rtiff, 4 ) ||
check_bits( rtiff, 8 ) ||
!tfequals( rtiff->tiff, TIFFTAG_INKSET, INKSET_CMYK ) )
return( -1 );
out->Bands = rtiff->samples_per_pixel;
out->BandFmt = VIPS_FORMAT_UCHAR;
out->Coding = VIPS_CODING_NONE;
out->Type = VIPS_INTERPRETATION_CMYK; out->Type = VIPS_INTERPRETATION_CMYK;
rtiff->sfn = memcpy_line; rtiff->sfn = memcpy_line;
@ -938,13 +891,49 @@ parse_resolution( TIFF *tiff, VipsImage *out )
return( 0 ); return( 0 );
} }
typedef int (*reader_fn)( ReadTiff *rtiff, VipsImage *out );
/* We have a range of output paths. Look at the tiff header and try to
* route the input image to the best output path.
*/
static reader_fn
pick_reader( ReadTiff *rtiff )
{
if( rtiff->photometric_interpretation == PHOTOMETRIC_CIELAB ) {
if( rtiff->bits_per_sample == 8 )
return( parse_labpack );
if( rtiff->bits_per_sample == 16 )
return( parse_labs );
}
if( rtiff->photometric_interpretation == PHOTOMETRIC_MINISWHITE ||
rtiff->photometric_interpretation == PHOTOMETRIC_MINISBLACK ) {
if( rtiff->bits_per_sample == 1 )
return( parse_onebit );
else
return( parse_greyscale );
}
if( rtiff->photometric_interpretation == PHOTOMETRIC_PALETTE )
return( parse_palette );
if( rtiff->photometric_interpretation == PHOTOMETRIC_YCBCR ) {
/* Sometimes JPEG in TIFF images are tagged as YCBCR. Ask
* libtiff to convert to RGB for us.
*/
TIFFSetField( rtiff->tiff,
TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB );
}
return( parse_copy );
}
/* Look at PhotometricInterpretation and BitsPerPixel and try to figure out /* Look at PhotometricInterpretation and BitsPerPixel and try to figure out
* which of the image classes this is. * which of the image classes this is.
*/ */
static int static int
parse_header( ReadTiff *rtiff, VipsImage *out ) parse_header( ReadTiff *rtiff, VipsImage *out )
{ {
int format;
uint32 data_length; uint32 data_length;
uint32 width, height; uint32 width, height;
void *data; void *data;
@ -970,6 +959,15 @@ parse_header( ReadTiff *rtiff, VipsImage *out )
&rtiff->photometric_interpretation ) ) &rtiff->photometric_interpretation ) )
return( -1 ); return( -1 );
/* Some optional fields.
*/
{
uint16 v;
TIFFGetFieldDefaulted( rtiff->tiff, TIFFTAG_SAMPLEFORMAT, &v );
rtiff->sample_format = v;
}
/* Arbitrary sanity-checking limits. /* Arbitrary sanity-checking limits.
*/ */
@ -999,141 +997,16 @@ parse_header( ReadTiff *rtiff, VipsImage *out )
rtiff->samples_per_pixel ); rtiff->samples_per_pixel );
printf( "parse_header: bits_per_sample = %d\n", printf( "parse_header: bits_per_sample = %d\n",
rtiff->bits_per_sample ); rtiff->bits_per_sample );
printf( "parse_header: sample_format = %d\n",
rtiff->sample_format );
#endif /*DEBUG*/ #endif /*DEBUG*/
switch( rtiff->photometric_interpretation ) { /* We have a range of output paths. Look at the tiff header and try to
case PHOTOMETRIC_CIELAB: * route the input image to the best output path.
switch( rtiff->bits_per_sample ) {
case 8:
if( parse_labpack( rtiff, out ) )
return( -1 );
break;
case 16:
if( parse_labs( rtiff, out ) )
return( -1 );
break;
case 32:
if( parse_32f( rtiff, out ) )
return( -1 );
break;
default:
vips_error( "tiff2vips",
_( "unsupported depth %d for LAB image" ),
rtiff->bits_per_sample );
return( -1 );
}
break;
case PHOTOMETRIC_MINISWHITE:
case PHOTOMETRIC_MINISBLACK:
switch( rtiff->bits_per_sample ) {
case 1:
if( parse_onebit( rtiff, out ) )
return( -1 );
break;
case 8:
if( parse_greyscale8( rtiff, out ) )
return( -1 );
break;
case 16:
if( parse_greyscale16( rtiff, out ) )
return( -1 );
break;
case 32:
if( !tfget16( rtiff->tiff,
TIFFTAG_SAMPLEFORMAT, &format ) )
return( -1 );
if( format == SAMPLEFORMAT_IEEEFP ) {
if( parse_greyscale32f( rtiff, out ) )
return( -1 );
}
else {
vips_error( "tiff2vips",
_( "unsupported sample format "
"%d for greyscale image" ),
format );
return( -1 );
}
break;
default:
vips_error( "tiff2vips",
_( "unsupported depth %d for greyscale image" ),
rtiff->bits_per_sample );
return( -1 );
}
break;
case PHOTOMETRIC_PALETTE:
/* Full colour pallette.
*/ */
if( parse_palette( rtiff, out ) ) if( pick_reader( rtiff )( rtiff, out ) )
return( -1 ); return( -1 );
break;
case PHOTOMETRIC_YCBCR:
/* Sometimes JPEG in TIFF images are tagged as YCBCR. Ask
* libtiff to convert to RGB for us.
*/
TIFFSetField( rtiff->tiff,
TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB );
if( parse_rgb8( rtiff, out ) )
return( -1 );
break;
case PHOTOMETRIC_RGB:
switch( rtiff->bits_per_sample ) {
case 8:
if( parse_rgb8( rtiff, out ) )
return( -1 );
break;
case 16:
if( parse_rgb16( rtiff, out ) )
return( -1 );
break;
case 32:
if( parse_32f( rtiff, out ) )
return( -1 );
break;
default:
vips_error( "tiff2vips",
_( "unsupported depth %d for RGB image" ),
rtiff->bits_per_sample );
return( -1 );
}
break;
case PHOTOMETRIC_SEPARATED:
if( parse_cmyk( rtiff, out ) )
return( -1 );
break;
default:
vips_error( "tiff2vips",
_( "unknown photometric interpretation %d" ),
rtiff->photometric_interpretation );
return( -1 );
}
/* Read any ICC profile. /* Read any ICC profile.
*/ */
if( TIFFGetField( rtiff->tiff, if( TIFFGetField( rtiff->tiff,