roentgen b75cab
/* $Id: tiffcp.c,v 1.49 2010-12-23 13:38:47 dron Exp $ */
roentgen b75cab
roentgen b75cab
/*
roentgen b75cab
 * Copyright (c) 1988-1997 Sam Leffler
roentgen b75cab
 * Copyright (c) 1991-1997 Silicon Graphics, Inc.
roentgen b75cab
 *
roentgen b75cab
 *  Revised:  2/18/01 BAR -- added syntax for extracting single images from
roentgen b75cab
 *                          multi-image TIFF files.
roentgen b75cab
 *
roentgen b75cab
 *    New syntax is:  sourceFileName,image#
roentgen b75cab
 *
roentgen b75cab
 * image# ranges from 0..<n-1> where n is the # of images in the file.</n-1>
roentgen b75cab
 * There may be no white space between the comma and the filename or
roentgen b75cab
 * image number.
roentgen b75cab
 *
roentgen b75cab
 *    Example:   tiffcp source.tif,1 destination.tif
roentgen b75cab
 *
roentgen b75cab
 * Copies the 2nd image in source.tif to the destination.
roentgen b75cab
 *
roentgen b75cab
 *****
roentgen b75cab
 * Permission to use, copy, modify, distribute, and sell this software and 
roentgen b75cab
 * its documentation for any purpose is hereby granted without fee, provided
roentgen b75cab
 * that (i) the above copyright notices and this permission notice appear in
roentgen b75cab
 * all copies of the software and related documentation, and (ii) the names of
roentgen b75cab
 * Sam Leffler and Silicon Graphics may not be used in any advertising or
roentgen b75cab
 * publicity relating to the software without the specific, prior written
roentgen b75cab
 * permission of Sam Leffler and Silicon Graphics.
roentgen b75cab
 * 
roentgen b75cab
 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
roentgen b75cab
 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
roentgen b75cab
 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
roentgen b75cab
 * 
roentgen b75cab
 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
roentgen b75cab
 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
roentgen b75cab
 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
roentgen b75cab
 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
roentgen b75cab
 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
roentgen b75cab
 * OF THIS SOFTWARE.
roentgen b75cab
 */
roentgen b75cab
roentgen b75cab
#include "tif_config.h"
roentgen b75cab
roentgen b75cab
#include <stdio.h></stdio.h>
roentgen b75cab
#include <stdlib.h></stdlib.h>
roentgen b75cab
#include <string.h></string.h>
roentgen b75cab
roentgen b75cab
#include <ctype.h></ctype.h>
roentgen b75cab
#include <assert.h></assert.h>
roentgen b75cab
roentgen b75cab
#ifdef HAVE_UNISTD_H
roentgen b75cab
# include <unistd.h></unistd.h>
roentgen b75cab
#endif
roentgen b75cab
roentgen b75cab
#include "tiffio.h"
roentgen b75cab
roentgen b75cab
#ifndef HAVE_GETOPT
roentgen b75cab
extern int getopt(int, char**, char*);
roentgen b75cab
#endif
roentgen b75cab
roentgen b75cab
#if defined(VMS)
roentgen b75cab
# define unlink delete
roentgen b75cab
#endif
roentgen b75cab
roentgen b75cab
#define	streq(a,b)	(strcmp(a,b) == 0)
roentgen b75cab
#define	strneq(a,b,n)	(strncmp(a,b,n) == 0)
roentgen b75cab
roentgen b75cab
#define	TRUE	1
roentgen b75cab
#define	FALSE	0
roentgen b75cab
roentgen b75cab
static int outtiled = -1;
roentgen b75cab
static uint32 tilewidth;
roentgen b75cab
static uint32 tilelength;
roentgen b75cab
roentgen b75cab
static uint16 config;
roentgen b75cab
static uint16 compression;
roentgen b75cab
static uint16 predictor;
roentgen b75cab
static int preset;
roentgen b75cab
static uint16 fillorder;
roentgen b75cab
static uint16 orientation;
roentgen b75cab
static uint32 rowsperstrip;
roentgen b75cab
static uint32 g3opts;
roentgen b75cab
static int ignore = FALSE;		/* if true, ignore read errors */
roentgen b75cab
static uint32 defg3opts = (uint32) -1;
roentgen b75cab
static int quality = 75;		/* JPEG quality */
roentgen b75cab
static int jpegcolormode = JPEGCOLORMODE_RGB;
roentgen b75cab
static uint16 defcompression = (uint16) -1;
roentgen b75cab
static uint16 defpredictor = (uint16) -1;
roentgen b75cab
static int defpreset =  -1;
roentgen b75cab
roentgen b75cab
static int tiffcp(TIFF*, TIFF*);
roentgen b75cab
static int processCompressOptions(char*);
roentgen b75cab
static void usage(void);
roentgen b75cab
roentgen b75cab
static char comma = ',';  /* (default) comma separator character */
roentgen b75cab
static TIFF* bias = NULL;
roentgen b75cab
static int pageNum = 0;
roentgen b75cab
static int pageInSeq = 0;
roentgen b75cab
roentgen b75cab
static int nextSrcImage (TIFF *tif, char **imageSpec)
roentgen b75cab
/*
roentgen b75cab
  seek to the next image specified in *imageSpec
roentgen b75cab
  returns 1 if success, 0 if no more images to process
roentgen b75cab
  *imageSpec=NULL if subsequent images should be processed in sequence
roentgen b75cab
*/
roentgen b75cab
{
roentgen b75cab
	if (**imageSpec == comma) {  /* if not @comma, we've done all images */
roentgen b75cab
		char *start = *imageSpec + 1;
roentgen b75cab
		tdir_t nextImage = (tdir_t)strtol(start, imageSpec, 0);
roentgen b75cab
		if (start == *imageSpec) nextImage = TIFFCurrentDirectory (tif);
roentgen b75cab
		if (**imageSpec)
roentgen b75cab
		{
roentgen b75cab
			if (**imageSpec == comma) {
roentgen b75cab
				/* a trailing comma denotes remaining images in sequence */
roentgen b75cab
				if ((*imageSpec)[1] == '\0') *imageSpec = NULL;
roentgen b75cab
			}else{
roentgen b75cab
				fprintf (stderr,
roentgen b75cab
				    "Expected a %c separated image # list after %s\n",
roentgen b75cab
				    comma, TIFFFileName (tif));
roentgen b75cab
				exit (-4);   /* syntax error */
roentgen b75cab
			}
roentgen b75cab
		}
roentgen b75cab
		if (TIFFSetDirectory (tif, nextImage)) return 1;
roentgen b75cab
		fprintf (stderr, "%s%c%d not found!\n",
roentgen b75cab
		    TIFFFileName(tif), comma, (int) nextImage);
roentgen b75cab
	}
roentgen b75cab
	return 0;
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
  
roentgen b75cab
static TIFF* openSrcImage (char **imageSpec)
roentgen b75cab
/*
roentgen b75cab
  imageSpec points to a pointer to a filename followed by optional ,image#'s
roentgen b75cab
  Open the TIFF file and assign *imageSpec to either NULL if there are
roentgen b75cab
  no images specified, or a pointer to the next image number text
roentgen b75cab
*/
roentgen b75cab
{
roentgen b75cab
	TIFF *tif;
roentgen b75cab
	char *fn = *imageSpec;
roentgen b75cab
	*imageSpec = strchr (fn, comma);
roentgen b75cab
	if (*imageSpec) {  /* there is at least one image number specifier */
roentgen b75cab
		**imageSpec = '\0';
roentgen b75cab
		tif = TIFFOpen (fn, "r");
roentgen b75cab
		/* but, ignore any single trailing comma */
roentgen b75cab
		if (!(*imageSpec)[1]) {*imageSpec = NULL; return tif;}
roentgen b75cab
		if (tif) {
roentgen b75cab
			**imageSpec = comma;  /* replace the comma */
roentgen b75cab
			if (!nextSrcImage(tif, imageSpec)) {
roentgen b75cab
				TIFFClose (tif);
roentgen b75cab
				tif = NULL;
roentgen b75cab
			}
roentgen b75cab
		}
roentgen b75cab
	}else
roentgen b75cab
		tif = TIFFOpen (fn, "r");
roentgen b75cab
	return tif;
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
int
roentgen b75cab
main(int argc, char* argv[])
roentgen b75cab
{
roentgen b75cab
	uint16 defconfig = (uint16) -1;
roentgen b75cab
	uint16 deffillorder = 0;
roentgen b75cab
	uint32 deftilewidth = (uint32) -1;
roentgen b75cab
	uint32 deftilelength = (uint32) -1;
roentgen b75cab
	uint32 defrowsperstrip = (uint32) 0;
roentgen b75cab
	uint64 diroff = 0;
roentgen b75cab
	TIFF* in;
roentgen b75cab
	TIFF* out;
roentgen b75cab
	char mode[10];
roentgen b75cab
	char* mp = mode;
roentgen b75cab
	int c;
roentgen b75cab
	extern int optind;
roentgen b75cab
	extern char* optarg;
roentgen b75cab
roentgen b75cab
	*mp++ = 'w';
roentgen b75cab
	*mp = '\0';
roentgen b75cab
	while ((c = getopt(argc, argv, ",:b:c:f:l:o:z:p:r:w:aistBLMC8x")) != -1)
roentgen b75cab
		switch (c) {
roentgen b75cab
		case ',':
roentgen b75cab
			if (optarg[0] != '=') usage();
roentgen b75cab
			comma = optarg[1];
roentgen b75cab
			break;
roentgen b75cab
		case 'b':   /* this file is bias image subtracted from others */
roentgen b75cab
			if (bias) {
roentgen b75cab
				fputs ("Only 1 bias image may be specified\n", stderr);
roentgen b75cab
				exit (-2);
roentgen b75cab
			}
roentgen b75cab
			{
roentgen b75cab
				uint16 samples = (uint16) -1;
roentgen b75cab
				char **biasFn = &optarg;
roentgen b75cab
				bias = openSrcImage (biasFn);
roentgen b75cab
				if (!bias) exit (-5);
roentgen b75cab
				if (TIFFIsTiled (bias)) {
roentgen b75cab
					fputs ("Bias image must be organized in strips\n", stderr);
roentgen b75cab
					exit (-7);
roentgen b75cab
				}
roentgen b75cab
				TIFFGetField(bias, TIFFTAG_SAMPLESPERPIXEL, &samples);
roentgen b75cab
				if (samples != 1) {
roentgen b75cab
					fputs ("Bias image must be monochrome\n", stderr);
roentgen b75cab
					exit (-7);
roentgen b75cab
				}
roentgen b75cab
			}
roentgen b75cab
			break;
roentgen b75cab
		case 'a':   /* append to output */
roentgen b75cab
			mode[0] = 'a';
roentgen b75cab
			break;
roentgen b75cab
		case 'c':   /* compression scheme */
roentgen b75cab
			if (!processCompressOptions(optarg))
roentgen b75cab
				usage();
roentgen b75cab
			break;
roentgen b75cab
		case 'f':   /* fill order */
roentgen b75cab
			if (streq(optarg, "lsb2msb"))
roentgen b75cab
				deffillorder = FILLORDER_LSB2MSB;
roentgen b75cab
			else if (streq(optarg, "msb2lsb"))
roentgen b75cab
				deffillorder = FILLORDER_MSB2LSB;
roentgen b75cab
			else
roentgen b75cab
				usage();
roentgen b75cab
			break;
roentgen b75cab
		case 'i':   /* ignore errors */
roentgen b75cab
			ignore = TRUE;
roentgen b75cab
			break;
roentgen b75cab
		case 'l':   /* tile length */
roentgen b75cab
			outtiled = TRUE;
roentgen b75cab
			deftilelength = atoi(optarg);
roentgen b75cab
			break;
roentgen b75cab
		case 'o':   /* initial directory offset */
roentgen b75cab
			diroff = strtoul(optarg, NULL, 0);
roentgen b75cab
			break;
roentgen b75cab
		case 'p':   /* planar configuration */
roentgen b75cab
			if (streq(optarg, "separate"))
roentgen b75cab
				defconfig = PLANARCONFIG_SEPARATE;
roentgen b75cab
			else if (streq(optarg, "contig"))
roentgen b75cab
				defconfig = PLANARCONFIG_CONTIG;
roentgen b75cab
			else
roentgen b75cab
				usage();
roentgen b75cab
			break;
roentgen b75cab
		case 'r':   /* rows/strip */
roentgen b75cab
			defrowsperstrip = atol(optarg);
roentgen b75cab
			break;
roentgen b75cab
		case 's':   /* generate stripped output */
roentgen b75cab
			outtiled = FALSE;
roentgen b75cab
			break;
roentgen b75cab
		case 't':   /* generate tiled output */
roentgen b75cab
			outtiled = TRUE;
roentgen b75cab
			break;
roentgen b75cab
		case 'w':   /* tile width */
roentgen b75cab
			outtiled = TRUE;
roentgen b75cab
			deftilewidth = atoi(optarg);
roentgen b75cab
			break;
roentgen b75cab
		case 'B':
roentgen b75cab
			*mp++ = 'b'; *mp = '\0';
roentgen b75cab
			break;
roentgen b75cab
		case 'L':
roentgen b75cab
			*mp++ = 'l'; *mp = '\0';
roentgen b75cab
			break;
roentgen b75cab
		case 'M':
roentgen b75cab
			*mp++ = 'm'; *mp = '\0';
roentgen b75cab
			break;
roentgen b75cab
		case 'C':
roentgen b75cab
			*mp++ = 'c'; *mp = '\0';
roentgen b75cab
			break;
roentgen b75cab
		case '8':
roentgen b75cab
			*mp++ = '8'; *mp = '\0';
roentgen b75cab
			break;
roentgen b75cab
		case 'x':
roentgen b75cab
			pageInSeq = 1;
roentgen b75cab
			break;
roentgen b75cab
		case '?':
roentgen b75cab
			usage();
roentgen b75cab
			/*NOTREACHED*/
roentgen b75cab
		}
roentgen b75cab
	if (argc - optind < 2)
roentgen b75cab
		usage();
roentgen b75cab
	out = TIFFOpen(argv[argc-1], mode);
roentgen b75cab
	if (out == NULL)
roentgen b75cab
		return (-2);
roentgen b75cab
	if ((argc - optind) == 2)
roentgen b75cab
		pageNum = -1;
roentgen b75cab
	for (; optind < argc-1 ; optind++) {
roentgen b75cab
		char *imageCursor = argv[optind];
roentgen b75cab
		in = openSrcImage (&imageCursor);
roentgen b75cab
		if (in == NULL) {
roentgen b75cab
			(void) TIFFClose(out);
roentgen b75cab
			return (-3);
roentgen b75cab
		}
roentgen b75cab
		if (diroff != 0 && !TIFFSetSubDirectory(in, diroff)) {
roentgen b75cab
			TIFFError(TIFFFileName(in),
roentgen b75cab
			    "Error, setting subdirectory at " TIFF_UINT64_FORMAT, diroff);
roentgen b75cab
			(void) TIFFClose(in);
roentgen b75cab
			(void) TIFFClose(out);
roentgen b75cab
			return (1);
roentgen b75cab
		}
roentgen b75cab
		for (;;) {
roentgen b75cab
			config = defconfig;
roentgen b75cab
			compression = defcompression;
roentgen b75cab
			predictor = defpredictor;
roentgen b75cab
                        preset = defpreset;
roentgen b75cab
			fillorder = deffillorder;
roentgen b75cab
			rowsperstrip = defrowsperstrip;
roentgen b75cab
			tilewidth = deftilewidth;
roentgen b75cab
			tilelength = deftilelength;
roentgen b75cab
			g3opts = defg3opts;
roentgen b75cab
			if (!tiffcp(in, out) || !TIFFWriteDirectory(out)) {
roentgen b75cab
				(void) TIFFClose(in);
roentgen b75cab
				(void) TIFFClose(out);
roentgen b75cab
				return (1);
roentgen b75cab
			}
roentgen b75cab
			if (imageCursor) { /* seek next image directory */
roentgen b75cab
				if (!nextSrcImage(in, &imageCursor)) break;
roentgen b75cab
			}else
roentgen b75cab
				if (!TIFFReadDirectory(in)) break;
roentgen b75cab
		}
roentgen b75cab
		(void) TIFFClose(in);
roentgen b75cab
	}
roentgen b75cab
roentgen b75cab
	(void) TIFFClose(out);
roentgen b75cab
	return (0);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
static void
roentgen b75cab
processZIPOptions(char* cp)
roentgen b75cab
{
roentgen b75cab
	if ( (cp = strchr(cp, ':')) ) {
roentgen b75cab
		do {
roentgen b75cab
			cp++;
roentgen b75cab
			if (isdigit((int)*cp))
roentgen b75cab
				defpredictor = atoi(cp);
roentgen b75cab
			else if (*cp == 'p')
roentgen b75cab
				defpreset = atoi(++cp);
roentgen b75cab
			else
roentgen b75cab
				usage();
roentgen b75cab
		} while( (cp = strchr(cp, ':')) );
roentgen b75cab
	}
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
static void
roentgen b75cab
processG3Options(char* cp)
roentgen b75cab
{
roentgen b75cab
	if( (cp = strchr(cp, ':')) ) {
roentgen b75cab
		if (defg3opts == (uint32) -1)
roentgen b75cab
			defg3opts = 0;
roentgen b75cab
		do {
roentgen b75cab
			cp++;
roentgen b75cab
			if (strneq(cp, "1d", 2))
roentgen b75cab
				defg3opts &= ~GROUP3OPT_2DENCODING;
roentgen b75cab
			else if (strneq(cp, "2d", 2))
roentgen b75cab
				defg3opts |= GROUP3OPT_2DENCODING;
roentgen b75cab
			else if (strneq(cp, "fill", 4))
roentgen b75cab
				defg3opts |= GROUP3OPT_FILLBITS;
roentgen b75cab
			else
roentgen b75cab
				usage();
roentgen b75cab
		} while( (cp = strchr(cp, ':')) );
roentgen b75cab
	}
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
static int
roentgen b75cab
processCompressOptions(char* opt)
roentgen b75cab
{
roentgen b75cab
	if (streq(opt, "none")) {
roentgen b75cab
		defcompression = COMPRESSION_NONE;
roentgen b75cab
	} else if (streq(opt, "packbits")) {
roentgen b75cab
		defcompression = COMPRESSION_PACKBITS;
roentgen b75cab
	} else if (strneq(opt, "jpeg", 4)) {
roentgen b75cab
		char* cp = strchr(opt, ':');
roentgen b75cab
roentgen b75cab
		defcompression = COMPRESSION_JPEG;
roentgen b75cab
		while( cp )
roentgen b75cab
		{
roentgen b75cab
			if (isdigit((int)cp[1]))
roentgen b75cab
				quality = atoi(cp+1);
roentgen b75cab
			else if (cp[1] == 'r' )
roentgen b75cab
				jpegcolormode = JPEGCOLORMODE_RAW;
roentgen b75cab
			else
roentgen b75cab
				usage();
roentgen b75cab
roentgen b75cab
			cp = strchr(cp+1,':');
roentgen b75cab
		}
roentgen b75cab
	} else if (strneq(opt, "g3", 2)) {
roentgen b75cab
		processG3Options(opt);
roentgen b75cab
		defcompression = COMPRESSION_CCITTFAX3;
roentgen b75cab
	} else if (streq(opt, "g4")) {
roentgen b75cab
		defcompression = COMPRESSION_CCITTFAX4;
roentgen b75cab
	} else if (strneq(opt, "lzw", 3)) {
roentgen b75cab
		char* cp = strchr(opt, ':');
roentgen b75cab
		if (cp)
roentgen b75cab
			defpredictor = atoi(cp+1);
roentgen b75cab
		defcompression = COMPRESSION_LZW;
roentgen b75cab
	} else if (strneq(opt, "zip", 3)) {
roentgen b75cab
		processZIPOptions(opt);
roentgen b75cab
		defcompression = COMPRESSION_ADOBE_DEFLATE;
roentgen b75cab
	} else if (strneq(opt, "lzma", 4)) {
roentgen b75cab
		processZIPOptions(opt);
roentgen b75cab
		defcompression = COMPRESSION_LZMA;
roentgen b75cab
	} else if (strneq(opt, "jbig", 4)) {
roentgen b75cab
		defcompression = COMPRESSION_JBIG;
roentgen b75cab
	} else if (strneq(opt, "sgilog", 6)) {
roentgen b75cab
		defcompression = COMPRESSION_SGILOG;
roentgen b75cab
	} else
roentgen b75cab
		return (0);
roentgen b75cab
	return (1);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
char* stuff[] = {
roentgen b75cab
"usage: tiffcp [options] input... output",
roentgen b75cab
"where options are:",
roentgen b75cab
" -a              append to output instead of overwriting",
roentgen b75cab
" -o offset       set initial directory offset",
roentgen b75cab
" -p contig       pack samples contiguously (e.g. RGBRGB...)",
roentgen b75cab
" -p separate     store samples separately (e.g. RRR...GGG...BBB...)",
roentgen b75cab
" -s              write output in strips",
roentgen b75cab
" -t              write output in tiles",
roentgen b75cab
" -8              write BigTIFF instead of default ClassicTIFF",
roentgen b75cab
" -i              ignore read errors",
roentgen b75cab
" -b file[,#]     bias (dark) monochrome image to be subtracted from all others",
roentgen b75cab
" -,=%            use % rather than , to separate image #'s (per Note below)",
roentgen b75cab
"",
roentgen b75cab
" -r #            make each strip have no more than # rows",
roentgen b75cab
" -w #            set output tile width (pixels)",
roentgen b75cab
" -l #            set output tile length (pixels)",
roentgen b75cab
"",
roentgen b75cab
" -f lsb2msb      force lsb-to-msb FillOrder for output",
roentgen b75cab
" -f msb2lsb      force msb-to-lsb FillOrder for output",
roentgen b75cab
"",
roentgen b75cab
" -c lzw[:opts]   compress output with Lempel-Ziv & Welch encoding",
roentgen b75cab
" -c zip[:opts]   compress output with deflate encoding",
roentgen b75cab
" -c lzma[:opts]  compress output with LZMA2 encoding",
roentgen b75cab
" -c jpeg[:opts]  compress output with JPEG encoding",
roentgen b75cab
" -c jbig         compress output with ISO JBIG encoding",
roentgen b75cab
" -c packbits     compress output with packbits encoding",
roentgen b75cab
" -c g3[:opts]    compress output with CCITT Group 3 encoding",
roentgen b75cab
" -c g4           compress output with CCITT Group 4 encoding",
roentgen b75cab
" -c sgilog       compress output with SGILOG encoding",
roentgen b75cab
" -c none         use no compression algorithm on output",
roentgen b75cab
" -x              force the merged tiff pages in sequence",
roentgen b75cab
"",
roentgen b75cab
"Group 3 options:",
roentgen b75cab
" 1d              use default CCITT Group 3 1D-encoding",
roentgen b75cab
" 2d              use optional CCITT Group 3 2D-encoding",
roentgen b75cab
" fill            byte-align EOL codes",
roentgen b75cab
"For example, -c g3:2d:fill to get G3-2D-encoded data with byte-aligned EOLs",
roentgen b75cab
"",
roentgen b75cab
"JPEG options:",
roentgen b75cab
" #               set compression quality level (0-100, default 75)",
roentgen b75cab
" r               output color image as RGB rather than YCbCr",
roentgen b75cab
"For example, -c jpeg:r:50 to get JPEG-encoded RGB data with 50% comp. quality",
roentgen b75cab
"",
roentgen b75cab
"LZW, Deflate (ZIP) and LZMA2 options:",
roentgen b75cab
" #               set predictor value",
roentgen b75cab
" p#              set compression level (preset)",
roentgen b75cab
"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing,",
roentgen b75cab
"-c zip:3:p9 for Deflate encoding with maximum compression level and floating",
roentgen b75cab
"point predictor.",
roentgen b75cab
"",
roentgen b75cab
"Note that input filenames may be of the form filename,x,y,z",
roentgen b75cab
"where x, y, and z specify image numbers in the filename to copy.",
roentgen b75cab
"example:  tiffcp -c none -b esp.tif,1 esp.tif,0 test.tif",
roentgen b75cab
"  subtract 2nd image in esp.tif from 1st yielding uncompressed result test.tif",
roentgen b75cab
NULL
roentgen b75cab
};
roentgen b75cab
roentgen b75cab
static void
roentgen b75cab
usage(void)
roentgen b75cab
{
roentgen b75cab
	char buf[BUFSIZ];
roentgen b75cab
	int i;
roentgen b75cab
roentgen b75cab
	setbuf(stderr, buf);
roentgen b75cab
	fprintf(stderr, "%s\n\n", TIFFGetVersion());
roentgen b75cab
	for (i = 0; stuff[i] != NULL; i++)
roentgen b75cab
		fprintf(stderr, "%s\n", stuff[i]);
roentgen b75cab
	exit(-1);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
#define	CopyField(tag, v) \
roentgen b75cab
    if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
roentgen b75cab
#define	CopyField2(tag, v1, v2) \
roentgen b75cab
    if (TIFFGetField(in, tag, &v1, &v2)) TIFFSetField(out, tag, v1, v2)
roentgen b75cab
#define	CopyField3(tag, v1, v2, v3) \
roentgen b75cab
    if (TIFFGetField(in, tag, &v1, &v2, &v3)) TIFFSetField(out, tag, v1, v2, v3)
roentgen b75cab
#define	CopyField4(tag, v1, v2, v3, v4) \
roentgen b75cab
    if (TIFFGetField(in, tag, &v1, &v2, &v3, &v4)) TIFFSetField(out, tag, v1, v2, v3, v4)
roentgen b75cab
roentgen b75cab
static void
roentgen b75cab
cpTag(TIFF* in, TIFF* out, uint16 tag, uint16 count, TIFFDataType type)
roentgen b75cab
{
roentgen b75cab
	switch (type) {
roentgen b75cab
	case TIFF_SHORT:
roentgen b75cab
		if (count == 1) {
roentgen b75cab
			uint16 shortv;
roentgen b75cab
			CopyField(tag, shortv);
roentgen b75cab
		} else if (count == 2) {
roentgen b75cab
			uint16 shortv1, shortv2;
roentgen b75cab
			CopyField2(tag, shortv1, shortv2);
roentgen b75cab
		} else if (count == 4) {
roentgen b75cab
			uint16 *tr, *tg, *tb, *ta;
roentgen b75cab
			CopyField4(tag, tr, tg, tb, ta);
roentgen b75cab
		} else if (count == (uint16) -1) {
roentgen b75cab
			uint16 shortv1;
roentgen b75cab
			uint16* shortav;
roentgen b75cab
			CopyField2(tag, shortv1, shortav);
roentgen b75cab
		}
roentgen b75cab
		break;
roentgen b75cab
	case TIFF_LONG:
roentgen b75cab
		{ uint32 longv;
roentgen b75cab
		  CopyField(tag, longv);
roentgen b75cab
		}
roentgen b75cab
		break;
roentgen b75cab
	case TIFF_RATIONAL:
roentgen b75cab
		if (count == 1) {
roentgen b75cab
			float floatv;
roentgen b75cab
			CopyField(tag, floatv);
roentgen b75cab
		} else if (count == (uint16) -1) {
roentgen b75cab
			float* floatav;
roentgen b75cab
			CopyField(tag, floatav);
roentgen b75cab
		}
roentgen b75cab
		break;
roentgen b75cab
	case TIFF_ASCII:
roentgen b75cab
		{ char* stringv;
roentgen b75cab
		  CopyField(tag, stringv);
roentgen b75cab
		}
roentgen b75cab
		break;
roentgen b75cab
	case TIFF_DOUBLE:
roentgen b75cab
		if (count == 1) {
roentgen b75cab
			double doublev;
roentgen b75cab
			CopyField(tag, doublev);
roentgen b75cab
		} else if (count == (uint16) -1) {
roentgen b75cab
			double* doubleav;
roentgen b75cab
			CopyField(tag, doubleav);
roentgen b75cab
		}
roentgen b75cab
		break;
roentgen b75cab
	default:
roentgen b75cab
		TIFFError(TIFFFileName(in),
roentgen b75cab
		    "Data type %d is not supported, tag %d skipped.",
roentgen b75cab
		    tag, type);
roentgen b75cab
	}
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
static struct cpTag {
roentgen b75cab
	uint16 tag;
roentgen b75cab
	uint16 count;
roentgen b75cab
	TIFFDataType type;
roentgen b75cab
} tags[] = {
roentgen b75cab
	{ TIFFTAG_SUBFILETYPE,		1, TIFF_LONG },
roentgen b75cab
	{ TIFFTAG_THRESHHOLDING,	1, TIFF_SHORT },
roentgen b75cab
	{ TIFFTAG_DOCUMENTNAME,		1, TIFF_ASCII },
roentgen b75cab
	{ TIFFTAG_IMAGEDESCRIPTION,	1, TIFF_ASCII },
roentgen b75cab
	{ TIFFTAG_MAKE,			1, TIFF_ASCII },
roentgen b75cab
	{ TIFFTAG_MODEL,		1, TIFF_ASCII },
roentgen b75cab
	{ TIFFTAG_MINSAMPLEVALUE,	1, TIFF_SHORT },
roentgen b75cab
	{ TIFFTAG_MAXSAMPLEVALUE,	1, TIFF_SHORT },
roentgen b75cab
	{ TIFFTAG_XRESOLUTION,		1, TIFF_RATIONAL },
roentgen b75cab
	{ TIFFTAG_YRESOLUTION,		1, TIFF_RATIONAL },
roentgen b75cab
	{ TIFFTAG_PAGENAME,		1, TIFF_ASCII },
roentgen b75cab
	{ TIFFTAG_XPOSITION,		1, TIFF_RATIONAL },
roentgen b75cab
	{ TIFFTAG_YPOSITION,		1, TIFF_RATIONAL },
roentgen b75cab
	{ TIFFTAG_RESOLUTIONUNIT,	1, TIFF_SHORT },
roentgen b75cab
	{ TIFFTAG_SOFTWARE,		1, TIFF_ASCII },
roentgen b75cab
	{ TIFFTAG_DATETIME,		1, TIFF_ASCII },
roentgen b75cab
	{ TIFFTAG_ARTIST,		1, TIFF_ASCII },
roentgen b75cab
	{ TIFFTAG_HOSTCOMPUTER,		1, TIFF_ASCII },
roentgen b75cab
	{ TIFFTAG_WHITEPOINT,		(uint16) -1, TIFF_RATIONAL },
roentgen b75cab
	{ TIFFTAG_PRIMARYCHROMATICITIES,(uint16) -1,TIFF_RATIONAL },
roentgen b75cab
	{ TIFFTAG_HALFTONEHINTS,	2, TIFF_SHORT },
roentgen b75cab
	{ TIFFTAG_INKSET,		1, TIFF_SHORT },
roentgen b75cab
	{ TIFFTAG_DOTRANGE,		2, TIFF_SHORT },
roentgen b75cab
	{ TIFFTAG_TARGETPRINTER,	1, TIFF_ASCII },
roentgen b75cab
	{ TIFFTAG_SAMPLEFORMAT,		1, TIFF_SHORT },
roentgen b75cab
	{ TIFFTAG_YCBCRCOEFFICIENTS,	(uint16) -1,TIFF_RATIONAL },
roentgen b75cab
	{ TIFFTAG_YCBCRSUBSAMPLING,	2, TIFF_SHORT },
roentgen b75cab
	{ TIFFTAG_YCBCRPOSITIONING,	1, TIFF_SHORT },
roentgen b75cab
	{ TIFFTAG_REFERENCEBLACKWHITE,	(uint16) -1,TIFF_RATIONAL },
roentgen b75cab
	{ TIFFTAG_EXTRASAMPLES,		(uint16) -1, TIFF_SHORT },
roentgen b75cab
	{ TIFFTAG_SMINSAMPLEVALUE,	1, TIFF_DOUBLE },
roentgen b75cab
	{ TIFFTAG_SMAXSAMPLEVALUE,	1, TIFF_DOUBLE },
roentgen b75cab
	{ TIFFTAG_STONITS,		1, TIFF_DOUBLE },
roentgen b75cab
};
roentgen b75cab
#define	NTAGS	(sizeof (tags) / sizeof (tags[0]))
roentgen b75cab
roentgen b75cab
#define	CopyTag(tag, count, type)	cpTag(in, out, tag, count, type)
roentgen b75cab
roentgen b75cab
typedef int (*copyFunc)
roentgen b75cab
    (TIFF* in, TIFF* out, uint32 l, uint32 w, uint16 samplesperpixel);
roentgen b75cab
static	copyFunc pickCopyFunc(TIFF*, TIFF*, uint16, uint16);
roentgen b75cab
roentgen b75cab
/* PODD */
roentgen b75cab
roentgen b75cab
static int
roentgen b75cab
tiffcp(TIFF* in, TIFF* out)
roentgen b75cab
{
roentgen b75cab
	uint16 bitspersample, samplesperpixel;
roentgen b75cab
	uint16 input_compression, input_photometric;
roentgen b75cab
	copyFunc cf;
roentgen b75cab
	uint32 width, length;
roentgen b75cab
	struct cpTag* p;
roentgen b75cab
roentgen b75cab
	CopyField(TIFFTAG_IMAGEWIDTH, width);
roentgen b75cab
	CopyField(TIFFTAG_IMAGELENGTH, length);
roentgen b75cab
	CopyField(TIFFTAG_BITSPERSAMPLE, bitspersample);
roentgen b75cab
	CopyField(TIFFTAG_SAMPLESPERPIXEL, samplesperpixel);
roentgen b75cab
	if (compression != (uint16)-1)
roentgen b75cab
		TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
roentgen b75cab
	else
roentgen b75cab
		CopyField(TIFFTAG_COMPRESSION, compression);
roentgen b75cab
	TIFFGetFieldDefaulted(in, TIFFTAG_COMPRESSION, &input_compression);
roentgen b75cab
	TIFFGetFieldDefaulted(in, TIFFTAG_PHOTOMETRIC, &input_photometric);
roentgen b75cab
	if (input_compression == COMPRESSION_JPEG) {
roentgen b75cab
		/* Force conversion to RGB */
roentgen b75cab
		TIFFSetField(in, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
roentgen b75cab
	} else if (input_photometric == PHOTOMETRIC_YCBCR) {
roentgen b75cab
		/* Otherwise, can't handle subsampled input */
roentgen b75cab
		uint16 subsamplinghor,subsamplingver;
roentgen b75cab
roentgen b75cab
		TIFFGetFieldDefaulted(in, TIFFTAG_YCBCRSUBSAMPLING,
roentgen b75cab
				      &subsamplinghor, &subsamplingver);
roentgen b75cab
		if (subsamplinghor!=1 || subsamplingver!=1) {
roentgen b75cab
			fprintf(stderr, "tiffcp: %s: Can't copy/convert subsampled image.\n",
roentgen b75cab
				TIFFFileName(in));
roentgen b75cab
			return FALSE;
roentgen b75cab
		}
roentgen b75cab
	}
roentgen b75cab
	if (compression == COMPRESSION_JPEG) {
roentgen b75cab
		if (input_photometric == PHOTOMETRIC_RGB &&
roentgen b75cab
		    jpegcolormode == JPEGCOLORMODE_RGB)
roentgen b75cab
		  TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR);
roentgen b75cab
		else
roentgen b75cab
		  TIFFSetField(out, TIFFTAG_PHOTOMETRIC, input_photometric);
roentgen b75cab
	}
roentgen b75cab
	else if (compression == COMPRESSION_SGILOG
roentgen b75cab
	    || compression == COMPRESSION_SGILOG24)
roentgen b75cab
		TIFFSetField(out, TIFFTAG_PHOTOMETRIC,
roentgen b75cab
		    samplesperpixel == 1 ?
roentgen b75cab
		    PHOTOMETRIC_LOGL : PHOTOMETRIC_LOGLUV);
roentgen b75cab
	else
roentgen b75cab
		CopyTag(TIFFTAG_PHOTOMETRIC, 1, TIFF_SHORT);
roentgen b75cab
	if (fillorder != 0)
roentgen b75cab
		TIFFSetField(out, TIFFTAG_FILLORDER, fillorder);
roentgen b75cab
	else
roentgen b75cab
		CopyTag(TIFFTAG_FILLORDER, 1, TIFF_SHORT);
roentgen b75cab
	/*
roentgen b75cab
	 * Will copy `Orientation' tag from input image
roentgen b75cab
	 */
roentgen b75cab
	TIFFGetFieldDefaulted(in, TIFFTAG_ORIENTATION, &orientation);
roentgen b75cab
	switch (orientation) {
roentgen b75cab
		case ORIENTATION_BOTRIGHT:
roentgen b75cab
		case ORIENTATION_RIGHTBOT:	/* XXX */
roentgen b75cab
			TIFFWarning(TIFFFileName(in), "using bottom-left orientation");
roentgen b75cab
			orientation = ORIENTATION_BOTLEFT;
roentgen b75cab
		/* fall thru... */
roentgen b75cab
		case ORIENTATION_LEFTBOT:	/* XXX */
roentgen b75cab
		case ORIENTATION_BOTLEFT:
roentgen b75cab
			break;
roentgen b75cab
		case ORIENTATION_TOPRIGHT:
roentgen b75cab
		case ORIENTATION_RIGHTTOP:	/* XXX */
roentgen b75cab
		default:
roentgen b75cab
			TIFFWarning(TIFFFileName(in), "using top-left orientation");
roentgen b75cab
			orientation = ORIENTATION_TOPLEFT;
roentgen b75cab
		/* fall thru... */
roentgen b75cab
		case ORIENTATION_LEFTTOP:	/* XXX */
roentgen b75cab
		case ORIENTATION_TOPLEFT:
roentgen b75cab
			break;
roentgen b75cab
	}
roentgen b75cab
	TIFFSetField(out, TIFFTAG_ORIENTATION, orientation);
roentgen b75cab
	/*
roentgen b75cab
	 * Choose tiles/strip for the output image according to
roentgen b75cab
	 * the command line arguments (-tiles, -strips) and the
roentgen b75cab
	 * structure of the input image.
roentgen b75cab
	 */
roentgen b75cab
	if (outtiled == -1)
roentgen b75cab
		outtiled = TIFFIsTiled(in);
roentgen b75cab
	if (outtiled) {
roentgen b75cab
		/*
roentgen b75cab
		 * Setup output file's tile width&height.  If either
roentgen b75cab
		 * is not specified, use either the value from the
roentgen b75cab
		 * input image or, if nothing is defined, use the
roentgen b75cab
		 * library default.
roentgen b75cab
		 */
roentgen b75cab
		if (tilewidth == (uint32) -1)
roentgen b75cab
			TIFFGetField(in, TIFFTAG_TILEWIDTH, &tilewidth);
roentgen b75cab
		if (tilelength == (uint32) -1)
roentgen b75cab
			TIFFGetField(in, TIFFTAG_TILELENGTH, &tilelength);
roentgen b75cab
		TIFFDefaultTileSize(out, &tilewidth, &tilelength);
roentgen b75cab
		TIFFSetField(out, TIFFTAG_TILEWIDTH, tilewidth);
roentgen b75cab
		TIFFSetField(out, TIFFTAG_TILELENGTH, tilelength);
roentgen b75cab
	} else {
roentgen b75cab
		/*
roentgen b75cab
		 * RowsPerStrip is left unspecified: use either the
roentgen b75cab
		 * value from the input image or, if nothing is defined,
roentgen b75cab
		 * use the library default.
roentgen b75cab
		 */
roentgen b75cab
		if (rowsperstrip == (uint32) 0) {
roentgen b75cab
			if (!TIFFGetField(in, TIFFTAG_ROWSPERSTRIP,
roentgen b75cab
			    &rowsperstrip)) {
roentgen b75cab
				rowsperstrip =
roentgen b75cab
				    TIFFDefaultStripSize(out, rowsperstrip);
roentgen b75cab
			}
roentgen b75cab
			if (rowsperstrip > length && rowsperstrip != (uint32)-1)
roentgen b75cab
				rowsperstrip = length;
roentgen b75cab
		}
roentgen b75cab
		else if (rowsperstrip == (uint32) -1)
roentgen b75cab
			rowsperstrip = length;
roentgen b75cab
		TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
roentgen b75cab
	}
roentgen b75cab
	if (config != (uint16) -1)
roentgen b75cab
		TIFFSetField(out, TIFFTAG_PLANARCONFIG, config);
roentgen b75cab
	else
roentgen b75cab
		CopyField(TIFFTAG_PLANARCONFIG, config);
roentgen b75cab
	if (samplesperpixel <= 4)
roentgen b75cab
		CopyTag(TIFFTAG_TRANSFERFUNCTION, 4, TIFF_SHORT);
roentgen b75cab
	CopyTag(TIFFTAG_COLORMAP, 4, TIFF_SHORT);
roentgen b75cab
/* SMinSampleValue & SMaxSampleValue */
roentgen b75cab
	switch (compression) {
roentgen b75cab
		case COMPRESSION_JPEG:
roentgen b75cab
			TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality);
roentgen b75cab
			TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode);
roentgen b75cab
			break;
roentgen b75cab
		case COMPRESSION_JBIG:
roentgen b75cab
			CopyTag(TIFFTAG_FAXRECVPARAMS, 1, TIFF_LONG);
roentgen b75cab
			CopyTag(TIFFTAG_FAXRECVTIME, 1, TIFF_LONG);
roentgen b75cab
			CopyTag(TIFFTAG_FAXSUBADDRESS, 1, TIFF_ASCII);
roentgen b75cab
			CopyTag(TIFFTAG_FAXDCS, 1, TIFF_ASCII);
roentgen b75cab
			break;
roentgen b75cab
		case COMPRESSION_LZW:
roentgen b75cab
		case COMPRESSION_ADOBE_DEFLATE:
roentgen b75cab
		case COMPRESSION_DEFLATE:
roentgen b75cab
                case COMPRESSION_LZMA:
roentgen b75cab
			if (predictor != (uint16)-1)
roentgen b75cab
				TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
roentgen b75cab
			else
roentgen b75cab
				CopyField(TIFFTAG_PREDICTOR, predictor);
roentgen b75cab
			if (preset != -1) {
roentgen b75cab
                                if (compression == COMPRESSION_ADOBE_DEFLATE
roentgen b75cab
                                         || compression == COMPRESSION_DEFLATE)
roentgen b75cab
                                        TIFFSetField(out, TIFFTAG_ZIPQUALITY, preset);
roentgen b75cab
				else if (compression == COMPRESSION_LZMA)
roentgen b75cab
					TIFFSetField(out, TIFFTAG_LZMAPRESET, preset);
roentgen b75cab
                        }
roentgen b75cab
			break;
roentgen b75cab
		case COMPRESSION_CCITTFAX3:
roentgen b75cab
		case COMPRESSION_CCITTFAX4:
roentgen b75cab
			if (compression == COMPRESSION_CCITTFAX3) {
roentgen b75cab
				if (g3opts != (uint32) -1)
roentgen b75cab
					TIFFSetField(out, TIFFTAG_GROUP3OPTIONS,
roentgen b75cab
					    g3opts);
roentgen b75cab
				else
roentgen b75cab
					CopyField(TIFFTAG_GROUP3OPTIONS, g3opts);
roentgen b75cab
			} else
roentgen b75cab
				CopyTag(TIFFTAG_GROUP4OPTIONS, 1, TIFF_LONG);
roentgen b75cab
			CopyTag(TIFFTAG_BADFAXLINES, 1, TIFF_LONG);
roentgen b75cab
			CopyTag(TIFFTAG_CLEANFAXDATA, 1, TIFF_LONG);
roentgen b75cab
			CopyTag(TIFFTAG_CONSECUTIVEBADFAXLINES, 1, TIFF_LONG);
roentgen b75cab
			CopyTag(TIFFTAG_FAXRECVPARAMS, 1, TIFF_LONG);
roentgen b75cab
			CopyTag(TIFFTAG_FAXRECVTIME, 1, TIFF_LONG);
roentgen b75cab
			CopyTag(TIFFTAG_FAXSUBADDRESS, 1, TIFF_ASCII);
roentgen b75cab
			break;
roentgen b75cab
	}
roentgen b75cab
	{
roentgen b75cab
		uint32 len32;
roentgen b75cab
		void** data;
roentgen b75cab
		if (TIFFGetField(in, TIFFTAG_ICCPROFILE, &len32, &data))
roentgen b75cab
			TIFFSetField(out, TIFFTAG_ICCPROFILE, len32, data);
roentgen b75cab
	}
roentgen b75cab
	{
roentgen b75cab
		uint16 ninks;
roentgen b75cab
		const char* inknames;
roentgen b75cab
		if (TIFFGetField(in, TIFFTAG_NUMBEROFINKS, &ninks)) {
roentgen b75cab
			TIFFSetField(out, TIFFTAG_NUMBEROFINKS, ninks);
roentgen b75cab
			if (TIFFGetField(in, TIFFTAG_INKNAMES, &inknames)) {
roentgen b75cab
				int inknameslen = strlen(inknames) + 1;
roentgen b75cab
				const char* cp = inknames;
roentgen b75cab
				while (ninks > 1) {
roentgen b75cab
					cp = strchr(cp, '\0');
roentgen b75cab
                                        cp++;
roentgen b75cab
                                        inknameslen += (strlen(cp) + 1);
roentgen b75cab
					ninks--;
roentgen b75cab
				}
roentgen b75cab
				TIFFSetField(out, TIFFTAG_INKNAMES, inknameslen, inknames);
roentgen b75cab
			}
roentgen b75cab
		}
roentgen b75cab
	}
roentgen b75cab
	{
roentgen b75cab
		unsigned short pg0, pg1;
roentgen b75cab
roentgen b75cab
		if (pageInSeq == 1) {
roentgen b75cab
			if (pageNum < 0) /* only one input file */ {
roentgen b75cab
				if (TIFFGetField(in, TIFFTAG_PAGENUMBER, &pg0, &pg1))
roentgen b75cab
					TIFFSetField(out, TIFFTAG_PAGENUMBER, pg0, pg1);
roentgen b75cab
			} else
roentgen b75cab
				TIFFSetField(out, TIFFTAG_PAGENUMBER, pageNum++, 0);
roentgen b75cab
roentgen b75cab
		} else {
roentgen b75cab
			if (TIFFGetField(in, TIFFTAG_PAGENUMBER, &pg0, &pg1)) {
roentgen b75cab
				if (pageNum < 0) /* only one input file */
roentgen b75cab
					TIFFSetField(out, TIFFTAG_PAGENUMBER, pg0, pg1);
roentgen b75cab
				else
roentgen b75cab
					TIFFSetField(out, TIFFTAG_PAGENUMBER, pageNum++, 0);
roentgen b75cab
			}
roentgen b75cab
		}
roentgen b75cab
	}
roentgen b75cab
roentgen b75cab
	for (p = tags; p < &tags[NTAGS]; p++)
roentgen b75cab
		CopyTag(p->tag, p->count, p->type);
roentgen b75cab
roentgen b75cab
	cf = pickCopyFunc(in, out, bitspersample, samplesperpixel);
roentgen b75cab
	return (cf ? (*cf)(in, out, length, width, samplesperpixel) : FALSE);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
/*
roentgen b75cab
 * Copy Functions.
roentgen b75cab
 */
roentgen b75cab
#define	DECLAREcpFunc(x) \
roentgen b75cab
static int x(TIFF* in, TIFF* out, \
roentgen b75cab
    uint32 imagelength, uint32 imagewidth, tsample_t spp)
roentgen b75cab
roentgen b75cab
#define	DECLAREreadFunc(x) \
roentgen b75cab
static int x(TIFF* in, \
roentgen b75cab
    uint8* buf, uint32 imagelength, uint32 imagewidth, tsample_t spp)
roentgen b75cab
typedef int (*readFunc)(TIFF*, uint8*, uint32, uint32, tsample_t);
roentgen b75cab
roentgen b75cab
#define	DECLAREwriteFunc(x) \
roentgen b75cab
static int x(TIFF* out, \
roentgen b75cab
    uint8* buf, uint32 imagelength, uint32 imagewidth, tsample_t spp)
roentgen b75cab
typedef int (*writeFunc)(TIFF*, uint8*, uint32, uint32, tsample_t);
roentgen b75cab
roentgen b75cab
/*
roentgen b75cab
 * Contig -> contig by scanline for rows/strip change.
roentgen b75cab
 */
roentgen b75cab
DECLAREcpFunc(cpContig2ContigByRow)
roentgen b75cab
{
roentgen b75cab
	tsize_t scanlinesize = TIFFScanlineSize(in);
roentgen b75cab
	tdata_t buf;
roentgen b75cab
	uint32 row;
roentgen b75cab
roentgen b75cab
	buf = _TIFFmalloc(scanlinesize);
roentgen b75cab
	if (!buf)
roentgen b75cab
		return 0;
roentgen b75cab
	_TIFFmemset(buf, 0, scanlinesize);
roentgen b75cab
	(void) imagewidth; (void) spp;
roentgen b75cab
	for (row = 0; row < imagelength; row++) {
roentgen b75cab
		if (TIFFReadScanline(in, buf, row, 0) < 0 && !ignore) {
roentgen b75cab
			TIFFError(TIFFFileName(in),
roentgen b75cab
				  "Error, can't read scanline %lu",
roentgen b75cab
				  (unsigned long) row);
roentgen b75cab
			goto bad;
roentgen b75cab
		}
roentgen b75cab
		if (TIFFWriteScanline(out, buf, row, 0) < 0) {
roentgen b75cab
			TIFFError(TIFFFileName(out),
roentgen b75cab
				  "Error, can't write scanline %lu",
roentgen b75cab
				  (unsigned long) row);
roentgen b75cab
			goto bad;
roentgen b75cab
		}
roentgen b75cab
	}
roentgen b75cab
	_TIFFfree(buf);
roentgen b75cab
	return 1;
roentgen b75cab
bad:
roentgen b75cab
	_TIFFfree(buf);
roentgen b75cab
	return 0;
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
roentgen b75cab
typedef void biasFn (void *image, void *bias, uint32 pixels);
roentgen b75cab
roentgen b75cab
#define subtract(bits) \
roentgen b75cab
static void subtract##bits (void *i, void *b, uint32 pixels)\
roentgen b75cab
{\
roentgen b75cab
   uint##bits *image = i;\
roentgen b75cab
   uint##bits *bias = b;\
roentgen b75cab
   while (pixels--) {\
roentgen b75cab
     *image = *image > *bias ? *image-*bias : 0;\
roentgen b75cab
     image++, bias++; \
roentgen b75cab
   } \
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
subtract(8)
roentgen b75cab
subtract(16)
roentgen b75cab
subtract(32)
roentgen b75cab
roentgen b75cab
static biasFn *lineSubtractFn (unsigned bits)
roentgen b75cab
{
roentgen b75cab
	switch (bits) {
roentgen b75cab
		case  8:  return subtract8;
roentgen b75cab
		case 16:  return subtract16;
roentgen b75cab
		case 32:  return subtract32;
roentgen b75cab
	}
roentgen b75cab
	return NULL;
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
/*
roentgen b75cab
 * Contig -> contig by scanline while subtracting a bias image.
roentgen b75cab
 */
roentgen b75cab
DECLAREcpFunc(cpBiasedContig2Contig)
roentgen b75cab
{
roentgen b75cab
	if (spp == 1) {
roentgen b75cab
		tsize_t biasSize = TIFFScanlineSize(bias);
roentgen b75cab
		tsize_t bufSize = TIFFScanlineSize(in);
roentgen b75cab
		tdata_t buf, biasBuf;
roentgen b75cab
		uint32 biasWidth = 0, biasLength = 0;
roentgen b75cab
		TIFFGetField(bias, TIFFTAG_IMAGEWIDTH, &biasWidth);
roentgen b75cab
		TIFFGetField(bias, TIFFTAG_IMAGELENGTH, &biasLength);
roentgen b75cab
		if (biasSize == bufSize &&
roentgen b75cab
		    imagelength == biasLength && imagewidth == biasWidth) {
roentgen b75cab
			uint16 sampleBits = 0;
roentgen b75cab
			biasFn *subtractLine;
roentgen b75cab
			TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &sampleBits);
roentgen b75cab
			subtractLine = lineSubtractFn (sampleBits);
roentgen b75cab
			if (subtractLine) {
roentgen b75cab
				uint32 row;
roentgen b75cab
				buf = _TIFFmalloc(bufSize);
roentgen b75cab
				biasBuf = _TIFFmalloc(bufSize);
roentgen b75cab
				for (row = 0; row < imagelength; row++) {
roentgen b75cab
					if (TIFFReadScanline(in, buf, row, 0) < 0
roentgen b75cab
					    && !ignore) {
roentgen b75cab
						TIFFError(TIFFFileName(in),
roentgen b75cab
						    "Error, can't read scanline %lu",
roentgen b75cab
						    (unsigned long) row);
roentgen b75cab
						goto bad;
roentgen b75cab
					}
roentgen b75cab
					if (TIFFReadScanline(bias, biasBuf, row, 0) < 0
roentgen b75cab
					    && !ignore) {
roentgen b75cab
						TIFFError(TIFFFileName(in),
roentgen b75cab
						    "Error, can't read biased scanline %lu",
roentgen b75cab
						    (unsigned long) row);
roentgen b75cab
						goto bad;
roentgen b75cab
					}
roentgen b75cab
					subtractLine (buf, biasBuf, imagewidth);
roentgen b75cab
					if (TIFFWriteScanline(out, buf, row, 0) < 0) {
roentgen b75cab
						TIFFError(TIFFFileName(out),
roentgen b75cab
						    "Error, can't write scanline %lu",
roentgen b75cab
						    (unsigned long) row);
roentgen b75cab
						goto bad;
roentgen b75cab
					}
roentgen b75cab
				}
roentgen b75cab
roentgen b75cab
				_TIFFfree(buf);
roentgen b75cab
				_TIFFfree(biasBuf);
roentgen b75cab
				TIFFSetDirectory(bias,
roentgen b75cab
				    TIFFCurrentDirectory(bias)); /* rewind */
roentgen b75cab
				return 1;
roentgen b75cab
bad:
roentgen b75cab
				_TIFFfree(buf);
roentgen b75cab
				_TIFFfree(biasBuf);
roentgen b75cab
				return 0;
roentgen b75cab
			} else {
roentgen b75cab
				TIFFError(TIFFFileName(in),
roentgen b75cab
				    "No support for biasing %d bit pixels\n",
roentgen b75cab
				    sampleBits);
roentgen b75cab
				return 0;
roentgen b75cab
			}
roentgen b75cab
		}
roentgen b75cab
		TIFFError(TIFFFileName(in),
roentgen b75cab
		    "Bias image %s,%d\nis not the same size as %s,%d\n",
roentgen b75cab
		    TIFFFileName(bias), TIFFCurrentDirectory(bias),
roentgen b75cab
		    TIFFFileName(in), TIFFCurrentDirectory(in));
roentgen b75cab
		return 0;
roentgen b75cab
	} else {
roentgen b75cab
		TIFFError(TIFFFileName(in),
roentgen b75cab
		    "Can't bias %s,%d as it has >1 Sample/Pixel\n",
roentgen b75cab
		    TIFFFileName(in), TIFFCurrentDirectory(in));
roentgen b75cab
		return 0;
roentgen b75cab
	}
roentgen b75cab
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
roentgen b75cab
/*
roentgen b75cab
 * Strip -> strip for change in encoding.
roentgen b75cab
 */
roentgen b75cab
DECLAREcpFunc(cpDecodedStrips)
roentgen b75cab
{
roentgen b75cab
	tsize_t stripsize  = TIFFStripSize(in);
roentgen b75cab
	tdata_t buf = _TIFFmalloc(stripsize);
roentgen b75cab
roentgen b75cab
	(void) imagewidth; (void) spp;
roentgen b75cab
	if (buf) {
roentgen b75cab
		tstrip_t s, ns = TIFFNumberOfStrips(in);
roentgen b75cab
		uint32 row = 0;
roentgen b75cab
		_TIFFmemset(buf, 0, stripsize);
roentgen b75cab
		for (s = 0; s < ns; s++) {
roentgen b75cab
			tsize_t cc = (row + rowsperstrip > imagelength) ?
roentgen b75cab
			    TIFFVStripSize(in, imagelength - row) : stripsize;
roentgen b75cab
			if (TIFFReadEncodedStrip(in, s, buf, cc) < 0
roentgen b75cab
			    && !ignore) {
roentgen b75cab
				TIFFError(TIFFFileName(in),
roentgen b75cab
				    "Error, can't read strip %lu",
roentgen b75cab
				    (unsigned long) s);
roentgen b75cab
				goto bad;
roentgen b75cab
			}
roentgen b75cab
			if (TIFFWriteEncodedStrip(out, s, buf, cc) < 0) {
roentgen b75cab
				TIFFError(TIFFFileName(out),
roentgen b75cab
				    "Error, can't write strip %lu",
roentgen b75cab
				    (unsigned long) s);
roentgen b75cab
				goto bad;
roentgen b75cab
			}
roentgen b75cab
			row += rowsperstrip;
roentgen b75cab
		}
roentgen b75cab
		_TIFFfree(buf);
roentgen b75cab
		return 1;
roentgen b75cab
	} else {
roentgen b75cab
		TIFFError(TIFFFileName(in),
roentgen b75cab
		    "Error, can't allocate memory buffer of size %lu "
roentgen b75cab
		    "to read strips", (unsigned long) stripsize);
roentgen b75cab
		return 0;
roentgen b75cab
	}
roentgen b75cab
roentgen b75cab
bad:
roentgen b75cab
	_TIFFfree(buf);
roentgen b75cab
	return 0;
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
/*
roentgen b75cab
 * Separate -> separate by row for rows/strip change.
roentgen b75cab
 */
roentgen b75cab
DECLAREcpFunc(cpSeparate2SeparateByRow)
roentgen b75cab
{
roentgen b75cab
	tsize_t scanlinesize = TIFFScanlineSize(in);
roentgen b75cab
	tdata_t buf;
roentgen b75cab
	uint32 row;
roentgen b75cab
	tsample_t s;
roentgen b75cab
roentgen b75cab
	(void) imagewidth;
roentgen b75cab
	buf = _TIFFmalloc(scanlinesize);
roentgen b75cab
	if (!buf)
roentgen b75cab
		return 0;
roentgen b75cab
	_TIFFmemset(buf, 0, scanlinesize);
roentgen b75cab
	for (s = 0; s < spp; s++) {
roentgen b75cab
		for (row = 0; row < imagelength; row++) {
roentgen b75cab
			if (TIFFReadScanline(in, buf, row, s) < 0 && !ignore) {
roentgen b75cab
				TIFFError(TIFFFileName(in),
roentgen b75cab
				    "Error, can't read scanline %lu",
roentgen b75cab
				    (unsigned long) row);
roentgen b75cab
				goto bad;
roentgen b75cab
			}
roentgen b75cab
			if (TIFFWriteScanline(out, buf, row, s) < 0) {
roentgen b75cab
				TIFFError(TIFFFileName(out),
roentgen b75cab
				    "Error, can't write scanline %lu",
roentgen b75cab
				    (unsigned long) row);
roentgen b75cab
				goto bad;
roentgen b75cab
			}
roentgen b75cab
		}
roentgen b75cab
	}
roentgen b75cab
	_TIFFfree(buf);
roentgen b75cab
	return 1;
roentgen b75cab
bad:
roentgen b75cab
	_TIFFfree(buf);
roentgen b75cab
	return 0;
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
/*
roentgen b75cab
 * Contig -> separate by row.
roentgen b75cab
 */
roentgen b75cab
DECLAREcpFunc(cpContig2SeparateByRow)
roentgen b75cab
{
roentgen b75cab
	tsize_t scanlinesizein = TIFFScanlineSize(in);
roentgen b75cab
	tsize_t scanlinesizeout = TIFFScanlineSize(out);
roentgen b75cab
	tdata_t inbuf;
roentgen b75cab
	tdata_t outbuf;
roentgen b75cab
	register uint8 *inp, *outp;
roentgen b75cab
	register uint32 n;
roentgen b75cab
	uint32 row;
roentgen b75cab
	tsample_t s;
roentgen b75cab
roentgen b75cab
	inbuf = _TIFFmalloc(scanlinesizein);
roentgen b75cab
	outbuf = _TIFFmalloc(scanlinesizeout);
roentgen b75cab
	if (!inbuf || !outbuf)
roentgen b75cab
		return 0;
roentgen b75cab
	_TIFFmemset(inbuf, 0, scanlinesizein);
roentgen b75cab
	_TIFFmemset(outbuf, 0, scanlinesizeout);
roentgen b75cab
	/* unpack channels */
roentgen b75cab
	for (s = 0; s < spp; s++) {
roentgen b75cab
		for (row = 0; row < imagelength; row++) {
roentgen b75cab
			if (TIFFReadScanline(in, inbuf, row, 0) < 0
roentgen b75cab
			    && !ignore) {
roentgen b75cab
				TIFFError(TIFFFileName(in),
roentgen b75cab
				    "Error, can't read scanline %lu",
roentgen b75cab
				    (unsigned long) row);
roentgen b75cab
				goto bad;
roentgen b75cab
			}
roentgen b75cab
			inp = ((uint8*)inbuf) + s;
roentgen b75cab
			outp = (uint8*)outbuf;
roentgen b75cab
			for (n = imagewidth; n-- > 0;) {
roentgen b75cab
				*outp++ = *inp;
roentgen b75cab
				inp += spp;
roentgen b75cab
			}
roentgen b75cab
			if (TIFFWriteScanline(out, outbuf, row, s) < 0) {
roentgen b75cab
				TIFFError(TIFFFileName(out),
roentgen b75cab
				    "Error, can't write scanline %lu",
roentgen b75cab
				    (unsigned long) row);
roentgen b75cab
				goto bad;
roentgen b75cab
			}
roentgen b75cab
		}
roentgen b75cab
	}
roentgen b75cab
	if (inbuf) _TIFFfree(inbuf);
roentgen b75cab
	if (outbuf) _TIFFfree(outbuf);
roentgen b75cab
	return 1;
roentgen b75cab
bad:
roentgen b75cab
	if (inbuf) _TIFFfree(inbuf);
roentgen b75cab
	if (outbuf) _TIFFfree(outbuf);
roentgen b75cab
	return 0;
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
/*
roentgen b75cab
 * Separate -> contig by row.
roentgen b75cab
 */
roentgen b75cab
DECLAREcpFunc(cpSeparate2ContigByRow)
roentgen b75cab
{
roentgen b75cab
	tsize_t scanlinesizein = TIFFScanlineSize(in);
roentgen b75cab
	tsize_t scanlinesizeout = TIFFScanlineSize(out);
roentgen b75cab
	tdata_t inbuf;
roentgen b75cab
	tdata_t outbuf;
roentgen b75cab
	register uint8 *inp, *outp;
roentgen b75cab
	register uint32 n;
roentgen b75cab
	uint32 row;
roentgen b75cab
	tsample_t s;
roentgen b75cab
roentgen b75cab
	inbuf = _TIFFmalloc(scanlinesizein);
roentgen b75cab
	outbuf = _TIFFmalloc(scanlinesizeout);
roentgen b75cab
	if (!inbuf || !outbuf)
roentgen b75cab
		return 0;
roentgen b75cab
	_TIFFmemset(inbuf, 0, scanlinesizein);
roentgen b75cab
	_TIFFmemset(outbuf, 0, scanlinesizeout);
roentgen b75cab
	for (row = 0; row < imagelength; row++) {
roentgen b75cab
		/* merge channels */
roentgen b75cab
		for (s = 0; s < spp; s++) {
roentgen b75cab
			if (TIFFReadScanline(in, inbuf, row, s) < 0
roentgen b75cab
			    && !ignore) {
roentgen b75cab
				TIFFError(TIFFFileName(in),
roentgen b75cab
				    "Error, can't read scanline %lu",
roentgen b75cab
				    (unsigned long) row);
roentgen b75cab
				goto bad;
roentgen b75cab
			}
roentgen b75cab
			inp = (uint8*)inbuf;
roentgen b75cab
			outp = ((uint8*)outbuf) + s;
roentgen b75cab
			for (n = imagewidth; n-- > 0;) {
roentgen b75cab
				*outp = *inp++;
roentgen b75cab
				outp += spp;
roentgen b75cab
			}
roentgen b75cab
		}
roentgen b75cab
		if (TIFFWriteScanline(out, outbuf, row, 0) < 0) {
roentgen b75cab
			TIFFError(TIFFFileName(out),
roentgen b75cab
			    "Error, can't write scanline %lu",
roentgen b75cab
			    (unsigned long) row);
roentgen b75cab
			goto bad;
roentgen b75cab
		}
roentgen b75cab
	}
roentgen b75cab
	if (inbuf) _TIFFfree(inbuf);
roentgen b75cab
	if (outbuf) _TIFFfree(outbuf);
roentgen b75cab
	return 1;
roentgen b75cab
bad:
roentgen b75cab
	if (inbuf) _TIFFfree(inbuf);
roentgen b75cab
	if (outbuf) _TIFFfree(outbuf);
roentgen b75cab
	return 0;
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
static void
roentgen b75cab
cpStripToTile(uint8* out, uint8* in,
roentgen b75cab
    uint32 rows, uint32 cols, int outskew, int inskew)
roentgen b75cab
{
roentgen b75cab
	while (rows-- > 0) {
roentgen b75cab
		uint32 j = cols;
roentgen b75cab
		while (j-- > 0)
roentgen b75cab
			*out++ = *in++;
roentgen b75cab
		out += outskew;
roentgen b75cab
		in += inskew;
roentgen b75cab
	}
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
static void
roentgen b75cab
cpContigBufToSeparateBuf(uint8* out, uint8* in,
roentgen b75cab
    uint32 rows, uint32 cols, int outskew, int inskew, tsample_t spp,
roentgen b75cab
    int bytes_per_sample )
roentgen b75cab
{
roentgen b75cab
	while (rows-- > 0) {
roentgen b75cab
		uint32 j = cols;
roentgen b75cab
		while (j-- > 0)
roentgen b75cab
		{
roentgen b75cab
			int n = bytes_per_sample;
roentgen b75cab
roentgen b75cab
			while( n-- ) {
roentgen b75cab
				*out++ = *in++;
roentgen b75cab
			}
roentgen b75cab
			in += (spp-1) * bytes_per_sample;
roentgen b75cab
		}
roentgen b75cab
		out += outskew;
roentgen b75cab
		in += inskew;
roentgen b75cab
	}
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
static void
roentgen b75cab
cpSeparateBufToContigBuf(uint8* out, uint8* in,
roentgen b75cab
    uint32 rows, uint32 cols, int outskew, int inskew, tsample_t spp,
roentgen b75cab
    int bytes_per_sample)
roentgen b75cab
{
roentgen b75cab
	while (rows-- > 0) {
roentgen b75cab
		uint32 j = cols;
roentgen b75cab
		while (j-- > 0) {
roentgen b75cab
			int n = bytes_per_sample;
roentgen b75cab
roentgen b75cab
			while( n-- ) {
roentgen b75cab
				*out++ = *in++;
roentgen b75cab
			}
roentgen b75cab
			out += (spp-1)*bytes_per_sample;
roentgen b75cab
		}
roentgen b75cab
		out += outskew;
roentgen b75cab
		in += inskew;
roentgen b75cab
	}
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
static int
roentgen b75cab
cpImage(TIFF* in, TIFF* out, readFunc fin, writeFunc fout,
roentgen b75cab
	uint32 imagelength, uint32 imagewidth, tsample_t spp)
roentgen b75cab
{
roentgen b75cab
	int status = 0;
roentgen b75cab
	tdata_t buf = NULL;
roentgen b75cab
	tsize_t scanlinesize = TIFFRasterScanlineSize(in);
roentgen b75cab
	tsize_t bytes = scanlinesize * (tsize_t)imagelength;
roentgen b75cab
	/*
roentgen b75cab
	 * XXX: Check for integer overflow.
roentgen b75cab
	 */
roentgen b75cab
	if (scanlinesize
roentgen b75cab
	    && imagelength
roentgen b75cab
	    && bytes / (tsize_t)imagelength == scanlinesize) {
roentgen b75cab
		buf = _TIFFmalloc(bytes);
roentgen b75cab
		if (buf) {
roentgen b75cab
			if ((*fin)(in, (uint8*)buf, imagelength,
roentgen b75cab
			    imagewidth, spp)) {
roentgen b75cab
				status = (*fout)(out, (uint8*)buf,
roentgen b75cab
				    imagelength, imagewidth, spp);
roentgen b75cab
			}
roentgen b75cab
			_TIFFfree(buf);
roentgen b75cab
		} else {
roentgen b75cab
			TIFFError(TIFFFileName(in),
roentgen b75cab
			    "Error, can't allocate space for image buffer");
roentgen b75cab
		}
roentgen b75cab
	} else {
roentgen b75cab
		TIFFError(TIFFFileName(in), "Error, no space for image buffer");
roentgen b75cab
	}
roentgen b75cab
roentgen b75cab
	return status;
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
DECLAREreadFunc(readContigStripsIntoBuffer)
roentgen b75cab
{
roentgen b75cab
	tsize_t scanlinesize = TIFFScanlineSize(in);
roentgen b75cab
	uint8* bufp = buf;
roentgen b75cab
	uint32 row;
roentgen b75cab
roentgen b75cab
	(void) imagewidth; (void) spp;
roentgen b75cab
	for (row = 0; row < imagelength; row++) {
roentgen b75cab
		if (TIFFReadScanline(in, (tdata_t) bufp, row, 0) < 0
roentgen b75cab
		    && !ignore) {
roentgen b75cab
			TIFFError(TIFFFileName(in),
roentgen b75cab
			    "Error, can't read scanline %lu",
roentgen b75cab
			    (unsigned long) row);
roentgen b75cab
			return 0;
roentgen b75cab
		}
roentgen b75cab
		bufp += scanlinesize;
roentgen b75cab
	}
roentgen b75cab
roentgen b75cab
	return 1;
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
DECLAREreadFunc(readSeparateStripsIntoBuffer)
roentgen b75cab
{
roentgen b75cab
	int status = 1;
roentgen b75cab
	tsize_t scanlinesize = TIFFScanlineSize(in);
roentgen b75cab
	tdata_t scanline;
roentgen b75cab
	if (!scanlinesize)
roentgen b75cab
		return 0;
roentgen b75cab
roentgen b75cab
	scanline = _TIFFmalloc(scanlinesize);
roentgen b75cab
	if (!scanline)
roentgen b75cab
		return 0;
roentgen b75cab
	_TIFFmemset(scanline, 0, scanlinesize);
roentgen b75cab
	(void) imagewidth;
roentgen b75cab
	if (scanline) {
roentgen b75cab
		uint8* bufp = (uint8*) buf;
roentgen b75cab
		uint32 row;
roentgen b75cab
		tsample_t s;
roentgen b75cab
		for (row = 0; row < imagelength; row++) {
roentgen b75cab
			/* merge channels */
roentgen b75cab
			for (s = 0; s < spp; s++) {
roentgen b75cab
				uint8* bp = bufp + s;
roentgen b75cab
				tsize_t n = scanlinesize;
roentgen b75cab
				uint8* sbuf = scanline;
roentgen b75cab
roentgen b75cab
				if (TIFFReadScanline(in, scanline, row, s) < 0
roentgen b75cab
				    && !ignore) {
roentgen b75cab
					TIFFError(TIFFFileName(in),
roentgen b75cab
					    "Error, can't read scanline %lu",
roentgen b75cab
					    (unsigned long) row);
roentgen b75cab
					    status = 0;
roentgen b75cab
					goto done;
roentgen b75cab
				}
roentgen b75cab
				while (n-- > 0)
roentgen b75cab
					*bp = *sbuf++, bp += spp;
roentgen b75cab
			}
roentgen b75cab
			bufp += scanlinesize * spp;
roentgen b75cab
		}
roentgen b75cab
	}
roentgen b75cab
roentgen b75cab
done:
roentgen b75cab
	_TIFFfree(scanline);
roentgen b75cab
	return status;
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
DECLAREreadFunc(readContigTilesIntoBuffer)
roentgen b75cab
{
roentgen b75cab
	int status = 1;
roentgen b75cab
	tsize_t tilesize = TIFFTileSize(in);
roentgen b75cab
	tdata_t tilebuf;
roentgen b75cab
	uint32 imagew = TIFFScanlineSize(in);
roentgen b75cab
	uint32 tilew  = TIFFTileRowSize(in);
roentgen b75cab
	int iskew = imagew - tilew;
roentgen b75cab
	uint8* bufp = (uint8*) buf;
roentgen b75cab
	uint32 tw, tl;
roentgen b75cab
	uint32 row;
roentgen b75cab
roentgen b75cab
	(void) spp;
roentgen b75cab
	tilebuf = _TIFFmalloc(tilesize);
roentgen b75cab
	if (tilebuf == 0)
roentgen b75cab
		return 0;
roentgen b75cab
	_TIFFmemset(tilebuf, 0, tilesize);
roentgen b75cab
	(void) TIFFGetField(in, TIFFTAG_TILEWIDTH, &tw);
roentgen b75cab
	(void) TIFFGetField(in, TIFFTAG_TILELENGTH, &tl);
roentgen b75cab
        
roentgen b75cab
	for (row = 0; row < imagelength; row += tl) {
roentgen b75cab
		uint32 nrow = (row+tl > imagelength) ? imagelength-row : tl;
roentgen b75cab
		uint32 colb = 0;
roentgen b75cab
		uint32 col;
roentgen b75cab
roentgen b75cab
		for (col = 0; col < imagewidth; col += tw) {
roentgen b75cab
			if (TIFFReadTile(in, tilebuf, col, row, 0, 0) < 0
roentgen b75cab
			    && !ignore) {
roentgen b75cab
				TIFFError(TIFFFileName(in),
roentgen b75cab
				    "Error, can't read tile at %lu %lu",
roentgen b75cab
				    (unsigned long) col,
roentgen b75cab
				    (unsigned long) row);
roentgen b75cab
				status = 0;
roentgen b75cab
				goto done;
roentgen b75cab
			}
roentgen b75cab
			if (colb + tilew > imagew) {
roentgen b75cab
				uint32 width = imagew - colb;
roentgen b75cab
				uint32 oskew = tilew - width;
roentgen b75cab
				cpStripToTile(bufp + colb,
roentgen b75cab
				    tilebuf, nrow, width,
roentgen b75cab
				    oskew + iskew, oskew );
roentgen b75cab
			} else
roentgen b75cab
				cpStripToTile(bufp + colb,
roentgen b75cab
				    tilebuf, nrow, tilew,
roentgen b75cab
				    iskew, 0);
roentgen b75cab
			colb += tilew;
roentgen b75cab
		}
roentgen b75cab
		bufp += imagew * nrow;
roentgen b75cab
	}
roentgen b75cab
done:
roentgen b75cab
	_TIFFfree(tilebuf);
roentgen b75cab
	return status;
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
DECLAREreadFunc(readSeparateTilesIntoBuffer)
roentgen b75cab
{
roentgen b75cab
	int status = 1;
roentgen b75cab
	uint32 imagew = TIFFRasterScanlineSize(in);
roentgen b75cab
	uint32 tilew = TIFFTileRowSize(in);
roentgen b75cab
	int iskew  = imagew - tilew*spp;
roentgen b75cab
	tsize_t tilesize = TIFFTileSize(in);
roentgen b75cab
	tdata_t tilebuf;
roentgen b75cab
	uint8* bufp = (uint8*) buf;
roentgen b75cab
	uint32 tw, tl;
roentgen b75cab
	uint32 row;
roentgen b75cab
	uint16 bps, bytes_per_sample;
roentgen b75cab
roentgen b75cab
	tilebuf = _TIFFmalloc(tilesize);
roentgen b75cab
	if (tilebuf == 0)
roentgen b75cab
		return 0;
roentgen b75cab
	_TIFFmemset(tilebuf, 0, tilesize);
roentgen b75cab
	(void) TIFFGetField(in, TIFFTAG_TILEWIDTH, &tw);
roentgen b75cab
	(void) TIFFGetField(in, TIFFTAG_TILELENGTH, &tl);
roentgen b75cab
	(void) TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bps);
roentgen b75cab
	assert( bps % 8 == 0 );
roentgen b75cab
	bytes_per_sample = bps/8;
roentgen b75cab
roentgen b75cab
	for (row = 0; row < imagelength; row += tl) {
roentgen b75cab
		uint32 nrow = (row+tl > imagelength) ? imagelength-row : tl;
roentgen b75cab
		uint32 colb = 0;
roentgen b75cab
		uint32 col;
roentgen b75cab
roentgen b75cab
		for (col = 0; col < imagewidth; col += tw) {
roentgen b75cab
			tsample_t s;
roentgen b75cab
roentgen b75cab
			for (s = 0; s < spp; s++) {
roentgen b75cab
				if (TIFFReadTile(in, tilebuf, col, row, 0, s) < 0
roentgen b75cab
				    && !ignore) {
roentgen b75cab
					TIFFError(TIFFFileName(in),
roentgen b75cab
					    "Error, can't read tile at %lu %lu, "
roentgen b75cab
					    "sample %lu",
roentgen b75cab
					    (unsigned long) col,
roentgen b75cab
					    (unsigned long) row,
roentgen b75cab
					    (unsigned long) s);
roentgen b75cab
					status = 0;
roentgen b75cab
					goto done;
roentgen b75cab
				}
roentgen b75cab
				/*
roentgen b75cab
				 * Tile is clipped horizontally.  Calculate
roentgen b75cab
				 * visible portion and skewing factors.
roentgen b75cab
				 */
roentgen b75cab
				if (colb + tilew*spp > imagew) {
roentgen b75cab
					uint32 width = imagew - colb;
roentgen b75cab
					int oskew = tilew*spp - width;
roentgen b75cab
					cpSeparateBufToContigBuf(
roentgen b75cab
					    bufp+colb+s*bytes_per_sample,
roentgen b75cab
					    tilebuf, nrow,
roentgen b75cab
					    width/(spp*bytes_per_sample),
roentgen b75cab
					    oskew + iskew,
roentgen b75cab
					    oskew/spp, spp,
roentgen b75cab
					    bytes_per_sample);
roentgen b75cab
				} else
roentgen b75cab
					cpSeparateBufToContigBuf(
roentgen b75cab
					    bufp+colb+s*bytes_per_sample,
roentgen b75cab
					    tilebuf, nrow, tw,
roentgen b75cab
					    iskew, 0, spp,
roentgen b75cab
					    bytes_per_sample);
roentgen b75cab
			}
roentgen b75cab
			colb += tilew*spp;
roentgen b75cab
		}
roentgen b75cab
		bufp += imagew * nrow;
roentgen b75cab
	}
roentgen b75cab
done:
roentgen b75cab
	_TIFFfree(tilebuf);
roentgen b75cab
	return status;
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
DECLAREwriteFunc(writeBufferToContigStrips)
roentgen b75cab
{
roentgen b75cab
	uint32 row, rowsperstrip;
roentgen b75cab
	tstrip_t strip = 0;
roentgen b75cab
roentgen b75cab
	(void) imagewidth; (void) spp;
roentgen b75cab
	(void) TIFFGetFieldDefaulted(out, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
roentgen b75cab
	for (row = 0; row < imagelength; row += rowsperstrip) {
roentgen b75cab
		uint32 nrows = (row+rowsperstrip > imagelength) ?
roentgen b75cab
		    imagelength-row : rowsperstrip;
roentgen b75cab
		tsize_t stripsize = TIFFVStripSize(out, nrows);
roentgen b75cab
		if (TIFFWriteEncodedStrip(out, strip++, buf, stripsize) < 0) {
roentgen b75cab
			TIFFError(TIFFFileName(out),
roentgen b75cab
			    "Error, can't write strip %u", strip - 1);
roentgen b75cab
			return 0;
roentgen b75cab
		}
roentgen b75cab
		buf += stripsize;
roentgen b75cab
	}
roentgen b75cab
	return 1;
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
DECLAREwriteFunc(writeBufferToSeparateStrips)
roentgen b75cab
{
roentgen b75cab
	uint32 rowsize = imagewidth * spp;
roentgen b75cab
	uint32 rowsperstrip;
roentgen b75cab
	tsize_t stripsize = TIFFStripSize(out);
roentgen b75cab
	tdata_t obuf;
roentgen b75cab
	tstrip_t strip = 0;
roentgen b75cab
	tsample_t s;
roentgen b75cab
roentgen b75cab
	obuf = _TIFFmalloc(stripsize);
roentgen b75cab
	if (obuf == NULL)
roentgen b75cab
		return (0);
roentgen b75cab
	_TIFFmemset(obuf, 0, stripsize);
roentgen b75cab
	(void) TIFFGetFieldDefaulted(out, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
roentgen b75cab
	for (s = 0; s < spp; s++) {
roentgen b75cab
		uint32 row;
roentgen b75cab
		for (row = 0; row < imagelength; row += rowsperstrip) {
roentgen b75cab
			uint32 nrows = (row+rowsperstrip > imagelength) ?
roentgen b75cab
			    imagelength-row : rowsperstrip;
roentgen b75cab
			tsize_t stripsize = TIFFVStripSize(out, nrows);
roentgen b75cab
roentgen b75cab
			cpContigBufToSeparateBuf(
roentgen b75cab
			    obuf, (uint8*) buf + row*rowsize + s,
roentgen b75cab
			    nrows, imagewidth, 0, 0, spp, 1);
roentgen b75cab
			if (TIFFWriteEncodedStrip(out, strip++, obuf, stripsize) < 0) {
roentgen b75cab
				TIFFError(TIFFFileName(out),
roentgen b75cab
				    "Error, can't write strip %u",
roentgen b75cab
				    strip - 1);
roentgen b75cab
				_TIFFfree(obuf);
roentgen b75cab
				return 0;
roentgen b75cab
			}
roentgen b75cab
		}
roentgen b75cab
	}
roentgen b75cab
	_TIFFfree(obuf);
roentgen b75cab
	return 1;
roentgen b75cab
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
DECLAREwriteFunc(writeBufferToContigTiles)
roentgen b75cab
{
roentgen b75cab
	uint32 imagew = TIFFScanlineSize(out);
roentgen b75cab
	uint32 tilew  = TIFFTileRowSize(out);
roentgen b75cab
	int iskew = imagew - tilew;
roentgen b75cab
	tsize_t tilesize = TIFFTileSize(out);
roentgen b75cab
	tdata_t obuf;
roentgen b75cab
	uint8* bufp = (uint8*) buf;
roentgen b75cab
	uint32 tl, tw;
roentgen b75cab
	uint32 row;
roentgen b75cab
roentgen b75cab
	(void) spp;
roentgen b75cab
roentgen b75cab
	obuf = _TIFFmalloc(TIFFTileSize(out));
roentgen b75cab
	if (obuf == NULL)
roentgen b75cab
		return 0;
roentgen b75cab
	_TIFFmemset(obuf, 0, tilesize);
roentgen b75cab
	(void) TIFFGetField(out, TIFFTAG_TILELENGTH, &tl);
roentgen b75cab
	(void) TIFFGetField(out, TIFFTAG_TILEWIDTH, &tw);
roentgen b75cab
	for (row = 0; row < imagelength; row += tilelength) {
roentgen b75cab
		uint32 nrow = (row+tl > imagelength) ? imagelength-row : tl;
roentgen b75cab
		uint32 colb = 0;
roentgen b75cab
		uint32 col;
roentgen b75cab
roentgen b75cab
		for (col = 0; col < imagewidth; col += tw) {
roentgen b75cab
			/*
roentgen b75cab
			 * Tile is clipped horizontally.  Calculate
roentgen b75cab
			 * visible portion and skewing factors.
roentgen b75cab
			 */
roentgen b75cab
			if (colb + tilew > imagew) {
roentgen b75cab
				uint32 width = imagew - colb;
roentgen b75cab
				int oskew = tilew - width;
roentgen b75cab
				cpStripToTile(obuf, bufp + colb, nrow, width,
roentgen b75cab
				    oskew, oskew + iskew);
roentgen b75cab
			} else
roentgen b75cab
				cpStripToTile(obuf, bufp + colb, nrow, tilew,
roentgen b75cab
				    0, iskew);
roentgen b75cab
			if (TIFFWriteTile(out, obuf, col, row, 0, 0) < 0) {
roentgen b75cab
				TIFFError(TIFFFileName(out),
roentgen b75cab
				    "Error, can't write tile at %lu %lu",
roentgen b75cab
				    (unsigned long) col,
roentgen b75cab
				    (unsigned long) row);
roentgen b75cab
				_TIFFfree(obuf);
roentgen b75cab
				return 0;
roentgen b75cab
			}
roentgen b75cab
			colb += tilew;
roentgen b75cab
		}
roentgen b75cab
		bufp += nrow * imagew;
roentgen b75cab
	}
roentgen b75cab
	_TIFFfree(obuf);
roentgen b75cab
	return 1;
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
DECLAREwriteFunc(writeBufferToSeparateTiles)
roentgen b75cab
{
roentgen b75cab
	uint32 imagew = TIFFScanlineSize(out);
roentgen b75cab
	tsize_t tilew  = TIFFTileRowSize(out);
roentgen b75cab
	uint32 iimagew = TIFFRasterScanlineSize(out);
roentgen b75cab
	int iskew = iimagew - tilew*spp;
roentgen b75cab
	tsize_t tilesize = TIFFTileSize(out);
roentgen b75cab
	tdata_t obuf;
roentgen b75cab
	uint8* bufp = (uint8*) buf;
roentgen b75cab
	uint32 tl, tw;
roentgen b75cab
	uint32 row;
roentgen b75cab
	uint16 bps, bytes_per_sample;
roentgen b75cab
roentgen b75cab
	obuf = _TIFFmalloc(TIFFTileSize(out));
roentgen b75cab
	if (obuf == NULL)
roentgen b75cab
		return 0;
roentgen b75cab
	_TIFFmemset(obuf, 0, tilesize);
roentgen b75cab
	(void) TIFFGetField(out, TIFFTAG_TILELENGTH, &tl);
roentgen b75cab
	(void) TIFFGetField(out, TIFFTAG_TILEWIDTH, &tw);
roentgen b75cab
	(void) TIFFGetField(out, TIFFTAG_BITSPERSAMPLE, &bps);
roentgen b75cab
	assert( bps % 8 == 0 );
roentgen b75cab
	bytes_per_sample = bps/8;
roentgen b75cab
roentgen b75cab
	for (row = 0; row < imagelength; row += tl) {
roentgen b75cab
		uint32 nrow = (row+tl > imagelength) ? imagelength-row : tl;
roentgen b75cab
		uint32 colb = 0;
roentgen b75cab
		uint32 col;
roentgen b75cab
roentgen b75cab
		for (col = 0; col < imagewidth; col += tw) {
roentgen b75cab
			tsample_t s;
roentgen b75cab
			for (s = 0; s < spp; s++) {
roentgen b75cab
				/*
roentgen b75cab
				 * Tile is clipped horizontally.  Calculate
roentgen b75cab
				 * visible portion and skewing factors.
roentgen b75cab
				 */
roentgen b75cab
				if (colb + tilew > imagew) {
roentgen b75cab
					uint32 width = (imagew - colb);
roentgen b75cab
					int oskew = tilew - width;
roentgen b75cab
roentgen b75cab
					cpContigBufToSeparateBuf(obuf,
roentgen b75cab
					    bufp + (colb*spp) + s,
roentgen b75cab
					    nrow, width/bytes_per_sample,
roentgen b75cab
					    oskew, (oskew*spp)+iskew, spp,
roentgen b75cab
					    bytes_per_sample);
roentgen b75cab
				} else
roentgen b75cab
					cpContigBufToSeparateBuf(obuf,
roentgen b75cab
					    bufp + (colb*spp) + s,
roentgen b75cab
					    nrow, tilewidth,
roentgen b75cab
					    0, iskew, spp,
roentgen b75cab
					    bytes_per_sample);
roentgen b75cab
				if (TIFFWriteTile(out, obuf, col, row, 0, s) < 0) {
roentgen b75cab
					TIFFError(TIFFFileName(out),
roentgen b75cab
					    "Error, can't write tile at %lu %lu "
roentgen b75cab
					    "sample %lu",
roentgen b75cab
					    (unsigned long) col,
roentgen b75cab
					    (unsigned long) row,
roentgen b75cab
					    (unsigned long) s);
roentgen b75cab
					_TIFFfree(obuf);
roentgen b75cab
					return 0;
roentgen b75cab
				}
roentgen b75cab
			}
roentgen b75cab
			colb += tilew;
roentgen b75cab
		}
roentgen b75cab
		bufp += nrow * iimagew;
roentgen b75cab
	}
roentgen b75cab
	_TIFFfree(obuf);
roentgen b75cab
	return 1;
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
/*
roentgen b75cab
 * Contig strips -> contig tiles.
roentgen b75cab
 */
roentgen b75cab
DECLAREcpFunc(cpContigStrips2ContigTiles)
roentgen b75cab
{
roentgen b75cab
	return cpImage(in, out,
roentgen b75cab
	    readContigStripsIntoBuffer,
roentgen b75cab
	    writeBufferToContigTiles,
roentgen b75cab
	    imagelength, imagewidth, spp);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
/*
roentgen b75cab
 * Contig strips -> separate tiles.
roentgen b75cab
 */
roentgen b75cab
DECLAREcpFunc(cpContigStrips2SeparateTiles)
roentgen b75cab
{
roentgen b75cab
	return cpImage(in, out,
roentgen b75cab
	    readContigStripsIntoBuffer,
roentgen b75cab
	    writeBufferToSeparateTiles,
roentgen b75cab
	    imagelength, imagewidth, spp);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
/*
roentgen b75cab
 * Separate strips -> contig tiles.
roentgen b75cab
 */
roentgen b75cab
DECLAREcpFunc(cpSeparateStrips2ContigTiles)
roentgen b75cab
{
roentgen b75cab
	return cpImage(in, out,
roentgen b75cab
	    readSeparateStripsIntoBuffer,
roentgen b75cab
	    writeBufferToContigTiles,
roentgen b75cab
	    imagelength, imagewidth, spp);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
/*
roentgen b75cab
 * Separate strips -> separate tiles.
roentgen b75cab
 */
roentgen b75cab
DECLAREcpFunc(cpSeparateStrips2SeparateTiles)
roentgen b75cab
{
roentgen b75cab
	return cpImage(in, out,
roentgen b75cab
	    readSeparateStripsIntoBuffer,
roentgen b75cab
	    writeBufferToSeparateTiles,
roentgen b75cab
	    imagelength, imagewidth, spp);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
/*
roentgen b75cab
 * Contig strips -> contig tiles.
roentgen b75cab
 */
roentgen b75cab
DECLAREcpFunc(cpContigTiles2ContigTiles)
roentgen b75cab
{
roentgen b75cab
	return cpImage(in, out,
roentgen b75cab
	    readContigTilesIntoBuffer,
roentgen b75cab
	    writeBufferToContigTiles,
roentgen b75cab
	    imagelength, imagewidth, spp);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
/*
roentgen b75cab
 * Contig tiles -> separate tiles.
roentgen b75cab
 */
roentgen b75cab
DECLAREcpFunc(cpContigTiles2SeparateTiles)
roentgen b75cab
{
roentgen b75cab
	return cpImage(in, out,
roentgen b75cab
	    readContigTilesIntoBuffer,
roentgen b75cab
	    writeBufferToSeparateTiles,
roentgen b75cab
	    imagelength, imagewidth, spp);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
/*
roentgen b75cab
 * Separate tiles -> contig tiles.
roentgen b75cab
 */
roentgen b75cab
DECLAREcpFunc(cpSeparateTiles2ContigTiles)
roentgen b75cab
{
roentgen b75cab
	return cpImage(in, out,
roentgen b75cab
	    readSeparateTilesIntoBuffer,
roentgen b75cab
	    writeBufferToContigTiles,
roentgen b75cab
	    imagelength, imagewidth, spp);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
/*
roentgen b75cab
 * Separate tiles -> separate tiles (tile dimension change).
roentgen b75cab
 */
roentgen b75cab
DECLAREcpFunc(cpSeparateTiles2SeparateTiles)
roentgen b75cab
{
roentgen b75cab
	return cpImage(in, out,
roentgen b75cab
	    readSeparateTilesIntoBuffer,
roentgen b75cab
	    writeBufferToSeparateTiles,
roentgen b75cab
	    imagelength, imagewidth, spp);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
/*
roentgen b75cab
 * Contig tiles -> contig tiles (tile dimension change).
roentgen b75cab
 */
roentgen b75cab
DECLAREcpFunc(cpContigTiles2ContigStrips)
roentgen b75cab
{
roentgen b75cab
	return cpImage(in, out,
roentgen b75cab
	    readContigTilesIntoBuffer,
roentgen b75cab
	    writeBufferToContigStrips,
roentgen b75cab
	    imagelength, imagewidth, spp);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
/*
roentgen b75cab
 * Contig tiles -> separate strips.
roentgen b75cab
 */
roentgen b75cab
DECLAREcpFunc(cpContigTiles2SeparateStrips)
roentgen b75cab
{
roentgen b75cab
	return cpImage(in, out,
roentgen b75cab
	    readContigTilesIntoBuffer,
roentgen b75cab
	    writeBufferToSeparateStrips,
roentgen b75cab
	    imagelength, imagewidth, spp);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
/*
roentgen b75cab
 * Separate tiles -> contig strips.
roentgen b75cab
 */
roentgen b75cab
DECLAREcpFunc(cpSeparateTiles2ContigStrips)
roentgen b75cab
{
roentgen b75cab
	return cpImage(in, out,
roentgen b75cab
	    readSeparateTilesIntoBuffer,
roentgen b75cab
	    writeBufferToContigStrips,
roentgen b75cab
	    imagelength, imagewidth, spp);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
/*
roentgen b75cab
 * Separate tiles -> separate strips.
roentgen b75cab
 */
roentgen b75cab
DECLAREcpFunc(cpSeparateTiles2SeparateStrips)
roentgen b75cab
{
roentgen b75cab
	return cpImage(in, out,
roentgen b75cab
	    readSeparateTilesIntoBuffer,
roentgen b75cab
	    writeBufferToSeparateStrips,
roentgen b75cab
	    imagelength, imagewidth, spp);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
/*
roentgen b75cab
 * Select the appropriate copy function to use.
roentgen b75cab
 */
roentgen b75cab
static copyFunc
roentgen b75cab
pickCopyFunc(TIFF* in, TIFF* out, uint16 bitspersample, uint16 samplesperpixel)
roentgen b75cab
{
roentgen b75cab
	uint16 shortv;
roentgen b75cab
	uint32 w, l, tw, tl;
roentgen b75cab
	int bychunk;
roentgen b75cab
roentgen b75cab
	(void) TIFFGetField(in, TIFFTAG_PLANARCONFIG, &shortv);
roentgen b75cab
	if (shortv != config && bitspersample != 8 && samplesperpixel > 1) {
roentgen b75cab
		fprintf(stderr,
roentgen b75cab
		    "%s: Cannot handle different planar configuration w/ bits/sample != 8\n",
roentgen b75cab
		    TIFFFileName(in));
roentgen b75cab
		return (NULL);
roentgen b75cab
	}
roentgen b75cab
	TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &w);
roentgen b75cab
	TIFFGetField(in, TIFFTAG_IMAGELENGTH, &l);
roentgen b75cab
	if (!(TIFFIsTiled(out) || TIFFIsTiled(in))) {
roentgen b75cab
		uint32 irps = (uint32) -1L;
roentgen b75cab
		TIFFGetField(in, TIFFTAG_ROWSPERSTRIP, &irps);
roentgen b75cab
		/* if biased, force decoded copying to allow image subtraction */
roentgen b75cab
		bychunk = !bias && (rowsperstrip == irps);
roentgen b75cab
	}else{  /* either in or out is tiled */
roentgen b75cab
		if (bias) {
roentgen b75cab
			fprintf(stderr,
roentgen b75cab
			    "%s: Cannot handle tiled configuration w/bias image\n",
roentgen b75cab
			TIFFFileName(in));
roentgen b75cab
			return (NULL);
roentgen b75cab
		}
roentgen b75cab
		if (TIFFIsTiled(out)) {
roentgen b75cab
			if (!TIFFGetField(in, TIFFTAG_TILEWIDTH, &tw))
roentgen b75cab
				tw = w;
roentgen b75cab
			if (!TIFFGetField(in, TIFFTAG_TILELENGTH, &tl))
roentgen b75cab
				tl = l;
roentgen b75cab
			bychunk = (tw == tilewidth && tl == tilelength);
roentgen b75cab
		} else {  /* out's not, so in must be tiled */
roentgen b75cab
			TIFFGetField(in, TIFFTAG_TILEWIDTH, &tw);
roentgen b75cab
			TIFFGetField(in, TIFFTAG_TILELENGTH, &tl);
roentgen b75cab
			bychunk = (tw == w && tl == rowsperstrip);
roentgen b75cab
		}
roentgen b75cab
	}
roentgen b75cab
#define	T 1
roentgen b75cab
#define	F 0
roentgen b75cab
#define pack(a,b,c,d,e)	((long)(((a)<<11)|((b)<<3)|((c)<<2)|((d)<<1)|(e)))
roentgen b75cab
	switch(pack(shortv,config,TIFFIsTiled(in),TIFFIsTiled(out),bychunk)) {
roentgen b75cab
		/* Strips -> Tiles */
roentgen b75cab
		case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_CONTIG,   F,T,F):
roentgen b75cab
		case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_CONTIG,   F,T,T):
roentgen b75cab
			return cpContigStrips2ContigTiles;
roentgen b75cab
		case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_SEPARATE, F,T,F):
roentgen b75cab
		case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_SEPARATE, F,T,T):
roentgen b75cab
			return cpContigStrips2SeparateTiles;
roentgen b75cab
		case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG,   F,T,F):
roentgen b75cab
		case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG,   F,T,T):
roentgen b75cab
			return cpSeparateStrips2ContigTiles;
roentgen b75cab
		case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F,T,F):
roentgen b75cab
		case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F,T,T):
roentgen b75cab
			return cpSeparateStrips2SeparateTiles;
roentgen b75cab
		/* Tiles -> Tiles */
roentgen b75cab
		case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_CONTIG,   T,T,F):
roentgen b75cab
		case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_CONTIG,   T,T,T):
roentgen b75cab
			return cpContigTiles2ContigTiles;
roentgen b75cab
		case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_SEPARATE, T,T,F):
roentgen b75cab
		case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_SEPARATE, T,T,T):
roentgen b75cab
			return cpContigTiles2SeparateTiles;
roentgen b75cab
		case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG,   T,T,F):
roentgen b75cab
		case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG,   T,T,T):
roentgen b75cab
			return cpSeparateTiles2ContigTiles;
roentgen b75cab
		case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, T,T,F):
roentgen b75cab
		case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, T,T,T):
roentgen b75cab
			return cpSeparateTiles2SeparateTiles;
roentgen b75cab
		/* Tiles -> Strips */
roentgen b75cab
		case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_CONTIG,   T,F,F):
roentgen b75cab
		case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_CONTIG,   T,F,T):
roentgen b75cab
			return cpContigTiles2ContigStrips;
roentgen b75cab
		case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_SEPARATE, T,F,F):
roentgen b75cab
		case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_SEPARATE, T,F,T):
roentgen b75cab
			return cpContigTiles2SeparateStrips;
roentgen b75cab
		case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG,   T,F,F):
roentgen b75cab
		case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG,   T,F,T):
roentgen b75cab
			return cpSeparateTiles2ContigStrips;
roentgen b75cab
		case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, T,F,F):
roentgen b75cab
		case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, T,F,T):
roentgen b75cab
			return cpSeparateTiles2SeparateStrips;
roentgen b75cab
		/* Strips -> Strips */
roentgen b75cab
		case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_CONTIG,   F,F,F):
roentgen b75cab
			return bias ? cpBiasedContig2Contig : cpContig2ContigByRow;
roentgen b75cab
		case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_CONTIG,   F,F,T):
roentgen b75cab
			return cpDecodedStrips;
roentgen b75cab
		case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE,   F,F,F):
roentgen b75cab
		case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE,   F,F,T):
roentgen b75cab
			return cpContig2SeparateByRow;
roentgen b75cab
		case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG,   F,F,F):
roentgen b75cab
		case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG,   F,F,T):
roentgen b75cab
			return cpSeparate2ContigByRow;
roentgen b75cab
		case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F,F,F):
roentgen b75cab
		case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F,F,T):
roentgen b75cab
			return cpSeparate2SeparateByRow;
roentgen b75cab
	}
roentgen b75cab
#undef pack
roentgen b75cab
#undef F
roentgen b75cab
#undef T
roentgen b75cab
	fprintf(stderr, "tiffcp: %s: Don't know how to copy/convert image.\n",
roentgen b75cab
	    TIFFFileName(in));
roentgen b75cab
	return (NULL);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
/* vim: set ts=8 sts=8 sw=8 noet: */
roentgen b75cab
/*
roentgen b75cab
 * Local Variables:
roentgen b75cab
 * mode: c
roentgen b75cab
 * c-basic-offset: 8
roentgen b75cab
 * fill-column: 78
roentgen b75cab
 * End:
roentgen b75cab
 */