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