Better fix
[wxWidgets.git] / src / tiff / tools / ppm2tiff.c
CommitLineData
8414a40c
VZ
1/* $Id$ */
2
3/*
4 * Copyright (c) 1991-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 <stdlib.h>
31#include <string.h>
32#include <ctype.h>
33
34#ifdef HAVE_UNISTD_H
35# include <unistd.h>
36#endif
37
38#include "tiffio.h"
39
40#ifndef HAVE_GETOPT
41extern int getopt(int, char**, char*);
42#endif
43
44#if defined(_WINDOWS) || defined(MSDOS)
45#define BINMODE "b"
46#else
47#define BINMODE
48#endif
49
50#define streq(a,b) (strcmp(a,b) == 0)
51#define strneq(a,b,n) (strncmp(a,b,n) == 0)
52
53static uint16 compression = COMPRESSION_PACKBITS;
54static uint16 predictor = 0;
55static int quality = 75; /* JPEG quality */
56static int jpegcolormode = JPEGCOLORMODE_RGB;
57static uint32 g3opts;
58
59static void usage(void);
60static int processCompressOptions(char*);
61
62static void
63BadPPM(char* file)
64{
65 fprintf(stderr, "%s: Not a PPM file.\n", file);
66 exit(-2);
67}
68
69int
70main(int argc, char* argv[])
71{
72 uint16 photometric = 0;
73 uint32 rowsperstrip = (uint32) -1;
74 double resolution = -1;
75 unsigned char *buf = NULL;
76 tsize_t linebytes = 0;
77 uint16 spp = 1;
78 uint16 bpp = 8;
79 TIFF *out;
80 FILE *in;
81 unsigned int w, h, prec, row;
82 char *infile;
83 int c;
84 extern int optind;
85 extern char* optarg;
86
87 if (argc < 2) {
88 fprintf(stderr, "%s: Too few arguments\n", argv[0]);
89 usage();
90 }
91 while ((c = getopt(argc, argv, "c:r:R:")) != -1)
92 switch (c) {
93 case 'c': /* compression scheme */
94 if (!processCompressOptions(optarg))
95 usage();
96 break;
97 case 'r': /* rows/strip */
98 rowsperstrip = atoi(optarg);
99 break;
100 case 'R': /* resolution */
101 resolution = atof(optarg);
102 break;
103 case '?':
104 usage();
105 /*NOTREACHED*/
106 }
107
108 if (optind + 2 < argc) {
109 fprintf(stderr, "%s: Too many arguments\n", argv[0]);
110 usage();
111 }
112
113 /*
114 * If only one file is specified, read input from
115 * stdin; otherwise usage is: ppm2tiff input output.
116 */
117 if (argc - optind > 1) {
118 infile = argv[optind++];
119 in = fopen(infile, "r" BINMODE);
120 if (in == NULL) {
121 fprintf(stderr, "%s: Can not open.\n", infile);
122 return (-1);
123 }
124 } else {
125 infile = "<stdin>";
126 in = stdin;
127 }
128
129 if (fgetc(in) != 'P')
130 BadPPM(infile);
131 switch (fgetc(in)) {
132 case '4': /* it's a PBM file */
133 bpp = 1;
134 spp = 1;
135 photometric = PHOTOMETRIC_MINISWHITE;
136 break;
137 case '5': /* it's a PGM file */
138 bpp = 8;
139 spp = 1;
140 photometric = PHOTOMETRIC_MINISBLACK;
141 break;
142 case '6': /* it's a PPM file */
143 bpp = 8;
144 spp = 3;
145 photometric = PHOTOMETRIC_RGB;
146 if (compression == COMPRESSION_JPEG &&
147 jpegcolormode == JPEGCOLORMODE_RGB)
148 photometric = PHOTOMETRIC_YCBCR;
149 break;
150 default:
151 BadPPM(infile);
152 }
153
154 /* Parse header */
155 while(1) {
156 if (feof(in))
157 BadPPM(infile);
158 c = fgetc(in);
159 /* Skip whitespaces (blanks, TABs, CRs, LFs) */
160 if (strchr(" \t\r\n", c))
161 continue;
162
163 /* Check for comment line */
164 if (c == '#') {
165 do {
166 c = fgetc(in);
167 } while(!strchr("\r\n", c) || feof(in));
168 continue;
169 }
170
171 ungetc(c, in);
172 break;
173 }
174 switch (bpp) {
175 case 1:
176 if (fscanf(in, " %u %u", &w, &h) != 2)
177 BadPPM(infile);
178 if (fgetc(in) != '\n')
179 BadPPM(infile);
180 break;
181 case 8:
182 if (fscanf(in, " %u %u %u", &w, &h, &prec) != 3)
183 BadPPM(infile);
184 if (fgetc(in) != '\n' || prec != 255)
185 BadPPM(infile);
186 break;
187 }
188 out = TIFFOpen(argv[optind], "w");
189 if (out == NULL)
190 return (-4);
191 TIFFSetField(out, TIFFTAG_IMAGEWIDTH, (uint32) w);
192 TIFFSetField(out, TIFFTAG_IMAGELENGTH, (uint32) h);
193 TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
194 TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, spp);
195 TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, bpp);
196 TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
197 TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric);
198 TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
199 switch (compression) {
200 case COMPRESSION_JPEG:
201 TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality);
202 TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode);
203 break;
204 case COMPRESSION_LZW:
205 case COMPRESSION_DEFLATE:
206 if (predictor != 0)
207 TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
208 break;
209 case COMPRESSION_CCITTFAX3:
210 TIFFSetField(out, TIFFTAG_GROUP3OPTIONS, g3opts);
211 break;
212 }
213 switch (bpp) {
214 case 1:
215 linebytes = (spp * w + (8 - 1)) / 8;
216 if (rowsperstrip == (uint32) -1) {
217 TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, h);
218 } else {
219 TIFFSetField(out, TIFFTAG_ROWSPERSTRIP,
220 TIFFDefaultStripSize(out, rowsperstrip));
221 }
222 break;
223 case 8:
224 linebytes = spp * w;
225 TIFFSetField(out, TIFFTAG_ROWSPERSTRIP,
226 TIFFDefaultStripSize(out, rowsperstrip));
227 break;
228 }
229 if (TIFFScanlineSize(out) > linebytes)
230 buf = (unsigned char *)_TIFFmalloc(linebytes);
231 else
232 buf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(out));
233 if (resolution > 0) {
234 TIFFSetField(out, TIFFTAG_XRESOLUTION, resolution);
235 TIFFSetField(out, TIFFTAG_YRESOLUTION, resolution);
236 TIFFSetField(out, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
237 }
238 for (row = 0; row < h; row++) {
239 if (fread(buf, linebytes, 1, in) != 1) {
240 fprintf(stderr, "%s: scanline %lu: Read error.\n",
241 infile, (unsigned long) row);
242 break;
243 }
244 if (TIFFWriteScanline(out, buf, row, 0) < 0)
245 break;
246 }
247 (void) TIFFClose(out);
248 if (buf)
249 _TIFFfree(buf);
250 return (0);
251}
252
253static void
254processG3Options(char* cp)
255{
256 g3opts = 0;
257 if( (cp = strchr(cp, ':')) ) {
258 do {
259 cp++;
260 if (strneq(cp, "1d", 2))
261 g3opts &= ~GROUP3OPT_2DENCODING;
262 else if (strneq(cp, "2d", 2))
263 g3opts |= GROUP3OPT_2DENCODING;
264 else if (strneq(cp, "fill", 4))
265 g3opts |= GROUP3OPT_FILLBITS;
266 else
267 usage();
268 } while( (cp = strchr(cp, ':')) );
269 }
270}
271
272static int
273processCompressOptions(char* opt)
274{
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, ':');
281
282 compression = COMPRESSION_JPEG;
283 while (cp)
284 {
285 if (isdigit((int)cp[1]))
286 quality = atoi(cp+1);
287 else if (cp[1] == 'r' )
288 jpegcolormode = JPEGCOLORMODE_RAW;
289 else
290 usage();
291
292 cp = strchr(cp+1,':');
293 }
294 } else if (strneq(opt, "g3", 2)) {
295 processG3Options(opt);
296 compression = COMPRESSION_CCITTFAX3;
297 } else if (streq(opt, "g4")) {
298 compression = COMPRESSION_CCITTFAX4;
299 } else if (strneq(opt, "lzw", 3)) {
300 char* cp = strchr(opt, ':');
301 if (cp)
302 predictor = atoi(cp+1);
303 compression = COMPRESSION_LZW;
304 } else if (strneq(opt, "zip", 3)) {
305 char* cp = strchr(opt, ':');
306 if (cp)
307 predictor = atoi(cp+1);
308 compression = COMPRESSION_DEFLATE;
309 } else
310 return (0);
311 return (1);
312}
313
314char* stuff[] = {
315"usage: ppm2tiff [options] input.ppm output.tif",
316"where options are:",
317" -r # make each strip have no more than # rows",
318" -R # set x&y resolution (dpi)",
319"",
320" -c jpeg[:opts] compress output with JPEG encoding",
321" -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
322" -c zip[:opts] compress output with deflate encoding",
323" -c packbits compress output with packbits encoding (the default)",
324" -c g3[:opts] compress output with CCITT Group 3 encoding",
325" -c g4 compress output with CCITT Group 4 encoding",
326" -c none use no compression algorithm on output",
327"",
328"JPEG options:",
329" # set compression quality level (0-100, default 75)",
330" r output color image as RGB rather than YCbCr",
331"LZW and deflate options:",
332" # set predictor value",
333"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
334NULL
335};
336
337static void
338usage(void)
339{
340 char buf[BUFSIZ];
341 int i;
342
343 setbuf(stderr, buf);
344 fprintf(stderr, "%s\n\n", TIFFGetVersion());
345 for (i = 0; stuff[i] != NULL; i++)
346 fprintf(stderr, "%s\n", stuff[i]);
347 exit(-1);
348}
349
350/* vim: set ts=8 sts=8 sw=8 noet: */