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