]> git.saurik.com Git - wxWidgets.git/blob - src/tiff/tools/gif2tiff.c
Fix typo in last commit
[wxWidgets.git] / src / tiff / tools / gif2tiff.c
1 /* $Id$ */
2
3 /*
4 * Copyright (c) 1990-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 /*
28 * convert a GIF file into a TIFF file.
29 * based on Paul Haeberli's fromgif program which in turn is
30 * based on a GIF file reader by Marcel J.E. Mol March 23 1989
31 *
32 * if input is 320 by 200 pixel aspect is probably 1.2
33 * if input is 640 350 pixel aspect is probably 1.37
34 *
35 */
36 #include "tif_config.h"
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <math.h>
42
43 #ifdef HAVE_UNISTD_H
44 # include <unistd.h>
45 #endif
46
47 #include "tiffio.h"
48
49 #define GIFGAMMA (1.5) /* smaller makes output img brighter */
50 #define IMAX 0xffff /* max intensity value */
51 #define EXTRAFUDGE 128 /* some people write BAD .gif files */
52
53 #define streq(a,b) (strcmp(a,b) == 0)
54 #define strneq(a,b,n) (strncmp(a,b,n) == 0)
55
56 unsigned short gamtab[256];
57
58 void
59 makegamtab(float gam)
60 {
61 int i;
62
63 for(i=0; i<256; i++)
64 gamtab[i] = (unsigned short) (IMAX*pow(i/255.0,gam)+0.5);
65 }
66
67 char* stuff[] = {
68 "usage: gif2tiff [options] input.gif output.tif",
69 "where options are:",
70 " -r # make each strip have no more than # rows",
71 "",
72 " -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
73 " -c zip[:opts] compress output with deflate encoding",
74 " -c packbits compress output with packbits encoding",
75 " -c none use no compression algorithm on output",
76 "",
77 "LZW and deflate options:",
78 " # set predictor value",
79 "For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
80 NULL
81 };
82
83 static void
84 usage(void)
85 {
86 char buf[BUFSIZ];
87 int i;
88
89 setbuf(stderr, buf);
90 fprintf(stderr, "%s\n\n", TIFFGetVersion());
91 for (i = 0; stuff[i] != NULL; i++)
92 fprintf(stderr, "%s\n", stuff[i]);
93 exit(-1);
94 }
95
96 #define COLSIZE 256
97
98 unsigned char *stackp;
99 unsigned int prefix[4096];
100 unsigned char suffix[4096];
101 unsigned char stack[4096];
102 int datasize,codesize,codemask; /* Decoder working variables */
103 int clear,eoi; /* Special code values */
104 int avail, oldcode;
105
106 FILE *infile;
107 int global; /* Is there a global color map? */
108 int globalbits; /* Number of bits of global colors */
109 unsigned char globalmap[COLSIZE][3];/* RGB values for global color map */
110 unsigned char *raster; /* Decoded image data */
111 unsigned long width, height;
112 unsigned short red[COLSIZE];
113 unsigned short green[COLSIZE];
114 unsigned short blue[COLSIZE];
115 char *filename, *imagename;
116
117 static uint16 compression = COMPRESSION_PACKBITS;
118 static uint16 predictor = 0;
119 static uint32 rowsperstrip = (uint32) -1;
120 static int processCompressOptions(char*);
121
122 int convert(void);
123 int checksignature(void);
124 void readscreen(void);
125 int readgifimage(char*);
126 void readextension(void);
127 int readraster(void);
128 int process(int, unsigned char**);
129 void initcolors(unsigned char [COLSIZE][3], int);
130 void rasterize(int, char*);
131
132 int
133 main(int argc, char* argv[])
134 {
135 extern int optind;
136 extern char *optarg;
137 int c, status;
138
139 while ((c = getopt(argc, argv, "c:r:")) != -1)
140 switch (c) {
141 case 'c': /* compression scheme */
142 if (!processCompressOptions(optarg))
143 usage();
144 break;
145 case 'r': /* rows/strip */
146 rowsperstrip = atoi(optarg);
147 break;
148 case '?':
149 usage();
150 /*NOTREACHED*/
151 }
152 if (argc - optind != 2)
153 usage();
154
155 makegamtab(GIFGAMMA);
156 filename = argv[optind];
157 imagename = argv[optind+1];
158 if ((infile = fopen(imagename, "rb")) != NULL) {
159 int c;
160 fclose(infile);
161 printf("overwrite %s? ", imagename); fflush(stdout);
162 c = getc(stdin);
163 if (c != 'y' && c != 'Y')
164 return (1);
165 }
166 if ((infile = fopen(filename, "rb")) == NULL) {
167 perror(filename);
168 return (1);
169 }
170 status = convert();
171 fclose(infile);
172 return (status);
173 }
174
175 static int
176 processCompressOptions(char* opt)
177 {
178 if (streq(opt, "none"))
179 compression = COMPRESSION_NONE;
180 else if (streq(opt, "packbits"))
181 compression = COMPRESSION_PACKBITS;
182 else if (strneq(opt, "lzw", 3)) {
183 char* cp = strchr(opt, ':');
184 if (cp)
185 predictor = atoi(cp+1);
186 compression = COMPRESSION_LZW;
187 } else if (strneq(opt, "zip", 3)) {
188 char* cp = strchr(opt, ':');
189 if (cp)
190 predictor = atoi(cp+1);
191 compression = COMPRESSION_DEFLATE;
192 } else
193 return (0);
194 return (1);
195 }
196
197 int
198 convert(void)
199 {
200 int ch;
201 char* mode = "w";
202
203 if (!checksignature())
204 return (-1);
205 readscreen();
206 while ((ch = getc(infile)) != ';' && ch != EOF) {
207 switch (ch) {
208 case '\0': break; /* this kludge for non-standard files */
209 case ',': if (!readgifimage(mode))
210 return (-1);
211 mode = "a"; /* subsequent images append */
212 break;
213 case '!': readextension();
214 break;
215 default: fprintf(stderr, "illegal GIF block type\n");
216 return (-1);
217 }
218 }
219 return (0);
220 }
221
222 int
223 checksignature(void)
224 {
225 char buf[6];
226
227 fread(buf,1,6,infile);
228 if (strncmp(buf,"GIF",3)) {
229 fprintf(stderr, "file is not a GIF file\n");
230 return 0;
231 }
232 if (strncmp(&buf[3],"87a",3)) {
233 fprintf(stderr, "unknown GIF version number\n");
234 return 0;
235 }
236 return 1;
237 }
238
239 /*
240 * readscreen -
241 * Get information which is global to all the images stored
242 * in the file
243 */
244 void
245 readscreen(void)
246 {
247 unsigned char buf[7];
248
249 fread(buf,1,7,infile);
250 global = buf[4] & 0x80;
251 if (global) {
252 globalbits = (buf[4] & 0x07) + 1;
253 fread(globalmap,3,1<<globalbits,infile);
254 }
255 }
256
257 int
258 readgifimage(char* mode)
259 {
260 unsigned char buf[9];
261 int local, interleaved;
262 unsigned char localmap[256][3];
263 int localbits;
264 int status;
265
266 if (fread(buf, 1, 9, infile) == 0) {
267 perror(filename);
268 return (0);
269 }
270 width = buf[4] + (buf[5] << 8);
271 height = buf[6] + (buf[7] << 8);
272 local = buf[8] & 0x80;
273 interleaved = buf[8] & 0x40;
274
275 if (local == 0 && global == 0) {
276 fprintf(stderr, "no colormap present for image\n");
277 return (0);
278 }
279 if ((raster = (unsigned char*) _TIFFmalloc(width*height+EXTRAFUDGE)) == NULL) {
280 fprintf(stderr, "not enough memory for image\n");
281 return (0);
282 }
283 if (local) {
284 localbits = (buf[8] & 0x7) + 1;
285
286 fprintf(stderr, " local colors: %d\n", 1<<localbits);
287
288 fread(localmap, 3, 1<<localbits, infile);
289 initcolors(localmap, 1<<localbits);
290 } else if (global) {
291 initcolors(globalmap, 1<<globalbits);
292 }
293 if ((status = readraster()))
294 rasterize(interleaved, mode);
295 _TIFFfree(raster);
296 return status;
297 }
298
299 /*
300 * readextension -
301 * Read a GIF extension block (and do nothing with it).
302 *
303 */
304 void
305 readextension(void)
306 {
307 int count;
308 char buf[255];
309
310 (void) getc(infile);
311 while ((count = getc(infile)))
312 fread(buf, 1, count, infile);
313 }
314
315 /*
316 * readraster -
317 * Decode a raster image
318 *
319 */
320 int
321 readraster(void)
322 {
323 unsigned char *fill = raster;
324 unsigned char buf[255];
325 register int bits=0;
326 register unsigned long datum=0;
327 register unsigned char *ch;
328 register int count, code;
329 int status = 1;
330
331 datasize = getc(infile);
332 clear = 1 << datasize;
333 eoi = clear + 1;
334 avail = clear + 2;
335 oldcode = -1;
336 codesize = datasize + 1;
337 codemask = (1 << codesize) - 1;
338 for (code = 0; code < clear; code++) {
339 prefix[code] = 0;
340 suffix[code] = code;
341 }
342 stackp = stack;
343 for (count = getc(infile); count > 0; count = getc(infile)) {
344 fread(buf,1,count,infile);
345 for (ch=buf; count-- > 0; ch++) {
346 datum += (unsigned long) *ch << bits;
347 bits += 8;
348 while (bits >= codesize) {
349 code = datum & codemask;
350 datum >>= codesize;
351 bits -= codesize;
352 if (code == eoi) { /* This kludge put in */
353 goto exitloop; /* because some GIF files*/
354 } /* aren't standard */
355 if (!process(code, &fill)) {
356 status = 0;
357 goto exitloop;
358 }
359 }
360 }
361 if (fill >= raster + width*height) {
362 fprintf(stderr, "raster full before eoi code\n");
363 break;
364 }
365 }
366 exitloop:
367 if (fill != raster + width*height) {
368 fprintf(stderr, "warning: wrong rastersize: %ld bytes\n",
369 (long) (fill-raster));
370 fprintf(stderr, " instead of %ld bytes\n",
371 (long) width*height);
372 }
373 return status;
374 }
375
376 /*
377 * process -
378 * Process a compression code. "clear" resets the code table.
379 * Otherwise make a new code table entry, and output the bytes
380 * associated with the code.
381 */
382 int
383 process(register int code, unsigned char** fill)
384 {
385 int incode;
386 static unsigned char firstchar;
387
388 if (code == clear) {
389 codesize = datasize + 1;
390 codemask = (1 << codesize) - 1;
391 avail = clear + 2;
392 oldcode = -1;
393 return 1;
394 }
395
396 if (oldcode == -1) {
397 *(*fill)++ = suffix[code];
398 firstchar = oldcode = code;
399 return 1;
400 }
401 if (code > avail) {
402 fprintf(stderr, "code %d too large for %d\n", code, avail);
403 return 0;
404 }
405
406 incode = code;
407 if (code == avail) { /* the first code is always < avail */
408 *stackp++ = firstchar;
409 code = oldcode;
410 }
411 while (code > clear) {
412 *stackp++ = suffix[code];
413 code = prefix[code];
414 }
415
416 *stackp++ = firstchar = suffix[code];
417 prefix[avail] = oldcode;
418 suffix[avail] = firstchar;
419 avail++;
420
421 if (((avail & codemask) == 0) && (avail < 4096)) {
422 codesize++;
423 codemask += avail;
424 }
425 oldcode = incode;
426 do {
427 *(*fill)++ = *--stackp;
428 } while (stackp > stack);
429 return 1;
430 }
431
432 /*
433 * initcolors -
434 * Convert a color map (local or global) to arrays with R, G and B
435 * values.
436 *
437 */
438 void
439 initcolors(unsigned char colormap[COLSIZE][3], int ncolors)
440 {
441 register int i;
442
443 for (i = 0; i < ncolors; i++) {
444 red[i] = gamtab[colormap[i][0]];
445 green[i] = gamtab[colormap[i][1]];
446 blue[i] = gamtab[colormap[i][2]];
447 }
448 }
449
450 void
451 rasterize(int interleaved, char* mode)
452 {
453 register unsigned long row;
454 unsigned char *newras;
455 unsigned char *ras;
456 TIFF *tif;
457 tstrip_t strip;
458 tsize_t stripsize;
459
460 if ((newras = (unsigned char*) _TIFFmalloc(width*height+EXTRAFUDGE)) == NULL) {
461 fprintf(stderr, "not enough memory for image\n");
462 return;
463 }
464 #define DRAWSEGMENT(offset, step) { \
465 for (row = offset; row < height; row += step) { \
466 _TIFFmemcpy(newras + row*width, ras, width);\
467 ras += width; \
468 } \
469 }
470 ras = raster;
471 if (interleaved) {
472 DRAWSEGMENT(0, 8);
473 DRAWSEGMENT(4, 8);
474 DRAWSEGMENT(2, 4);
475 DRAWSEGMENT(1, 2);
476 } else
477 DRAWSEGMENT(0, 1);
478 #undef DRAWSEGMENT
479
480 tif = TIFFOpen(imagename, mode);
481 if (!tif) {
482 TIFFError(imagename,"Can not open output image");
483 exit(-1);
484 }
485 TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (uint32) width);
486 TIFFSetField(tif, TIFFTAG_IMAGELENGTH, (uint32) height);
487 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE);
488 TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
489 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
490 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
491 TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP,
492 rowsperstrip = TIFFDefaultStripSize(tif, rowsperstrip));
493 TIFFSetField(tif, TIFFTAG_COMPRESSION, compression);
494 switch (compression) {
495 case COMPRESSION_LZW:
496 case COMPRESSION_DEFLATE:
497 if (predictor != 0)
498 TIFFSetField(tif, TIFFTAG_PREDICTOR, predictor);
499 break;
500 }
501 TIFFSetField(tif, TIFFTAG_COLORMAP, red, green, blue);
502 TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
503 strip = 0;
504 stripsize = TIFFStripSize(tif);
505 for (row=0; row<height; row += rowsperstrip) {
506 if (TIFFWriteEncodedStrip(tif, strip, newras+row*width, stripsize) < 0)
507 break;
508 strip++;
509 }
510 TIFFClose(tif);
511
512 _TIFFfree(newras);
513 }
514
515 /* vim: set ts=8 sts=8 sw=8 noet: */