1/* $Id: gif2tiff.c 276 2010-06-30 12:18:30Z nijtmans $ */ 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 56unsigned short gamtab[256]; 57 58void 59makegamtab(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 67char* 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", 80NULL 81}; 82 83static void 84usage(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 98unsigned char *stackp; 99unsigned int prefix[4096]; 100unsigned char suffix[4096]; 101unsigned char stack[4096]; 102int datasize,codesize,codemask; /* Decoder working variables */ 103int clear,eoi; /* Special code values */ 104int avail, oldcode; 105 106FILE *infile; 107int global; /* Is there a global color map? */ 108int globalbits; /* Number of bits of global colors */ 109unsigned char globalmap[COLSIZE][3];/* RGB values for global color map */ 110unsigned char *raster; /* Decoded image data */ 111unsigned long width, height; 112unsigned short red[COLSIZE]; 113unsigned short green[COLSIZE]; 114unsigned short blue[COLSIZE]; 115char *filename, *imagename; 116 117static uint16 compression = COMPRESSION_PACKBITS; 118static uint16 predictor = 0; 119static uint32 rowsperstrip = (uint32) -1; 120static int processCompressOptions(char*); 121 122int convert(void); 123int checksignature(void); 124void readscreen(void); 125int readgifimage(char*); 126void readextension(void); 127int readraster(void); 128int process(int, unsigned char**); 129void initcolors(unsigned char [COLSIZE][3], int); 130void rasterize(int, char*); 131 132int 133main(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 175static int 176processCompressOptions(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 197int 198convert(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 222int 223checksignature(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 */ 244void 245readscreen(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 257int 258readgifimage(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 */ 304void 305readextension(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 */ 320int 321readraster(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 } 366exitloop: 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 */ 382int 383process(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 */ 438void 439initcolors(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 450void 451rasterize(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: */ 516/* 517 * Local Variables: 518 * mode: c 519 * c-basic-offset: 8 520 * fill-column: 78 521 * End: 522 */ 523