/* TIFF parts: Copyright (c) 1988, 1990 by Sam Leffler.
 * All rights reserved.
 *
 * This file is provided for unrestricted use provided that this
 * legend is included on all tape media and as a part of the
 * software program in whole or part.  Users may copy, modify or
 * distribute this file at will.
 * -----------------------------
 * Modifications for VIPS:  Kirk Martinez 1994
 * 22/11/94 JC
 *	- more general
 *	- memory leaks fixed
 * 20/3/95 JC
 *	- TIFF error handler added
 *	- read errors detected correctly
 *
 * Modified to handle LAB in tiff format.
 * It convert LAB-tiff format to IM_TYPE_LABQ in vips format.
 *  Copyright July-1995 Ahmed Abbood.
 *
 *
 * 19/9/95 JC
 *	- now calls TIFFClose ... stupid
 * 25/1/96 JC
 *	- typo on MINISBLACK ...
 * 7/4/97 JC
 *	- completely redone for TIFF 6
 *	- now full baseline TIFF 6 reader, and does CIELAB as well
 * 11/4/97 JC
 *	- added partial read for tiled images
 * 23/4/97 JC
 *	- extra subsample parameter
 *	- im_istiffpyramid() added
 * 5/12/97 JC
 *	- if loading YCbCr, convert to IM_CODING_LABQ
 * 1/5/98 JC
 *	- now reads 16-bit greyscale and RGB
 * 26/10/98 JC
 *	- now used "rb" mode on systems that need binary open
 * 12/11/98 JC
 *	- no sub-sampling if sub == 1
 * 26/2/99 JC
 *	- ooops, else missing for subsample stuff above
 * 2/10/99 JC
 *	- tiled 16-bit greyscale read was broken
 *	- added mutex for TIFFReadTile() calls
 * 11/5/00 JC
 *	- removed TIFFmalloc/TIFFfree usage
 * 23/4/01 JC
 *	- HAVE_TIFF turns on TIFF goodness
 * 24/5/01 JC
 *	- im_tiff2vips_header() added
 * 11/7/01 JC
 *	- subsample now in input filename
 *	- ... and it's a page number (from 0) instead
 * 21/8/02 JC
 *	- now reads CMYK
 *	- hmm, dpi -> ppm conversion was wrong!
 * 10/9/02 JC
 *	- oops, handle TIFF errors better
 * 2/12/02 JC
 *	- reads 8-bit RGBA
 * 12/12/02 JC
 *	- reads 16-bit LAB
 * 13/2/03 JC
 *	- pixels/cm res read was wrong
 * 17/11/03 Andrey Kiselev
 *	- read 32-bit float greyscale and rgb
 * 5/4/04
 *	- better handling of edge tiles (thanks Ruven)
 * 16/4/04
 *	- cleanup
 *	- added broken tile read mode
 * 18/5/04 Andrey Kiselev
 *	- better no resolution diagnostic
 * 26/5/04
 *	- reads 16 bit RGBA
 * 28/7/04
 *	- arrg, 16bit RGB was broken, thanks haida
 * 26/11/04
 *	- add a TIFF warning handler, stops occasional libMagick exceptions
 * 9/3/05
 *	- load 32-bit float LAB
 * 8/4/05
 *	- onebit read no longer reads one byte too many on multiple of 8 wide
 *	  images
 * 22/6/05
 *	- 16 bit LAB read was broken
 * 9/9/05
 * 	- read any ICCPROFILE tag
 * 8/5/06
 * 	- set RGB16 and GREY16 Type
 * 21/5/06
 * 	- use external im_tile_cache() operation for great code shrinkage
 * 	- less RAM usage too, esp. with >1 CPU
 * 	- should be slightly faster
 * 	- removed 'broken' read option
 * 18/7/07 Andrey Kiselev
 * 	- remove "b" option on TIFFOpen()
 * 9/4/08
 * 	- set IM_META_RESOLUTION_UNIT
 * 17/4/08
 * 	- allow CMYKA (thanks Doron)
 * 17/7/08
 * 	- convert YCbCr to RGB on read (thanks Ole)
 * 15/8/08
 * 	- reorganise for image format system
 * 20/12/08
 * 	- dont read with mmap: no performance advantage with libtiff, chews up 
 * 	  VM wastefully
 * 13/1/09
 * 	- read strip-wise, not scanline-wise ... works with more compression /
 * 	  subsampling schemes (esp. subsampled YCbCr), and it's a bit quicker
 * 4/2/10
 * 	- gtkdoc
 */

/*

    This file is part of VIPS.
    
    VIPS is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

 */

/*

    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk

 */

/* Turn on debugging output.
#define DEBUG
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>

#ifndef HAVE_TIFF

#include <vips/vips.h>

int
im_tiff2vips( const char *tiffile, IMAGE *im )
{
	im_error( "im_tiff2vips", "%s",
		_( "TIFF support disabled" ) );
	return( -1 );
}

#else /*HAVE_TIFF*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include <vips/vips.h>
#include <vips/internal.h>
#include <vips/thread.h>

#include <tiffio.h>

#ifdef WITH_DMALLOC
#include <dmalloc.h>
#endif /*WITH_DMALLOC*/

/* Scanline-type process function.
 */
typedef void (*scanline_process_fn)( PEL *q, PEL *p, int n, void *user );

/* Stuff we track during a read.
 */
typedef struct {
	/* Parameters.
	 */
	char *filename;
	IMAGE *out;

	/* From filename.
	 */
	int page;

	/* The TIFF we read.
	 */
	TIFF *tiff;

	/* Process for this image type.
	 */
	scanline_process_fn sfn;
	void *client;

	/* Geometry.
	 */
	int twidth, theight;		/* Tile size */

	/* Only need one of these, since we mutex around TIFF*().
	 */
	GMutex *tlock;			/* Lock for TIFF*() calls */
} ReadTiff;

/* Reading a YCbCr image ... parameters we use for conversion.
 */
typedef struct {
	/* Input and output.
	 */
	TIFF *tif;			/* From here */
	IMAGE *im;			/* To here */

	/* RGB <-> YCbCr conversion.
	 */
	float LumaRed, LumaGreen, LumaBlue;

	/* RGB -> LAB conversion.
	 */
	void *table;
} YCbCrParams;

/* Handle TIFF errors here. Shared with im_vips2tiff. These can be called from
 * more than one thread, but im_error and im_warn have mutexes in, so that's
 * OK.
 */
void 
im__thandler_error( char *module, char *fmt, va_list ap )
{
	im_verror( module, fmt, ap );
}

void 
im__thandler_warning( char *module, char *fmt, va_list ap )
{
	char buf[256];

	im_vsnprintf( buf, 256, fmt, ap );
	im_warn( module, "%s", buf );
}

/* Test for field exists.
 */
static int
tfexists( TIFF *tif, ttag_t tag )
{
	uint32 a, b;

	if( TIFFGetField( tif, tag, &a, &b ) ) 
		return( 1 );
	else 
		return( 0 );
}

/* Test a uint16 field. Field must be defined and equal to the value.
 */
static int
tfequals( TIFF *tif, ttag_t tag, uint16 val )
{
	uint16 fld;

	if( !TIFFGetFieldDefaulted( tif, tag, &fld ) ) {
		im_error( "im_tiff2vips", 
			_( "required field %d missing" ), tag );
		return( 0 );
	}
	if( fld != val ) {
		im_error( "im_tiff2vips", _( "required field %d=%d, not %d" ),
			tag, fld, val );
		return( 0 );
	}

	/* All ok.
	 */
	return( 1 );
}

/* Get a uint32 field.
 */
static int
tfget32( TIFF *tif, ttag_t tag, int *out )
{
	uint32 fld;

	if( !TIFFGetFieldDefaulted( tif, tag, &fld ) ) {
		im_error( "im_tiff2vips", 
			_( "required field %d missing" ), tag );
		return( 0 );
	}

	/* All ok.
	 */
	*out = fld;
	return( 1 );
}

/* Get a uint16 field.
 */
static int
tfget16( TIFF *tif, ttag_t tag, int *out )
{
	uint16 fld;

	if( !TIFFGetFieldDefaulted( tif, tag, &fld ) ) {
		im_error( "im_tiff2vips", 
			_( "required field %d missing" ), tag );
		return( 0 );
	}

	/* All ok.
	 */
	*out = fld;
	return( 1 );
}

/* Per-scanline process function for IM_CODING_LABQ.
 */
static void
labpack_line( PEL *q, PEL *p, int n, void *dummy )
{
	int x;

	for( x = 0; x < n; x++ ) {
		q[0] = p[0];
		q[1] = p[1];
		q[2] = p[2];
		q[3] = 0;

		q += 4;
		p += 3;
	}
}

/* Read an 8-bit LAB image.
 */
static int
parse_labpack( ReadTiff *rtiff, IMAGE *out )
{
	if( !tfequals( rtiff->tiff, TIFFTAG_SAMPLESPERPIXEL, 3 ) ||
		!tfequals( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, 8 ) )
		return( -1 );

	out->Bands = 4; 
	out->BandFmt = IM_BANDFMT_UCHAR; 
	out->Coding = IM_CODING_LABQ; 
	out->Type = IM_TYPE_LAB; 

	rtiff->sfn = labpack_line;
	rtiff->client = NULL;

	return( 0 );
}

/* Per-scanline process function for IM_CODING_LABQ.
 */
static void
labs_line( PEL *q, PEL *p, int n, void *dummy )
{
	int x;
	unsigned short *p1 = (unsigned short *) p;
	short *q1 = (short *) q;

	for( x = 0; x < n; x++ ) {
		q1[0] = p1[0] >> 1;
		q1[1] = p1[1];
		q1[2] = p1[2];

		q1 += 3;
		p1 += 3;
	}
}

/* Read a 16-bit LAB image.
 */
static int
parse_labs( ReadTiff *rtiff, IMAGE *out )
{
	if( !tfequals( rtiff->tiff, TIFFTAG_SAMPLESPERPIXEL, 3 ) ||
		!tfequals( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, 16 ) )
		return( -1 );

	out->Bands = 3; 
	out->BandFmt = IM_BANDFMT_SHORT; 
	out->Coding = IM_CODING_NONE; 
	out->Type = IM_TYPE_LABS; 

	rtiff->sfn = labs_line;
	rtiff->client = NULL;

	return( 0 );
}

/* Per-scanline process function for 1 bit images.
 */
static void
onebit_line( PEL *q, PEL *p, int n, void *flg )
{
	/* Extract PHOTOMETRIC_INTERPRETATION.
	 */
	int pm = *((int *) flg);
	int x, i, z;
	PEL bits;

	int black = (pm == PHOTOMETRIC_MINISBLACK) ? 0 : 255;
	int white = black ^ -1;

	/* (sigh) how many times have I written this?
	 */
	for( x = 0, i = 0; i < (n >> 3); i++ ) {
		bits = (PEL) p[i];

		for( z = 0; z < 8; z++, x++ ) {
			q[x] = (bits & 128) ? white : black;
			bits <<= 1;
		}
	}

	/* Do last byte in line.
	 */
	if( n & 7 ) {
		bits = p[i];
		for( z = 0; z < (n & 7); z++ ) {
			q[x + z] = (bits & 128) ? white : black;
			bits <<= 1;
		}
	}
}

/* Read a 1-bit TIFF image. Pass in pixel values to use for black and white.
 */
static int
parse_onebit( ReadTiff *rtiff, int pm, IMAGE *out )
{
	int *ppm;

	if( !tfequals( rtiff->tiff, TIFFTAG_SAMPLESPERPIXEL, 1 ) ||
		!tfequals( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, 1 ) )
		return( -1 );

	out->Bands = 1; 
	out->BandFmt = IM_BANDFMT_UCHAR; 
	out->Coding = IM_CODING_NONE; 
	out->Type = IM_TYPE_B_W; 

	/* Note pm for later.
	 */
	if( !(ppm = IM_ARRAY( out, 1, int )) )
		return( -1 );
	*ppm = pm;

	rtiff->sfn = onebit_line;
	rtiff->client = ppm;

	return( 0 );
}

/* Per-scanline process function for 8-bit greyscale images.
 */
static void
greyscale8_line( PEL *q, PEL *p, int n, void *flg )
{
	/* Extract swap mask.
	 */
	PEL mask = *((PEL *) flg);
	int x;

	/* Read bytes, swapping sense if necessary.
	 */
	for( x = 0; x < n; x++ ) 
		q[x] = p[x] ^ mask;
}

/* Read a 8-bit grey-scale TIFF image. 
 */
static int
parse_greyscale8( ReadTiff *rtiff, int pm, IMAGE *out )
{
	PEL *mask;

	if( !tfequals( rtiff->tiff, TIFFTAG_SAMPLESPERPIXEL, 1 ) ||
		!tfequals( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, 8 ) )
		return( -1 );

	/* Eor each pel with this later.
	 */
	if( !(mask = IM_ARRAY( out, 1, PEL )) )
		return( -1 );
	*mask = (pm == PHOTOMETRIC_MINISBLACK) ? 0 : 255;

	out->Bands = 1; 
	out->BandFmt = IM_BANDFMT_UCHAR; 
	out->Coding = IM_CODING_NONE; 
	out->Type = IM_TYPE_B_W; 

	rtiff->sfn = greyscale8_line;
	rtiff->client = mask;

	return( 0 );
}

/* Per-scanline process function for 16-bit greyscale images.
 */
static void
greyscale16_line( PEL *q, PEL *p, int n, void *flg )
{
	/* Extract swap mask.
	 */
	unsigned short mask = *((unsigned short *) flg);
	unsigned short *p1 = (unsigned short *) p;
	unsigned short *q1 = (unsigned short *) q;
	int x;

	/* Read bytes, swapping sense if necessary.
	 */
	for( x = 0; x < n; x++ ) 
		q1[x] = p1[x] ^ mask;
}

/* Read a 16-bit grey-scale TIFF image. 
 */
static int
parse_greyscale16( ReadTiff *rtiff, int pm, IMAGE *out )
{
	unsigned short *mask;

	if( !tfequals( rtiff->tiff, TIFFTAG_SAMPLESPERPIXEL, 1 ) ||
		!tfequals( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, 16 ) )
		return( -1 );

	/* Eor each pel with this later.
	 */
	if( !(mask = IM_ARRAY( out, 1, unsigned short )) )
		return( -1 );
	mask[0] = (pm == PHOTOMETRIC_MINISBLACK) ? 0 : 65535;

	out->Bands = 1; 
	out->BandFmt = IM_BANDFMT_USHORT; 
	out->Coding = IM_CODING_NONE; 
	out->Type = IM_TYPE_GREY16; 

	rtiff->sfn = greyscale16_line;
	rtiff->client = mask;

	return( 0 );
}

/* Per-scanline process function for 32-bit floating point greyscale images.
 */
static void
greyscale32f_line( PEL *q, PEL *p, int n )
{
	float *p1 = (float *) p;
	float *q1 = (float *) q;
	int x;

	for( x = 0; x < n; x++ )
		q1[x] = p1[x];
}

/* 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, int pm, IMAGE *out )
{
	if( !tfequals( rtiff->tiff, TIFFTAG_SAMPLESPERPIXEL, 1 ) ||
		!tfequals( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, 32 ) )
		return( -1 );

	out->Bands = 1; 
	out->BandFmt = IM_BANDFMT_FLOAT;
	out->Coding = IM_CODING_NONE; 
	out->Type = IM_TYPE_B_W; 

	rtiff->sfn = (scanline_process_fn) greyscale32f_line;
	rtiff->client = NULL;

	return( 0 );
}

/* Per-scanline process function for palette images.
 */
static void
palette_line( PEL *q, PEL *p, int n, void *flg )
{
	/* Extract maps.
	 */
	PEL *red = ((PEL **) flg)[0];
	PEL *green = ((PEL **) flg)[1];
	PEL *blue = ((PEL **) flg)[2];
	int x;

	/* Read bytes, generating colour.
	 */
	for( x = 0; x < n; x++ ) {
		int i = *p++;

		q[0] = red[i];
		q[1] = green[i];
		q[2] = blue[i];

		q += 3;
	}
}

/* Read a palette-ised TIFF image. Again, we only allow 8-bits for now.
 */
static int
parse_palette( ReadTiff *rtiff, IMAGE *out )
{
	uint16 *tred, *tgreen, *tblue;
	PEL *red, *green, *blue;
	PEL **maps;
	int i;

	if( !tfequals( rtiff->tiff, TIFFTAG_SAMPLESPERPIXEL, 1 ) ||
		!tfequals( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, 8 ) )
		return( -1 );
	
	/* Allocate mem for VIPS colour maps.
	 */
	if( !(red = IM_ARRAY( out, 256, PEL )) ||
		!(green = IM_ARRAY( out, 256, PEL )) ||
		!(blue = IM_ARRAY( out, 256, PEL )) ||
		!(maps = IM_ARRAY( out, 3, PEL * )) )
		return( -1 );

	/* Get maps, convert to 8-bit data.
	 */
	if( !TIFFGetField( rtiff->tiff, 
		TIFFTAG_COLORMAP, &tred, &tgreen, &tblue ) ) {
		im_error( "im_tiff2vips", "%s", _( "bad colormap" ) );
		return( -1 );
	}
	for( i = 0; i < 256; i++ ) {
		red[i] = tred[i] >> 8;
		green[i] = tgreen[i] >> 8;
		blue[i] = tblue[i] >> 8;
	}
	maps[0] = red; 
	maps[1] = green; 
	maps[2] = blue;

	out->Bands = 3; 
	out->BandFmt = IM_BANDFMT_UCHAR; 
	out->Coding = IM_CODING_NONE; 
	out->Type = IM_TYPE_sRGB; 

	rtiff->sfn = palette_line;
	rtiff->client = maps;

	return( 0 );
}

/* Per-scanline process function for 8-bit RGB/RGBA/CMYK/CMYKA/etc.
 */
static void
rgbcmyk8_line( PEL *q, PEL *p, int n, IMAGE *im )
{
	int x, b;

	for( x = 0; x < n; x++ ) {
		for( b = 0; b < im->Bands; b++ )
			q[b] = p[b];

		q += im->Bands;
		p += im->Bands;
	}
}

/* Read an 8-bit RGB/RGBA image.
 */
static int
parse_rgb8( ReadTiff *rtiff, IMAGE *out )
{
	int bands;

	/* Check other TIFF fields to make sure we can read this. Can have 4
	 * bands for RGBA.
	 */
	if( !tfequals( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, 8 ) ||
		!tfget16( rtiff->tiff, TIFFTAG_SAMPLESPERPIXEL, &bands ) )
		return( -1 );
	if( bands != 3 && bands != 4 ) {
		im_error( "im_tiff2vips", 
			"%s", _( "3 or 4 bands RGB TIFF only" ) );
		return( -1 );
	}

	out->Bands = bands; 
	out->BandFmt = IM_BANDFMT_UCHAR; 
	out->Coding = IM_CODING_NONE; 
	out->Type = IM_TYPE_sRGB; 

	rtiff->sfn = (scanline_process_fn) rgbcmyk8_line;
	rtiff->client = out;

	return( 0 );
}

/* Per-scanline process function for RGB/RGBA 16.
 */
static void
rgb16_line( PEL *q, PEL *p, int n, IMAGE *im )
{
	int x, b;
	unsigned short *p1 = (unsigned short *) p;
	unsigned short *q1 = (unsigned short *) q;

	for( x = 0; x < n; x++ ) {
		for( b = 0; b < im->Bands; b++ )
			q1[b] = p1[b];

		q1 += im->Bands;
		p1 += im->Bands;
	}
}

/* Read a 16-bit RGB/RGBA image.
 */
static int
parse_rgb16( ReadTiff *rtiff, IMAGE *out )
{
	int bands;

	/* Check other TIFF fields to make sure we can read this. Can have 4
	 * bands for RGBA.
	 */
	if( !tfequals( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, 16 ) ||
		!tfget16( rtiff->tiff, TIFFTAG_SAMPLESPERPIXEL, &bands ) )
		return( -1 );
	if( bands != 3 && bands != 4 ) {
		im_error( "im_tiff2vips", 
			"%s", _( "3 or 4 bands RGB TIFF only" ) );
		return( -1 );
	}

	out->Bands = bands; 
	out->BandFmt = IM_BANDFMT_USHORT; 
	out->Coding = IM_CODING_NONE; 
	out->Type = IM_TYPE_RGB16; 

	rtiff->sfn = (scanline_process_fn) rgb16_line;
	rtiff->client = out;

	return( 0 );
}

/* Per-scanline process function for 32f.
 */
static void
r32f_line( PEL *q, PEL *p, int n, void *dummy )
{
	int x;
	float *p1 = (float *) p;
	float *q1 = (float *) q;

	for( x = 0; x < n; x++ ) {
		q1[0] = p1[0];
		q1[1] = p1[1];
		q1[2] = p1[2];

		q1 += 3;
		p1 += 3;
	}
}

/* Read a 32-bit float image. RGB or LAB, with or without alpha.
 */
static int
parse_32f( ReadTiff *rtiff, int pm, IMAGE *out )
{
	int bands;

	if( !tfget16( rtiff->tiff, TIFFTAG_SAMPLESPERPIXEL, &bands ) ||
		!tfequals( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, 32 ) )
		return( -1 );

	/* Can be 4 for images with an alpha channel.
	 */
	assert( bands == 3 || bands == 4 );

	out->Bands = bands; 
	out->BandFmt = IM_BANDFMT_FLOAT; 
	out->Coding = IM_CODING_NONE; 

	switch( pm ) {
	case PHOTOMETRIC_CIELAB:
		out->Type = IM_TYPE_LAB; 
		break;

	case PHOTOMETRIC_RGB:
		out->Type = IM_TYPE_sRGB; 
		break;

	default:
		assert( 0 );
	}

	rtiff->sfn = r32f_line;
	rtiff->client = NULL;

	return( 0 );
}

/* Read a CMYK image.
 */
static int
parse_cmyk( ReadTiff *rtiff, IMAGE *out )
{
	int bands;

	/* Check other TIFF fields to make sure we can read this. Can have 5
	 * bands for CMYKA.
	 */
	if( !tfequals( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, 8 ) ||
		!tfequals( rtiff->tiff, TIFFTAG_INKSET, INKSET_CMYK ) ||
		!tfget16( rtiff->tiff, TIFFTAG_SAMPLESPERPIXEL, &bands ) )
		return( -1 );
	if( bands != 4 && bands != 5 ) {
		im_error( "im_tiff2vips", 
			"%s", _( "4 or 5 bands CMYK TIFF only" ) );
		return( -1 );
	}

	out->Bands = bands; 
	out->BandFmt = IM_BANDFMT_UCHAR; 
	out->Coding = IM_CODING_NONE; 
	out->Type = IM_TYPE_CMYK; 

	rtiff->sfn = (scanline_process_fn) rgbcmyk8_line;
	rtiff->client = out;

	return( 0 );
}

/* Read resolution from a TIFF image.
 */
static int
parse_resolution( TIFF *tiff, IMAGE *out )
{
	float x, y;
	int ru;

	if( TIFFGetFieldDefaulted( tiff, TIFFTAG_XRESOLUTION, &x ) &&
		TIFFGetFieldDefaulted( tiff, TIFFTAG_YRESOLUTION, &y ) &&
		tfget16( tiff, TIFFTAG_RESOLUTIONUNIT, &ru ) ) {
		switch( ru ) {
		case RESUNIT_NONE:
			break;

		case RESUNIT_INCH:
			/* In pixels-per-inch ... convert to mm.
			 */
			x /= 10.0 * 2.54;
			y /= 10.0 * 2.54;
			im_meta_set_string( out, 
				IM_META_RESOLUTION_UNIT, "in" );
			break;

		case RESUNIT_CENTIMETER:
			/* In pixels-per-centimetre ... convert to mm.
			 */
			x /= 10.0;
			y /= 10.0;
			im_meta_set_string( out, 
				IM_META_RESOLUTION_UNIT, "cm" );
			break;

		default:
			im_error( "im_tiff2vips", 
				"%s", _( "unknown resolution unit" ) );
			return( -1 );
		}
	}
	else {
		im_warn( "im_tiff2vips", _( "no resolution information for "
			"TIFF image \"%s\" -- defaulting to 1 pixel per mm" ), 
			TIFFFileName( tiff ) );
		x = 1.0;
		y = 1.0;
	}

	out->Xres = x;
	out->Yres = y;

	return( 0 );
}

/* Look at PhotometricInterpretation and BitsPerPixel, and try to figure out 
 * which of the image classes this is.
 */
static int
parse_header( ReadTiff *rtiff, IMAGE *out )
{
	int pm, bps, format;
	uint32 data_length;
	void *data;

	/* Ban separate planes, too annoying.
	 */
	if( tfexists( rtiff->tiff, TIFFTAG_PLANARCONFIG ) && 
		!tfequals( rtiff->tiff, 
			TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG ) ) 
		return( -1 );

	/* Always need dimensions.
	 */
	if( !tfget32( rtiff->tiff, TIFFTAG_IMAGEWIDTH, &out->Xsize ) ||
		!tfget32( rtiff->tiff, TIFFTAG_IMAGELENGTH, &out->Ysize ) ||
		parse_resolution( rtiff->tiff, out ) )
		return( -1 );

	/* Try to find out which type of TIFF image it is.
	 */
	if( !tfget16( rtiff->tiff, TIFFTAG_PHOTOMETRIC, &pm ) ||
		!tfget16( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, &bps ) )
		return( -1 );

	switch( pm ) {
	case PHOTOMETRIC_CIELAB:
		switch( bps ) {
		case 8:
			if( parse_labpack( rtiff, out ) )
				return( -1 );
			break;

		case 16:
			if( parse_labs( rtiff, out ) )
				return( -1 );
			break;

		case 32:
			if( !tfget16( rtiff->tiff, 
				TIFFTAG_SAMPLEFORMAT, &format ) ) 
				return( -1 );

			if( format == SAMPLEFORMAT_IEEEFP ) {
				if( parse_32f( rtiff, pm, out ) )
					return( -1 );
			}
			else {
				im_error( "im_tiff2vips", 
					_( "unsupported sample "
					"format %d for lab image" ),
					format );
				return( -1 );
			}

			break;

		default:
			im_error( "im_tiff2vips", 
				_( "unsupported depth %d for LAB image" ), 
				bps );
			return( -1 );
		}

		break;

	case PHOTOMETRIC_MINISWHITE:
	case PHOTOMETRIC_MINISBLACK:
		switch( bps ) {
		case 1:
			if( parse_onebit( rtiff, pm, out ) )
				return( -1 );

			break;

		case 8:
			if( parse_greyscale8( rtiff, pm, out ) )
				return( -1 );

			break;

		case 16:
			if( parse_greyscale16( rtiff, pm, out ) )
				return( -1 );

			break;

		case 32:
			if( !tfget16( rtiff->tiff, 
				TIFFTAG_SAMPLEFORMAT, &format ) ) 
				return( -1 );

			if( format == SAMPLEFORMAT_IEEEFP ) {
				if( parse_greyscale32f( rtiff, pm, out ) )
					return( -1 );
			}
			else {
				im_error( "im_tiff2vips", 
					_( "unsupported sample format "
					"%d for greyscale image" ),
					format );
				return( -1 );
			}

			break;

		default:
			im_error( "im_tiff2vips", _( "unsupported depth %d "
				"for greyscale image" ), bps );
			return( -1 );
		}

		break;

	case PHOTOMETRIC_PALETTE:
		/* Full colour pallette.
		 */
		if( parse_palette( rtiff, out ) )
			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( bps ) {
		case 8:
			if( parse_rgb8( rtiff, out ) )
				return( -1 );
			break;

		case 16:
			if( parse_rgb16( rtiff, out ) )
				return( -1 );
			break;

		case 32:
			if( !tfget16( rtiff->tiff, 
				TIFFTAG_SAMPLEFORMAT, &format ) ) 
				return( -1 );

			if( format == SAMPLEFORMAT_IEEEFP ) {
				if( parse_32f( rtiff, pm, out ) )
					return( -1 );
			}
			else {
				im_error( "im_tiff2vips", 
					_( "unsupported sample "
					"format %d for rgb image" ),
					format );
				return( -1 );
			}

			break;

		default:
			im_error( "im_tiff2vips", _( "unsupported depth %d "
				"for RGB image" ), bps );
			return( -1 );
		}

		break;

	case PHOTOMETRIC_SEPARATED:
		if( parse_cmyk( rtiff, out ) )
			return( -1 );

		break;

	default:
		im_error( "im_tiff2vips", _( "unknown photometric "
			"interpretation %d" ), pm );
		return( -1 );
	}

	/* Read any ICC profile.
	 */
	if( TIFFGetField( rtiff->tiff, 
		TIFFTAG_ICCPROFILE, &data_length, &data ) ) {
		void *data_copy;

		if( !(data_copy = im_malloc( NULL, data_length )) ) 
			return( -1 );
		memcpy( data_copy, data, data_length );
		if( im_meta_set_blob( out, IM_META_ICC_NAME, 
			(im_callback_fn) im_free, data_copy, data_length ) ) {
			im_free( data_copy );
			return( -1 );
		}
	}

	return( 0 );
}

/* Allocate a tile buffer. Have one of these for each thread so we can unpack
 * to vips in parallel.
 */
static void *
seq_start( IMAGE *out, void *a, void *b )
{
	ReadTiff *rtiff = (ReadTiff *) a;
	tdata_t *buf;

	if( !(buf = im_malloc( NULL, TIFFTileSize( rtiff->tiff ) )) )
		return( NULL );

	return( (void *) buf );
}

/* Loop over the output region, painting in tiles from the file.
 */
static int
fill_region( REGION *out, void *seq, void *a, void *b )
{
	tdata_t *buf = (tdata_t *) seq;
	ReadTiff *rtiff = (ReadTiff *) a;
	Rect *r = &out->valid;

	/* Find top left of tiles we need.
	 */
	int xs = (r->left / rtiff->twidth) * rtiff->twidth;
	int ys = (r->top / rtiff->theight) * rtiff->theight;

	/* Sizeof a line of bytes in the TIFF tile.
	 */
	int tls = TIFFTileSize( rtiff->tiff ) / rtiff->theight;

	/* Sizeof a pel in the TIFF file. This won't work for formats which
	 * are <1 byte per pel, like onebit :-( Fortunately, it's only used
	 * to calculate addresses within a tile, and because we are wrapped in
	 * im_tile_cache(), we will never have to calculate positions within a
	 * tile.
	 */
	int tps = tls / rtiff->twidth;

	int x, y, z;

	for( y = ys; y < IM_RECT_BOTTOM( r ); y += rtiff->theight )
		for( x = xs; x < IM_RECT_RIGHT( r ); x += rtiff->twidth ) {
			Rect tile;
			Rect hit;

			/* Read that tile.
			 */
			g_mutex_lock( rtiff->tlock );
			if( TIFFReadTile( rtiff->tiff, buf, 
				x, y, 0, 0 ) < 0 ) {
				g_mutex_unlock( rtiff->tlock );
				return( -1 );
			}
			g_mutex_unlock( rtiff->tlock );

			/* The tile we read.
			 */
			tile.left = x;
			tile.top = y;
			tile.width = rtiff->twidth;
			tile.height = rtiff->twidth;

			/* The section that hits the region we are building.
			 */
			im_rect_intersectrect( &tile, r, &hit );

			/* Unpack to VIPS format. We can do this in parallel.
			 * Just unpack the section of the tile we need.
			 */
			for( z = 0; z < hit.height; z++ ) {
				PEL *p = (PEL *) buf +
					(hit.left - tile.left) * tps +
					(hit.top - tile.top + z) * tls;
				PEL *q = (PEL *) IM_REGION_ADDR( out, 
					hit.left, hit.top + z );

				rtiff->sfn( q, p, hit.width, rtiff->client );
			}
		}

	return( 0 );
}

static int
seq_stop( void *seq, void *a, void *b )
{
	im_free( seq );

	return( 0 );
}

/* Tile-type TIFF reader core - pass in a per-tile transform. Generate into
 * the im and do it all partially.
 */
static int
read_tilewise( ReadTiff *rtiff, IMAGE *out )
{
	IMAGE *raw;

	/* Tile cache: keep enough for two complete rows of tiles.
	 * This lets us do (smallish) area ops, like im_conv(), while
	 * still only hitting each TIFF tile once.
	 */
	if( !(raw = im_open_local( out, "cache", "p" )) )
		return( -1 );

	/* Get tiling geometry.
	 */
	if( !tfget32( rtiff->tiff, TIFFTAG_TILEWIDTH, &rtiff->twidth ) ||
		!tfget32( rtiff->tiff, TIFFTAG_TILELENGTH, &rtiff->theight ) )
		return( -1 );

	/* Make sure we can write PIO-style.
	 */
	if( im_poutcheck( raw ) )
		return( -1 );

	/* Parse the TIFF header and set up raw.
	 */
	if( parse_header( rtiff, raw ) )
		return( -1 );

	/* Process and save as VIPS.
	 */
	if( im_demand_hint( raw, IM_SMALLTILE, NULL ) ||
		im_generate( raw, 
			seq_start, fill_region, seq_stop, rtiff, NULL ) )
		return( -1 );

	/* Copy to out, adding a cache. Enough tiles for two complete rows.
	 */
	if( im_tile_cache( raw, out, 
		rtiff->twidth, rtiff->theight,
		2 * (1 + raw->Xsize / rtiff->twidth) ) ) 
		return( -1 );

	return( 0 );
}

/* Stripwise reading - we assume strips are written top-to-bottom. Not sure if
 * this is always correct.
 */
static int
read_stripwise( ReadTiff *rtiff, IMAGE *out )
{
	int rows_per_strip;
	tsize_t scanline_size;
	tsize_t strip_size;
	int number_of_strips;

	PEL *vbuf;
	tdata_t tbuf;
	tstrip_t strip;
	tsize_t length;
	int y;
	int i;
	PEL *p;

	if( parse_header( rtiff, out ) )
		return( -1 );

	if( !tfget32( rtiff->tiff, TIFFTAG_ROWSPERSTRIP, &rows_per_strip ) )
		return( -1 );
	scanline_size = TIFFScanlineSize( rtiff->tiff );
	strip_size = TIFFStripSize( rtiff->tiff );
	number_of_strips = TIFFNumberOfStrips( rtiff->tiff );

#ifdef DEBUG
	printf( "read_stripwise: rows_per_strip = %d\n", rows_per_strip );
	printf( "read_stripwise: scanline_size = %d\n", scanline_size );
	printf( "read_stripwise: strip_size = %d\n", strip_size );
	printf( "read_stripwise: number_of_strips = %d\n", number_of_strips );
#endif /*DEBUG*/

	/* Make sure we can write WIO-style.
	 */
	if( im_outcheck( out ) || 
		im_setupout( out ) )
		return( -1 );

	/* Make buffers.
	 */
	if( !(vbuf = IM_ARRAY( out, IM_IMAGE_SIZEOF_LINE( out ), PEL )) ||
		!(tbuf = im_malloc( out, strip_size )) ) 
		return( -1 );

	for( strip = 0, y = 0; 
		strip < number_of_strips; 
		strip += 1, y += rows_per_strip ) {
		length = TIFFReadEncodedStrip( rtiff->tiff, 
			strip, tbuf, (tsize_t) -1 );
		if( length == -1 ) {
			im_error( "im_tiff2vips", "%s", _( "read error" ) );
			return( -1 );
		}

		for( p = tbuf, i = 0; 
			i < rows_per_strip && y + i < out->Ysize; 
			i += 1, p += scanline_size ) {
			/* Process and save as VIPS.
			 */
			rtiff->sfn( vbuf, p, out->Xsize, rtiff->client );
			if( im_writeline( y + i, out, vbuf ) ) 
				return( -1 );
		}
	}

	return( 0 );
}

/* Free a ReadTiff.
 */
static int
readtiff_destroy( ReadTiff *rtiff )
{
	IM_FREEF( TIFFClose, rtiff->tiff );
	IM_FREEF( g_mutex_free, rtiff->tlock );

	return( 0 );
}

/* Make a ReadTiff.
 */
static ReadTiff *
readtiff_new( const char *filename, IMAGE *out )
{
	ReadTiff *rtiff;
	char name[FILENAME_MAX];
	char mode[FILENAME_MAX];
	char *p, *q;

	if( !(rtiff = IM_NEW( out, ReadTiff )) )
		return( NULL );
	rtiff->filename = NULL;
	rtiff->out = out;
	im_filename_split( filename, name, mode );
	rtiff->filename = im_strdup( out, name );
	rtiff->page = 0;
	rtiff->tiff = NULL;
	rtiff->sfn = NULL;
	rtiff->client = NULL;
	rtiff->twidth = 0;
	rtiff->theight = 0;
	rtiff->tlock = g_mutex_new();

	if( im_add_close_callback( out, 
		(im_callback_fn) readtiff_destroy, rtiff, NULL ) ) {
		readtiff_destroy( rtiff );
		return( NULL );
	}

	/* Parse out params.
	 */
	p = &mode[0];
	if( (q = im_getnextoption( &p )) ) {
		rtiff->page = atoi( q );

		if( rtiff->page < 0 || rtiff->page > 1000 ) {
			im_error( "im_tiff2vips", _( "bad page number %d" ),
				rtiff->page );
			return( NULL );
		}
	}

	return( rtiff );
}

/* Pull out the nth directory from a TIFF file.
 */
static TIFF *
get_directory( const char *filename, int page )
{
	TIFF *tif;
	int i;

	/* No mmap --- no performance advantage with libtiff, and it burns up
	 * our VM if the tiff file is large.
	 */
	if( !(tif = TIFFOpen( filename, "rm" )) ) {
		im_error( "im_tiff2vips", 
			_( "unable to open \"%s\" for input" ),
			filename );
		return( NULL );
	}

	for( i = 0; i < page; i++ ) 
		if( !TIFFReadDirectory( tif ) ) {
			/* Run out of directories.
			 */
			TIFFClose( tif );
			return( NULL );
		}

	return( tif );
}

/* 

	FIXME ... Unused for now, perhaps if we add another format flag.

static int
istiffpyramid( const char *name )
{
	TIFF *tif;

	TIFFSetErrorHandler( (TIFFErrorHandler) im__thandler_error );
	TIFFSetWarningHandler( (TIFFErrorHandler) im__thandler_warning );

	if( (tif = get_directory( name, 2 )) ) {
		// We can see page 2 ... assume it is.
		TIFFClose( tif );
		return( 1 );
	}

	return( 0 );
}
 */

/**
 * im_tiff2vips:
 * @filename: file to load
 * @out: image to write to
 *
 * Read a TIFF file into a VIPS image. It is a full baseline TIFF 6 reader, 
 * with extensions for tiled images, multipage images, LAB colour space, 
 * pyramidal images and JPEG compression. including CMYK and YCbCr.
 *
 * You can embed a page number in the filename. For example: 
 *
 * |[
 * im_tiff2vips( "fred.tif:23", out );
 * ]|
 *
 * Will read page 23. By default, the operation reads the first page.
 *
 * Any ICC profile is read out and attached to the VIPS image.
 *
 * See also: #VipsFormat, im_vips2tiff().
 *
 * Returns: 0 on success, -1 on error.
 */
int
im_tiff2vips( const char *filename, IMAGE *out )
{
	ReadTiff *rtiff;

#ifdef DEBUG
	printf( "im_tiff2vips: libtiff version is \"%s\"\n", TIFFGetVersion() );
#endif /*DEBUG*/

	TIFFSetErrorHandler( (TIFFErrorHandler) im__thandler_error );
	TIFFSetWarningHandler( (TIFFErrorHandler) im__thandler_warning );

	if( !(rtiff = readtiff_new( filename, out )) )
		return( -1 );

	if( !(rtiff->tiff = get_directory( rtiff->filename, rtiff->page )) ) {
		im_error( "im_tiff2vips", _( "TIFF file does not "
			"contain page %d" ), rtiff->page );
		return( -1 );
	}

	if( TIFFIsTiled( rtiff->tiff ) ) {
		if( read_tilewise( rtiff, out ) )
			return( -1 );
	}
	else {
		if( read_stripwise( rtiff, out ) )
			return( -1 );
	}

	return( 0 );
}

/* Just parse the header.
 */
static int
tiff2vips_header( const char *filename, IMAGE *out )
{
	ReadTiff *rtiff;

	TIFFSetErrorHandler( (TIFFErrorHandler) im__thandler_error );
	TIFFSetWarningHandler( (TIFFErrorHandler) im__thandler_warning );

	if( !(rtiff = readtiff_new( filename, out )) )
		return( -1 );

	if( !(rtiff->tiff = get_directory( rtiff->filename, rtiff->page )) ) {
		im_error( "im_tiff2vips", 
			_( "TIFF file does not contain page %d" ), 
			rtiff->page );
		return( -1 );
	}

	if( parse_header( rtiff, out ) )
		return( -1 );

	return( 0 );
}

static int
istiff( const char *filename )
{
	unsigned char buf[2];

	if( im__get_bytes( filename, buf, 2 ) )
		if( (buf[0] == 'M' && buf[1] == 'M') ||
			(buf[0] == 'I' && buf[1] == 'I') ) 
			return( 1 );

	return( 0 );
}

static int
istifftiled( const char *filename )
{
	TIFF *tif;
	int tiled;

	/* Override the default TIFF error handler.
	 */
	TIFFSetErrorHandler( (TIFFErrorHandler) im__thandler_error );
	TIFFSetWarningHandler( (TIFFErrorHandler) im__thandler_warning );

	if( !(tif = TIFFOpen( filename, "rm" )) ) {
		/* Not a TIFF file ... return False.
		 */
		im_error_clear();
		return( 0 );
	}
	tiled = TIFFIsTiled( tif );
	TIFFClose( tif );

	return( tiled );
}

/* TIFF flags function.
 */
static VipsFormatFlags
tiff_flags( const char *filename )
{
	VipsFormatFlags flags;

	flags = 0;
	if( istifftiled( filename ) )
		flags |= VIPS_FORMAT_PARTIAL;

	return( flags );
}

static const char *tiff_suffs[] = { ".tif", ".tiff", NULL };

/* tiff format adds no new members.
 */
typedef VipsFormat VipsFormatTiff;
typedef VipsFormatClass VipsFormatTiffClass;

static void
vips_format_tiff_class_init( VipsFormatTiffClass *class )
{
	VipsObjectClass *object_class = (VipsObjectClass *) class;
	VipsFormatClass *format_class = (VipsFormatClass *) class;

	object_class->nickname = "tiff";
	object_class->description = _( "TIFF" );

	format_class->is_a = istiff;
	format_class->header = tiff2vips_header;
	format_class->load = im_tiff2vips;
	format_class->save = im_vips2tiff;
	format_class->get_flags = tiff_flags;
	format_class->suffs = tiff_suffs;
}

static void
vips_format_tiff_init( VipsFormatTiff *object )
{
}

G_DEFINE_TYPE( VipsFormatTiff, vips_format_tiff, VIPS_TYPE_FORMAT );

#endif /*HAVE_TIFF*/
