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" 
  40 #define streq(a,b)      (strcmp((a),(b)) == 0) 
  41 #define strneq(a,b,n)   (strncmp(a,b,n) == 0) 
  43 /* x% weighting -> fraction of full color */ 
  44 #define PCT(x)  (((x)*255+127)/100) 
  45 int     RED 
= PCT(30);          /* 30% */ 
  46 int     GREEN 
= PCT(59);        /* 59% */ 
  47 int     BLUE 
= PCT(11);         /* 11% */ 
  49 static  void usage(void); 
  50 static  int processCompressOptions(char*); 
  53 compresscontig(unsigned char* out
, unsigned char* rgb
, uint32 n
) 
  55         register int v
, red 
= RED
, green 
= GREEN
, blue 
= BLUE
; 
  66 compresssep(unsigned char* out
, 
  67             unsigned char* r
, unsigned char* g
, unsigned char* b
, uint32 n
) 
  69         register uint32 red 
= RED
, green 
= GREEN
, blue 
= BLUE
; 
  72                 *out
++ = (unsigned char) 
  73                         ((red
*(*r
++) + green
*(*g
++) + blue
*(*b
++)) >> 8); 
  77 checkcmap(TIFF
* tif
, int n
, uint16
* r
, uint16
* g
, uint16
* b
) 
  80                 if (*r
++ >= 256 || *g
++ >= 256 || *b
++ >= 256) 
  82         TIFFWarning(TIFFFileName(tif
), "Assuming 8-bit colormap"); 
  87 compresspalette(unsigned char* out
, unsigned char* data
, uint32 n
, uint16
* rmap
, uint16
* gmap
, uint16
* bmap
) 
  89         register int v
, red 
= RED
, green 
= GREEN
, blue 
= BLUE
; 
  92                 unsigned int ix 
= *data
++; 
 100 static  uint16 compression 
= (uint16
) -1; 
 101 static  uint16 predictor 
= 0; 
 102 static  int jpegcolormode 
= JPEGCOLORMODE_RGB
; 
 103 static  int quality 
= 75;               /* JPEG quality */ 
 105 static  void cpTags(TIFF
* in
, TIFF
* out
); 
 108 main(int argc
, char* argv
[]) 
 110         uint32 rowsperstrip 
= (uint32
) -1; 
 113         uint16 samplesperpixel
; 
 114         uint16 bitspersample
; 
 122         register tsample_t s
; 
 123         unsigned char *inbuf
, *outbuf
; 
 129         while ((c 
= getopt(argc
, argv
, "c:r:R:G:B:")) != -1) 
 131                 case 'c':               /* compression scheme */ 
 132                         if (!processCompressOptions(optarg
)) 
 135                 case 'r':               /* rows/strip */ 
 136                         rowsperstrip 
= atoi(optarg
); 
 139                         RED 
= PCT(atoi(optarg
)); 
 142                         GREEN 
= PCT(atoi(optarg
)); 
 145                         BLUE 
= PCT(atoi(optarg
)); 
 151         if (argc 
- optind 
< 2) 
 153         in 
= TIFFOpen(argv
[optind
], "r"); 
 157         TIFFGetField(in
, TIFFTAG_PHOTOMETRIC
, &photometric
); 
 158         if (photometric 
!= PHOTOMETRIC_RGB 
&& photometric 
!= PHOTOMETRIC_PALETTE 
) { 
 160             "%s: Bad photometric; can only handle RGB and Palette images.\n", 
 164         TIFFGetField(in
, TIFFTAG_SAMPLESPERPIXEL
, &samplesperpixel
); 
 165         if (samplesperpixel 
!= 1 && samplesperpixel 
!= 3) { 
 166                 fprintf(stderr
, "%s: Bad samples/pixel %u.\n", 
 167                     argv
[optind
], samplesperpixel
); 
 170         TIFFGetField(in
, TIFFTAG_BITSPERSAMPLE
, &bitspersample
); 
 171         if (bitspersample 
!= 8) { 
 173                     " %s: Sorry, only handle 8-bit samples.\n", argv
[optind
]); 
 176         TIFFGetField(in
, TIFFTAG_IMAGEWIDTH
, &w
); 
 177         TIFFGetField(in
, TIFFTAG_IMAGELENGTH
, &h
); 
 178         TIFFGetField(in
, TIFFTAG_PLANARCONFIG
, &config
); 
 180         out 
= TIFFOpen(argv
[optind
+1], "w"); 
 183         TIFFSetField(out
, TIFFTAG_IMAGEWIDTH
, w
); 
 184         TIFFSetField(out
, TIFFTAG_IMAGELENGTH
, h
); 
 185         TIFFSetField(out
, TIFFTAG_BITSPERSAMPLE
, 8); 
 186         TIFFSetField(out
, TIFFTAG_SAMPLESPERPIXEL
, 1); 
 187         TIFFSetField(out
, TIFFTAG_PLANARCONFIG
, PLANARCONFIG_CONTIG
); 
 189         if (compression 
!= (uint16
) -1) { 
 190                 TIFFSetField(out
, TIFFTAG_COMPRESSION
, compression
); 
 191                 switch (compression
) { 
 192                 case COMPRESSION_JPEG
: 
 193                         TIFFSetField(out
, TIFFTAG_JPEGQUALITY
, quality
); 
 194                         TIFFSetField(out
, TIFFTAG_JPEGCOLORMODE
, jpegcolormode
); 
 196                 case COMPRESSION_LZW
: 
 197                 case COMPRESSION_DEFLATE
: 
 199                                 TIFFSetField(out
, TIFFTAG_PREDICTOR
, predictor
); 
 203         TIFFSetField(out
, TIFFTAG_PHOTOMETRIC
, PHOTOMETRIC_MINISBLACK
); 
 204         sprintf(thing
, "B&W version of %s", argv
[optind
]); 
 205         TIFFSetField(out
, TIFFTAG_IMAGEDESCRIPTION
, thing
); 
 206         TIFFSetField(out
, TIFFTAG_SOFTWARE
, "tiff2bw"); 
 207         outbuf 
= (unsigned char *)_TIFFmalloc(TIFFScanlineSize(out
)); 
 208         TIFFSetField(out
, TIFFTAG_ROWSPERSTRIP
, 
 209             TIFFDefaultStripSize(out
, rowsperstrip
)); 
 211 #define pack(a,b)       ((a)<<8 | (b)) 
 212         switch (pack(photometric
, config
)) { 
 213         case pack(PHOTOMETRIC_PALETTE
, PLANARCONFIG_CONTIG
): 
 214         case pack(PHOTOMETRIC_PALETTE
, PLANARCONFIG_SEPARATE
): 
 215                 TIFFGetField(in
, TIFFTAG_COLORMAP
, &red
, &green
, &blue
); 
 217                  * Convert 16-bit colormap to 8-bit (unless it looks 
 218                  * like an old-style 8-bit colormap). 
 220                 if (checkcmap(in
, 1<<bitspersample
, red
, green
, blue
) == 16) { 
 222 #define CVT(x)          (((x) * 255L) / ((1L<<16)-1)) 
 223                         for (i 
= (1<<bitspersample
)-1; i 
>= 0; i
--) { 
 224                                 red
[i
] = CVT(red
[i
]); 
 225                                 green
[i
] = CVT(green
[i
]); 
 226                                 blue
[i
] = CVT(blue
[i
]); 
 230                 inbuf 
= (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in
)); 
 231                 for (row 
= 0; row 
< h
; row
++) { 
 232                         if (TIFFReadScanline(in
, inbuf
, row
, 0) < 0) 
 234                         compresspalette(outbuf
, inbuf
, w
, red
, green
, blue
); 
 235                         if (TIFFWriteScanline(out
, outbuf
, row
, 0) < 0) 
 239         case pack(PHOTOMETRIC_RGB
, PLANARCONFIG_CONTIG
): 
 240                 inbuf 
= (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in
)); 
 241                 for (row 
= 0; row 
< h
; row
++) { 
 242                         if (TIFFReadScanline(in
, inbuf
, row
, 0) < 0) 
 244                         compresscontig(outbuf
, inbuf
, w
); 
 245                         if (TIFFWriteScanline(out
, outbuf
, row
, 0) < 0) 
 249         case pack(PHOTOMETRIC_RGB
, PLANARCONFIG_SEPARATE
): 
 250                 rowsize 
= TIFFScanlineSize(in
); 
 251                 inbuf 
= (unsigned char *)_TIFFmalloc(3*rowsize
); 
 252                 for (row 
= 0; row 
< h
; row
++) { 
 253                         for (s 
= 0; s 
< 3; s
++) 
 254                                 if (TIFFReadScanline(in
, 
 255                                     inbuf
+s
*rowsize
, row
, s
) < 0) 
 258                             inbuf
, inbuf
+rowsize
, inbuf
+2*rowsize
, w
); 
 259                         if (TIFFWriteScanline(out
, outbuf
, row
, 0) < 0) 
 270 processCompressOptions(char* opt
) 
 272         if (streq(opt
, "none")) 
 273                 compression 
= COMPRESSION_NONE
; 
 274         else if (streq(opt
, "packbits")) 
 275                 compression 
= COMPRESSION_PACKBITS
; 
 276         else if (strneq(opt
, "jpeg", 4)) { 
 277                 char* cp 
= strchr(opt
, ':'); 
 279                 compression 
= COMPRESSION_JPEG
; 
 282                     if (isdigit((int)cp
[1])) 
 283                         quality 
= atoi(cp
+1); 
 284                     else if (cp
[1] == 'r' ) 
 285                         jpegcolormode 
= JPEGCOLORMODE_RAW
; 
 289                     cp 
= strchr(cp
+1,':'); 
 291         } else if (strneq(opt
, "lzw", 3)) { 
 292                 char* cp 
= strchr(opt
, ':'); 
 294                         predictor 
= atoi(cp
+1); 
 295                 compression 
= COMPRESSION_LZW
; 
 296         } else if (strneq(opt
, "zip", 3)) { 
 297                 char* cp 
= strchr(opt
, ':'); 
 299                         predictor 
= atoi(cp
+1); 
 300                 compression 
= COMPRESSION_DEFLATE
; 
 306 #define CopyField(tag, v) \ 
 307     if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v) 
 308 #define CopyField2(tag, v1, v2) \ 
 309     if (TIFFGetField(in, tag, &v1, &v2)) TIFFSetField(out, tag, v1, v2) 
 310 #define CopyField3(tag, v1, v2, v3) \ 
 311     if (TIFFGetField(in, tag, &v1, &v2, &v3)) TIFFSetField(out, tag, v1, v2, v3) 
 312 #define CopyField4(tag, v1, v2, v3, v4) \ 
 313     if (TIFFGetField(in, tag, &v1, &v2, &v3, &v4)) TIFFSetField(out, tag, v1, v2, v3, v4) 
 316 cpTag(TIFF
* in
, TIFF
* out
, uint16 tag
, uint16 count
, TIFFDataType type
) 
 322                         CopyField(tag
, shortv
); 
 323                 } else if (count 
== 2) { 
 324                         uint16 shortv1
, shortv2
; 
 325                         CopyField2(tag
, shortv1
, shortv2
); 
 326                 } else if (count 
== 4) { 
 327                         uint16 
*tr
, *tg
, *tb
, *ta
; 
 328                         CopyField4(tag
, tr
, tg
, tb
, ta
); 
 329                 } else if (count 
== (uint16
) -1) { 
 332                         CopyField2(tag
, shortv1
, shortav
); 
 337                   CopyField(tag
, longv
); 
 343                         CopyField(tag
, floatv
); 
 344                 } else if (count 
== (uint16
) -1) { 
 346                         CopyField(tag
, floatav
); 
 351                   CopyField(tag
, stringv
); 
 357                         CopyField(tag
, doublev
); 
 358                 } else if (count 
== (uint16
) -1) { 
 360                         CopyField(tag
, doubleav
); 
 364                 TIFFError(TIFFFileName(in
), 
 365                           "Data type %d is not supported, tag %d skipped.", 
 375 static struct cpTag 
{ 
 380         { TIFFTAG_SUBFILETYPE
,          1, TIFF_LONG 
}, 
 381         { TIFFTAG_THRESHHOLDING
,        1, TIFF_SHORT 
}, 
 382         { TIFFTAG_DOCUMENTNAME
,         1, TIFF_ASCII 
}, 
 383         { TIFFTAG_IMAGEDESCRIPTION
,     1, TIFF_ASCII 
}, 
 384         { TIFFTAG_MAKE
,                 1, TIFF_ASCII 
}, 
 385         { TIFFTAG_MODEL
,                1, TIFF_ASCII 
}, 
 386         { TIFFTAG_MINSAMPLEVALUE
,       1, TIFF_SHORT 
}, 
 387         { TIFFTAG_MAXSAMPLEVALUE
,       1, TIFF_SHORT 
}, 
 388         { TIFFTAG_XRESOLUTION
,          1, TIFF_RATIONAL 
}, 
 389         { TIFFTAG_YRESOLUTION
,          1, TIFF_RATIONAL 
}, 
 390         { TIFFTAG_PAGENAME
,             1, TIFF_ASCII 
}, 
 391         { TIFFTAG_XPOSITION
,            1, TIFF_RATIONAL 
}, 
 392         { TIFFTAG_YPOSITION
,            1, TIFF_RATIONAL 
}, 
 393         { TIFFTAG_RESOLUTIONUNIT
,       1, TIFF_SHORT 
}, 
 394         { TIFFTAG_SOFTWARE
,             1, TIFF_ASCII 
}, 
 395         { TIFFTAG_DATETIME
,             1, TIFF_ASCII 
}, 
 396         { TIFFTAG_ARTIST
,               1, TIFF_ASCII 
}, 
 397         { TIFFTAG_HOSTCOMPUTER
,         1, TIFF_ASCII 
}, 
 398         { TIFFTAG_WHITEPOINT
,           1, TIFF_RATIONAL 
}, 
 399         { TIFFTAG_PRIMARYCHROMATICITIES
,(uint16
) -1,TIFF_RATIONAL 
}, 
 400         { TIFFTAG_HALFTONEHINTS
,        2, TIFF_SHORT 
}, 
 401         { TIFFTAG_INKSET
,               1, TIFF_SHORT 
}, 
 402         { TIFFTAG_DOTRANGE
,             2, TIFF_SHORT 
}, 
 403         { TIFFTAG_TARGETPRINTER
,        1, TIFF_ASCII 
}, 
 404         { TIFFTAG_SAMPLEFORMAT
,         1, TIFF_SHORT 
}, 
 405         { TIFFTAG_YCBCRCOEFFICIENTS
,    (uint16
) -1,TIFF_RATIONAL 
}, 
 406         { TIFFTAG_YCBCRSUBSAMPLING
,     2, TIFF_SHORT 
}, 
 407         { TIFFTAG_YCBCRPOSITIONING
,     1, TIFF_SHORT 
}, 
 408         { TIFFTAG_REFERENCEBLACKWHITE
,  (uint16
) -1,TIFF_RATIONAL 
}, 
 409         { TIFFTAG_EXTRASAMPLES
,         (uint16
) -1, TIFF_SHORT 
}, 
 410         { TIFFTAG_SMINSAMPLEVALUE
,      1, TIFF_DOUBLE 
}, 
 411         { TIFFTAG_SMAXSAMPLEVALUE
,      1, TIFF_DOUBLE 
}, 
 412         { TIFFTAG_STONITS
,              1, TIFF_DOUBLE 
}, 
 414 #define NTAGS   (sizeof (tags) / sizeof (tags[0])) 
 417 cpTags(TIFF
* in
, TIFF
* out
) 
 420     for (p 
= tags
; p 
< &tags
[NTAGS
]; p
++) 
 421         cpTag(in
, out
, p
->tag
, p
->count
, p
->type
); 
 426 "usage: tiff2bw [options] input.tif output.tif", 
 427 "where options are:", 
 428 " -R %          use #% from red channel", 
 429 " -G %          use #% from green channel", 
 430 " -B %          use #% from blue channel", 
 432 " -r #          make each strip have no more than # rows", 
 434 " -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding", 
 435 " -c zip[:opts] compress output with deflate encoding", 
 436 " -c packbits   compress output with packbits encoding", 
 437 " -c g3[:opts]  compress output with CCITT Group 3 encoding", 
 438 " -c g4         compress output with CCITT Group 4 encoding", 
 439 " -c none       use no compression algorithm on output", 
 441 "LZW and deflate options:", 
 442 " #             set predictor value", 
 443 "For example, -c lzw:2 to get LZW-encoded data with horizontal differencing", 
 454         fprintf(stderr
, "%s\n\n", TIFFGetVersion()); 
 455         for (i 
= 0; stuff
[i
] != NULL
; i
++) 
 456                 fprintf(stderr
, "%s\n", stuff
[i
]); 
 460 /* vim: set ts=8 sts=8 sw=8 noet: */