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: */