4  * Copyright (c) 1988-1997 Sam Leffler 
   5  * Copyright (c) 1991-1997 Silicon Graphics, Inc. 
   7  * Permission to use, copy, modify, distribute, and sell this software and  
   8  * its documentation for any purpose is hereby granted without fee, provided 
   9  * that (i) the above copyright notices and this permission notice appear in 
  10  * all copies of the software and related documentation, and (ii) the names of 
  11  * Sam Leffler and Silicon Graphics may not be used in any advertising or 
  12  * publicity relating to the software without the specific, prior written 
  13  * permission of Sam Leffler and Silicon Graphics. 
  15  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,  
  16  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY  
  17  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.   
  19  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR 
  20  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, 
  21  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 
  22  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF  
  23  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE  
  27 #include "tif_config.h" 
  44 #define streq(a,b)      (strcmp((a),(b)) == 0) 
  45 #define strneq(a,b,n)   (strncmp(a,b,n) == 0) 
  47 /* x% weighting -> fraction of full color */ 
  48 #define PCT(x)  (((x)*255+127)/100) 
  49 int     RED 
= PCT(30);          /* 30% */ 
  50 int     GREEN 
= PCT(59);        /* 59% */ 
  51 int     BLUE 
= PCT(11);         /* 11% */ 
  53 static  void usage(void); 
  54 static  int processCompressOptions(char*); 
  57 compresscontig(unsigned char* out
, unsigned char* rgb
, uint32 n
) 
  59         register int v
, red 
= RED
, green 
= GREEN
, blue 
= BLUE
; 
  70 compresssep(unsigned char* out
, 
  71             unsigned char* r
, unsigned char* g
, unsigned char* b
, uint32 n
) 
  73         register uint32 red 
= RED
, green 
= GREEN
, blue 
= BLUE
; 
  76                 *out
++ = (unsigned char) 
  77                         ((red
*(*r
++) + green
*(*g
++) + blue
*(*b
++)) >> 8); 
  81 checkcmap(TIFF
* tif
, int n
, uint16
* r
, uint16
* g
, uint16
* b
) 
  84                 if (*r
++ >= 256 || *g
++ >= 256 || *b
++ >= 256) 
  86         TIFFWarning(TIFFFileName(tif
), "Assuming 8-bit colormap"); 
  91 compresspalette(unsigned char* out
, unsigned char* data
, uint32 n
, uint16
* rmap
, uint16
* gmap
, uint16
* bmap
) 
  93         register int v
, red 
= RED
, green 
= GREEN
, blue 
= BLUE
; 
  96                 unsigned int ix 
= *data
++; 
 104 static  uint16 compression 
= (uint16
) -1; 
 105 static  uint16 predictor 
= 0; 
 106 static  int jpegcolormode 
= JPEGCOLORMODE_RGB
; 
 107 static  int quality 
= 75;               /* JPEG quality */ 
 109 static  void cpTags(TIFF
* in
, TIFF
* out
); 
 112 main(int argc
, char* argv
[]) 
 114         uint32 rowsperstrip 
= (uint32
) -1; 
 117         uint16 samplesperpixel
; 
 118         uint16 bitspersample
; 
 126         register tsample_t s
; 
 127         unsigned char *inbuf
, *outbuf
; 
 133         while ((c 
= getopt(argc
, argv
, "c:r:R:G:B:")) != -1) 
 135                 case 'c':               /* compression scheme */ 
 136                         if (!processCompressOptions(optarg
)) 
 139                 case 'r':               /* rows/strip */ 
 140                         rowsperstrip 
= atoi(optarg
); 
 143                         RED 
= PCT(atoi(optarg
)); 
 146                         GREEN 
= PCT(atoi(optarg
)); 
 149                         BLUE 
= PCT(atoi(optarg
)); 
 155         if (argc 
- optind 
< 2) 
 157         in 
= TIFFOpen(argv
[optind
], "r"); 
 161         TIFFGetField(in
, TIFFTAG_PHOTOMETRIC
, &photometric
); 
 162         if (photometric 
!= PHOTOMETRIC_RGB 
&& photometric 
!= PHOTOMETRIC_PALETTE 
) { 
 164             "%s: Bad photometric; can only handle RGB and Palette images.\n", 
 168         TIFFGetField(in
, TIFFTAG_SAMPLESPERPIXEL
, &samplesperpixel
); 
 169         if (samplesperpixel 
!= 1 && samplesperpixel 
!= 3) { 
 170                 fprintf(stderr
, "%s: Bad samples/pixel %u.\n", 
 171                     argv
[optind
], samplesperpixel
); 
 174         TIFFGetField(in
, TIFFTAG_BITSPERSAMPLE
, &bitspersample
); 
 175         if (bitspersample 
!= 8) { 
 177                     " %s: Sorry, only handle 8-bit samples.\n", argv
[optind
]); 
 180         TIFFGetField(in
, TIFFTAG_IMAGEWIDTH
, &w
); 
 181         TIFFGetField(in
, TIFFTAG_IMAGELENGTH
, &h
); 
 182         TIFFGetField(in
, TIFFTAG_PLANARCONFIG
, &config
); 
 184         out 
= TIFFOpen(argv
[optind
+1], "w"); 
 187         TIFFSetField(out
, TIFFTAG_IMAGEWIDTH
, w
); 
 188         TIFFSetField(out
, TIFFTAG_IMAGELENGTH
, h
); 
 189         TIFFSetField(out
, TIFFTAG_BITSPERSAMPLE
, 8); 
 190         TIFFSetField(out
, TIFFTAG_SAMPLESPERPIXEL
, 1); 
 191         TIFFSetField(out
, TIFFTAG_PLANARCONFIG
, PLANARCONFIG_CONTIG
); 
 193         if (compression 
!= (uint16
) -1) { 
 194                 TIFFSetField(out
, TIFFTAG_COMPRESSION
, compression
); 
 195                 switch (compression
) { 
 196                 case COMPRESSION_JPEG
: 
 197                         TIFFSetField(out
, TIFFTAG_JPEGQUALITY
, quality
); 
 198                         TIFFSetField(out
, TIFFTAG_JPEGCOLORMODE
, jpegcolormode
); 
 200                 case COMPRESSION_LZW
: 
 201                 case COMPRESSION_DEFLATE
: 
 203                                 TIFFSetField(out
, TIFFTAG_PREDICTOR
, predictor
); 
 207         TIFFSetField(out
, TIFFTAG_PHOTOMETRIC
, PHOTOMETRIC_MINISBLACK
); 
 208         sprintf(thing
, "B&W version of %s", argv
[optind
]); 
 209         TIFFSetField(out
, TIFFTAG_IMAGEDESCRIPTION
, thing
); 
 210         TIFFSetField(out
, TIFFTAG_SOFTWARE
, "tiff2bw"); 
 211         outbuf 
= (unsigned char *)_TIFFmalloc(TIFFScanlineSize(out
)); 
 212         TIFFSetField(out
, TIFFTAG_ROWSPERSTRIP
, 
 213             TIFFDefaultStripSize(out
, rowsperstrip
)); 
 215 #define pack(a,b)       ((a)<<8 | (b)) 
 216         switch (pack(photometric
, config
)) { 
 217         case pack(PHOTOMETRIC_PALETTE
, PLANARCONFIG_CONTIG
): 
 218         case pack(PHOTOMETRIC_PALETTE
, PLANARCONFIG_SEPARATE
): 
 219                 TIFFGetField(in
, TIFFTAG_COLORMAP
, &red
, &green
, &blue
); 
 221                  * Convert 16-bit colormap to 8-bit (unless it looks 
 222                  * like an old-style 8-bit colormap). 
 224                 if (checkcmap(in
, 1<<bitspersample
, red
, green
, blue
) == 16) { 
 226 #define CVT(x)          (((x) * 255L) / ((1L<<16)-1)) 
 227                         for (i 
= (1<<bitspersample
)-1; i 
>= 0; i
--) { 
 228                                 red
[i
] = CVT(red
[i
]); 
 229                                 green
[i
] = CVT(green
[i
]); 
 230                                 blue
[i
] = CVT(blue
[i
]); 
 234                 inbuf 
= (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in
)); 
 235                 for (row 
= 0; row 
< h
; row
++) { 
 236                         if (TIFFReadScanline(in
, inbuf
, row
, 0) < 0) 
 238                         compresspalette(outbuf
, inbuf
, w
, red
, green
, blue
); 
 239                         if (TIFFWriteScanline(out
, outbuf
, row
, 0) < 0) 
 243         case pack(PHOTOMETRIC_RGB
, PLANARCONFIG_CONTIG
): 
 244                 inbuf 
= (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in
)); 
 245                 for (row 
= 0; row 
< h
; row
++) { 
 246                         if (TIFFReadScanline(in
, inbuf
, row
, 0) < 0) 
 248                         compresscontig(outbuf
, inbuf
, w
); 
 249                         if (TIFFWriteScanline(out
, outbuf
, row
, 0) < 0) 
 253         case pack(PHOTOMETRIC_RGB
, PLANARCONFIG_SEPARATE
): 
 254                 rowsize 
= TIFFScanlineSize(in
); 
 255                 inbuf 
= (unsigned char *)_TIFFmalloc(3*rowsize
); 
 256                 for (row 
= 0; row 
< h
; row
++) { 
 257                         for (s 
= 0; s 
< 3; s
++) 
 258                                 if (TIFFReadScanline(in
, 
 259                                     inbuf
+s
*rowsize
, row
, s
) < 0) 
 262                             inbuf
, inbuf
+rowsize
, inbuf
+2*rowsize
, w
); 
 263                         if (TIFFWriteScanline(out
, outbuf
, row
, 0) < 0) 
 274 processCompressOptions(char* opt
) 
 276         if (streq(opt
, "none")) 
 277                 compression 
= COMPRESSION_NONE
; 
 278         else if (streq(opt
, "packbits")) 
 279                 compression 
= COMPRESSION_PACKBITS
; 
 280         else if (strneq(opt
, "jpeg", 4)) { 
 281                 char* cp 
= strchr(opt
, ':'); 
 283                 compression 
= COMPRESSION_JPEG
; 
 286                     if (isdigit((int)cp
[1])) 
 287                         quality 
= atoi(cp
+1); 
 288                     else if (cp
[1] == 'r' ) 
 289                         jpegcolormode 
= JPEGCOLORMODE_RAW
; 
 293                     cp 
= strchr(cp
+1,':'); 
 295         } else if (strneq(opt
, "lzw", 3)) { 
 296                 char* cp 
= strchr(opt
, ':'); 
 298                         predictor 
= atoi(cp
+1); 
 299                 compression 
= COMPRESSION_LZW
; 
 300         } else if (strneq(opt
, "zip", 3)) { 
 301                 char* cp 
= strchr(opt
, ':'); 
 303                         predictor 
= atoi(cp
+1); 
 304                 compression 
= COMPRESSION_DEFLATE
; 
 310 #define CopyField(tag, v) \ 
 311     if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v) 
 312 #define CopyField2(tag, v1, v2) \ 
 313     if (TIFFGetField(in, tag, &v1, &v2)) TIFFSetField(out, tag, v1, v2) 
 314 #define CopyField3(tag, v1, v2, v3) \ 
 315     if (TIFFGetField(in, tag, &v1, &v2, &v3)) TIFFSetField(out, tag, v1, v2, v3) 
 316 #define CopyField4(tag, v1, v2, v3, v4) \ 
 317     if (TIFFGetField(in, tag, &v1, &v2, &v3, &v4)) TIFFSetField(out, tag, v1, v2, v3, v4) 
 320 cpTag(TIFF
* in
, TIFF
* out
, uint16 tag
, uint16 count
, TIFFDataType type
) 
 326                         CopyField(tag
, shortv
); 
 327                 } else if (count 
== 2) { 
 328                         uint16 shortv1
, shortv2
; 
 329                         CopyField2(tag
, shortv1
, shortv2
); 
 330                 } else if (count 
== 4) { 
 331                         uint16 
*tr
, *tg
, *tb
, *ta
; 
 332                         CopyField4(tag
, tr
, tg
, tb
, ta
); 
 333                 } else if (count 
== (uint16
) -1) { 
 336                         CopyField2(tag
, shortv1
, shortav
); 
 341                   CopyField(tag
, longv
); 
 347                         CopyField(tag
, floatv
); 
 348                 } else if (count 
== (uint16
) -1) { 
 350                         CopyField(tag
, floatav
); 
 355                   CopyField(tag
, stringv
); 
 361                         CopyField(tag
, doublev
); 
 362                 } else if (count 
== (uint16
) -1) { 
 364                         CopyField(tag
, doubleav
); 
 368                 TIFFError(TIFFFileName(in
), 
 369                           "Data type %d is not supported, tag %d skipped.", 
 379 static struct cpTag 
{ 
 384         { TIFFTAG_SUBFILETYPE
,          1, TIFF_LONG 
}, 
 385         { TIFFTAG_THRESHHOLDING
,        1, TIFF_SHORT 
}, 
 386         { TIFFTAG_DOCUMENTNAME
,         1, TIFF_ASCII 
}, 
 387         { TIFFTAG_IMAGEDESCRIPTION
,     1, TIFF_ASCII 
}, 
 388         { TIFFTAG_MAKE
,                 1, TIFF_ASCII 
}, 
 389         { TIFFTAG_MODEL
,                1, TIFF_ASCII 
}, 
 390         { TIFFTAG_MINSAMPLEVALUE
,       1, TIFF_SHORT 
}, 
 391         { TIFFTAG_MAXSAMPLEVALUE
,       1, TIFF_SHORT 
}, 
 392         { TIFFTAG_XRESOLUTION
,          1, TIFF_RATIONAL 
}, 
 393         { TIFFTAG_YRESOLUTION
,          1, TIFF_RATIONAL 
}, 
 394         { TIFFTAG_PAGENAME
,             1, TIFF_ASCII 
}, 
 395         { TIFFTAG_XPOSITION
,            1, TIFF_RATIONAL 
}, 
 396         { TIFFTAG_YPOSITION
,            1, TIFF_RATIONAL 
}, 
 397         { TIFFTAG_RESOLUTIONUNIT
,       1, TIFF_SHORT 
}, 
 398         { TIFFTAG_SOFTWARE
,             1, TIFF_ASCII 
}, 
 399         { TIFFTAG_DATETIME
,             1, TIFF_ASCII 
}, 
 400         { TIFFTAG_ARTIST
,               1, TIFF_ASCII 
}, 
 401         { TIFFTAG_HOSTCOMPUTER
,         1, TIFF_ASCII 
}, 
 402         { TIFFTAG_WHITEPOINT
,           2, TIFF_RATIONAL 
}, 
 403         { TIFFTAG_PRIMARYCHROMATICITIES
,(uint16
) -1,TIFF_RATIONAL 
}, 
 404         { TIFFTAG_HALFTONEHINTS
,        2, TIFF_SHORT 
}, 
 405         { TIFFTAG_INKSET
,               1, TIFF_SHORT 
}, 
 406         { TIFFTAG_DOTRANGE
,             2, TIFF_SHORT 
}, 
 407         { TIFFTAG_TARGETPRINTER
,        1, TIFF_ASCII 
}, 
 408         { TIFFTAG_SAMPLEFORMAT
,         1, TIFF_SHORT 
}, 
 409         { TIFFTAG_YCBCRCOEFFICIENTS
,    (uint16
) -1,TIFF_RATIONAL 
}, 
 410         { TIFFTAG_YCBCRSUBSAMPLING
,     2, TIFF_SHORT 
}, 
 411         { TIFFTAG_YCBCRPOSITIONING
,     1, TIFF_SHORT 
}, 
 412         { TIFFTAG_REFERENCEBLACKWHITE
,  (uint16
) -1,TIFF_RATIONAL 
}, 
 413         { TIFFTAG_EXTRASAMPLES
,         (uint16
) -1, TIFF_SHORT 
}, 
 414         { TIFFTAG_SMINSAMPLEVALUE
,      1, TIFF_DOUBLE 
}, 
 415         { TIFFTAG_SMAXSAMPLEVALUE
,      1, TIFF_DOUBLE 
}, 
 416         { TIFFTAG_STONITS
,              1, TIFF_DOUBLE 
}, 
 418 #define NTAGS   (sizeof (tags) / sizeof (tags[0])) 
 421 cpTags(TIFF
* in
, TIFF
* out
) 
 424     for (p 
= tags
; p 
< &tags
[NTAGS
]; p
++) 
 425         cpTag(in
, out
, p
->tag
, p
->count
, p
->type
); 
 430 "usage: tiff2bw [options] input.tif output.tif", 
 431 "where options are:", 
 432 " -R %          use #% from red channel", 
 433 " -G %          use #% from green channel", 
 434 " -B %          use #% from blue channel", 
 436 " -r #          make each strip have no more than # rows", 
 438 " -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding", 
 439 " -c zip[:opts] compress output with deflate encoding", 
 440 " -c packbits   compress output with packbits encoding", 
 441 " -c g3[:opts]  compress output with CCITT Group 3 encoding", 
 442 " -c g4         compress output with CCITT Group 4 encoding", 
 443 " -c none       use no compression algorithm on output", 
 445 "LZW and deflate options:", 
 446 " #             set predictor value", 
 447 "For example, -c lzw:2 to get LZW-encoded data with horizontal differencing", 
 458         fprintf(stderr
, "%s\n\n", TIFFGetVersion()); 
 459         for (i 
= 0; stuff
[i
] != NULL
; i
++) 
 460                 fprintf(stderr
, "%s\n", stuff
[i
]); 
 464 /* vim: set ts=8 sts=8 sw=8 noet: */