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 static void usage(void);
47 static void cpTags(TIFF
* in
, TIFF
* out
);
50 checkcmap(int n
, uint16
* r
, uint16
* g
, uint16
* b
)
53 if (*r
++ >= 256 || *g
++ >= 256 || *b
++ >= 256)
55 fprintf(stderr
, "Warning, assuming 8-bit colormap.\n");
59 #define CopyField(tag, v) \
60 if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
61 #define CopyField3(tag, v1, v2, v3) \
62 if (TIFFGetField(in, tag, &v1, &v2, &v3)) TIFFSetField(out, tag, v1, v2, v3)
64 static uint16 compression
= (uint16
) -1;
65 static uint16 predictor
= 0;
66 static int quality
= 75; /* JPEG quality */
67 static int jpegcolormode
= JPEGCOLORMODE_RGB
;
68 static int processCompressOptions(char*);
71 main(int argc
, char* argv
[])
73 uint16 bitspersample
, shortv
;
74 uint32 imagewidth
, imagelength
;
75 uint16 config
= PLANARCONFIG_CONTIG
;
76 uint32 rowsperstrip
= (uint32
) -1;
77 uint16 photometric
= PHOTOMETRIC_RGB
;
78 uint16
*rmap
, *gmap
, *bmap
;
86 while ((c
= getopt(argc
, argv
, "C:c:p:r:")) != -1)
88 case 'C': /* force colormap interpretation */
91 case 'c': /* compression scheme */
92 if (!processCompressOptions(optarg
))
95 case 'p': /* planar configuration */
96 if (streq(optarg
, "separate"))
97 config
= PLANARCONFIG_SEPARATE
;
98 else if (streq(optarg
, "contig"))
99 config
= PLANARCONFIG_CONTIG
;
103 case 'r': /* rows/strip */
104 rowsperstrip
= atoi(optarg
);
110 if (argc
- optind
!= 2)
112 in
= TIFFOpen(argv
[optind
], "r");
115 if (!TIFFGetField(in
, TIFFTAG_PHOTOMETRIC
, &shortv
) ||
116 shortv
!= PHOTOMETRIC_PALETTE
) {
117 fprintf(stderr
, "%s: Expecting a palette image.\n",
121 if (!TIFFGetField(in
, TIFFTAG_COLORMAP
, &rmap
, &gmap
, &bmap
)) {
123 "%s: No colormap (not a valid palette image).\n",
128 TIFFGetField(in
, TIFFTAG_BITSPERSAMPLE
, &bitspersample
);
129 if (bitspersample
!= 8) {
130 fprintf(stderr
, "%s: Sorry, can only handle 8-bit images.\n",
134 out
= TIFFOpen(argv
[optind
+1], "w");
138 TIFFGetField(in
, TIFFTAG_IMAGEWIDTH
, &imagewidth
);
139 TIFFGetField(in
, TIFFTAG_IMAGELENGTH
, &imagelength
);
140 if (compression
!= (uint16
)-1)
141 TIFFSetField(out
, TIFFTAG_COMPRESSION
, compression
);
143 TIFFGetField(in
, TIFFTAG_COMPRESSION
, &compression
);
144 switch (compression
) {
145 case COMPRESSION_JPEG
:
146 if (jpegcolormode
== JPEGCOLORMODE_RGB
)
147 photometric
= PHOTOMETRIC_YCBCR
;
149 photometric
= PHOTOMETRIC_RGB
;
150 TIFFSetField(out
, TIFFTAG_JPEGQUALITY
, quality
);
151 TIFFSetField(out
, TIFFTAG_JPEGCOLORMODE
, jpegcolormode
);
153 case COMPRESSION_LZW
:
154 case COMPRESSION_DEFLATE
:
156 TIFFSetField(out
, TIFFTAG_PREDICTOR
, predictor
);
159 TIFFSetField(out
, TIFFTAG_PHOTOMETRIC
, photometric
);
160 TIFFSetField(out
, TIFFTAG_SAMPLESPERPIXEL
, 3);
161 TIFFSetField(out
, TIFFTAG_PLANARCONFIG
, config
);
162 TIFFSetField(out
, TIFFTAG_ROWSPERSTRIP
,
163 rowsperstrip
= TIFFDefaultStripSize(out
, rowsperstrip
));
164 (void) TIFFGetField(in
, TIFFTAG_PLANARCONFIG
, &shortv
);
166 cmap
= checkcmap(1<<bitspersample
, rmap
, gmap
, bmap
);
169 * Convert 16-bit colormap to 8-bit.
173 for (i
= (1<<bitspersample
)-1; i
>= 0; i
--) {
174 #define CVT(x) (((x) * 255) / ((1L<<16)-1))
175 rmap
[i
] = CVT(rmap
[i
]);
176 gmap
[i
] = CVT(gmap
[i
]);
177 bmap
[i
] = CVT(bmap
[i
]);
180 { unsigned char *ibuf
, *obuf
;
181 register unsigned char* pp
;
183 ibuf
= (unsigned char*)_TIFFmalloc(TIFFScanlineSize(in
));
184 obuf
= (unsigned char*)_TIFFmalloc(TIFFScanlineSize(out
));
186 case PLANARCONFIG_CONTIG
:
187 for (row
= 0; row
< imagelength
; row
++) {
188 if (!TIFFReadScanline(in
, ibuf
, row
, 0))
191 for (x
= 0; x
< imagewidth
; x
++) {
192 *pp
++ = (unsigned char) rmap
[ibuf
[x
]];
193 *pp
++ = (unsigned char) gmap
[ibuf
[x
]];
194 *pp
++ = (unsigned char) bmap
[ibuf
[x
]];
196 if (!TIFFWriteScanline(out
, obuf
, row
, 0))
200 case PLANARCONFIG_SEPARATE
:
201 for (row
= 0; row
< imagelength
; row
++) {
202 if (!TIFFReadScanline(in
, ibuf
, row
, 0))
204 for (pp
= obuf
, x
= 0; x
< imagewidth
; x
++)
205 *pp
++ = (unsigned char) rmap
[ibuf
[x
]];
206 if (!TIFFWriteScanline(out
, obuf
, row
, 0))
208 for (pp
= obuf
, x
= 0; x
< imagewidth
; x
++)
209 *pp
++ = (unsigned char) gmap
[ibuf
[x
]];
210 if (!TIFFWriteScanline(out
, obuf
, row
, 0))
212 for (pp
= obuf
, x
= 0; x
< imagewidth
; x
++)
213 *pp
++ = (unsigned char) bmap
[ibuf
[x
]];
214 if (!TIFFWriteScanline(out
, obuf
, row
, 0))
223 (void) TIFFClose(in
);
224 (void) TIFFClose(out
);
229 processCompressOptions(char* opt
)
231 if (streq(opt
, "none"))
232 compression
= COMPRESSION_NONE
;
233 else if (streq(opt
, "packbits"))
234 compression
= COMPRESSION_PACKBITS
;
235 else if (strneq(opt
, "jpeg", 4)) {
236 char* cp
= strchr(opt
, ':');
238 compression
= COMPRESSION_JPEG
;
241 if (isdigit((int)cp
[1]))
242 quality
= atoi(cp
+1);
243 else if (cp
[1] == 'r' )
244 jpegcolormode
= JPEGCOLORMODE_RAW
;
248 cp
= strchr(cp
+1,':');
250 } else if (strneq(opt
, "lzw", 3)) {
251 char* cp
= strchr(opt
, ':');
253 predictor
= atoi(cp
+1);
254 compression
= COMPRESSION_LZW
;
255 } else if (strneq(opt
, "zip", 3)) {
256 char* cp
= strchr(opt
, ':');
258 predictor
= atoi(cp
+1);
259 compression
= COMPRESSION_DEFLATE
;
265 #define CopyField(tag, v) \
266 if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
267 #define CopyField2(tag, v1, v2) \
268 if (TIFFGetField(in, tag, &v1, &v2)) TIFFSetField(out, tag, v1, v2)
269 #define CopyField3(tag, v1, v2, v3) \
270 if (TIFFGetField(in, tag, &v1, &v2, &v3)) TIFFSetField(out, tag, v1, v2, v3)
271 #define CopyField4(tag, v1, v2, v3, v4) \
272 if (TIFFGetField(in, tag, &v1, &v2, &v3, &v4)) TIFFSetField(out, tag, v1, v2, v3, v4)
275 cpTag(TIFF
* in
, TIFF
* out
, uint16 tag
, uint16 count
, TIFFDataType type
)
281 CopyField(tag
, shortv
);
282 } else if (count
== 2) {
283 uint16 shortv1
, shortv2
;
284 CopyField2(tag
, shortv1
, shortv2
);
285 } else if (count
== 4) {
286 uint16
*tr
, *tg
, *tb
, *ta
;
287 CopyField4(tag
, tr
, tg
, tb
, ta
);
288 } else if (count
== (uint16
) -1) {
291 CopyField2(tag
, shortv1
, shortav
);
296 CopyField(tag
, longv
);
302 CopyField(tag
, floatv
);
303 } else if (count
== (uint16
) -1) {
305 CopyField(tag
, floatav
);
310 CopyField(tag
, stringv
);
316 CopyField(tag
, doublev
);
317 } else if (count
== (uint16
) -1) {
319 CopyField(tag
, doubleav
);
323 TIFFError(TIFFFileName(in
),
324 "Data type %d is not supported, tag %d skipped.",
334 static struct cpTag
{
339 { TIFFTAG_IMAGEWIDTH
, 1, TIFF_LONG
},
340 { TIFFTAG_IMAGELENGTH
, 1, TIFF_LONG
},
341 { TIFFTAG_BITSPERSAMPLE
, 1, TIFF_SHORT
},
342 { TIFFTAG_COMPRESSION
, 1, TIFF_SHORT
},
343 { TIFFTAG_FILLORDER
, 1, TIFF_SHORT
},
344 { TIFFTAG_ROWSPERSTRIP
, 1, TIFF_LONG
},
345 { TIFFTAG_GROUP3OPTIONS
, 1, TIFF_LONG
},
346 { TIFFTAG_SUBFILETYPE
, 1, TIFF_LONG
},
347 { TIFFTAG_THRESHHOLDING
, 1, TIFF_SHORT
},
348 { TIFFTAG_DOCUMENTNAME
, 1, TIFF_ASCII
},
349 { TIFFTAG_IMAGEDESCRIPTION
, 1, TIFF_ASCII
},
350 { TIFFTAG_MAKE
, 1, TIFF_ASCII
},
351 { TIFFTAG_MODEL
, 1, TIFF_ASCII
},
352 { TIFFTAG_ORIENTATION
, 1, TIFF_SHORT
},
353 { TIFFTAG_MINSAMPLEVALUE
, 1, TIFF_SHORT
},
354 { TIFFTAG_MAXSAMPLEVALUE
, 1, TIFF_SHORT
},
355 { TIFFTAG_XRESOLUTION
, 1, TIFF_RATIONAL
},
356 { TIFFTAG_YRESOLUTION
, 1, TIFF_RATIONAL
},
357 { TIFFTAG_PAGENAME
, 1, TIFF_ASCII
},
358 { TIFFTAG_XPOSITION
, 1, TIFF_RATIONAL
},
359 { TIFFTAG_YPOSITION
, 1, TIFF_RATIONAL
},
360 { TIFFTAG_GROUP4OPTIONS
, 1, TIFF_LONG
},
361 { TIFFTAG_RESOLUTIONUNIT
, 1, TIFF_SHORT
},
362 { TIFFTAG_PAGENUMBER
, 2, TIFF_SHORT
},
363 { TIFFTAG_SOFTWARE
, 1, TIFF_ASCII
},
364 { TIFFTAG_DATETIME
, 1, TIFF_ASCII
},
365 { TIFFTAG_ARTIST
, 1, TIFF_ASCII
},
366 { TIFFTAG_HOSTCOMPUTER
, 1, TIFF_ASCII
},
367 { TIFFTAG_WHITEPOINT
, 2, TIFF_RATIONAL
},
368 { TIFFTAG_PRIMARYCHROMATICITIES
, (uint16
) -1,TIFF_RATIONAL
},
369 { TIFFTAG_HALFTONEHINTS
, 2, TIFF_SHORT
},
370 { TIFFTAG_BADFAXLINES
, 1, TIFF_LONG
},
371 { TIFFTAG_CLEANFAXDATA
, 1, TIFF_SHORT
},
372 { TIFFTAG_CONSECUTIVEBADFAXLINES
, 1, TIFF_LONG
},
373 { TIFFTAG_INKSET
, 1, TIFF_SHORT
},
374 { TIFFTAG_INKNAMES
, 1, TIFF_ASCII
},
375 { TIFFTAG_DOTRANGE
, 2, TIFF_SHORT
},
376 { TIFFTAG_TARGETPRINTER
, 1, TIFF_ASCII
},
377 { TIFFTAG_SAMPLEFORMAT
, 1, TIFF_SHORT
},
378 { TIFFTAG_YCBCRCOEFFICIENTS
, (uint16
) -1,TIFF_RATIONAL
},
379 { TIFFTAG_YCBCRSUBSAMPLING
, 2, TIFF_SHORT
},
380 { TIFFTAG_YCBCRPOSITIONING
, 1, TIFF_SHORT
},
381 { TIFFTAG_REFERENCEBLACKWHITE
, (uint16
) -1,TIFF_RATIONAL
},
383 #define NTAGS (sizeof (tags) / sizeof (tags[0]))
386 cpTags(TIFF
* in
, TIFF
* out
)
389 for (p
= tags
; p
< &tags
[NTAGS
]; p
++)
390 cpTag(in
, out
, p
->tag
, p
->count
, p
->type
);
395 "usage: pal2rgb [options] input.tif output.tif",
396 "where options are:",
397 " -p contig pack samples contiguously (e.g. RGBRGB...)",
398 " -p separate store samples separately (e.g. RRR...GGG...BBB...)",
399 " -r # make each strip have no more than # rows",
400 " -C 8 assume 8-bit colormap values (instead of 16-bit)",
401 " -C 16 assume 16-bit colormap values",
403 " -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
404 " -c zip[:opts] compress output with deflate encoding",
405 " -c packbits compress output with packbits encoding",
406 " -c none use no compression algorithm on output",
408 "LZW and deflate options:",
409 " # set predictor value",
410 "For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
421 fprintf(stderr
, "%s\n\n", TIFFGetVersion());
422 for (i
= 0; stuff
[i
] != NULL
; i
++)
423 fprintf(stderr
, "%s\n", stuff
[i
]);
427 /* vim: set ts=8 sts=8 sw=8 noet: */