123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588 |
- /*
- SDL_image: An example image loading library for use with SDL
- Copyright (C) 1999, 2000, 2001 Sam Lantinga
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- Sam Lantinga
- slouken@libsdl.org
- */
- /* $Id: IMG_gif.c,v 1.1 2004/07/21 16:24:11 paigoddess Exp $ */
- /* This is a GIF image file loading framework */
- #include <stdio.h>
- #include <string.h>
- #include "SDL_image.h"
- /* See if an image is contained in a data source */
- int IMG_isGIF(SDL_RWops *src)
- {
- int is_GIF;
- char magic[6];
- is_GIF = 0;
- if ( SDL_RWread(src, magic, 6, 1) ) {
- if ( (strncmp(magic, "GIF", 3) == 0) &&
- ((memcmp(magic + 3, "87a", 3) == 0) ||
- (memcmp(magic + 3, "89a", 3) == 0)) ) {
- is_GIF = 1;
- }
- }
- return(is_GIF);
- }
- /* Code from here to end of file has been adapted from XPaint: */
- /* +-------------------------------------------------------------------+ */
- /* | Copyright 1990, 1991, 1993 David Koblas. | */
- /* | Copyright 1996 Torsten Martinsen. | */
- /* | 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. | */
- /* +-------------------------------------------------------------------+ */
- /* Adapted for use in SDL by Sam Lantinga -- 7/20/98 */
- #define USED_BY_SDL
- #include <stdio.h>
- #include <string.h>
- #ifdef USED_BY_SDL
- /* Changes to work with SDL:
- Include SDL header file
- Use SDL_Surface rather than xpaint Image structure
- Define SDL versions of RWSetMsg(), ImageNewCmap() and ImageSetCmap()
- */
- #include "SDL.h"
- #define Image SDL_Surface
- #define RWSetMsg IMG_SetError
- #define ImageNewCmap(w, h, s) SDL_AllocSurface(SDL_SWSURFACE,w,h,8,0,0,0,0)
- #define ImageSetCmap(s, i, R, G, B) do { \
- s->format->palette->colors[i].r = R; \
- s->format->palette->colors[i].g = G; \
- s->format->palette->colors[i].b = B; \
- } while (0)
- /* * * * * */
- #else
- /* Original XPaint sources */
- #include "image.h"
- #include "rwTable.h"
- #define SDL_RWops FILE
- #define SDL_RWclose fclose
- #endif /* USED_BY_SDL */
- #define MAXCOLORMAPSIZE 256
- #define TRUE 1
- #define FALSE 0
- #define CM_RED 0
- #define CM_GREEN 1
- #define CM_BLUE 2
- #define MAX_LWZ_BITS 12
- #define INTERLACE 0x40
- #define LOCALCOLORMAP 0x80
- #define BitSet(byte, bit) (((byte) & (bit)) == (bit))
- #define ReadOK(file,buffer,len) SDL_RWread(file, buffer, len, 1)
- #define LM_to_uint(a,b) (((b)<<8)|(a))
- static struct {
- unsigned int Width;
- unsigned int Height;
- unsigned char ColorMap[3][MAXCOLORMAPSIZE];
- unsigned int BitPixel;
- unsigned int ColorResolution;
- unsigned int Background;
- unsigned int AspectRatio;
- int GrayScale;
- } GifScreen;
- static struct {
- int transparent;
- int delayTime;
- int inputFlag;
- int disposal;
- } Gif89;
- static int ReadColorMap(SDL_RWops * src, int number,
- unsigned char buffer[3][MAXCOLORMAPSIZE], int *flag);
- static int DoExtension(SDL_RWops * src, int label);
- static int GetDataBlock(SDL_RWops * src, unsigned char *buf);
- static int GetCode(SDL_RWops * src, int code_size, int flag);
- static int LWZReadByte(SDL_RWops * src, int flag, int input_code_size);
- static Image *ReadImage(SDL_RWops * src, int len, int height, int,
- unsigned char cmap[3][MAXCOLORMAPSIZE],
- int gray, int interlace, int ignore);
- Image *
- IMG_LoadGIF_RW(SDL_RWops *src)
- {
- unsigned char buf[16];
- unsigned char c;
- unsigned char localColorMap[3][MAXCOLORMAPSIZE];
- int grayScale;
- int useGlobalColormap;
- int bitPixel;
- int imageCount = 0;
- char version[4];
- int imageNumber = 1;
- Image *image = NULL;
- if ( src == NULL ) {
- goto done;
- }
- if (!ReadOK(src, buf, 6)) {
- RWSetMsg("error reading magic number");
- goto done;
- }
- if (strncmp((char *) buf, "GIF", 3) != 0) {
- RWSetMsg("not a GIF file");
- goto done;
- }
- strncpy(version, (char *) buf + 3, 3);
- version[3] = '\0';
- if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) {
- RWSetMsg("bad version number, not '87a' or '89a'");
- goto done;
- }
- Gif89.transparent = -1;
- Gif89.delayTime = -1;
- Gif89.inputFlag = -1;
- Gif89.disposal = 0;
- if (!ReadOK(src, buf, 7)) {
- RWSetMsg("failed to read screen descriptor");
- goto done;
- }
- 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 = (((buf[4] & 0x70) >> 3) + 1);
- GifScreen.Background = buf[5];
- GifScreen.AspectRatio = buf[6];
- if (BitSet(buf[4], LOCALCOLORMAP)) { /* Global Colormap */
- if (ReadColorMap(src, GifScreen.BitPixel, GifScreen.ColorMap,
- &GifScreen.GrayScale)) {
- RWSetMsg("error reading global colormap");
- goto done;
- }
- }
- do {
- if (!ReadOK(src, &c, 1)) {
- RWSetMsg("EOF / read error on image data");
- goto done;
- }
- if (c == ';') { /* GIF terminator */
- if (imageCount < imageNumber) {
- RWSetMsg("only %d image%s found in file",
- imageCount, imageCount > 1 ? "s" : "");
- goto done;
- }
- }
- if (c == '!') { /* Extension */
- if (!ReadOK(src, &c, 1)) {
- RWSetMsg("EOF / read error on extention function code");
- goto done;
- }
- DoExtension(src, c);
- continue;
- }
- if (c != ',') { /* Not a valid start character */
- continue;
- }
- ++imageCount;
- if (!ReadOK(src, buf, 9)) {
- RWSetMsg("couldn't read left/top/width/height");
- goto done;
- }
- useGlobalColormap = !BitSet(buf[8], LOCALCOLORMAP);
- bitPixel = 1 << ((buf[8] & 0x07) + 1);
- if (!useGlobalColormap) {
- if (ReadColorMap(src, bitPixel, localColorMap, &grayScale)) {
- RWSetMsg("error reading local colormap");
- goto done;
- }
- image = ReadImage(src, LM_to_uint(buf[4], buf[5]),
- LM_to_uint(buf[6], buf[7]),
- bitPixel, localColorMap, grayScale,
- BitSet(buf[8], INTERLACE),
- imageCount != imageNumber);
- } else {
- image = ReadImage(src, LM_to_uint(buf[4], buf[5]),
- LM_to_uint(buf[6], buf[7]),
- GifScreen.BitPixel, GifScreen.ColorMap,
- GifScreen.GrayScale, BitSet(buf[8], INTERLACE),
- imageCount != imageNumber);
- }
- } while (image == NULL);
- #ifdef USED_BY_SDL
- if ( Gif89.transparent >= 0 ) {
- SDL_SetColorKey(image, SDL_SRCCOLORKEY, Gif89.transparent);
- }
- #endif
- done:
- return image;
- }
- static int
- ReadColorMap(SDL_RWops *src, int number,
- unsigned char buffer[3][MAXCOLORMAPSIZE], int *gray)
- {
- int i;
- unsigned char rgb[3];
- int flag;
- flag = TRUE;
- for (i = 0; i < number; ++i) {
- if (!ReadOK(src, rgb, sizeof(rgb))) {
- RWSetMsg("bad colormap");
- return 1;
- }
- buffer[CM_RED][i] = rgb[0];
- buffer[CM_GREEN][i] = rgb[1];
- buffer[CM_BLUE][i] = rgb[2];
- flag &= (rgb[0] == rgb[1] && rgb[1] == rgb[2]);
- }
- #if 0
- if (flag)
- *gray = (number == 2) ? PBM_TYPE : PGM_TYPE;
- else
- *gray = PPM_TYPE;
- #else
- *gray = 0;
- #endif
- return FALSE;
- }
- static int
- DoExtension(SDL_RWops *src, 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(src, (unsigned char *) buf) != 0);
- return FALSE;
- case 0xf9: /* Graphic Control Extension */
- str = "Graphic Control Extension";
- (void) GetDataBlock(src, (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(src, (unsigned char *) buf) != 0);
- return FALSE;
- default:
- str = (char *)buf;
- sprintf(str, "UNKNOWN (0x%02x)", label);
- break;
- }
- while (GetDataBlock(src, (unsigned char *) buf) != 0);
- return FALSE;
- }
- static int ZeroDataBlock = FALSE;
- static int
- GetDataBlock(SDL_RWops *src, unsigned char *buf)
- {
- unsigned char count;
- if (!ReadOK(src, &count, 1)) {
- /* pm_message("error in getting DataBlock size" ); */
- return -1;
- }
- ZeroDataBlock = count == 0;
- if ((count != 0) && (!ReadOK(src, buf, count))) {
- /* pm_message("error in reading DataBlock" ); */
- return -1;
- }
- return count;
- }
- static int
- GetCode(SDL_RWops *src, int code_size, int flag)
- {
- static unsigned char buf[280];
- static int curbit, lastbit, done, last_byte;
- int i, j, ret;
- unsigned char count;
- if (flag) {
- curbit = 0;
- lastbit = 0;
- done = FALSE;
- return 0;
- }
- if ((curbit + code_size) >= lastbit) {
- if (done) {
- if (curbit >= lastbit)
- RWSetMsg("ran off the end of my bits");
- return -1;
- }
- buf[0] = buf[last_byte - 2];
- buf[1] = buf[last_byte - 1];
- if ((count = GetDataBlock(src, &buf[2])) == 0)
- done = TRUE;
- last_byte = 2 + count;
- curbit = (curbit - lastbit) + 16;
- lastbit = (2 + count) * 8;
- }
- ret = 0;
- for (i = curbit, j = 0; j < code_size; ++i, ++j)
- ret |= ((buf[i / 8] & (1 << (i % 8))) != 0) << j;
- curbit += code_size;
- return ret;
- }
- static int
- LWZReadByte(SDL_RWops *src, int flag, int input_code_size)
- {
- static int fresh = FALSE;
- int code, incode;
- static int code_size, set_code_size;
- static int max_code, max_code_size;
- static int firstcode, oldcode;
- static int clear_code, end_code;
- static int table[2][(1 << MAX_LWZ_BITS)];
- static int stack[(1 << (MAX_LWZ_BITS)) * 2], *sp;
- register int i;
- if (flag) {
- set_code_size = input_code_size;
- code_size = set_code_size + 1;
- clear_code = 1 << set_code_size;
- end_code = clear_code + 1;
- max_code_size = 2 * clear_code;
- max_code = clear_code + 2;
- GetCode(src, 0, TRUE);
- fresh = TRUE;
- for (i = 0; i < clear_code; ++i) {
- table[0][i] = 0;
- table[1][i] = i;
- }
- for (; i < (1 << MAX_LWZ_BITS); ++i)
- table[0][i] = table[1][0] = 0;
- sp = stack;
- return 0;
- } else if (fresh) {
- fresh = FALSE;
- do {
- firstcode = oldcode = GetCode(src, code_size, FALSE);
- } while (firstcode == clear_code);
- return firstcode;
- }
- if (sp > stack)
- return *--sp;
- while ((code = GetCode(src, code_size, FALSE)) >= 0) {
- if (code == clear_code) {
- for (i = 0; i < clear_code; ++i) {
- table[0][i] = 0;
- table[1][i] = i;
- }
- for (; i < (1 << MAX_LWZ_BITS); ++i)
- table[0][i] = table[1][i] = 0;
- code_size = set_code_size + 1;
- max_code_size = 2 * clear_code;
- max_code = clear_code + 2;
- sp = stack;
- firstcode = oldcode = GetCode(src, code_size, FALSE);
- return firstcode;
- } else if (code == end_code) {
- int count;
- unsigned char buf[260];
- if (ZeroDataBlock)
- return -2;
- while ((count = GetDataBlock(src, buf)) > 0);
- if (count != 0) {
- /*
- * pm_message("missing EOD in data stream (common occurence)");
- */
- }
- return -2;
- }
- incode = code;
- if (code >= max_code) {
- *sp++ = firstcode;
- code = oldcode;
- }
- while (code >= clear_code) {
- *sp++ = table[1][code];
- if (code == table[0][code])
- RWSetMsg("circular table entry BIG ERROR");
- code = table[0][code];
- }
- *sp++ = firstcode = table[1][code];
- if ((code = max_code) < (1 << MAX_LWZ_BITS)) {
- table[0][code] = oldcode;
- table[1][code] = firstcode;
- ++max_code;
- if ((max_code >= max_code_size) &&
- (max_code_size < (1 << MAX_LWZ_BITS))) {
- max_code_size *= 2;
- ++code_size;
- }
- }
- oldcode = incode;
- if (sp > stack)
- return *--sp;
- }
- return code;
- }
- static Image *
- ReadImage(SDL_RWops * src, int len, int height, int cmapSize,
- unsigned char cmap[3][MAXCOLORMAPSIZE],
- int gray, int interlace, int ignore)
- {
- Image *image;
- unsigned char c;
- int i, v;
- int xpos = 0, ypos = 0, pass = 0;
- /*
- ** Initialize the compression routines
- */
- if (!ReadOK(src, &c, 1)) {
- RWSetMsg("EOF / read error on image data");
- return NULL;
- }
- if (LWZReadByte(src, TRUE, c) < 0) {
- RWSetMsg("error reading image");
- return NULL;
- }
- /*
- ** If this is an "uninteresting picture" ignore it.
- */
- if (ignore) {
- while (LWZReadByte(src, FALSE, c) >= 0);
- return NULL;
- }
- image = ImageNewCmap(len, height, cmapSize);
- for (i = 0; i < cmapSize; i++)
- ImageSetCmap(image, i, cmap[CM_RED][i],
- cmap[CM_GREEN][i], cmap[CM_BLUE][i]);
- while ((v = LWZReadByte(src, FALSE, c)) >= 0) {
- #ifdef USED_BY_SDL
- ((Uint8 *)image->pixels)[xpos + ypos * image->pitch] = v;
- #else
- image->data[xpos + ypos * len] = v;
- #endif
- ++xpos;
- if (xpos == len) {
- xpos = 0;
- if (interlace) {
- switch (pass) {
- case 0:
- case 1:
- ypos += 8;
- break;
- case 2:
- ypos += 4;
- break;
- case 3:
- ypos += 2;
- break;
- }
- if (ypos >= height) {
- ++pass;
- switch (pass) {
- case 1:
- ypos = 4;
- break;
- case 2:
- ypos = 2;
- break;
- case 3:
- ypos = 1;
- break;
- default:
- goto fini;
- }
- }
- } else {
- ++ypos;
- }
- }
- if (ypos >= height)
- break;
- }
- fini:
- return image;
- }
|