]>
Commit | Line | Data |
---|---|---|
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 <stdio.h> | |
28 | #include <stdlib.h> | |
29 | #include <string.h> | |
30 | #include <gl/image.h> | |
31 | #include <ctype.h> | |
32 | ||
33 | #include "tiffio.h" | |
34 | ||
35 | #define streq(a,b) (strcmp(a,b) == 0) | |
36 | #define strneq(a,b,n) (strncmp(a,b,n) == 0) | |
37 | ||
38 | static short config = PLANARCONFIG_CONTIG; | |
39 | static uint16 compression = COMPRESSION_PACKBITS; | |
40 | static uint16 predictor = 0; | |
41 | static uint16 fillorder = 0; | |
42 | static uint32 rowsperstrip = (uint32) -1; | |
43 | static int jpegcolormode = JPEGCOLORMODE_RGB; | |
44 | static int quality = 75; /* JPEG quality */ | |
45 | static uint16 photometric; | |
46 | ||
47 | static void usage(void); | |
48 | static int cpContig(IMAGE*, TIFF*); | |
49 | static int cpSeparate(IMAGE*, TIFF*); | |
50 | static int processCompressOptions(char*); | |
51 | ||
52 | /* XXX image library has no prototypes */ | |
53 | extern IMAGE* iopen(const char*, const char*); | |
54 | extern void iclose(IMAGE*); | |
55 | extern void getrow(IMAGE*, short*, int, int); | |
56 | ||
57 | int | |
58 | main(int argc, char* argv[]) | |
59 | { | |
60 | IMAGE *in; | |
61 | TIFF *out; | |
62 | int c; | |
63 | extern int optind; | |
64 | extern char* optarg; | |
65 | ||
66 | while ((c = getopt(argc, argv, "c:p:r:")) != -1) | |
67 | switch (c) { | |
68 | case 'c': /* compression scheme */ | |
69 | if (!processCompressOptions(optarg)) | |
70 | usage(); | |
71 | break; | |
72 | case 'f': /* fill order */ | |
73 | if (streq(optarg, "lsb2msb")) | |
74 | fillorder = FILLORDER_LSB2MSB; | |
75 | else if (streq(optarg, "msb2lsb")) | |
76 | fillorder = FILLORDER_MSB2LSB; | |
77 | else | |
78 | usage(); | |
79 | break; | |
80 | case 'p': /* planar configuration */ | |
81 | if (streq(optarg, "separate")) | |
82 | config = PLANARCONFIG_SEPARATE; | |
83 | else if (streq(optarg, "contig")) | |
84 | config = PLANARCONFIG_CONTIG; | |
85 | else | |
86 | usage(); | |
87 | break; | |
88 | case 'r': /* rows/strip */ | |
89 | rowsperstrip = atoi(optarg); | |
90 | break; | |
91 | case '?': | |
92 | usage(); | |
93 | /*NOTREACHED*/ | |
94 | } | |
95 | if (argc - optind != 2) | |
96 | usage(); | |
97 | in = iopen(argv[optind], "r"); | |
98 | if (in == NULL) | |
99 | return (-1); | |
100 | out = TIFFOpen(argv[optind+1], "w"); | |
101 | if (out == NULL) | |
102 | return (-2); | |
103 | TIFFSetField(out, TIFFTAG_IMAGEWIDTH, (uint32) in->xsize); | |
104 | TIFFSetField(out, TIFFTAG_IMAGELENGTH, (uint32) in->ysize); | |
105 | TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 8); | |
106 | TIFFSetField(out, TIFFTAG_COMPRESSION, compression); | |
107 | if (in->zsize == 1) | |
108 | photometric = PHOTOMETRIC_MINISBLACK; | |
109 | else | |
110 | photometric = PHOTOMETRIC_RGB; | |
111 | switch (compression) { | |
112 | case COMPRESSION_JPEG: | |
113 | if (photometric == PHOTOMETRIC_RGB && jpegcolormode == JPEGCOLORMODE_RGB) | |
114 | photometric = PHOTOMETRIC_YCBCR; | |
115 | TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality); | |
116 | TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode); | |
117 | break; | |
118 | case COMPRESSION_LZW: | |
119 | case COMPRESSION_DEFLATE: | |
120 | if (predictor != 0) | |
121 | TIFFSetField(out, TIFFTAG_PREDICTOR, predictor); | |
122 | break; | |
123 | } | |
124 | TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric); | |
125 | if (fillorder != 0) | |
126 | TIFFSetField(out, TIFFTAG_FILLORDER, fillorder); | |
127 | TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); | |
128 | TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, in->zsize); | |
129 | if (in->zsize > 3) { | |
130 | uint16 v[1]; | |
131 | v[0] = EXTRASAMPLE_UNASSALPHA; | |
132 | TIFFSetField(out, TIFFTAG_EXTRASAMPLES, 1, v); | |
133 | } | |
134 | TIFFSetField(out, TIFFTAG_MINSAMPLEVALUE, (uint16) in->min); | |
135 | TIFFSetField(out, TIFFTAG_MAXSAMPLEVALUE, (uint16) in->max); | |
136 | TIFFSetField(out, TIFFTAG_PLANARCONFIG, config); | |
137 | if (config != PLANARCONFIG_SEPARATE) | |
138 | TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, | |
139 | TIFFDefaultStripSize(out, rowsperstrip)); | |
140 | else /* force 1 row/strip for library limitation */ | |
141 | TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, 1L); | |
142 | if (in->name[0] != '\0') | |
143 | TIFFSetField(out, TIFFTAG_IMAGEDESCRIPTION, in->name); | |
144 | if (config == PLANARCONFIG_CONTIG) | |
145 | cpContig(in, out); | |
146 | else | |
147 | cpSeparate(in, out); | |
148 | (void) iclose(in); | |
149 | (void) TIFFClose(out); | |
150 | return (0); | |
151 | } | |
152 | ||
153 | static int | |
154 | processCompressOptions(char* opt) | |
155 | { | |
156 | if (streq(opt, "none")) | |
157 | compression = COMPRESSION_NONE; | |
158 | else if (streq(opt, "packbits")) | |
159 | compression = COMPRESSION_PACKBITS; | |
160 | else if (strneq(opt, "jpeg", 4)) { | |
161 | char* cp = strchr(opt, ':'); | |
162 | ||
163 | defcompression = COMPRESSION_JPEG; | |
164 | while( cp ) | |
165 | { | |
166 | if (isdigit((int)cp[1])) | |
167 | quality = atoi(cp+1); | |
168 | else if (cp[1] == 'r' ) | |
169 | jpegcolormode = JPEGCOLORMODE_RAW; | |
170 | else | |
171 | usage(); | |
172 | ||
173 | cp = strchr(cp+1,':'); | |
174 | } | |
175 | } else if (strneq(opt, "lzw", 3)) { | |
176 | char* cp = strchr(opt, ':'); | |
177 | if (cp) | |
178 | predictor = atoi(cp+1); | |
179 | compression = COMPRESSION_LZW; | |
180 | } else if (strneq(opt, "zip", 3)) { | |
181 | char* cp = strchr(opt, ':'); | |
182 | if (cp) | |
183 | predictor = atoi(cp+1); | |
184 | compression = COMPRESSION_DEFLATE; | |
185 | } else | |
186 | return (0); | |
187 | return (1); | |
188 | } | |
189 | ||
190 | static int | |
191 | cpContig(IMAGE* in, TIFF* out) | |
192 | { | |
193 | tdata_t buf = _TIFFmalloc(TIFFScanlineSize(out)); | |
194 | short *r = NULL; | |
195 | int x, y; | |
196 | ||
197 | if (in->zsize == 3) { | |
198 | short *g, *b; | |
199 | ||
200 | r = (short *)_TIFFmalloc(3 * in->xsize * sizeof (short)); | |
201 | g = r + in->xsize; | |
202 | b = g + in->xsize; | |
203 | for (y = in->ysize-1; y >= 0; y--) { | |
204 | uint8* pp = (uint8*) buf; | |
205 | ||
206 | getrow(in, r, y, 0); | |
207 | getrow(in, g, y, 1); | |
208 | getrow(in, b, y, 2); | |
209 | for (x = 0; x < in->xsize; x++) { | |
210 | pp[0] = r[x]; | |
211 | pp[1] = g[x]; | |
212 | pp[2] = b[x]; | |
213 | pp += 3; | |
214 | } | |
215 | if (TIFFWriteScanline(out, buf, in->ysize-y-1, 0) < 0) | |
216 | goto bad; | |
217 | } | |
218 | } else if (in->zsize == 4) { | |
219 | short *g, *b, *a; | |
220 | ||
221 | r = (short *)_TIFFmalloc(4 * in->xsize * sizeof (short)); | |
222 | g = r + in->xsize; | |
223 | b = g + in->xsize; | |
224 | a = b + in->xsize; | |
225 | for (y = in->ysize-1; y >= 0; y--) { | |
226 | uint8* pp = (uint8*) buf; | |
227 | ||
228 | getrow(in, r, y, 0); | |
229 | getrow(in, g, y, 1); | |
230 | getrow(in, b, y, 2); | |
231 | getrow(in, a, y, 3); | |
232 | for (x = 0; x < in->xsize; x++) { | |
233 | pp[0] = r[x]; | |
234 | pp[1] = g[x]; | |
235 | pp[2] = b[x]; | |
236 | pp[3] = a[x]; | |
237 | pp += 4; | |
238 | } | |
239 | if (TIFFWriteScanline(out, buf, in->ysize-y-1, 0) < 0) | |
240 | goto bad; | |
241 | } | |
242 | } else { | |
243 | uint8* pp = (uint8*) buf; | |
244 | ||
245 | r = (short *)_TIFFmalloc(in->xsize * sizeof (short)); | |
246 | for (y = in->ysize-1; y >= 0; y--) { | |
247 | getrow(in, r, y, 0); | |
248 | for (x = in->xsize-1; x >= 0; x--) | |
249 | pp[x] = r[x]; | |
250 | if (TIFFWriteScanline(out, buf, in->ysize-y-1, 0) < 0) | |
251 | goto bad; | |
252 | } | |
253 | } | |
254 | if (r) | |
255 | _TIFFfree(r); | |
256 | _TIFFfree(buf); | |
257 | return (1); | |
258 | bad: | |
259 | if (r) | |
260 | _TIFFfree(r); | |
261 | _TIFFfree(buf); | |
262 | return (0); | |
263 | } | |
264 | ||
265 | static int | |
266 | cpSeparate(IMAGE* in, TIFF* out) | |
267 | { | |
268 | tdata_t buf = _TIFFmalloc(TIFFScanlineSize(out)); | |
269 | short *r = (short *)_TIFFmalloc(in->xsize * sizeof (short)); | |
270 | uint8* pp = (uint8*) buf; | |
271 | int x, y, z; | |
272 | ||
273 | for (z = 0; z < in->zsize; z++) { | |
274 | for (y = in->ysize-1; y >= 0; y--) { | |
275 | getrow(in, r, y, z); | |
276 | for (x = 0; x < in->xsize; x++) | |
277 | pp[x] = r[x]; | |
278 | if (TIFFWriteScanline(out, buf, in->ysize-y-1, z) < 0) | |
279 | goto bad; | |
280 | } | |
281 | } | |
282 | _TIFFfree(r); | |
283 | _TIFFfree(buf); | |
284 | return (1); | |
285 | bad: | |
286 | _TIFFfree(r); | |
287 | _TIFFfree(buf); | |
288 | return (0); | |
289 | } | |
290 | ||
291 | char* stuff[] = { | |
292 | "usage: sgi2tiff [options] input.rgb output.tif", | |
293 | "where options are:", | |
294 | " -r # make each strip have no more than # rows", | |
295 | "", | |
296 | " -p contig pack samples contiguously (e.g. RGBRGB...)", | |
297 | " -p separate store samples separately (e.g. RRR...GGG...BBB...)", | |
298 | "", | |
299 | " -f lsb2msb force lsb-to-msb FillOrder for output", | |
300 | " -f msb2lsb force msb-to-lsb FillOrder for output", | |
301 | "", | |
302 | " -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding", | |
303 | " -c zip[:opts] compress output with deflate encoding", | |
304 | " -c jpeg[:opts]compress output with JPEG encoding", | |
305 | " -c packbits compress output with packbits encoding", | |
306 | " -c none use no compression algorithm on output", | |
307 | "", | |
308 | "JPEG options:", | |
309 | " # set compression quality level (0-100, default 75)", | |
310 | " r output color image as RGB rather than YCbCr", | |
311 | "", | |
312 | "LZW and deflate options:", | |
313 | " # set predictor value", | |
314 | "For example, -c lzw:2 to get LZW-encoded data with horizontal differencing", | |
315 | NULL | |
316 | }; | |
317 | ||
318 | static void | |
319 | usage(void) | |
320 | { | |
321 | char buf[BUFSIZ]; | |
322 | int i; | |
323 | ||
324 | setbuf(stderr, buf); | |
325 | for (i = 0; stuff[i] != NULL; i++) | |
326 | fprintf(stderr, "%s\n", stuff[i]); | |
327 | exit(-1); | |
328 | } |