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