1/* $Id: tiffcp.c 276 2010-06-30 12:18:30Z nijtmans $ */
2
3/*
4 * Copyright (c) 1988-1997 Sam Leffler
5 * Copyright (c) 1991-1997 Silicon Graphics, Inc.
6 *
7 *  Revised:  2/18/01 BAR -- added syntax for extracting single images from
8 *                          multi-image TIFF files.
9 *
10 *    New syntax is:  sourceFileName,image#
11 *
12 * image# ranges from 0..<n-1> where n is the # of images in the file.
13 * There may be no white space between the comma and the filename or
14 * image number.
15 *
16 *    Example:   tiffcp source.tif,1 destination.tif
17 *
18 * Copies the 2nd image in source.tif to the destination.
19 *
20 *****
21 * Permission to use, copy, modify, distribute, and sell this software and
22 * its documentation for any purpose is hereby granted without fee, provided
23 * that (i) the above copyright notices and this permission notice appear in
24 * all copies of the software and related documentation, and (ii) the names of
25 * Sam Leffler and Silicon Graphics may not be used in any advertising or
26 * publicity relating to the software without the specific, prior written
27 * permission of Sam Leffler and Silicon Graphics.
28 *
29 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
30 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
31 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
32 *
33 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
34 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
35 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
36 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
37 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
38 * OF THIS SOFTWARE.
39 */
40
41#include "tif_config.h"
42
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46
47#include <ctype.h>
48#include <assert.h>
49
50#ifdef HAVE_UNISTD_H
51# include <unistd.h>
52#endif
53
54#include "tiffio.h"
55
56#ifndef HAVE_GETOPT
57extern int getopt(int, char**, char*);
58#endif
59
60#if defined(VMS)
61# define unlink delete
62#endif
63
64#define	streq(a,b)	(strcmp(a,b) == 0)
65#define	strneq(a,b,n)	(strncmp(a,b,n) == 0)
66
67#define	TRUE	1
68#define	FALSE	0
69
70static  int outtiled = -1;
71static  uint32 tilewidth;
72static  uint32 tilelength;
73
74static	uint16 config;
75static	uint16 compression;
76static	uint16 predictor;
77static	uint16 fillorder;
78static	uint16 orientation;
79static	uint32 rowsperstrip;
80static	uint32 g3opts;
81static	int ignore = FALSE;		/* if true, ignore read errors */
82static	uint32 defg3opts = (uint32) -1;
83static	int quality = 75;		/* JPEG quality */
84static	int jpegcolormode = JPEGCOLORMODE_RGB;
85static	uint16 defcompression = (uint16) -1;
86static	uint16 defpredictor = (uint16) -1;
87
88static	int tiffcp(TIFF*, TIFF*);
89static	int processCompressOptions(char*);
90static	void usage(void);
91
92static char comma = ',';  /* (default) comma separator character */
93static TIFF* bias = NULL;
94static int pageNum = 0;
95static int pageInSeq = 0;
96
97static int nextSrcImage (TIFF *tif, char **imageSpec)
98/*
99  seek to the next image specified in *imageSpec
100  returns 1 if success, 0 if no more images to process
101  *imageSpec=NULL if subsequent images should be processed in sequence
102*/
103{
104  if (**imageSpec == comma) {  /* if not @comma, we've done all images */
105    char *start = *imageSpec + 1;
106    tdir_t nextImage = (tdir_t)strtol(start, imageSpec, 0);
107    if (start == *imageSpec) nextImage = TIFFCurrentDirectory (tif);
108    if (**imageSpec)
109    {
110      if (**imageSpec == comma) {
111        /* a trailing comma denotes remaining images in sequence */
112        if ((*imageSpec)[1] == '\0') *imageSpec = NULL;
113      }else{
114        fprintf (stderr,
115          "Expected a %c separated image # list after %s\n",
116          comma, TIFFFileName (tif));
117        exit (-4);   /* syntax error */
118      }
119    }
120    if (TIFFSetDirectory (tif, nextImage)) return 1;
121    fprintf (stderr, "%s%c%d not found!\n",
122             TIFFFileName(tif), comma, (int) nextImage);
123  }
124  return 0;
125}
126
127
128static TIFF* openSrcImage (char **imageSpec)
129/*
130  imageSpec points to a pointer to a filename followed by optional ,image#'s
131  Open the TIFF file and assign *imageSpec to either NULL if there are
132  no images specified, or a pointer to the next image number text
133*/
134{
135    TIFF *tif;
136    char *fn = *imageSpec;
137    *imageSpec = strchr (fn, comma);
138    if (*imageSpec) {  /* there is at least one image number specifier */
139        **imageSpec = '\0';
140        tif = TIFFOpen (fn, "r");
141        /* but, ignore any single trailing comma */
142        if (!(*imageSpec)[1]) {*imageSpec = NULL; return tif;}
143        if (tif) {
144            **imageSpec = comma;  /* replace the comma */
145            if (!nextSrcImage(tif, imageSpec)) {
146              TIFFClose (tif);
147              tif = NULL;
148            }
149        }
150    }else
151        tif = TIFFOpen (fn, "r");
152    return tif;
153}
154
155
156int
157main(int argc, char* argv[])
158{
159	uint16 defconfig = (uint16) -1;
160	uint16 deffillorder = 0;
161	uint32 deftilewidth = (uint32) -1;
162	uint32 deftilelength = (uint32) -1;
163	uint32 defrowsperstrip = (uint32) 0;
164	uint32 diroff = 0;
165	TIFF* in;
166	TIFF* out;
167	char mode[10];
168	char* mp = mode;
169	int c;
170	extern int optind;
171	extern char* optarg;
172
173	*mp++ = 'w';
174	*mp = '\0';
175	while ((c = getopt(argc, argv, ",:b:c:f:l:o:z:p:r:w:aistBLMCx")) != -1)
176		switch (c) {
177                case ',':
178                        if (optarg[0] != '=') usage();
179                        comma = optarg[1];
180                        break;
181                case 'b':   /* this file is bias image subtracted from others */
182                        if (bias) {
183                          fputs ("Only 1 bias image may be specified\n", stderr);
184                          exit (-2);
185                        }
186                        {
187                          uint16    samples = (uint16) -1;
188                          char **biasFn = &optarg;
189                          bias = openSrcImage (biasFn);
190                          if (!bias) exit (-5);
191                          if (TIFFIsTiled (bias)) {
192                     fputs ("Bias image must be organized in strips\n", stderr);
193                            exit (-7);
194                          }
195			  TIFFGetField(bias, TIFFTAG_SAMPLESPERPIXEL, &samples);
196                          if (samples != 1) {
197                     fputs ("Bias image must be monochrome\n", stderr);
198                            exit (-7);
199                          }
200                        }
201                        break;
202		case 'a':		/* append to output */
203			mode[0] = 'a';
204			break;
205		case 'c':		/* compression scheme */
206			if (!processCompressOptions(optarg))
207				usage();
208			break;
209		case 'f':		/* fill order */
210			if (streq(optarg, "lsb2msb"))
211				deffillorder = FILLORDER_LSB2MSB;
212			else if (streq(optarg, "msb2lsb"))
213				deffillorder = FILLORDER_MSB2LSB;
214			else
215				usage();
216			break;
217		case 'i':		/* ignore errors */
218			ignore = TRUE;
219			break;
220		case 'l':		/* tile length */
221			outtiled = TRUE;
222			deftilelength = atoi(optarg);
223			break;
224		case 'o':		/* initial directory offset */
225			diroff = strtoul(optarg, NULL, 0);
226			break;
227		case 'p':		/* planar configuration */
228			if (streq(optarg, "separate"))
229				defconfig = PLANARCONFIG_SEPARATE;
230			else if (streq(optarg, "contig"))
231				defconfig = PLANARCONFIG_CONTIG;
232			else
233				usage();
234			break;
235		case 'r':		/* rows/strip */
236			defrowsperstrip = atol(optarg);
237			break;
238		case 's':		/* generate stripped output */
239			outtiled = FALSE;
240			break;
241		case 't':		/* generate tiled output */
242			outtiled = TRUE;
243			break;
244		case 'w':		/* tile width */
245			outtiled = TRUE;
246			deftilewidth = atoi(optarg);
247			break;
248		case 'B':
249			*mp++ = 'b'; *mp = '\0';
250			break;
251		case 'L':
252			*mp++ = 'l'; *mp = '\0';
253			break;
254		case 'M':
255			*mp++ = 'm'; *mp = '\0';
256			break;
257		case 'C':
258			*mp++ = 'c'; *mp = '\0';
259			break;
260		case 'x':
261			pageInSeq = 1;
262			break;
263		case '?':
264			usage();
265			/*NOTREACHED*/
266		}
267	if (argc - optind < 2)
268		usage();
269	out = TIFFOpen(argv[argc-1], mode);
270	if (out == NULL)
271		return (-2);
272	if ((argc - optind) == 2)
273	  pageNum = -1;
274	for (; optind < argc-1 ; optind++) {
275                char *imageCursor = argv[optind];
276		in = openSrcImage (&imageCursor);
277		if (in == NULL) {
278			(void) TIFFClose(out);
279			return (-3);
280		}
281		if (diroff != 0 && !TIFFSetSubDirectory(in, diroff)) {
282			TIFFError(TIFFFileName(in),
283			    "Error, setting subdirectory at %#x", diroff);
284			(void) TIFFClose(in);
285			(void) TIFFClose(out);
286			return (1);
287		}
288                for (;;) {
289                   config = defconfig;
290                   compression = defcompression;
291                   predictor = defpredictor;
292                   fillorder = deffillorder;
293                   rowsperstrip = defrowsperstrip;
294                   tilewidth = deftilewidth;
295                   tilelength = deftilelength;
296                   g3opts = defg3opts;
297                   if (!tiffcp(in, out) || !TIFFWriteDirectory(out)) {
298			(void) TIFFClose(in);
299                        (void) TIFFClose(out);
300                        return (1);
301                   }
302                   if (imageCursor) { /* seek next image directory */
303                        if (!nextSrcImage(in, &imageCursor)) break;
304                   }else
305                        if (!TIFFReadDirectory(in)) break;
306		}
307		(void) TIFFClose(in);
308	}
309
310        (void) TIFFClose(out);
311        return (0);
312}
313
314
315static void
316processG3Options(char* cp)
317{
318	if( (cp = strchr(cp, ':')) ) {
319		if (defg3opts == (uint32) -1)
320			defg3opts = 0;
321		do {
322			cp++;
323			if (strneq(cp, "1d", 2))
324				defg3opts &= ~GROUP3OPT_2DENCODING;
325			else if (strneq(cp, "2d", 2))
326				defg3opts |= GROUP3OPT_2DENCODING;
327			else if (strneq(cp, "fill", 4))
328				defg3opts |= GROUP3OPT_FILLBITS;
329			else
330				usage();
331		} while( (cp = strchr(cp, ':')) );
332	}
333}
334
335static int
336processCompressOptions(char* opt)
337{
338	if (streq(opt, "none")) {
339		defcompression = COMPRESSION_NONE;
340	} else if (streq(opt, "packbits")) {
341		defcompression = COMPRESSION_PACKBITS;
342	} else if (strneq(opt, "jpeg", 4)) {
343		char* cp = strchr(opt, ':');
344
345                defcompression = COMPRESSION_JPEG;
346                while( cp )
347                {
348                    if (isdigit((int)cp[1]))
349			quality = atoi(cp+1);
350                    else if (cp[1] == 'r' )
351			jpegcolormode = JPEGCOLORMODE_RAW;
352                    else
353                        usage();
354
355                    cp = strchr(cp+1,':');
356                }
357	} else if (strneq(opt, "g3", 2)) {
358		processG3Options(opt);
359		defcompression = COMPRESSION_CCITTFAX3;
360	} else if (streq(opt, "g4")) {
361		defcompression = COMPRESSION_CCITTFAX4;
362	} else if (strneq(opt, "lzw", 3)) {
363		char* cp = strchr(opt, ':');
364		if (cp)
365			defpredictor = atoi(cp+1);
366		defcompression = COMPRESSION_LZW;
367	} else if (strneq(opt, "zip", 3)) {
368		char* cp = strchr(opt, ':');
369		if (cp)
370			defpredictor = atoi(cp+1);
371		defcompression = COMPRESSION_ADOBE_DEFLATE;
372	} else if (strneq(opt, "jbig", 4)) {
373		defcompression = COMPRESSION_JBIG;
374	} else
375		return (0);
376	return (1);
377}
378
379char* stuff[] = {
380"usage: tiffcp [options] input... output",
381"where options are:",
382" -a		append to output instead of overwriting",
383" -o offset	set initial directory offset",
384" -p contig	pack samples contiguously (e.g. RGBRGB...)",
385" -p separate	store samples separately (e.g. RRR...GGG...BBB...)",
386" -s		write output in strips",
387" -t		write output in tiles",
388" -i		ignore read errors",
389" -b file[,#]	bias (dark) monochrome image to be subtracted from all others",
390" -,=%		use % rather than , to separate image #'s (per Note below)",
391"",
392" -r #		make each strip have no more than # rows",
393" -w #		set output tile width (pixels)",
394" -l #		set output tile length (pixels)",
395"",
396" -f lsb2msb	force lsb-to-msb FillOrder for output",
397" -f msb2lsb	force msb-to-lsb FillOrder for output",
398"",
399" -c lzw[:opts]	compress output with Lempel-Ziv & Welch encoding",
400" -c zip[:opts]	compress output with deflate encoding",
401" -c jpeg[:opts]	compress output with JPEG encoding",
402" -c jbig	compress output with ISO JBIG encoding",
403" -c packbits	compress output with packbits encoding",
404" -c g3[:opts]	compress output with CCITT Group 3 encoding",
405" -c g4		compress output with CCITT Group 4 encoding",
406" -c none	use no compression algorithm on output",
407"",
408"Group 3 options:",
409" 1d		use default CCITT Group 3 1D-encoding",
410" 2d		use optional CCITT Group 3 2D-encoding",
411" fill		byte-align EOL codes",
412"For example, -c g3:2d:fill to get G3-2D-encoded data with byte-aligned EOLs",
413"",
414"JPEG options:",
415" #		set compression quality level (0-100, default 75)",
416" r		output color image as RGB rather than YCbCr",
417"For example, -c jpeg:r:50 to get JPEG-encoded RGB data with 50% comp. quality",
418"",
419"LZW and deflate options:",
420" #		set predictor value",
421"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
422"",
423"Note that input filenames may be of the form filename,x,y,z",
424"where x, y, and z specify image numbers in the filename to copy.",
425"example:  tiffcp -c none -b esp.tif,1 esp.tif,0 test.tif",
426"  subtract 2nd image in esp.tif from 1st yielding uncompressed result test.tif",
427NULL
428};
429
430static void
431usage(void)
432{
433	char buf[BUFSIZ];
434	int i;
435
436	setbuf(stderr, buf);
437        fprintf(stderr, "%s\n\n", TIFFGetVersion());
438	for (i = 0; stuff[i] != NULL; i++)
439		fprintf(stderr, "%s\n", stuff[i]);
440	exit(-1);
441}
442
443#define	CopyField(tag, v) \
444    if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
445#define	CopyField2(tag, v1, v2) \
446    if (TIFFGetField(in, tag, &v1, &v2)) TIFFSetField(out, tag, v1, v2)
447#define	CopyField3(tag, v1, v2, v3) \
448    if (TIFFGetField(in, tag, &v1, &v2, &v3)) TIFFSetField(out, tag, v1, v2, v3)
449#define	CopyField4(tag, v1, v2, v3, v4) \
450    if (TIFFGetField(in, tag, &v1, &v2, &v3, &v4)) TIFFSetField(out, tag, v1, v2, v3, v4)
451
452static void
453cpTag(TIFF* in, TIFF* out, uint16 tag, uint16 count, TIFFDataType type)
454{
455	switch (type) {
456	case TIFF_SHORT:
457		if (count == 1) {
458			uint16 shortv;
459			CopyField(tag, shortv);
460		} else if (count == 2) {
461			uint16 shortv1, shortv2;
462			CopyField2(tag, shortv1, shortv2);
463		} else if (count == 4) {
464			uint16 *tr, *tg, *tb, *ta;
465			CopyField4(tag, tr, tg, tb, ta);
466		} else if (count == (uint16) -1) {
467			uint16 shortv1;
468			uint16* shortav;
469			CopyField2(tag, shortv1, shortav);
470		}
471		break;
472	case TIFF_LONG:
473		{ uint32 longv;
474		  CopyField(tag, longv);
475		}
476		break;
477	case TIFF_RATIONAL:
478		if (count == 1) {
479			float floatv;
480			CopyField(tag, floatv);
481		} else if (count == (uint16) -1) {
482			float* floatav;
483			CopyField(tag, floatav);
484		}
485		break;
486	case TIFF_ASCII:
487		{ char* stringv;
488		  CopyField(tag, stringv);
489		}
490		break;
491	case TIFF_DOUBLE:
492		if (count == 1) {
493			double doublev;
494			CopyField(tag, doublev);
495		} else if (count == (uint16) -1) {
496			double* doubleav;
497			CopyField(tag, doubleav);
498		}
499		break;
500          default:
501                TIFFError(TIFFFileName(in),
502                          "Data type %d is not supported, tag %d skipped.",
503                          tag, type);
504	}
505}
506
507static struct cpTag {
508	uint16	tag;
509	uint16	count;
510	TIFFDataType type;
511} tags[] = {
512	{ TIFFTAG_SUBFILETYPE,		1, TIFF_LONG },
513	{ TIFFTAG_THRESHHOLDING,	1, TIFF_SHORT },
514	{ TIFFTAG_DOCUMENTNAME,		1, TIFF_ASCII },
515	{ TIFFTAG_IMAGEDESCRIPTION,	1, TIFF_ASCII },
516	{ TIFFTAG_MAKE,			1, TIFF_ASCII },
517	{ TIFFTAG_MODEL,		1, TIFF_ASCII },
518	{ TIFFTAG_MINSAMPLEVALUE,	1, TIFF_SHORT },
519	{ TIFFTAG_MAXSAMPLEVALUE,	1, TIFF_SHORT },
520	{ TIFFTAG_XRESOLUTION,		1, TIFF_RATIONAL },
521	{ TIFFTAG_YRESOLUTION,		1, TIFF_RATIONAL },
522	{ TIFFTAG_PAGENAME,		1, TIFF_ASCII },
523	{ TIFFTAG_XPOSITION,		1, TIFF_RATIONAL },
524	{ TIFFTAG_YPOSITION,		1, TIFF_RATIONAL },
525	{ TIFFTAG_RESOLUTIONUNIT,	1, TIFF_SHORT },
526	{ TIFFTAG_SOFTWARE,		1, TIFF_ASCII },
527	{ TIFFTAG_DATETIME,		1, TIFF_ASCII },
528	{ TIFFTAG_ARTIST,		1, TIFF_ASCII },
529	{ TIFFTAG_HOSTCOMPUTER,		1, TIFF_ASCII },
530	{ TIFFTAG_WHITEPOINT,		(uint16) -1, TIFF_RATIONAL },
531	{ TIFFTAG_PRIMARYCHROMATICITIES,(uint16) -1,TIFF_RATIONAL },
532	{ TIFFTAG_HALFTONEHINTS,	2, TIFF_SHORT },
533	{ TIFFTAG_INKSET,		1, TIFF_SHORT },
534	{ TIFFTAG_DOTRANGE,		2, TIFF_SHORT },
535	{ TIFFTAG_TARGETPRINTER,	1, TIFF_ASCII },
536	{ TIFFTAG_SAMPLEFORMAT,		1, TIFF_SHORT },
537	{ TIFFTAG_YCBCRCOEFFICIENTS,	(uint16) -1,TIFF_RATIONAL },
538	{ TIFFTAG_YCBCRSUBSAMPLING,	2, TIFF_SHORT },
539	{ TIFFTAG_YCBCRPOSITIONING,	1, TIFF_SHORT },
540	{ TIFFTAG_REFERENCEBLACKWHITE,	(uint16) -1,TIFF_RATIONAL },
541	{ TIFFTAG_EXTRASAMPLES,		(uint16) -1, TIFF_SHORT },
542	{ TIFFTAG_SMINSAMPLEVALUE,	1, TIFF_DOUBLE },
543	{ TIFFTAG_SMAXSAMPLEVALUE,	1, TIFF_DOUBLE },
544	{ TIFFTAG_STONITS,		1, TIFF_DOUBLE },
545};
546#define	NTAGS	(sizeof (tags) / sizeof (tags[0]))
547
548#define	CopyTag(tag, count, type)	cpTag(in, out, tag, count, type)
549
550typedef int (*copyFunc)
551    (TIFF* in, TIFF* out, uint32 l, uint32 w, uint16 samplesperpixel);
552static	copyFunc pickCopyFunc(TIFF*, TIFF*, uint16, uint16);
553
554static int
555tiffcp(TIFF* in, TIFF* out)
556{
557	uint16 bitspersample, samplesperpixel;
558	uint16 input_compression, input_photometric;
559	copyFunc cf;
560	uint32 width, length;
561	struct cpTag* p;
562
563	CopyField(TIFFTAG_IMAGEWIDTH, width);
564	CopyField(TIFFTAG_IMAGELENGTH, length);
565	CopyField(TIFFTAG_BITSPERSAMPLE, bitspersample);
566	CopyField(TIFFTAG_SAMPLESPERPIXEL, samplesperpixel);
567	if (compression != (uint16)-1)
568		TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
569	else
570		CopyField(TIFFTAG_COMPRESSION, compression);
571	TIFFGetFieldDefaulted(in, TIFFTAG_COMPRESSION, &input_compression);
572	TIFFGetFieldDefaulted(in, TIFFTAG_PHOTOMETRIC, &input_photometric);
573	if (input_compression == COMPRESSION_JPEG) {
574		/* Force conversion to RGB */
575		TIFFSetField(in, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
576	} else if (input_photometric == PHOTOMETRIC_YCBCR) {
577		/* Otherwise, can't handle subsampled input */
578		uint16 subsamplinghor,subsamplingver;
579
580		TIFFGetFieldDefaulted(in, TIFFTAG_YCBCRSUBSAMPLING,
581				      &subsamplinghor, &subsamplingver);
582		if (subsamplinghor!=1 || subsamplingver!=1) {
583			fprintf(stderr, "tiffcp: %s: Can't copy/convert subsampled image.\n",
584				TIFFFileName(in));
585			return FALSE;
586		}
587	}
588	if (compression == COMPRESSION_JPEG) {
589		if (input_photometric == PHOTOMETRIC_RGB &&
590		    jpegcolormode == JPEGCOLORMODE_RGB)
591		  TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR);
592		else
593		  TIFFSetField(out, TIFFTAG_PHOTOMETRIC, input_photometric);
594	}
595	else if (compression == COMPRESSION_SGILOG
596		 || compression == COMPRESSION_SGILOG24)
597		TIFFSetField(out, TIFFTAG_PHOTOMETRIC,
598		    samplesperpixel == 1 ?
599			PHOTOMETRIC_LOGL : PHOTOMETRIC_LOGLUV);
600	else
601		CopyTag(TIFFTAG_PHOTOMETRIC, 1, TIFF_SHORT);
602	if (fillorder != 0)
603		TIFFSetField(out, TIFFTAG_FILLORDER, fillorder);
604	else
605		CopyTag(TIFFTAG_FILLORDER, 1, TIFF_SHORT);
606	/*
607	 * Will copy `Orientation' tag from input image
608	 */
609	TIFFGetFieldDefaulted(in, TIFFTAG_ORIENTATION, &orientation);
610	switch (orientation) {
611		case ORIENTATION_BOTRIGHT:
612		case ORIENTATION_RIGHTBOT:	/* XXX */
613			TIFFWarning(TIFFFileName(in), "using bottom-left orientation");
614			orientation = ORIENTATION_BOTLEFT;
615		/* fall thru... */
616		case ORIENTATION_LEFTBOT:	/* XXX */
617		case ORIENTATION_BOTLEFT:
618			break;
619		case ORIENTATION_TOPRIGHT:
620		case ORIENTATION_RIGHTTOP:	/* XXX */
621		default:
622			TIFFWarning(TIFFFileName(in), "using top-left orientation");
623			orientation = ORIENTATION_TOPLEFT;
624		/* fall thru... */
625		case ORIENTATION_LEFTTOP:	/* XXX */
626		case ORIENTATION_TOPLEFT:
627			break;
628	}
629	TIFFSetField(out, TIFFTAG_ORIENTATION, orientation);
630	/*
631	 * Choose tiles/strip for the output image according to
632	 * the command line arguments (-tiles, -strips) and the
633	 * structure of the input image.
634	 */
635	if (outtiled == -1)
636		outtiled = TIFFIsTiled(in);
637	if (outtiled) {
638		/*
639		 * Setup output file's tile width&height.  If either
640		 * is not specified, use either the value from the
641		 * input image or, if nothing is defined, use the
642		 * library default.
643		 */
644		if (tilewidth == (uint32) -1)
645			TIFFGetField(in, TIFFTAG_TILEWIDTH, &tilewidth);
646		if (tilelength == (uint32) -1)
647			TIFFGetField(in, TIFFTAG_TILELENGTH, &tilelength);
648		TIFFDefaultTileSize(out, &tilewidth, &tilelength);
649		TIFFSetField(out, TIFFTAG_TILEWIDTH, tilewidth);
650		TIFFSetField(out, TIFFTAG_TILELENGTH, tilelength);
651	} else {
652		/*
653		 * RowsPerStrip is left unspecified: use either the
654		 * value from the input image or, if nothing is defined,
655		 * use the library default.
656		 */
657		if (rowsperstrip == (uint32) 0) {
658			if (!TIFFGetField(in, TIFFTAG_ROWSPERSTRIP,
659					  &rowsperstrip)) {
660				rowsperstrip =
661					TIFFDefaultStripSize(out, rowsperstrip);
662			}
663			if (rowsperstrip > length && rowsperstrip != (uint32)-1)
664				rowsperstrip = length;
665		}
666		else if (rowsperstrip == (uint32) -1)
667			rowsperstrip = length;
668		TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
669	}
670	if (config != (uint16) -1)
671		TIFFSetField(out, TIFFTAG_PLANARCONFIG, config);
672	else
673		CopyField(TIFFTAG_PLANARCONFIG, config);
674	if (samplesperpixel <= 4)
675		CopyTag(TIFFTAG_TRANSFERFUNCTION, 4, TIFF_SHORT);
676	CopyTag(TIFFTAG_COLORMAP, 4, TIFF_SHORT);
677/* SMinSampleValue & SMaxSampleValue */
678	switch (compression) {
679	case COMPRESSION_JPEG:
680		TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality);
681		TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode);
682		break;
683	case COMPRESSION_JBIG:
684		CopyTag(TIFFTAG_FAXRECVPARAMS, 1, TIFF_LONG);
685		CopyTag(TIFFTAG_FAXRECVTIME, 1, TIFF_LONG);
686		CopyTag(TIFFTAG_FAXSUBADDRESS, 1, TIFF_ASCII);
687		CopyTag(TIFFTAG_FAXDCS, 1, TIFF_ASCII);
688		break;
689	case COMPRESSION_LZW:
690	case COMPRESSION_ADOBE_DEFLATE:
691	case COMPRESSION_DEFLATE:
692		if (predictor != (uint16)-1)
693			TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
694		else
695			CopyField(TIFFTAG_PREDICTOR, predictor);
696		break;
697	case COMPRESSION_CCITTFAX3:
698	case COMPRESSION_CCITTFAX4:
699		if (compression == COMPRESSION_CCITTFAX3) {
700			if (g3opts != (uint32) -1)
701				TIFFSetField(out, TIFFTAG_GROUP3OPTIONS,
702				    g3opts);
703			else
704				CopyField(TIFFTAG_GROUP3OPTIONS, g3opts);
705		} else
706			CopyTag(TIFFTAG_GROUP4OPTIONS, 1, TIFF_LONG);
707		CopyTag(TIFFTAG_BADFAXLINES, 1, TIFF_LONG);
708		CopyTag(TIFFTAG_CLEANFAXDATA, 1, TIFF_LONG);
709		CopyTag(TIFFTAG_CONSECUTIVEBADFAXLINES, 1, TIFF_LONG);
710		CopyTag(TIFFTAG_FAXRECVPARAMS, 1, TIFF_LONG);
711		CopyTag(TIFFTAG_FAXRECVTIME, 1, TIFF_LONG);
712		CopyTag(TIFFTAG_FAXSUBADDRESS, 1, TIFF_ASCII);
713		break;
714	}
715	{ uint32 len32;
716	  void** data;
717	  if (TIFFGetField(in, TIFFTAG_ICCPROFILE, &len32, &data))
718		TIFFSetField(out, TIFFTAG_ICCPROFILE, len32, data);
719	}
720	{ uint16 ninks;
721	  const char* inknames;
722	  if (TIFFGetField(in, TIFFTAG_NUMBEROFINKS, &ninks)) {
723		TIFFSetField(out, TIFFTAG_NUMBEROFINKS, ninks);
724		if (TIFFGetField(in, TIFFTAG_INKNAMES, &inknames)) {
725		    int inknameslen = strlen(inknames) + 1;
726		    const char* cp = inknames;
727		    while (ninks > 1) {
728			    cp = strchr(cp, '\0');
729			    if (cp) {
730				    cp++;
731				    inknameslen += (strlen(cp) + 1);
732			    }
733			    ninks--;
734		    }
735		    TIFFSetField(out, TIFFTAG_INKNAMES, inknameslen, inknames);
736		}
737	  }
738	}
739	{
740	  unsigned short pg0, pg1;
741	  if(pageInSeq == 1) {
742	  	if (pageNum < 0) /* only one input file */ {
743		  if (TIFFGetField(in, TIFFTAG_PAGENUMBER, &pg0, &pg1))
744			TIFFSetField(out, TIFFTAG_PAGENUMBER, pg0, pg1);
745		} else
746			TIFFSetField(out, TIFFTAG_PAGENUMBER, pageNum++, 0);
747	  } else
748		  if (TIFFGetField(in, TIFFTAG_PAGENUMBER, &pg0, &pg1)) {
749			if (pageNum < 0) /* only one input file */
750				TIFFSetField(out, TIFFTAG_PAGENUMBER, pg0, pg1);
751			else
752				TIFFSetField(out, TIFFTAG_PAGENUMBER, pageNum++, 0);
753		  }
754	}
755
756	for (p = tags; p < &tags[NTAGS]; p++)
757		CopyTag(p->tag, p->count, p->type);
758
759	cf = pickCopyFunc(in, out, bitspersample, samplesperpixel);
760	return (cf ? (*cf)(in, out, length, width, samplesperpixel) : FALSE);
761}
762
763/*
764 * Copy Functions.
765 */
766#define	DECLAREcpFunc(x) \
767static int x(TIFF* in, TIFF* out, \
768    uint32 imagelength, uint32 imagewidth, tsample_t spp)
769
770#define	DECLAREreadFunc(x) \
771static int x(TIFF* in, \
772    uint8* buf, uint32 imagelength, uint32 imagewidth, tsample_t spp)
773typedef int (*readFunc)(TIFF*, uint8*, uint32, uint32, tsample_t);
774
775#define	DECLAREwriteFunc(x) \
776static int x(TIFF* out, \
777    uint8* buf, uint32 imagelength, uint32 imagewidth, tsample_t spp)
778typedef int (*writeFunc)(TIFF*, uint8*, uint32, uint32, tsample_t);
779
780/*
781 * Contig -> contig by scanline for rows/strip change.
782 */
783DECLAREcpFunc(cpContig2ContigByRow)
784{
785	tdata_t buf = _TIFFmalloc(TIFFScanlineSize(in));
786	uint32 row;
787
788	(void) imagewidth; (void) spp;
789	for (row = 0; row < imagelength; row++) {
790		if (TIFFReadScanline(in, buf, row, 0) < 0 && !ignore) {
791			TIFFError(TIFFFileName(in),
792				  "Error, can't read scanline %lu",
793				  (unsigned long) row);
794			goto bad;
795		}
796		if (TIFFWriteScanline(out, buf, row, 0) < 0) {
797			TIFFError(TIFFFileName(out),
798				  "Error, can't write scanline %lu",
799				  (unsigned long) row);
800			goto bad;
801		}
802	}
803	_TIFFfree(buf);
804	return 1;
805bad:
806	_TIFFfree(buf);
807	return 0;
808}
809
810
811typedef void biasFn (void *image, void *bias, uint32 pixels);
812
813#define subtract(bits) \
814static void subtract##bits (void *i, void *b, uint32 pixels)\
815{\
816   uint##bits *image = i;\
817   uint##bits *bias = b;\
818   while (pixels--) {\
819     *image = *image > *bias ? *image-*bias : 0;\
820     image++, bias++; \
821   } \
822}
823
824subtract(8)
825subtract(16)
826subtract(32)
827
828static biasFn *lineSubtractFn (unsigned bits)
829{
830    switch (bits) {
831      case  8:  return subtract8;
832      case 16:  return subtract16;
833      case 32:  return subtract32;
834    }
835    return NULL;
836}
837
838/*
839 * Contig -> contig by scanline while subtracting a bias image.
840 */
841DECLAREcpFunc(cpBiasedContig2Contig)
842{
843	if (spp == 1) {
844	  tsize_t biasSize = TIFFScanlineSize(bias);
845	  tsize_t bufSize = TIFFScanlineSize(in);
846	  tdata_t buf, biasBuf;
847	  uint32 biasWidth = 0, biasLength = 0;
848	  TIFFGetField(bias, TIFFTAG_IMAGEWIDTH, &biasWidth);
849	  TIFFGetField(bias, TIFFTAG_IMAGELENGTH, &biasLength);
850	  if (biasSize == bufSize &&
851	      imagelength == biasLength && imagewidth == biasWidth) {
852		uint16 sampleBits = 0;
853		biasFn *subtractLine;
854		TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &sampleBits);
855		subtractLine = lineSubtractFn (sampleBits);
856		if (subtractLine) {
857			uint32 row;
858			buf = _TIFFmalloc(bufSize);
859			biasBuf = _TIFFmalloc(bufSize);
860			for (row = 0; row < imagelength; row++) {
861				if (TIFFReadScanline(in, buf, row, 0) < 0
862				    && !ignore) {
863					TIFFError(TIFFFileName(in),
864					"Error, can't read scanline %lu",
865					(unsigned long) row);
866					goto bad;
867				}
868				if (TIFFReadScanline(bias, biasBuf, row, 0) < 0
869				    && !ignore) {
870					TIFFError(TIFFFileName(in),
871					"Error, can't read biased scanline %lu",
872					(unsigned long) row);
873					goto bad;
874				}
875				subtractLine (buf, biasBuf, imagewidth);
876				if (TIFFWriteScanline(out, buf, row, 0) < 0) {
877					TIFFError(TIFFFileName(out),
878					"Error, can't write scanline %lu",
879					(unsigned long) row);
880					goto bad;
881				}
882			}
883
884			_TIFFfree(buf);
885			_TIFFfree(biasBuf);
886			TIFFSetDirectory(bias,
887				TIFFCurrentDirectory(bias)); /* rewind */
888			return 1;
889bad:
890			_TIFFfree(buf);
891			_TIFFfree(biasBuf);
892			return 0;
893	    } else {
894	      TIFFError(TIFFFileName(in),
895			"No support for biasing %d bit pixels\n",
896			sampleBits);
897	      return 0;
898	    }
899	  }
900	  TIFFError(TIFFFileName(in),
901		    "Bias image %s,%d\nis not the same size as %s,%d\n",
902		    TIFFFileName(bias), TIFFCurrentDirectory(bias),
903		    TIFFFileName(in), TIFFCurrentDirectory(in));
904	  return 0;
905	} else {
906	  TIFFError(TIFFFileName(in),
907		    "Can't bias %s,%d as it has >1 Sample/Pixel\n",
908		    TIFFFileName(in), TIFFCurrentDirectory(in));
909	  return 0;
910	}
911
912}
913
914
915/*
916 * Strip -> strip for change in encoding.
917 */
918DECLAREcpFunc(cpDecodedStrips)
919{
920	tsize_t stripsize  = TIFFStripSize(in);
921	tdata_t buf = _TIFFmalloc(stripsize);
922
923	(void) imagewidth; (void) spp;
924	if (buf) {
925		tstrip_t s, ns = TIFFNumberOfStrips(in);
926		uint32 row = 0;
927		for (s = 0; s < ns; s++) {
928			tsize_t cc = (row + rowsperstrip > imagelength) ?
929			    TIFFVStripSize(in, imagelength - row) : stripsize;
930			if (TIFFReadEncodedStrip(in, s, buf, cc) < 0
931			    && !ignore) {
932				TIFFError(TIFFFileName(in),
933					  "Error, can't read strip %lu",
934					  (unsigned long) s);
935				goto bad;
936			}
937			if (TIFFWriteEncodedStrip(out, s, buf, cc) < 0) {
938				TIFFError(TIFFFileName(out),
939					  "Error, can't write strip %lu",
940					  (unsigned long) s);
941				goto bad;
942			}
943			row += rowsperstrip;
944		}
945		_TIFFfree(buf);
946		return 1;
947	} else {
948		TIFFError(TIFFFileName(in),
949			  "Error, can't allocate memory buffer of size %lu "
950			  "to read strips", (unsigned long) stripsize);
951		return 0;
952	}
953
954bad:
955	_TIFFfree(buf);
956	return 0;
957}
958
959/*
960 * Separate -> separate by row for rows/strip change.
961 */
962DECLAREcpFunc(cpSeparate2SeparateByRow)
963{
964	tdata_t buf = _TIFFmalloc(TIFFScanlineSize(in));
965	uint32 row;
966	tsample_t s;
967
968	(void) imagewidth;
969	for (s = 0; s < spp; s++) {
970		for (row = 0; row < imagelength; row++) {
971			if (TIFFReadScanline(in, buf, row, s) < 0 && !ignore) {
972				TIFFError(TIFFFileName(in),
973					  "Error, can't read scanline %lu",
974					  (unsigned long) row);
975				goto bad;
976			}
977			if (TIFFWriteScanline(out, buf, row, s) < 0) {
978				TIFFError(TIFFFileName(out),
979					  "Error, can't write scanline %lu",
980					  (unsigned long) row);
981				goto bad;
982			}
983		}
984	}
985	_TIFFfree(buf);
986	return 1;
987bad:
988	_TIFFfree(buf);
989	return 0;
990}
991
992/*
993 * Contig -> separate by row.
994 */
995DECLAREcpFunc(cpContig2SeparateByRow)
996{
997	tdata_t inbuf = _TIFFmalloc(TIFFScanlineSize(in));
998	tdata_t outbuf = _TIFFmalloc(TIFFScanlineSize(out));
999	register uint8 *inp, *outp;
1000	register uint32 n;
1001	uint32 row;
1002	tsample_t s;
1003
1004	/* unpack channels */
1005	for (s = 0; s < spp; s++) {
1006		for (row = 0; row < imagelength; row++) {
1007			if (TIFFReadScanline(in, inbuf, row, 0) < 0
1008			    && !ignore) {
1009				TIFFError(TIFFFileName(in),
1010					  "Error, can't read scanline %lu",
1011					  (unsigned long) row);
1012				goto bad;
1013			}
1014			inp = ((uint8*)inbuf) + s;
1015			outp = (uint8*)outbuf;
1016			for (n = imagewidth; n-- > 0;) {
1017				*outp++ = *inp;
1018				inp += spp;
1019			}
1020			if (TIFFWriteScanline(out, outbuf, row, s) < 0) {
1021				TIFFError(TIFFFileName(out),
1022					  "Error, can't write scanline %lu",
1023					  (unsigned long) row);
1024				goto bad;
1025			}
1026		}
1027	}
1028	if (inbuf) _TIFFfree(inbuf);
1029	if (outbuf) _TIFFfree(outbuf);
1030	return 1;
1031bad:
1032	if (inbuf) _TIFFfree(inbuf);
1033	if (outbuf) _TIFFfree(outbuf);
1034	return 0;
1035}
1036
1037/*
1038 * Separate -> contig by row.
1039 */
1040DECLAREcpFunc(cpSeparate2ContigByRow)
1041{
1042	tdata_t inbuf = _TIFFmalloc(TIFFScanlineSize(in));
1043	tdata_t outbuf = _TIFFmalloc(TIFFScanlineSize(out));
1044	register uint8 *inp, *outp;
1045	register uint32 n;
1046	uint32 row;
1047	tsample_t s;
1048
1049	for (row = 0; row < imagelength; row++) {
1050		/* merge channels */
1051		for (s = 0; s < spp; s++) {
1052			if (TIFFReadScanline(in, inbuf, row, s) < 0
1053			    && !ignore) {
1054				TIFFError(TIFFFileName(in),
1055					  "Error, can't read scanline %lu",
1056					  (unsigned long) row);
1057				goto bad;
1058			}
1059			inp = (uint8*)inbuf;
1060			outp = ((uint8*)outbuf) + s;
1061			for (n = imagewidth; n-- > 0;) {
1062				*outp = *inp++;
1063				outp += spp;
1064			}
1065		}
1066		if (TIFFWriteScanline(out, outbuf, row, 0) < 0) {
1067			TIFFError(TIFFFileName(out),
1068				  "Error, can't write scanline %lu",
1069				  (unsigned long) row);
1070			goto bad;
1071		}
1072	}
1073	if (inbuf) _TIFFfree(inbuf);
1074	if (outbuf) _TIFFfree(outbuf);
1075	return 1;
1076bad:
1077	if (inbuf) _TIFFfree(inbuf);
1078	if (outbuf) _TIFFfree(outbuf);
1079	return 0;
1080}
1081
1082static void
1083cpStripToTile(uint8* out, uint8* in,
1084	uint32 rows, uint32 cols, int outskew, int inskew)
1085{
1086	while (rows-- > 0) {
1087		uint32 j = cols;
1088		while (j-- > 0)
1089			*out++ = *in++;
1090		out += outskew;
1091		in += inskew;
1092	}
1093}
1094
1095static void
1096cpContigBufToSeparateBuf(uint8* out, uint8* in,
1097           uint32 rows, uint32 cols, int outskew, int inskew, tsample_t spp,
1098           int bytes_per_sample )
1099{
1100	while (rows-- > 0) {
1101		uint32 j = cols;
1102		while (j-- > 0)
1103                {
1104                        int n = bytes_per_sample;
1105
1106                        while( n-- ) {
1107                            *out++ = *in++;
1108                        }
1109                        in += (spp-1) * bytes_per_sample;
1110                }
1111		out += outskew;
1112		in += inskew;
1113	}
1114}
1115
1116static void
1117cpSeparateBufToContigBuf(uint8* out, uint8* in,
1118	uint32 rows, uint32 cols, int outskew, int inskew, tsample_t spp,
1119                         int bytes_per_sample)
1120{
1121	while (rows-- > 0) {
1122		uint32 j = cols;
1123		while (j-- > 0) {
1124                        int n = bytes_per_sample;
1125
1126                        while( n-- ) {
1127                                *out++ = *in++;
1128                        }
1129                        out += (spp-1)*bytes_per_sample;
1130                }
1131		out += outskew;
1132		in += inskew;
1133	}
1134}
1135
1136static int
1137cpImage(TIFF* in, TIFF* out, readFunc fin, writeFunc fout,
1138	uint32 imagelength, uint32 imagewidth, tsample_t spp)
1139{
1140	int status = 0;
1141	tdata_t buf = NULL;
1142	tsize_t scanlinesize = TIFFRasterScanlineSize(in);
1143        tsize_t bytes = scanlinesize * (tsize_t)imagelength;
1144        /*
1145         * XXX: Check for integer overflow.
1146         */
1147        if (scanlinesize
1148	    && imagelength
1149	    && bytes / (tsize_t)imagelength == scanlinesize) {
1150                buf = _TIFFmalloc(bytes);
1151		if (buf) {
1152			if ((*fin)(in, (uint8*)buf, imagelength,
1153				   imagewidth, spp)) {
1154				status = (*fout)(out, (uint8*)buf,
1155						 imagelength, imagewidth, spp);
1156			}
1157			_TIFFfree(buf);
1158		} else {
1159			TIFFError(TIFFFileName(in),
1160				"Error, can't allocate space for image buffer");
1161		}
1162	} else {
1163		TIFFError(TIFFFileName(in), "Error, no space for image buffer");
1164	}
1165
1166	return status;
1167}
1168
1169DECLAREreadFunc(readContigStripsIntoBuffer)
1170{
1171	tsize_t scanlinesize = TIFFScanlineSize(in);
1172	uint8* bufp = buf;
1173	uint32 row;
1174
1175	(void) imagewidth; (void) spp;
1176	for (row = 0; row < imagelength; row++) {
1177		if (TIFFReadScanline(in, (tdata_t) bufp, row, 0) < 0
1178		    && !ignore) {
1179			TIFFError(TIFFFileName(in),
1180				  "Error, can't read scanline %lu",
1181				  (unsigned long) row);
1182			return 0;
1183		}
1184		bufp += scanlinesize;
1185	}
1186
1187	return 1;
1188}
1189
1190DECLAREreadFunc(readSeparateStripsIntoBuffer)
1191{
1192	int status = 1;
1193	tsize_t scanlinesize = TIFFScanlineSize(in);
1194	tdata_t scanline = _TIFFmalloc(scanlinesize);
1195	if (!scanlinesize)
1196		return 0;
1197
1198	(void) imagewidth;
1199	if (scanline) {
1200		uint8* bufp = (uint8*) buf;
1201		uint32 row;
1202		tsample_t s;
1203		for (row = 0; row < imagelength; row++) {
1204			/* merge channels */
1205			for (s = 0; s < spp; s++) {
1206				uint8* bp = bufp + s;
1207				tsize_t n = scanlinesize;
1208                                uint8* sbuf = scanline;
1209
1210				if (TIFFReadScanline(in, scanline, row, s) < 0
1211				    && !ignore) {
1212					TIFFError(TIFFFileName(in),
1213					"Error, can't read scanline %lu",
1214					(unsigned long) row);
1215					status = 0;
1216					goto done;
1217				}
1218				while (n-- > 0)
1219					*bp = *sbuf++, bp += spp;
1220			}
1221			bufp += scanlinesize * spp;
1222		}
1223	}
1224
1225done:
1226	_TIFFfree(scanline);
1227	return status;
1228}
1229
1230DECLAREreadFunc(readContigTilesIntoBuffer)
1231{
1232	int status = 1;
1233	tdata_t tilebuf = _TIFFmalloc(TIFFTileSize(in));
1234	uint32 imagew = TIFFScanlineSize(in);
1235	uint32 tilew  = TIFFTileRowSize(in);
1236	int iskew = imagew - tilew;
1237	uint8* bufp = (uint8*) buf;
1238	uint32 tw, tl;
1239	uint32 row;
1240
1241	(void) spp;
1242	if (tilebuf == 0)
1243		return 0;
1244	(void) TIFFGetField(in, TIFFTAG_TILEWIDTH, &tw);
1245	(void) TIFFGetField(in, TIFFTAG_TILELENGTH, &tl);
1246
1247	for (row = 0; row < imagelength; row += tl) {
1248		uint32 nrow = (row+tl > imagelength) ? imagelength-row : tl;
1249		uint32 colb = 0;
1250		uint32 col;
1251
1252		for (col = 0; col < imagewidth; col += tw) {
1253			if (TIFFReadTile(in, tilebuf, col, row, 0, 0) < 0
1254			    && !ignore) {
1255				TIFFError(TIFFFileName(in),
1256					  "Error, can't read tile at %lu %lu",
1257					  (unsigned long) col,
1258					  (unsigned long) row);
1259				status = 0;
1260				goto done;
1261			}
1262			if (colb + tilew > imagew) {
1263				uint32 width = imagew - colb;
1264				uint32 oskew = tilew - width;
1265				cpStripToTile(bufp + colb,
1266                                              tilebuf, nrow, width,
1267                                              oskew + iskew, oskew );
1268			} else
1269				cpStripToTile(bufp + colb,
1270                                              tilebuf, nrow, tilew,
1271                                              iskew, 0);
1272			colb += tilew;
1273		}
1274		bufp += imagew * nrow;
1275	}
1276done:
1277	_TIFFfree(tilebuf);
1278	return status;
1279}
1280
1281DECLAREreadFunc(readSeparateTilesIntoBuffer)
1282{
1283	int status = 1;
1284	uint32 imagew = TIFFRasterScanlineSize(in);
1285	uint32 tilew = TIFFTileRowSize(in);
1286	int iskew  = imagew - tilew*spp;
1287	tdata_t tilebuf = _TIFFmalloc(TIFFTileSize(in));
1288	uint8* bufp = (uint8*) buf;
1289	uint32 tw, tl;
1290	uint32 row;
1291        uint16 bps, bytes_per_sample;
1292
1293	if (tilebuf == 0)
1294		return 0;
1295	(void) TIFFGetField(in, TIFFTAG_TILEWIDTH, &tw);
1296	(void) TIFFGetField(in, TIFFTAG_TILELENGTH, &tl);
1297	(void) TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bps);
1298        assert( bps % 8 == 0 );
1299        bytes_per_sample = bps/8;
1300
1301	for (row = 0; row < imagelength; row += tl) {
1302		uint32 nrow = (row+tl > imagelength) ? imagelength-row : tl;
1303		uint32 colb = 0;
1304		uint32 col;
1305
1306		for (col = 0; col < imagewidth; col += tw) {
1307			tsample_t s;
1308
1309			for (s = 0; s < spp; s++) {
1310				if (TIFFReadTile(in, tilebuf, col, row, 0, s) < 0
1311				    && !ignore) {
1312					TIFFError(TIFFFileName(in),
1313					  "Error, can't read tile at %lu %lu, "
1314					  "sample %lu",
1315					  (unsigned long) col,
1316					  (unsigned long) row,
1317					  (unsigned long) s);
1318					status = 0;
1319					goto done;
1320				}
1321				/*
1322				 * Tile is clipped horizontally.  Calculate
1323				 * visible portion and skewing factors.
1324				 */
1325				if (colb + tilew*spp > imagew) {
1326					uint32 width = imagew - colb;
1327					int oskew = tilew*spp - width;
1328					cpSeparateBufToContigBuf(
1329                                            bufp+colb+s*bytes_per_sample,
1330					    tilebuf, nrow,
1331                                            width/(spp*bytes_per_sample),
1332					    oskew + iskew,
1333                                            oskew/spp, spp,
1334                                            bytes_per_sample);
1335				} else
1336					cpSeparateBufToContigBuf(
1337                                            bufp+colb+s*bytes_per_sample,
1338					    tilebuf, nrow, tw,
1339					    iskew, 0, spp,
1340                                            bytes_per_sample);
1341			}
1342			colb += tilew*spp;
1343		}
1344		bufp += imagew * nrow;
1345	}
1346done:
1347	_TIFFfree(tilebuf);
1348	return status;
1349}
1350
1351DECLAREwriteFunc(writeBufferToContigStrips)
1352{
1353	uint32 row, rowsperstrip;
1354	tstrip_t strip = 0;
1355
1356	(void) imagewidth; (void) spp;
1357	(void) TIFFGetFieldDefaulted(out, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
1358	for (row = 0; row < imagelength; row += rowsperstrip) {
1359		uint32 nrows = (row+rowsperstrip > imagelength) ?
1360		    imagelength-row : rowsperstrip;
1361		tsize_t stripsize = TIFFVStripSize(out, nrows);
1362		if (TIFFWriteEncodedStrip(out, strip++, buf, stripsize) < 0) {
1363			TIFFError(TIFFFileName(out),
1364				  "Error, can't write strip %u", strip - 1);
1365			return 0;
1366		}
1367		buf += stripsize;
1368	}
1369	return 1;
1370}
1371
1372DECLAREwriteFunc(writeBufferToSeparateStrips)
1373{
1374	uint32 rowsize = imagewidth * spp;
1375	uint32 rowsperstrip;
1376	tdata_t obuf = _TIFFmalloc(TIFFStripSize(out));
1377	tstrip_t strip = 0;
1378	tsample_t s;
1379
1380	if (obuf == NULL)
1381		return (0);
1382	(void) TIFFGetFieldDefaulted(out, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
1383	for (s = 0; s < spp; s++) {
1384		uint32 row;
1385		for (row = 0; row < imagelength; row += rowsperstrip) {
1386			uint32 nrows = (row+rowsperstrip > imagelength) ?
1387			    imagelength-row : rowsperstrip;
1388			tsize_t stripsize = TIFFVStripSize(out, nrows);
1389
1390			cpContigBufToSeparateBuf(
1391			    obuf, (uint8*) buf + row*rowsize + s,
1392			    nrows, imagewidth, 0, 0, spp, 1);
1393			if (TIFFWriteEncodedStrip(out, strip++, obuf, stripsize) < 0) {
1394				TIFFError(TIFFFileName(out),
1395					  "Error, can't write strip %u",
1396					  strip - 1);
1397				_TIFFfree(obuf);
1398				return 0;
1399			}
1400		}
1401	}
1402	_TIFFfree(obuf);
1403	return 1;
1404
1405}
1406
1407DECLAREwriteFunc(writeBufferToContigTiles)
1408{
1409	uint32 imagew = TIFFScanlineSize(out);
1410	uint32 tilew  = TIFFTileRowSize(out);
1411	int iskew = imagew - tilew;
1412	tdata_t obuf = _TIFFmalloc(TIFFTileSize(out));
1413	uint8* bufp = (uint8*) buf;
1414	uint32 tl, tw;
1415	uint32 row;
1416
1417	(void) spp;
1418	if (obuf == NULL)
1419		return 0;
1420	(void) TIFFGetField(out, TIFFTAG_TILELENGTH, &tl);
1421	(void) TIFFGetField(out, TIFFTAG_TILEWIDTH, &tw);
1422	for (row = 0; row < imagelength; row += tilelength) {
1423		uint32 nrow = (row+tl > imagelength) ? imagelength-row : tl;
1424		uint32 colb = 0;
1425		uint32 col;
1426
1427		for (col = 0; col < imagewidth; col += tw) {
1428			/*
1429			 * Tile is clipped horizontally.  Calculate
1430			 * visible portion and skewing factors.
1431			 */
1432			if (colb + tilew > imagew) {
1433				uint32 width = imagew - colb;
1434				int oskew = tilew - width;
1435				cpStripToTile(obuf, bufp + colb, nrow, width,
1436				    oskew, oskew + iskew);
1437			} else
1438				cpStripToTile(obuf, bufp + colb, nrow, tilew,
1439				    0, iskew);
1440			if (TIFFWriteTile(out, obuf, col, row, 0, 0) < 0) {
1441				TIFFError(TIFFFileName(out),
1442					  "Error, can't write tile at %lu %lu",
1443					  (unsigned long) col,
1444					  (unsigned long) row);
1445				_TIFFfree(obuf);
1446				return 0;
1447			}
1448			colb += tilew;
1449		}
1450		bufp += nrow * imagew;
1451	}
1452	_TIFFfree(obuf);
1453	return 1;
1454}
1455
1456DECLAREwriteFunc(writeBufferToSeparateTiles)
1457{
1458	uint32 imagew = TIFFScanlineSize(out);
1459	tsize_t tilew  = TIFFTileRowSize(out);
1460	uint32 iimagew = TIFFRasterScanlineSize(out);
1461	int iskew = iimagew - tilew*spp;
1462	tdata_t obuf = _TIFFmalloc(TIFFTileSize(out));
1463	uint8* bufp = (uint8*) buf;
1464	uint32 tl, tw;
1465	uint32 row;
1466        uint16 bps, bytes_per_sample;
1467
1468	if (obuf == NULL)
1469		return 0;
1470	(void) TIFFGetField(out, TIFFTAG_TILELENGTH, &tl);
1471	(void) TIFFGetField(out, TIFFTAG_TILEWIDTH, &tw);
1472	(void) TIFFGetField(out, TIFFTAG_BITSPERSAMPLE, &bps);
1473        assert( bps % 8 == 0 );
1474        bytes_per_sample = bps/8;
1475
1476	for (row = 0; row < imagelength; row += tl) {
1477		uint32 nrow = (row+tl > imagelength) ? imagelength-row : tl;
1478		uint32 colb = 0;
1479		uint32 col;
1480
1481		for (col = 0; col < imagewidth; col += tw) {
1482			tsample_t s;
1483			for (s = 0; s < spp; s++) {
1484				/*
1485				 * Tile is clipped horizontally.  Calculate
1486				 * visible portion and skewing factors.
1487				 */
1488				if (colb + tilew > imagew) {
1489					uint32 width = (imagew - colb);
1490					int oskew = tilew - width;
1491
1492					cpContigBufToSeparateBuf(obuf,
1493					    bufp + (colb*spp) + s,
1494					    nrow, width/bytes_per_sample,
1495					    oskew, (oskew*spp)+iskew, spp,
1496                                            bytes_per_sample);
1497				} else
1498					cpContigBufToSeparateBuf(obuf,
1499					    bufp + (colb*spp) + s,
1500					    nrow, tilewidth,
1501					    0, iskew, spp,
1502                                            bytes_per_sample);
1503				if (TIFFWriteTile(out, obuf, col, row, 0, s) < 0) {
1504					TIFFError(TIFFFileName(out),
1505					"Error, can't write tile at %lu %lu "
1506					"sample %lu",
1507					(unsigned long) col,
1508					(unsigned long) row,
1509					(unsigned long) s);
1510					_TIFFfree(obuf);
1511					return 0;
1512				}
1513			}
1514			colb += tilew;
1515		}
1516		bufp += nrow * iimagew;
1517	}
1518	_TIFFfree(obuf);
1519	return 1;
1520}
1521
1522/*
1523 * Contig strips -> contig tiles.
1524 */
1525DECLAREcpFunc(cpContigStrips2ContigTiles)
1526{
1527	return cpImage(in, out,
1528	    readContigStripsIntoBuffer,
1529	    writeBufferToContigTiles,
1530	    imagelength, imagewidth, spp);
1531}
1532
1533/*
1534 * Contig strips -> separate tiles.
1535 */
1536DECLAREcpFunc(cpContigStrips2SeparateTiles)
1537{
1538	return cpImage(in, out,
1539	    readContigStripsIntoBuffer,
1540	    writeBufferToSeparateTiles,
1541	    imagelength, imagewidth, spp);
1542}
1543
1544/*
1545 * Separate strips -> contig tiles.
1546 */
1547DECLAREcpFunc(cpSeparateStrips2ContigTiles)
1548{
1549	return cpImage(in, out,
1550	    readSeparateStripsIntoBuffer,
1551	    writeBufferToContigTiles,
1552	    imagelength, imagewidth, spp);
1553}
1554
1555/*
1556 * Separate strips -> separate tiles.
1557 */
1558DECLAREcpFunc(cpSeparateStrips2SeparateTiles)
1559{
1560	return cpImage(in, out,
1561	    readSeparateStripsIntoBuffer,
1562	    writeBufferToSeparateTiles,
1563	    imagelength, imagewidth, spp);
1564}
1565
1566/*
1567 * Contig strips -> contig tiles.
1568 */
1569DECLAREcpFunc(cpContigTiles2ContigTiles)
1570{
1571	return cpImage(in, out,
1572	    readContigTilesIntoBuffer,
1573	    writeBufferToContigTiles,
1574	    imagelength, imagewidth, spp);
1575}
1576
1577/*
1578 * Contig tiles -> separate tiles.
1579 */
1580DECLAREcpFunc(cpContigTiles2SeparateTiles)
1581{
1582	return cpImage(in, out,
1583	    readContigTilesIntoBuffer,
1584	    writeBufferToSeparateTiles,
1585	    imagelength, imagewidth, spp);
1586}
1587
1588/*
1589 * Separate tiles -> contig tiles.
1590 */
1591DECLAREcpFunc(cpSeparateTiles2ContigTiles)
1592{
1593	return cpImage(in, out,
1594	    readSeparateTilesIntoBuffer,
1595	    writeBufferToContigTiles,
1596	    imagelength, imagewidth, spp);
1597}
1598
1599/*
1600 * Separate tiles -> separate tiles (tile dimension change).
1601 */
1602DECLAREcpFunc(cpSeparateTiles2SeparateTiles)
1603{
1604	return cpImage(in, out,
1605	    readSeparateTilesIntoBuffer,
1606	    writeBufferToSeparateTiles,
1607	    imagelength, imagewidth, spp);
1608}
1609
1610/*
1611 * Contig tiles -> contig tiles (tile dimension change).
1612 */
1613DECLAREcpFunc(cpContigTiles2ContigStrips)
1614{
1615	return cpImage(in, out,
1616	    readContigTilesIntoBuffer,
1617	    writeBufferToContigStrips,
1618	    imagelength, imagewidth, spp);
1619}
1620
1621/*
1622 * Contig tiles -> separate strips.
1623 */
1624DECLAREcpFunc(cpContigTiles2SeparateStrips)
1625{
1626	return cpImage(in, out,
1627	    readContigTilesIntoBuffer,
1628	    writeBufferToSeparateStrips,
1629	    imagelength, imagewidth, spp);
1630}
1631
1632/*
1633 * Separate tiles -> contig strips.
1634 */
1635DECLAREcpFunc(cpSeparateTiles2ContigStrips)
1636{
1637	return cpImage(in, out,
1638	    readSeparateTilesIntoBuffer,
1639	    writeBufferToContigStrips,
1640	    imagelength, imagewidth, spp);
1641}
1642
1643/*
1644 * Separate tiles -> separate strips.
1645 */
1646DECLAREcpFunc(cpSeparateTiles2SeparateStrips)
1647{
1648	return cpImage(in, out,
1649	    readSeparateTilesIntoBuffer,
1650	    writeBufferToSeparateStrips,
1651	    imagelength, imagewidth, spp);
1652}
1653
1654/*
1655 * Select the appropriate copy function to use.
1656 */
1657static copyFunc
1658pickCopyFunc(TIFF* in, TIFF* out, uint16 bitspersample, uint16 samplesperpixel)
1659{
1660	uint16 shortv;
1661	uint32 w, l, tw, tl;
1662	int bychunk;
1663
1664	(void) TIFFGetField(in, TIFFTAG_PLANARCONFIG, &shortv);
1665	if (shortv != config && bitspersample != 8 && samplesperpixel > 1) {
1666		fprintf(stderr,
1667"%s: Cannot handle different planar configuration w/ bits/sample != 8\n",
1668		    TIFFFileName(in));
1669		return (NULL);
1670	}
1671	TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &w);
1672	TIFFGetField(in, TIFFTAG_IMAGELENGTH, &l);
1673        if (!(TIFFIsTiled(out) || TIFFIsTiled(in))) {
1674	    uint32 irps = (uint32) -1L;
1675	    TIFFGetField(in, TIFFTAG_ROWSPERSTRIP, &irps);
1676            /* if biased, force decoded copying to allow image subtraction */
1677	    bychunk = !bias && (rowsperstrip == irps);
1678	}else{  /* either in or out is tiled */
1679            if (bias) {
1680                  fprintf(stderr,
1681"%s: Cannot handle tiled configuration w/bias image\n",
1682                  TIFFFileName(in));
1683                  return (NULL);
1684            }
1685	    if (TIFFIsTiled(out)) {
1686		if (!TIFFGetField(in, TIFFTAG_TILEWIDTH, &tw))
1687			tw = w;
1688		if (!TIFFGetField(in, TIFFTAG_TILELENGTH, &tl))
1689			tl = l;
1690		bychunk = (tw == tilewidth && tl == tilelength);
1691	    } else {  /* out's not, so in must be tiled */
1692		TIFFGetField(in, TIFFTAG_TILEWIDTH, &tw);
1693		TIFFGetField(in, TIFFTAG_TILELENGTH, &tl);
1694		bychunk = (tw == w && tl == rowsperstrip);
1695            }
1696	}
1697#define	T 1
1698#define	F 0
1699#define pack(a,b,c,d,e)	((long)(((a)<<11)|((b)<<3)|((c)<<2)|((d)<<1)|(e)))
1700	switch(pack(shortv,config,TIFFIsTiled(in),TIFFIsTiled(out),bychunk)) {
1701/* Strips -> Tiles */
1702	case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_CONTIG,   F,T,F):
1703	case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_CONTIG,   F,T,T):
1704		return cpContigStrips2ContigTiles;
1705	case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_SEPARATE, F,T,F):
1706	case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_SEPARATE, F,T,T):
1707		return cpContigStrips2SeparateTiles;
1708        case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG,   F,T,F):
1709        case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG,   F,T,T):
1710		return cpSeparateStrips2ContigTiles;
1711	case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F,T,F):
1712	case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F,T,T):
1713		return cpSeparateStrips2SeparateTiles;
1714/* Tiles -> Tiles */
1715	case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_CONTIG,   T,T,F):
1716	case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_CONTIG,   T,T,T):
1717		return cpContigTiles2ContigTiles;
1718	case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_SEPARATE, T,T,F):
1719	case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_SEPARATE, T,T,T):
1720		return cpContigTiles2SeparateTiles;
1721        case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG,   T,T,F):
1722        case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG,   T,T,T):
1723		return cpSeparateTiles2ContigTiles;
1724	case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, T,T,F):
1725	case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, T,T,T):
1726		return cpSeparateTiles2SeparateTiles;
1727/* Tiles -> Strips */
1728	case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_CONTIG,   T,F,F):
1729	case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_CONTIG,   T,F,T):
1730		return cpContigTiles2ContigStrips;
1731	case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_SEPARATE, T,F,F):
1732	case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_SEPARATE, T,F,T):
1733		return cpContigTiles2SeparateStrips;
1734        case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG,   T,F,F):
1735        case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG,   T,F,T):
1736		return cpSeparateTiles2ContigStrips;
1737	case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, T,F,F):
1738	case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, T,F,T):
1739		return cpSeparateTiles2SeparateStrips;
1740/* Strips -> Strips */
1741	case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_CONTIG,   F,F,F):
1742		return bias ? cpBiasedContig2Contig : cpContig2ContigByRow;
1743	case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_CONTIG,   F,F,T):
1744		return cpDecodedStrips;
1745	case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE,   F,F,F):
1746	case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE,   F,F,T):
1747		return cpContig2SeparateByRow;
1748	case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG,   F,F,F):
1749	case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG,   F,F,T):
1750		return cpSeparate2ContigByRow;
1751	case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F,F,F):
1752	case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F,F,T):
1753		return cpSeparate2SeparateByRow;
1754	}
1755#undef pack
1756#undef F
1757#undef T
1758	fprintf(stderr, "tiffcp: %s: Don't know how to copy/convert image.\n",
1759	    TIFFFileName(in));
1760	return (NULL);
1761}
1762
1763/* vim: set ts=8 sts=8 sw=8 noet: */
1764/*
1765 * Local Variables:
1766 * mode: c
1767 * c-basic-offset: 8
1768 * fill-column: 78
1769 * End:
1770 */
1771