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