📄 tkimggif.c
字号:
/* * tkImgGIF.c -- * * A photo image file handler for GIF files. Reads 87a and 89a GIF * files. At present there is no write function. GIF images may be * read using the -data option of the photo image by representing * the data as BASE64 encoded ascii. Derived from the giftoppm code * found in the pbmplus package and tkImgFmtPPM.c in the tk4.0b2 * distribution. * * Copyright (c) Reed Wade (wade@cs.utk.edu), University of Tennessee * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * This file also contains code from the giftoppm program, which is * copyrighted as follows: * * +-------------------------------------------------------------------+ * | 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. | * +-------------------------------------------------------------------+ * * SCCS: @(#) tkImgGIF.c 1.19 97/08/13 15:23:45 *//* * GIF's are represented as data in base64 format. * base64 strings consist of 4 6-bit characters -> 3 8 bit bytes. * A-Z, a-z, 0-9, + and / represent the 64 values (in order). * '=' is a trailing padding char when the un-encoded data is not a * multiple of 3 bytes. We'll ignore white space when encountered. * Any other invalid character is treated as an EOF */#define GIF_SPECIAL (256)#define GIF_PAD (GIF_SPECIAL+1)#define GIF_SPACE (GIF_SPECIAL+2)#define GIF_BAD (GIF_SPECIAL+3)#define GIF_DONE (GIF_SPECIAL+4)/* * structure to "mimic" FILE for Mread, so we can look like fread. * The decoder state keeps track of which byte we are about to read, * or EOF. */typedef struct mFile { unsigned char *data; /* mmencoded source string */ int c; /* bits left over from previous character */ int state; /* decoder state (0-4 or GIF_DONE) */} MFile;#include "tkInt.h"#include "tkPort.h"/* * The format record for the GIF file format: */static int FileMatchGIF _ANSI_ARGS_((Tcl_Channel chan, char *fileName, char *formatString, int *widthPtr, int *heightPtr));static int FileReadGIF _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Channel chan, char *fileName, char *formatString, Tk_PhotoHandle imageHandle, int destX, int destY, int width, int height, int srcX, int srcY));static int StringMatchGIF _ANSI_ARGS_(( char *string, char *formatString, int *widthPtr, int *heightPtr));static int StringReadGIF _ANSI_ARGS_((Tcl_Interp *interp, char *string, char *formatString, Tk_PhotoHandle imageHandle, int destX, int destY, int width, int height, int srcX, int srcY));Tk_PhotoImageFormat tkImgFmtGIF = { "GIF", /* name */ FileMatchGIF, /* fileMatchProc */ StringMatchGIF, /* stringMatchProc */ FileReadGIF, /* fileReadProc */ StringReadGIF, /* stringReadProc */ NULL, /* fileWriteProc */ NULL, /* stringWriteProc */};#define INTERLACE 0x40#define LOCALCOLORMAP 0x80#define BitSet(byte, bit) (((byte) & (bit)) == (bit))#define MAXCOLORMAPSIZE 256#define CM_RED 0#define CM_GREEN 1#define CM_BLUE 2#define CM_ALPHA 3#define MAX_LWZ_BITS 12#define LM_to_uint(a,b) (((b)<<8)|(a))#define ReadOK(file,buffer,len) (Fread(buffer, len, 1, file) != 0)/* * HACK ALERT!! HACK ALERT!! HACK ALERT!! * This code is hard-wired for reading from files. In order to read * from a data stream, we'll trick fread so we can reuse the same code */ static int fromData=0;/* * Prototypes for local procedures defined in this file: */static int DoExtension _ANSI_ARGS_((Tcl_Channel chan, int label, int *transparent));static int GetCode _ANSI_ARGS_((Tcl_Channel chan, int code_size, int flag));static int GetDataBlock _ANSI_ARGS_((Tcl_Channel chan, unsigned char *buf));static int LWZReadByte _ANSI_ARGS_((Tcl_Channel chan, int flag, int input_code_size));static int ReadColorMap _ANSI_ARGS_((Tcl_Channel chan, int number, unsigned char buffer[MAXCOLORMAPSIZE][4]));static int ReadGIFHeader _ANSI_ARGS_((Tcl_Channel chan, int *widthPtr, int *heightPtr));static int ReadImage _ANSI_ARGS_((Tcl_Interp *interp, char *imagePtr, Tcl_Channel chan, int len, int rows, unsigned char cmap[MAXCOLORMAPSIZE][4], int width, int height, int srcX, int srcY, int interlace, int transparent));/* * these are for the BASE64 image reader code only */static int Fread _ANSI_ARGS_((unsigned char *dst, size_t size, size_t count, Tcl_Channel chan));static int Mread _ANSI_ARGS_((unsigned char *dst, size_t size, size_t count, MFile *handle));static int Mgetc _ANSI_ARGS_((MFile *handle));static int char64 _ANSI_ARGS_((int c));static void mInit _ANSI_ARGS_((unsigned char *string, MFile *handle));/* *---------------------------------------------------------------------- * * FileMatchGIF -- * * This procedure is invoked by the photo image type to see if * a file contains image data in GIF format. * * Results: * The return value is 1 if the first characters in file f look * like GIF data, and 0 otherwise. * * Side effects: * The access position in f may change. * *---------------------------------------------------------------------- */static intFileMatchGIF(chan, fileName, formatString, widthPtr, heightPtr) Tcl_Channel chan; /* The image file, open for reading. */ char *fileName; /* The name of the image file. */ char *formatString; /* User-specified format string, or NULL. */ int *widthPtr, *heightPtr; /* The dimensions of the image are * returned here if the file is a valid * raw GIF file. */{ return ReadGIFHeader(chan, widthPtr, heightPtr);}/* *---------------------------------------------------------------------- * * FileReadGIF -- * * This procedure is called by the photo image type to read * GIF format data from a file and write it into a given * photo image. * * Results: * A standard TCL completion code. If TCL_ERROR is returned * then an error message is left in interp->result. * * Side effects: * The access position in file f is changed, and new data is * added to the image given by imageHandle. * *---------------------------------------------------------------------- */static intFileReadGIF(interp, chan, fileName, formatString, imageHandle, destX, destY, width, height, srcX, srcY) Tcl_Interp *interp; /* Interpreter to use for reporting errors. */ Tcl_Channel chan; /* The image file, open for reading. */ char *fileName; /* The name of the image file. */ char *formatString; /* User-specified format string, or NULL. */ Tk_PhotoHandle imageHandle; /* The photo image to write into. */ int destX, destY; /* Coordinates of top-left pixel in * photo image to be written to. */ int width, height; /* Dimensions of block of photo image to * be written to. */ int srcX, srcY; /* Coordinates of top-left pixel to be used * in image being read. */{ int fileWidth, fileHeight; int nBytes; Tk_PhotoImageBlock block; unsigned char buf[100]; int bitPixel; unsigned char colorMap[MAXCOLORMAPSIZE][4]; int transparent = -1; if (!ReadGIFHeader(chan, &fileWidth, &fileHeight)) { Tcl_AppendResult(interp, "couldn't read GIF header from file \"", fileName, "\"", NULL); return TCL_ERROR; } if ((fileWidth <= 0) || (fileHeight <= 0)) { Tcl_AppendResult(interp, "GIF image file \"", fileName, "\" has dimension(s) <= 0", (char *) NULL); return TCL_ERROR; } if (Fread(buf, 1, 3, chan) != 3) { return TCL_OK; } bitPixel = 2<<(buf[0]&0x07); if (BitSet(buf[0], LOCALCOLORMAP)) { /* Global Colormap */ if (!ReadColorMap(chan, bitPixel, colorMap)) { Tcl_AppendResult(interp, "error reading color map", (char *) NULL); return TCL_ERROR; } } if ((srcX + width) > fileWidth) { width = fileWidth - srcX; } if ((srcY + height) > fileHeight) { height = fileHeight - srcY; } if ((width <= 0) || (height <= 0) || (srcX >= fileWidth) || (srcY >= fileHeight)) { return TCL_OK; } Tk_PhotoExpand(imageHandle, destX + width, destY + height); block.width = width; block.height = height; block.pixelSize = 4; block.pitch = block.pixelSize * block.width; block.offset[0] = 0; block.offset[1] = 1; block.offset[2] = 2; nBytes = height * block.pitch; block.pixelPtr = (unsigned char *) ckalloc((unsigned) nBytes); while (1) { if (Fread(buf, 1, 1, chan) != 1) { /* * Premature end of image. We should really notify * the user, but for now just show garbage. */ break; } if (buf[0] == ';') { /* * GIF terminator. */ break; } if (buf[0] == '!') { /* * This is a GIF extension. */ if (Fread(buf, 1, 1, chan) != 1) { interp->result = "error reading extension function code in GIF image"; goto error; } if (DoExtension(chan, buf[0], &transparent) < 0) { interp->result = "error reading extension in GIF image"; goto error; } continue; } if (buf[0] != ',') { /* * Not a valid start character; ignore it. */ continue; } if (Fread(buf, 1, 9, chan) != 9) { interp->result = "couldn't read left/top/width/height in GIF image"; goto error; } bitPixel = 1<<((buf[8]&0x07)+1); if (BitSet(buf[8], LOCALCOLORMAP)) { if (!ReadColorMap(chan, bitPixel, colorMap)) { Tcl_AppendResult(interp, "error reading color map", (char *) NULL); goto error; } } if (ReadImage(interp, (char *) block.pixelPtr, chan, width, height, colorMap, fileWidth, fileHeight, srcX, srcY, BitSet(buf[8], INTERLACE), transparent) != TCL_OK) { goto error; } break; } if (transparent == -1) { Tk_PhotoPutBlock(imageHandle, &block, destX, destY, width, height); } else { int x, y, end; unsigned char *imagePtr, *rowPtr, *pixelPtr; imagePtr = rowPtr = block.pixelPtr; for (y = 0; y < height; y++) { x = 0; pixelPtr = rowPtr; while(x < width) { /* search for first non-transparent pixel */ while ((x < width) && !(pixelPtr[CM_ALPHA])) { x++; pixelPtr += 4; } end = x; /* search for first transparent pixel */ while ((end < width) && pixelPtr[CM_ALPHA]) { end++; pixelPtr += 4; } if (end > x) { block.pixelPtr = rowPtr + 4 * x; Tk_PhotoPutBlock(imageHandle, &block, destX+x, destY+y, end-x, 1); } x = end; } rowPtr += block.pitch; } block.pixelPtr = imagePtr; } ckfree((char *) block.pixelPtr); return TCL_OK; error: ckfree((char *) block.pixelPtr); return TCL_ERROR;}/* *---------------------------------------------------------------------- * * StringMatchGIF -- * * This procedure is invoked by the photo image type to see if * a string contains image data in GIF format. * * Results: * The return value is 1 if the first characters in the string * like GIF data, and 0 otherwise. * * Side effects: * the size of the image is placed in widthPre and heightPtr. * *---------------------------------------------------------------------- */static intStringMatchGIF(string, formatString, widthPtr, heightPtr) char *string; /* the string containing the image data */ char *formatString; /* the image format string */ int *widthPtr; /* where to put the string width */ int *heightPtr; /* where to put the string height */{ unsigned char header[10]; int got; MFile handle; mInit((unsigned char *) string, &handle); got = Mread(header, 10, 1, &handle); if (got != 10 || ((strncmp("GIF87a", (char *) header, 6) != 0) && (strncmp("GIF89a", (char *) header, 6) != 0))) { return 0; } *widthPtr = LM_to_uint(header[6],header[7]); *heightPtr = LM_to_uint(header[8],header[9]); return 1;}/* *---------------------------------------------------------------------- * * StringReadGif -- -- * * This procedure is called by the photo image type to read * GIF format data from a base64 encoded string, and give it to * the photo image. * * Results: * A standard TCL completion code. If TCL_ERROR is returned * then an error message is left in interp->result. * * Side effects: * new data is added to the image given by imageHandle. This * procedure calls FileReadGif by redefining the operation of * fprintf temporarily. * *---------------------------------------------------------------------- */static intStringReadGIF(interp,string,formatString,imageHandle, destX, destY, width, height, srcX, srcY) Tcl_Interp *interp; /* interpreter for reporting errors in */ char *string; /* string containing the image */ char *formatString; /* format string if any */ Tk_PhotoHandle imageHandle; /* the image to write this data into */ int destX, destY; /* The rectangular region of the */ int width, height; /* image to copy */ int srcX, srcY;{ int result; MFile handle; mInit((unsigned char *)string,&handle); fromData = 1; result = FileReadGIF(interp, (Tcl_Channel) &handle, "inline data", formatString, imageHandle, destX, destY, width, height, srcX, srcY); fromData = 0; return(result);}/* *---------------------------------------------------------------------- * * ReadGIFHeader -- * * This procedure reads the GIF header from the beginning of a * GIF file and returns the dimensions of the image. * * Results: * The return value is 1 if file "f" appears to start with * a valid GIF header, 0 otherwise. If the header is valid, * then *widthPtr and *heightPtr are modified to hold the * dimensions of the image. * * Side effects: * The access position in f advances. * *---------------------------------------------------------------------- */static intReadGIFHeader(chan, widthPtr, heightPtr) Tcl_Channel chan; /* Image file to read the header from */ int *widthPtr, *heightPtr; /* The dimensions of the image are * returned here. */{ unsigned char buf[7]; if ((Fread(buf, 1, 6, chan) != 6) || ((strncmp("GIF87a", (char *) buf, 6) != 0) && (strncmp("GIF89a", (char *) buf, 6) != 0))) { return 0; } if (Fread(buf, 1, 4, chan) != 4) { return 0; } *widthPtr = LM_to_uint(buf[0],buf[1]); *heightPtr = LM_to_uint(buf[2],buf[3]); return 1;}/* *----------------------------------------------------------------- * The code below is copied from the giftoppm program and modified * just slightly. *----------------------------------------------------------------- */static intReadColorMap(chan, number, buffer) Tcl_Channel chan; int number; unsigned char buffer[MAXCOLORMAPSIZE][4];{ int i; unsigned char rgb[3]; for (i = 0; i < number; ++i) { if (! ReadOK(chan, rgb, sizeof(rgb))) { return 0; } buffer[i][CM_RED] = rgb[0] ; buffer[i][CM_GREEN] = rgb[1] ; buffer[i][CM_BLUE] = rgb[2] ; buffer[i][CM_ALPHA] = 255 ; } return 1;}static intDoExtension(chan, label, transparent) Tcl_Channel chan; int label;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -