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