3 * Copyright (c) 1988-1997 Sam Leffler
4 * Copyright (c) 1991-1997 Silicon Graphics, Inc.
6 * Permission to use, copy, modify, distribute, and sell this software and
7 * its documentation for any purpose is hereby granted without fee, provided
8 * that (i) the above copyright notices and this permission notice appear in
9 * all copies of the software and related documentation, and (ii) the names of
10 * Sam Leffler and Silicon Graphics may not be used in any advertising or
11 * publicity relating to the software without the specific, prior written
12 * permission of Sam Leffler and Silicon Graphics.
14 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
15 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
16 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
18 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
19 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
20 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
21 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
22 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
26 #include "tif_config.h"
43 #define streq(a,b) (strcmp((a),(b)) == 0)
44 #define strneq(a,b,n) (strncmp(a,b,n) == 0)
46 /* x% weighting -> fraction of full color */
47 #define PCT(x) (((x)*255+127)/100)
48 int RED
= PCT(30); /* 30% */
49 int GREEN
= PCT(59); /* 59% */
50 int BLUE
= PCT(11); /* 11% */
52 static void usage(void);
53 static int processCompressOptions(char*);
56 compresscontig(unsigned char* out
, unsigned char* rgb
, uint32 n
)
58 register int v
, red
= RED
, green
= GREEN
, blue
= BLUE
;
69 compresssep(unsigned char* out
,
70 unsigned char* r
, unsigned char* g
, unsigned char* b
, uint32 n
)
72 register uint32 red
= RED
, green
= GREEN
, blue
= BLUE
;
75 *out
++ = (unsigned char)
76 ((red
*(*r
++) + green
*(*g
++) + blue
*(*b
++)) >> 8);
80 checkcmap(TIFF
* tif
, int n
, uint16
* r
, uint16
* g
, uint16
* b
)
83 if (*r
++ >= 256 || *g
++ >= 256 || *b
++ >= 256)
85 TIFFWarning(TIFFFileName(tif
), "Assuming 8-bit colormap");
90 compresspalette(unsigned char* out
, unsigned char* data
, uint32 n
, uint16
* rmap
, uint16
* gmap
, uint16
* bmap
)
92 register int v
, red
= RED
, green
= GREEN
, blue
= BLUE
;
95 unsigned int ix
= *data
++;
103 static uint16 compression
= (uint16
) -1;
104 static uint16 predictor
= 0;
105 static int jpegcolormode
= JPEGCOLORMODE_RGB
;
106 static int quality
= 75; /* JPEG quality */
108 static void cpTags(TIFF
* in
, TIFF
* out
);
111 main(int argc
, char* argv
[])
113 uint32 rowsperstrip
= (uint32
) -1;
116 uint16 samplesperpixel
;
117 uint16 bitspersample
;
125 register tsample_t s
;
126 unsigned char *inbuf
, *outbuf
;
132 while ((c
= getopt(argc
, argv
, "c:r:R:G:B:")) != -1)
134 case 'c': /* compression scheme */
135 if (!processCompressOptions(optarg
))
138 case 'r': /* rows/strip */
139 rowsperstrip
= atoi(optarg
);
142 RED
= PCT(atoi(optarg
));
145 GREEN
= PCT(atoi(optarg
));
148 BLUE
= PCT(atoi(optarg
));
154 if (argc
- optind
< 2)
156 in
= TIFFOpen(argv
[optind
], "r");
160 TIFFGetField(in
, TIFFTAG_PHOTOMETRIC
, &photometric
);
161 if (photometric
!= PHOTOMETRIC_RGB
&& photometric
!= PHOTOMETRIC_PALETTE
) {
163 "%s: Bad photometric; can only handle RGB and Palette images.\n",
167 TIFFGetField(in
, TIFFTAG_SAMPLESPERPIXEL
, &samplesperpixel
);
168 if (samplesperpixel
!= 1 && samplesperpixel
!= 3) {
169 fprintf(stderr
, "%s: Bad samples/pixel %u.\n",
170 argv
[optind
], samplesperpixel
);
173 TIFFGetField(in
, TIFFTAG_BITSPERSAMPLE
, &bitspersample
);
174 if (bitspersample
!= 8) {
176 " %s: Sorry, only handle 8-bit samples.\n", argv
[optind
]);
179 TIFFGetField(in
, TIFFTAG_IMAGEWIDTH
, &w
);
180 TIFFGetField(in
, TIFFTAG_IMAGELENGTH
, &h
);
181 TIFFGetField(in
, TIFFTAG_PLANARCONFIG
, &config
);
183 out
= TIFFOpen(argv
[optind
+1], "w");
186 TIFFSetField(out
, TIFFTAG_IMAGEWIDTH
, w
);
187 TIFFSetField(out
, TIFFTAG_IMAGELENGTH
, h
);
188 TIFFSetField(out
, TIFFTAG_BITSPERSAMPLE
, 8);
189 TIFFSetField(out
, TIFFTAG_SAMPLESPERPIXEL
, 1);
190 TIFFSetField(out
, TIFFTAG_PLANARCONFIG
, PLANARCONFIG_CONTIG
);
192 if (compression
!= (uint16
) -1) {
193 TIFFSetField(out
, TIFFTAG_COMPRESSION
, compression
);
194 switch (compression
) {
195 case COMPRESSION_JPEG
:
196 TIFFSetField(out
, TIFFTAG_JPEGQUALITY
, quality
);
197 TIFFSetField(out
, TIFFTAG_JPEGCOLORMODE
, jpegcolormode
);
199 case COMPRESSION_LZW
:
200 case COMPRESSION_DEFLATE
:
202 TIFFSetField(out
, TIFFTAG_PREDICTOR
, predictor
);
206 TIFFSetField(out
, TIFFTAG_PHOTOMETRIC
, PHOTOMETRIC_MINISBLACK
);
207 sprintf(thing
, "B&W version of %s", argv
[optind
]);
208 TIFFSetField(out
, TIFFTAG_IMAGEDESCRIPTION
, thing
);
209 TIFFSetField(out
, TIFFTAG_SOFTWARE
, "tiff2bw");
210 outbuf
= (unsigned char *)_TIFFmalloc(TIFFScanlineSize(out
));
211 TIFFSetField(out
, TIFFTAG_ROWSPERSTRIP
,
212 TIFFDefaultStripSize(out
, rowsperstrip
));
214 #define pack(a,b) ((a)<<8 | (b))
215 switch (pack(photometric
, config
)) {
216 case pack(PHOTOMETRIC_PALETTE
, PLANARCONFIG_CONTIG
):
217 case pack(PHOTOMETRIC_PALETTE
, PLANARCONFIG_SEPARATE
):
218 TIFFGetField(in
, TIFFTAG_COLORMAP
, &red
, &green
, &blue
);
220 * Convert 16-bit colormap to 8-bit (unless it looks
221 * like an old-style 8-bit colormap).
223 if (checkcmap(in
, 1<<bitspersample
, red
, green
, blue
) == 16) {
225 #define CVT(x) (((x) * 255L) / ((1L<<16)-1))
226 for (i
= (1<<bitspersample
)-1; i
>= 0; i
--) {
227 red
[i
] = CVT(red
[i
]);
228 green
[i
] = CVT(green
[i
]);
229 blue
[i
] = CVT(blue
[i
]);
233 inbuf
= (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in
));
234 for (row
= 0; row
< h
; row
++) {
235 if (TIFFReadScanline(in
, inbuf
, row
, 0) < 0)
237 compresspalette(outbuf
, inbuf
, w
, red
, green
, blue
);
238 if (TIFFWriteScanline(out
, outbuf
, row
, 0) < 0)
242 case pack(PHOTOMETRIC_RGB
, PLANARCONFIG_CONTIG
):
243 inbuf
= (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in
));
244 for (row
= 0; row
< h
; row
++) {
245 if (TIFFReadScanline(in
, inbuf
, row
, 0) < 0)
247 compresscontig(outbuf
, inbuf
, w
);
248 if (TIFFWriteScanline(out
, outbuf
, row
, 0) < 0)
252 case pack(PHOTOMETRIC_RGB
, PLANARCONFIG_SEPARATE
):
253 rowsize
= TIFFScanlineSize(in
);
254 inbuf
= (unsigned char *)_TIFFmalloc(3*rowsize
);
255 for (row
= 0; row
< h
; row
++) {
256 for (s
= 0; s
< 3; s
++)
257 if (TIFFReadScanline(in
,
258 inbuf
+s
*rowsize
, row
, s
) < 0)
261 inbuf
, inbuf
+rowsize
, inbuf
+2*rowsize
, w
);
262 if (TIFFWriteScanline(out
, outbuf
, row
, 0) < 0)
273 processCompressOptions(char* opt
)
275 if (streq(opt
, "none"))
276 compression
= COMPRESSION_NONE
;
277 else if (streq(opt
, "packbits"))
278 compression
= COMPRESSION_PACKBITS
;
279 else if (strneq(opt
, "jpeg", 4)) {
280 char* cp
= strchr(opt
, ':');
282 compression
= COMPRESSION_JPEG
;
285 if (isdigit((int)cp
[1]))
286 quality
= atoi(cp
+1);
287 else if (cp
[1] == 'r' )
288 jpegcolormode
= JPEGCOLORMODE_RAW
;
292 cp
= strchr(cp
+1,':');
294 } else if (strneq(opt
, "lzw", 3)) {
295 char* cp
= strchr(opt
, ':');
297 predictor
= atoi(cp
+1);
298 compression
= COMPRESSION_LZW
;
299 } else if (strneq(opt
, "zip", 3)) {
300 char* cp
= strchr(opt
, ':');
302 predictor
= atoi(cp
+1);
303 compression
= COMPRESSION_DEFLATE
;
309 #define CopyField(tag, v) \
310 if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
311 #define CopyField2(tag, v1, v2) \
312 if (TIFFGetField(in, tag, &v1, &v2)) TIFFSetField(out, tag, v1, v2)
313 #define CopyField3(tag, v1, v2, v3) \
314 if (TIFFGetField(in, tag, &v1, &v2, &v3)) TIFFSetField(out, tag, v1, v2, v3)
315 #define CopyField4(tag, v1, v2, v3, v4) \
316 if (TIFFGetField(in, tag, &v1, &v2, &v3, &v4)) TIFFSetField(out, tag, v1, v2, v3, v4)
319 cpTag(TIFF
* in
, TIFF
* out
, uint16 tag
, uint16 count
, TIFFDataType type
)
325 CopyField(tag
, shortv
);
326 } else if (count
== 2) {
327 uint16 shortv1
, shortv2
;
328 CopyField2(tag
, shortv1
, shortv2
);
329 } else if (count
== 4) {
330 uint16
*tr
, *tg
, *tb
, *ta
;
331 CopyField4(tag
, tr
, tg
, tb
, ta
);
332 } else if (count
== (uint16
) -1) {
335 CopyField2(tag
, shortv1
, shortav
);
340 CopyField(tag
, longv
);
346 CopyField(tag
, floatv
);
347 } else if (count
== (uint16
) -1) {
349 CopyField(tag
, floatav
);
354 CopyField(tag
, stringv
);
360 CopyField(tag
, doublev
);
361 } else if (count
== (uint16
) -1) {
363 CopyField(tag
, doubleav
);
367 TIFFError(TIFFFileName(in
),
368 "Data type %d is not supported, tag %d skipped.",
378 static struct cpTag
{
383 { TIFFTAG_SUBFILETYPE
, 1, TIFF_LONG
},
384 { TIFFTAG_THRESHHOLDING
, 1, TIFF_SHORT
},
385 { TIFFTAG_DOCUMENTNAME
, 1, TIFF_ASCII
},
386 { TIFFTAG_IMAGEDESCRIPTION
, 1, TIFF_ASCII
},
387 { TIFFTAG_MAKE
, 1, TIFF_ASCII
},
388 { TIFFTAG_MODEL
, 1, TIFF_ASCII
},
389 { TIFFTAG_MINSAMPLEVALUE
, 1, TIFF_SHORT
},
390 { TIFFTAG_MAXSAMPLEVALUE
, 1, TIFF_SHORT
},
391 { TIFFTAG_XRESOLUTION
, 1, TIFF_RATIONAL
},
392 { TIFFTAG_YRESOLUTION
, 1, TIFF_RATIONAL
},
393 { TIFFTAG_PAGENAME
, 1, TIFF_ASCII
},
394 { TIFFTAG_XPOSITION
, 1, TIFF_RATIONAL
},
395 { TIFFTAG_YPOSITION
, 1, TIFF_RATIONAL
},
396 { TIFFTAG_RESOLUTIONUNIT
, 1, TIFF_SHORT
},
397 { TIFFTAG_SOFTWARE
, 1, TIFF_ASCII
},
398 { TIFFTAG_DATETIME
, 1, TIFF_ASCII
},
399 { TIFFTAG_ARTIST
, 1, TIFF_ASCII
},
400 { TIFFTAG_HOSTCOMPUTER
, 1, TIFF_ASCII
},
401 { TIFFTAG_WHITEPOINT
, 2, TIFF_RATIONAL
},
402 { TIFFTAG_PRIMARYCHROMATICITIES
,(uint16
) -1,TIFF_RATIONAL
},
403 { TIFFTAG_HALFTONEHINTS
, 2, TIFF_SHORT
},
404 { TIFFTAG_INKSET
, 1, TIFF_SHORT
},
405 { TIFFTAG_DOTRANGE
, 2, TIFF_SHORT
},
406 { TIFFTAG_TARGETPRINTER
, 1, TIFF_ASCII
},
407 { TIFFTAG_SAMPLEFORMAT
, 1, TIFF_SHORT
},
408 { TIFFTAG_YCBCRCOEFFICIENTS
, (uint16
) -1,TIFF_RATIONAL
},
409 { TIFFTAG_YCBCRSUBSAMPLING
, 2, TIFF_SHORT
},
410 { TIFFTAG_YCBCRPOSITIONING
, 1, TIFF_SHORT
},
411 { TIFFTAG_REFERENCEBLACKWHITE
, (uint16
) -1,TIFF_RATIONAL
},
412 { TIFFTAG_EXTRASAMPLES
, (uint16
) -1, TIFF_SHORT
},
413 { TIFFTAG_SMINSAMPLEVALUE
, 1, TIFF_DOUBLE
},
414 { TIFFTAG_SMAXSAMPLEVALUE
, 1, TIFF_DOUBLE
},
415 { TIFFTAG_STONITS
, 1, TIFF_DOUBLE
},
417 #define NTAGS (sizeof (tags) / sizeof (tags[0]))
420 cpTags(TIFF
* in
, TIFF
* out
)
423 for (p
= tags
; p
< &tags
[NTAGS
]; p
++)
424 cpTag(in
, out
, p
->tag
, p
->count
, p
->type
);
429 "usage: tiff2bw [options] input.tif output.tif",
430 "where options are:",
431 " -R % use #% from red channel",
432 " -G % use #% from green channel",
433 " -B % use #% from blue channel",
435 " -r # make each strip have no more than # rows",
437 " -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
438 " -c zip[:opts] compress output with deflate encoding",
439 " -c packbits compress output with packbits encoding",
440 " -c g3[:opts] compress output with CCITT Group 3 encoding",
441 " -c g4 compress output with CCITT Group 4 encoding",
442 " -c none use no compression algorithm on output",
444 "LZW and deflate options:",
445 " # set predictor value",
446 "For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
457 fprintf(stderr
, "%s\n\n", TIFFGetVersion());
458 for (i
= 0; stuff
[i
] != NULL
; i
++)
459 fprintf(stderr
, "%s\n", stuff
[i
]);
463 /* vim: set ts=8 sts=8 sw=8 noet: */