/* * FIG : Facility for Interactive Generation of figures * Parts Copyright (c) 1990 David Koblas * Parts Copyright (c) 1989-2002 by Brian V. Smith * * Any party obtaining a copy of these files is granted, free of charge, a * full and unrestricted irrevocable, world-wide, paid up, royalty-free, * nonexclusive right and license to deal in this software and documentation * files (the "Software"), including without limitation the rights to use, * copy, modify, merge, publish distribute, sublicense and/or sell copies of * the Software, and to permit persons who receive copies from any such * party to do so, with the only requirement being that the above copyright * and this permission notice remain intact. * */ #include "fig.h" #include "resources.h" #include "object.h" #include "f_picobj.h" #include "w_msgpanel.h" #define BUFLEN 1024 /* Some of the following code is extracted from giftopnm.c, from the netpbm package */ /* +-------------------------------------------------------------------+ */ /* | Copyright 1990, David Koblas. | */ /* | Permission to use, copy, modify, and distribute this software | */ /* | and its documentation for any purpose and without fee is hereby | */ /* | granted, provided that the above copyright notice appear in all | */ /* | copies and that both that copyright notice and this permission | */ /* | notice appear in supporting documentation. This software is | */ /* | provided "as is" without express or implied warranty. | */ /* +-------------------------------------------------------------------+ */ static Boolean ReadColorMap(); static Boolean DoGIFextension(); static int GetDataBlock(); #define LOCALCOLORMAP 0x80 #define ReadOK(file,buffer,len) (fread((void *) buffer, (size_t) len, (size_t) 1, (FILE *) file) != 0) #define BitSet(byte, bit) (((byte) & (bit)) == (bit)) #define LM_to_uint(a,b) (((b)<<8)|(a)) struct { unsigned int Width; unsigned int Height; struct Cmap ColorMap[MAX_COLORMAP_SIZE]; unsigned int BitPixel; unsigned int ColorResolution; unsigned int Background; unsigned int AspectRatio; } GifScreen; struct { int transparent; int delayTime; int inputFlag; int disposal; } Gif89 = { -1, -1, -1, 0 }; /* return codes: PicSuccess (1) : success FileInvalid (-2) : invalid file */ int read_gif(file,filetype,pic) FILE *file; int filetype; F_pic *pic; { char buf[BUFLEN],pcxname[PATH_MAX]; FILE *giftopcx; struct Cmap localColorMap[MAX_COLORMAP_SIZE]; int i, stat, size; int useGlobalColormap; unsigned int bitPixel, red, green, blue; unsigned char c; char version[4]; /* first read header to look for any transparent color extension */ if (! ReadOK(file,buf,6)) { return FileInvalid; } if (strncmp((char*)buf,"GIF",3) != 0) { return FileInvalid; } strncpy(version, (char*)(buf + 3), 3); version[3] = '\0'; if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) { file_msg("Unknown GIF version %s",version); return FileInvalid; } if (! ReadOK(file,buf,7)) { return FileInvalid; /* failed to read screen descriptor */ } GifScreen.Width = LM_to_uint(buf[0],buf[1]); GifScreen.Height = LM_to_uint(buf[2],buf[3]); GifScreen.BitPixel = 2<<(buf[4]&0x07); GifScreen.ColorResolution = (((((int)buf[4])&0x70)>>3)+1); GifScreen.Background = (unsigned int) buf[5]; GifScreen.AspectRatio = (unsigned int) buf[6]; if (BitSet(buf[4], LOCALCOLORMAP)) { /* Global Colormap */ if (!ReadColorMap(file,GifScreen.BitPixel,GifScreen.ColorMap)) { return FileInvalid; /* error reading global colormap */ } } if (GifScreen.AspectRatio != 0 && GifScreen.AspectRatio != 49) { if (appres.DEBUG) fprintf(stderr,"warning - non-square pixels\n"); } /* assume no transparent color for now */ Gif89.transparent = TRANSP_NONE; /* read the full header to get any transparency information */ for (;;) { if (! ReadOK(file,&c,1)) { return FileInvalid; /* EOF / read error on image data */ } if (c == ';') { /* GIF terminator, finish up */ return PicSuccess; /* all done */ } if (c == '!') { /* Extension */ if (! ReadOK(file,&c,1)) file_msg("GIF read error on extention function code"); (void) DoGIFextension(file, c); continue; } if (c != ',') { /* Not a valid start character */ continue; } if (! ReadOK(file,buf,9)) { return FileInvalid; /* couldn't read left/top/width/height */ } useGlobalColormap = ! BitSet(buf[8], LOCALCOLORMAP); bitPixel = 1<<((buf[8]&0x07)+1); if (! useGlobalColormap) { if (!ReadColorMap(file, bitPixel, localColorMap)) { file_msg("error reading local GIF colormap" ); return PicSuccess; } } break; /* image starts here, header is done */ } /* save transparent indicator */ pic->pic_cache->transp = Gif89.transparent; /* close it and open it again (it may be a pipe so we can't just rewind) */ close_picfile(file, filetype); file = open_picfile(pic->pic_cache->file, &filetype, PIPEOK, pcxname); /* now call giftopnm and ppmtopcx */ /* make name for temp output file */ sprintf(pcxname, "%s/%s%06d.pix", TMPDIR, "xfig-pcx", getpid()); /* make command to convert gif to pcx into temp file */ sprintf(buf, "giftopnm | ppmtopcx > %s 2> /dev/null", pcxname); if ((giftopcx = popen(buf,"w" )) == 0) { file_msg("Cannot open pipe to giftopnm or ppmtopcx\n"); close_picfile(file,filetype); return FileInvalid; } while ((size=fread(buf, 1, BUFLEN, file)) != 0) { fwrite(buf, size, 1, giftopcx); } /* close pipe */ pclose(giftopcx); if ((giftopcx = fopen(pcxname, "rb")) == NULL) { file_msg("Can't open temp output file\n"); close_picfile(file,filetype); return FileInvalid; } /* now call read_pcx to read the pcx file */ stat = read_pcx(giftopcx, filetype, pic); pic->pic_cache->subtype = T_PIC_GIF; /* remove temp file */ unlink(pcxname); /* now match original transparent colortable index with possibly new colortable from ppmtopcx */ if (pic->pic_cache->transp != TRANSP_NONE) { if (useGlobalColormap) { red = GifScreen.ColorMap[pic->pic_cache->transp].red; green = GifScreen.ColorMap[pic->pic_cache->transp].green; blue = GifScreen.ColorMap[pic->pic_cache->transp].blue; } else { red = localColorMap[pic->pic_cache->transp].red; green = localColorMap[pic->pic_cache->transp].green; blue = localColorMap[pic->pic_cache->transp].blue; } for (i=0; ipic_cache->numcols; i++) { if (pic->pic_cache->cmap[i].red == red && pic->pic_cache->cmap[i].green == green && pic->pic_cache->cmap[i].blue == blue) break; } if (i < pic->pic_cache->numcols) pic->pic_cache->transp = i; } return stat; } static Boolean ReadColorMap(fd,number,cmap) FILE *fd; unsigned int number; struct Cmap cmap[MAX_COLORMAP_SIZE]; { int i; unsigned char rgb[3]; for (i = 0; i < number; ++i) { if (! ReadOK(fd, rgb, sizeof(rgb))) { file_msg("bad GIF colormap" ); return False; } cmap[i].red = rgb[0]; cmap[i].green = rgb[1]; cmap[i].blue = rgb[2]; } return True; } static Boolean DoGIFextension(fd, label) FILE *fd; int label; { static unsigned char buf[256]; char *str; switch (label) { case 0x01: /* Plain Text Extension */ str = "Plain Text Extension"; break; case 0xff: /* Application Extension */ str = "Application Extension"; break; case 0xfe: /* Comment Extension */ str = "Comment Extension"; while (GetDataBlock(fd, buf) != 0) { ; /* GIF comment */ } return False; case 0xf9: /* Graphic Control Extension */ str = "Graphic Control Extension"; (void) GetDataBlock(fd, (unsigned char*) buf); Gif89.disposal = (buf[0] >> 2) & 0x7; Gif89.inputFlag = (buf[0] >> 1) & 0x1; Gif89.delayTime = LM_to_uint(buf[1],buf[2]); if ((buf[0] & 0x1) != 0) Gif89.transparent = buf[3]; while (GetDataBlock(fd, buf) != 0) ; return False; default: str = (char *) buf; sprintf(str, "UNKNOWN (0x%02x)", label); break; } if (appres.DEBUG) fprintf(stderr,"got a '%s' extension\n", str ); while (GetDataBlock(fd, buf) != 0) ; return False; } int ZeroDataBlock = False; static int GetDataBlock(fd, buf) FILE *fd; unsigned char *buf; { unsigned char count; /* error in getting DataBlock size */ if (! ReadOK(fd,&count,1)) { return -1; } ZeroDataBlock = count == 0; /* error in reading DataBlock */ if ((count != 0) && (! ReadOK(fd, buf, count))) { return -1; } return count; }