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