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