]> git.saurik.com Git - wxWidgets.git/blob - src/tiff/tools/pal2rgb.c
bfe7899d8be9bbed61adef9b8cd72a8bacded9b3
[wxWidgets.git] / src / tiff / tools / pal2rgb.c
1 /* $Id$ */
2
3 /*
4 * Copyright (c) 1988-1997 Sam Leffler
5 * Copyright (c) 1991-1997 Silicon Graphics, Inc.
6 *
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.
14 *
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.
18 *
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
24 * OF THIS SOFTWARE.
25 */
26
27 #include "tif_config.h"
28
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <ctype.h>
33
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif
37
38 #ifdef NEED_LIBPORT
39 # include "libport.h"
40 #endif
41
42 #include "tiffio.h"
43
44 #define streq(a,b) (strcmp(a,b) == 0)
45 #define strneq(a,b,n) (strncmp(a,b,n) == 0)
46
47 static void usage(void);
48 static void cpTags(TIFF* in, TIFF* out);
49
50 static int
51 checkcmap(int n, uint16* r, uint16* g, uint16* b)
52 {
53 while (n-- > 0)
54 if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256)
55 return (16);
56 fprintf(stderr, "Warning, assuming 8-bit colormap.\n");
57 return (8);
58 }
59
60 #define CopyField(tag, v) \
61 if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
62 #define CopyField3(tag, v1, v2, v3) \
63 if (TIFFGetField(in, tag, &v1, &v2, &v3)) TIFFSetField(out, tag, v1, v2, v3)
64
65 static uint16 compression = (uint16) -1;
66 static uint16 predictor = 0;
67 static int quality = 75; /* JPEG quality */
68 static int jpegcolormode = JPEGCOLORMODE_RGB;
69 static int processCompressOptions(char*);
70
71 int
72 main(int argc, char* argv[])
73 {
74 uint16 bitspersample, shortv;
75 uint32 imagewidth, imagelength;
76 uint16 config = PLANARCONFIG_CONTIG;
77 uint32 rowsperstrip = (uint32) -1;
78 uint16 photometric = PHOTOMETRIC_RGB;
79 uint16 *rmap, *gmap, *bmap;
80 uint32 row;
81 int cmap = -1;
82 TIFF *in, *out;
83 int c;
84 extern int optind;
85 extern char* optarg;
86
87 while ((c = getopt(argc, argv, "C:c:p:r:")) != -1)
88 switch (c) {
89 case 'C': /* force colormap interpretation */
90 cmap = atoi(optarg);
91 break;
92 case 'c': /* compression scheme */
93 if (!processCompressOptions(optarg))
94 usage();
95 break;
96 case 'p': /* planar configuration */
97 if (streq(optarg, "separate"))
98 config = PLANARCONFIG_SEPARATE;
99 else if (streq(optarg, "contig"))
100 config = PLANARCONFIG_CONTIG;
101 else
102 usage();
103 break;
104 case 'r': /* rows/strip */
105 rowsperstrip = atoi(optarg);
106 break;
107 case '?':
108 usage();
109 /*NOTREACHED*/
110 }
111 if (argc - optind != 2)
112 usage();
113 in = TIFFOpen(argv[optind], "r");
114 if (in == NULL)
115 return (-1);
116 if (!TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &shortv) ||
117 shortv != PHOTOMETRIC_PALETTE) {
118 fprintf(stderr, "%s: Expecting a palette image.\n",
119 argv[optind]);
120 return (-1);
121 }
122 if (!TIFFGetField(in, TIFFTAG_COLORMAP, &rmap, &gmap, &bmap)) {
123 fprintf(stderr,
124 "%s: No colormap (not a valid palette image).\n",
125 argv[optind]);
126 return (-1);
127 }
128 bitspersample = 0;
129 TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bitspersample);
130 if (bitspersample != 8) {
131 fprintf(stderr, "%s: Sorry, can only handle 8-bit images.\n",
132 argv[optind]);
133 return (-1);
134 }
135 out = TIFFOpen(argv[optind+1], "w");
136 if (out == NULL)
137 return (-2);
138 cpTags(in, out);
139 TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &imagewidth);
140 TIFFGetField(in, TIFFTAG_IMAGELENGTH, &imagelength);
141 if (compression != (uint16)-1)
142 TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
143 else
144 TIFFGetField(in, TIFFTAG_COMPRESSION, &compression);
145 switch (compression) {
146 case COMPRESSION_JPEG:
147 if (jpegcolormode == JPEGCOLORMODE_RGB)
148 photometric = PHOTOMETRIC_YCBCR;
149 else
150 photometric = PHOTOMETRIC_RGB;
151 TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality);
152 TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode);
153 break;
154 case COMPRESSION_LZW:
155 case COMPRESSION_DEFLATE:
156 if (predictor != 0)
157 TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
158 break;
159 }
160 TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric);
161 TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 3);
162 TIFFSetField(out, TIFFTAG_PLANARCONFIG, config);
163 TIFFSetField(out, TIFFTAG_ROWSPERSTRIP,
164 rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip));
165 (void) TIFFGetField(in, TIFFTAG_PLANARCONFIG, &shortv);
166 if (cmap == -1)
167 cmap = checkcmap(1<<bitspersample, rmap, gmap, bmap);
168 if (cmap == 16) {
169 /*
170 * Convert 16-bit colormap to 8-bit.
171 */
172 int i;
173
174 for (i = (1<<bitspersample)-1; i >= 0; i--) {
175 #define CVT(x) (((x) * 255) / ((1L<<16)-1))
176 rmap[i] = CVT(rmap[i]);
177 gmap[i] = CVT(gmap[i]);
178 bmap[i] = CVT(bmap[i]);
179 }
180 }
181 { unsigned char *ibuf, *obuf;
182 register unsigned char* pp;
183 register uint32 x;
184 ibuf = (unsigned char*)_TIFFmalloc(TIFFScanlineSize(in));
185 obuf = (unsigned char*)_TIFFmalloc(TIFFScanlineSize(out));
186 switch (config) {
187 case PLANARCONFIG_CONTIG:
188 for (row = 0; row < imagelength; row++) {
189 if (!TIFFReadScanline(in, ibuf, row, 0))
190 goto done;
191 pp = obuf;
192 for (x = 0; x < imagewidth; x++) {
193 *pp++ = (unsigned char) rmap[ibuf[x]];
194 *pp++ = (unsigned char) gmap[ibuf[x]];
195 *pp++ = (unsigned char) bmap[ibuf[x]];
196 }
197 if (!TIFFWriteScanline(out, obuf, row, 0))
198 goto done;
199 }
200 break;
201 case PLANARCONFIG_SEPARATE:
202 for (row = 0; row < imagelength; row++) {
203 if (!TIFFReadScanline(in, ibuf, row, 0))
204 goto done;
205 for (pp = obuf, x = 0; x < imagewidth; x++)
206 *pp++ = (unsigned char) rmap[ibuf[x]];
207 if (!TIFFWriteScanline(out, obuf, row, 0))
208 goto done;
209 for (pp = obuf, x = 0; x < imagewidth; x++)
210 *pp++ = (unsigned char) gmap[ibuf[x]];
211 if (!TIFFWriteScanline(out, obuf, row, 0))
212 goto done;
213 for (pp = obuf, x = 0; x < imagewidth; x++)
214 *pp++ = (unsigned char) bmap[ibuf[x]];
215 if (!TIFFWriteScanline(out, obuf, row, 0))
216 goto done;
217 }
218 break;
219 }
220 _TIFFfree(ibuf);
221 _TIFFfree(obuf);
222 }
223 done:
224 (void) TIFFClose(in);
225 (void) TIFFClose(out);
226 return (0);
227 }
228
229 static int
230 processCompressOptions(char* opt)
231 {
232 if (streq(opt, "none"))
233 compression = COMPRESSION_NONE;
234 else if (streq(opt, "packbits"))
235 compression = COMPRESSION_PACKBITS;
236 else if (strneq(opt, "jpeg", 4)) {
237 char* cp = strchr(opt, ':');
238
239 compression = COMPRESSION_JPEG;
240 while( cp )
241 {
242 if (isdigit((int)cp[1]))
243 quality = atoi(cp+1);
244 else if (cp[1] == 'r' )
245 jpegcolormode = JPEGCOLORMODE_RAW;
246 else
247 usage();
248
249 cp = strchr(cp+1,':');
250 }
251 } else if (strneq(opt, "lzw", 3)) {
252 char* cp = strchr(opt, ':');
253 if (cp)
254 predictor = atoi(cp+1);
255 compression = COMPRESSION_LZW;
256 } else if (strneq(opt, "zip", 3)) {
257 char* cp = strchr(opt, ':');
258 if (cp)
259 predictor = atoi(cp+1);
260 compression = COMPRESSION_DEFLATE;
261 } else
262 return (0);
263 return (1);
264 }
265
266 #define CopyField(tag, v) \
267 if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
268 #define CopyField2(tag, v1, v2) \
269 if (TIFFGetField(in, tag, &v1, &v2)) TIFFSetField(out, tag, v1, v2)
270 #define CopyField3(tag, v1, v2, v3) \
271 if (TIFFGetField(in, tag, &v1, &v2, &v3)) TIFFSetField(out, tag, v1, v2, v3)
272 #define CopyField4(tag, v1, v2, v3, v4) \
273 if (TIFFGetField(in, tag, &v1, &v2, &v3, &v4)) TIFFSetField(out, tag, v1, v2, v3, v4)
274
275 static void
276 cpTag(TIFF* in, TIFF* out, uint16 tag, uint16 count, TIFFDataType type)
277 {
278 switch (type) {
279 case TIFF_SHORT:
280 if (count == 1) {
281 uint16 shortv;
282 CopyField(tag, shortv);
283 } else if (count == 2) {
284 uint16 shortv1, shortv2;
285 CopyField2(tag, shortv1, shortv2);
286 } else if (count == 4) {
287 uint16 *tr, *tg, *tb, *ta;
288 CopyField4(tag, tr, tg, tb, ta);
289 } else if (count == (uint16) -1) {
290 uint16 shortv1;
291 uint16* shortav;
292 CopyField2(tag, shortv1, shortav);
293 }
294 break;
295 case TIFF_LONG:
296 { uint32 longv;
297 CopyField(tag, longv);
298 }
299 break;
300 case TIFF_RATIONAL:
301 if (count == 1) {
302 float floatv;
303 CopyField(tag, floatv);
304 } else if (count == (uint16) -1) {
305 float* floatav;
306 CopyField(tag, floatav);
307 }
308 break;
309 case TIFF_ASCII:
310 { char* stringv;
311 CopyField(tag, stringv);
312 }
313 break;
314 case TIFF_DOUBLE:
315 if (count == 1) {
316 double doublev;
317 CopyField(tag, doublev);
318 } else if (count == (uint16) -1) {
319 double* doubleav;
320 CopyField(tag, doubleav);
321 }
322 break;
323 default:
324 TIFFError(TIFFFileName(in),
325 "Data type %d is not supported, tag %d skipped.",
326 tag, type);
327 }
328 }
329
330 #undef CopyField4
331 #undef CopyField3
332 #undef CopyField2
333 #undef CopyField
334
335 static struct cpTag {
336 uint16 tag;
337 uint16 count;
338 TIFFDataType type;
339 } tags[] = {
340 { TIFFTAG_IMAGEWIDTH, 1, TIFF_LONG },
341 { TIFFTAG_IMAGELENGTH, 1, TIFF_LONG },
342 { TIFFTAG_BITSPERSAMPLE, 1, TIFF_SHORT },
343 { TIFFTAG_COMPRESSION, 1, TIFF_SHORT },
344 { TIFFTAG_FILLORDER, 1, TIFF_SHORT },
345 { TIFFTAG_ROWSPERSTRIP, 1, TIFF_LONG },
346 { TIFFTAG_GROUP3OPTIONS, 1, TIFF_LONG },
347 { TIFFTAG_SUBFILETYPE, 1, TIFF_LONG },
348 { TIFFTAG_THRESHHOLDING, 1, TIFF_SHORT },
349 { TIFFTAG_DOCUMENTNAME, 1, TIFF_ASCII },
350 { TIFFTAG_IMAGEDESCRIPTION, 1, TIFF_ASCII },
351 { TIFFTAG_MAKE, 1, TIFF_ASCII },
352 { TIFFTAG_MODEL, 1, TIFF_ASCII },
353 { TIFFTAG_ORIENTATION, 1, TIFF_SHORT },
354 { TIFFTAG_MINSAMPLEVALUE, 1, TIFF_SHORT },
355 { TIFFTAG_MAXSAMPLEVALUE, 1, TIFF_SHORT },
356 { TIFFTAG_XRESOLUTION, 1, TIFF_RATIONAL },
357 { TIFFTAG_YRESOLUTION, 1, TIFF_RATIONAL },
358 { TIFFTAG_PAGENAME, 1, TIFF_ASCII },
359 { TIFFTAG_XPOSITION, 1, TIFF_RATIONAL },
360 { TIFFTAG_YPOSITION, 1, TIFF_RATIONAL },
361 { TIFFTAG_GROUP4OPTIONS, 1, TIFF_LONG },
362 { TIFFTAG_RESOLUTIONUNIT, 1, TIFF_SHORT },
363 { TIFFTAG_PAGENUMBER, 2, TIFF_SHORT },
364 { TIFFTAG_SOFTWARE, 1, TIFF_ASCII },
365 { TIFFTAG_DATETIME, 1, TIFF_ASCII },
366 { TIFFTAG_ARTIST, 1, TIFF_ASCII },
367 { TIFFTAG_HOSTCOMPUTER, 1, TIFF_ASCII },
368 { TIFFTAG_WHITEPOINT, 2, TIFF_RATIONAL },
369 { TIFFTAG_PRIMARYCHROMATICITIES, (uint16) -1,TIFF_RATIONAL },
370 { TIFFTAG_HALFTONEHINTS, 2, TIFF_SHORT },
371 { TIFFTAG_BADFAXLINES, 1, TIFF_LONG },
372 { TIFFTAG_CLEANFAXDATA, 1, TIFF_SHORT },
373 { TIFFTAG_CONSECUTIVEBADFAXLINES, 1, TIFF_LONG },
374 { TIFFTAG_INKSET, 1, TIFF_SHORT },
375 { TIFFTAG_INKNAMES, 1, TIFF_ASCII },
376 { TIFFTAG_DOTRANGE, 2, TIFF_SHORT },
377 { TIFFTAG_TARGETPRINTER, 1, TIFF_ASCII },
378 { TIFFTAG_SAMPLEFORMAT, 1, TIFF_SHORT },
379 { TIFFTAG_YCBCRCOEFFICIENTS, (uint16) -1,TIFF_RATIONAL },
380 { TIFFTAG_YCBCRSUBSAMPLING, 2, TIFF_SHORT },
381 { TIFFTAG_YCBCRPOSITIONING, 1, TIFF_SHORT },
382 { TIFFTAG_REFERENCEBLACKWHITE, (uint16) -1,TIFF_RATIONAL },
383 };
384 #define NTAGS (sizeof (tags) / sizeof (tags[0]))
385
386 static void
387 cpTags(TIFF* in, TIFF* out)
388 {
389 struct cpTag *p;
390 for (p = tags; p < &tags[NTAGS]; p++)
391 cpTag(in, out, p->tag, p->count, p->type);
392 }
393 #undef NTAGS
394
395 char* stuff[] = {
396 "usage: pal2rgb [options] input.tif output.tif",
397 "where options are:",
398 " -p contig pack samples contiguously (e.g. RGBRGB...)",
399 " -p separate store samples separately (e.g. RRR...GGG...BBB...)",
400 " -r # make each strip have no more than # rows",
401 " -C 8 assume 8-bit colormap values (instead of 16-bit)",
402 " -C 16 assume 16-bit colormap values",
403 "",
404 " -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
405 " -c zip[:opts] compress output with deflate encoding",
406 " -c packbits compress output with packbits encoding",
407 " -c none use no compression algorithm on output",
408 "",
409 "LZW and deflate options:",
410 " # set predictor value",
411 "For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
412 NULL
413 };
414
415 static void
416 usage(void)
417 {
418 char buf[BUFSIZ];
419 int i;
420
421 setbuf(stderr, buf);
422 fprintf(stderr, "%s\n\n", TIFFGetVersion());
423 for (i = 0; stuff[i] != NULL; i++)
424 fprintf(stderr, "%s\n", stuff[i]);
425 exit(-1);
426 }
427
428 /* vim: set ts=8 sts=8 sw=8 noet: */
429 /*
430 * Local Variables:
431 * mode: c
432 * c-basic-offset: 8
433 * fill-column: 78
434 * End:
435 */