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