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