Image * IMG_LoadGIF_RW(SDL_RWops *src) { Sint64 start; 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 ) { return NULL; } start = SDL_RWtell(src); if (!ReadOK(src, buf, 6)) { RWSetMsg("error reading magic number"); goto done; } if (SDL_strncmp((char *) buf, "GIF", 3) != 0) { RWSetMsg("not a GIF file"); goto done; } SDL_memcpy(version, (char *) buf + 3, 3); version[3] = '\0'; if ((SDL_strcmp(version, "87a") != 0) && (SDL_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_TRUE, Gif89.transparent); } #endif done: if ( image == NULL ) { SDL_RWseek(src, start, RW_SEEK_SET); } return image; }
/* TODO: (Chase) dump frames into frameset instead of combining into one frame */ int IMG_LoadGIF_RW(SDL_RWops *src, IMG_File* dst) { int start; 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; /*<-- I believe this is what we want to control in order to change what frame to grab*/ int successCount = 0; int w = 0; int i = 0; Uint32 color = 0; SDL_Surface*image = NULL; SDL_Surface*nextImage = NULL; GifFrame frame; GifFrame* frames; if ( src == NULL ) { return 0; } start = SDL_RWtell(src); if (!ReadOK(src, buf, 6)) { IMG_SetError("error reading magic number"); goto done; } if (strncmp((char *) buf, "GIF", 3) != 0) { IMG_SetError("not a GIF file"); goto done; } strncpy(version, (char *) buf + 3, 3); version[3] = '\0'; if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) { IMG_SetError("bad version number, not '87a' or '89a'"); goto done; } frame.transparent = -1; frame.delayMs = -1; frame.inputFlag = -1; frame.disposal = 0; if (!ReadOK(src, buf, 7)) { IMG_SetError("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)) { IMG_SetError("error reading global colormap"); goto done; } } dbgout("GLOBAL BG COLOR: Index:%i RGB:%i,%i,%i\n", GifScreen.Background, GifScreen.ColorMap[CM_RED][GifScreen.Background], GifScreen.ColorMap[CM_GREEN][GifScreen.Background], GifScreen.ColorMap[CM_BLUE][GifScreen.Background]); frames = (GifFrame*)malloc(sizeof(GifFrame)); if (!frames) { IMG_SetError("Malloc Failed"); goto done; } do { /* This loop goes through and reads every image and sends its data to ReadImage, if its the one we want (index 1) it'll output SDL_Surface*/ /* What this SHOULD do... METHOD 1 (Lazy): Read every image, output an SDL_Surface into a vector After loop, count vector images, make a new image which has a w equal to the vector.size() * image width Render each image from the vector onto the new image, each one with an x offset of image width * index Free all surfaces in the vector, return the new combined one. METHOD 2 (hardcore): Read every image, count the number of images we get. Create a surface with a w equal to count * width Go back and read every images data, writing their pixels, leftmost to images x * index GENERAL PROBLEM: We have no delay info. We'd have to manually set the frame delay... However, this isn't a problem. =3 Looks like we can have local layer color maps.. of course being able to do this in imageready is a whole other issue. But as far as we know.. maybe? */ if (!ReadOK(src, &c, 1)) { IMG_SetError("EOF / read error on image data"); goto done; } else dbgout("%c", c); if (c == ';') { /* GIF terminator -0x3b */ /*if (imageCount < imageNumber) { IMG_SetError("only %d image%s found in file", imageCount, imageCount > 1 ? "s" : ""); goto done; }*/ break; } if (c == '!') { /* Extension 0x21 */ if (!ReadOK(src, &c, 1)) { IMG_SetError("EOF / read error on extention function code"); goto done; } DoExtension(&frame, src, c); continue; } if (c != ',') { /* Image seperator - 0x2c */ continue; } ++imageCount; if (!ReadOK(src, buf, 9)) { IMG_SetError("couldn't read left/top/width/height"); goto done; } /* Offset Length Contents 0 1 byte Image Separator (0x2c) 1 2 bytes Image Left Position 3 2 bytes Image Top Position 5 2 bytes Image Width 7 2 bytes Image Height 8 1 byte bit 0: Local Color Table Flag (LCTF) bit 1: Interlace Flag bit 2: Sort Flag bit 2..3: Reserved bit 4..7: Size of Local Color Table: 2^(1+n) ? bytes Local Color Table(0..255 x 3 bytes) if LCTF is one 1 byte LZW Minimum Code Size [ // Blocks 1 byte Block Size (s) œSx (s)bytes Image Data ]* 1 byte Block Terminator(0x00) */ useGlobalColormap = !BitSet(buf[8], LOCALCOLORMAP); frame.x = LM_to_uint(buf[0], buf[1]); frame.y = LM_to_uint(buf[2], buf[3]); dbgout("X:%i, Y:%i\n", frame.x, frame.y); bitPixel = 1 << ((buf[8] & 0x07) + 1); dbgout("Checkpoint\n"); if (!useGlobalColormap) { if (ReadColorMap(src, bitPixel, localColorMap, &grayScale)) { IMG_SetError("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), 0); if (image) color = SDL_MapRGB(image->format, localColorMap[CM_RED][frame.transparent], localColorMap[CM_GREEN][frame.transparent], localColorMap[CM_BLUE][frame.transparent]); } 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), 0); if (image) color = SDL_MapRGB(image->format, GifScreen.ColorMap[CM_RED][frame.transparent], GifScreen.ColorMap[CM_GREEN][frame.transparent], GifScreen.ColorMap[CM_BLUE][frame.transparent]); } dbgout("Image: %p\n", image); if (image) { ++successCount; /*image = convertTo32bit(image); */ /* transform to a 32 bit surface because I HATE palettes*/ dbgout("Converted Image: %ix%i [%p]\n", image->w, image->h, image); if (image) { if ( frame.transparent >= 0 ) { SDL_SetColorKey(image, SDL_SRCCOLORKEY, frame.transparent); } /*if ( frame.transparent >= 0 ) { SDL_SetColorKey(image, SDL_SRCCOLORKEY, color); Uint8 r, g, b; SDL_GetRGB(color, image->format, &r, &g, &b); dbgout("Local Transparency: %i,%i,%i\n", r, g, b); }*/ /*Reallocate room for another image in the list*/ frames = (GifFrame*)realloc(frames, successCount * sizeof(GifFrame)); if (!frames) { /*realloc failed*/ IMG_SetError("Realloc Failed"); goto done; } frame.surf = image; /* Copy the current state of the GifFrame before the next read loop */ frames[successCount-1] = frame; /*int i = 0; while (i < successCount) { dbgout("Frames[%i]: %p\n", i, frames[i]); i++; }*/ image = NULL; } } } while (1); /*let the above ... goto's... handle it*/ SDL_Frame* framesArray; if (successCount > 0) { dbgout("Mallocing Frames %i\n", successCount);fflush(stdout); framesArray = IMG_MallocFrames(successCount); i = 0; //first frame image = SDL_CreateRGBSurface(SDL_SWSURFACE, GifScreen.Width, GifScreen.Height, 32, RMASK, GMASK, BMASK, 0); color = SDL_MapRGB(image->format, GifScreen.ColorMap[CM_RED][frames[0].transparent], GifScreen.ColorMap[CM_GREEN][frames[0].transparent], GifScreen.ColorMap[CM_BLUE][frames[0].transparent]); Uint8 r, g, b; SDL_GetRGB(color, image->format, &r, &g, &b); dbgout("Final Transparency: %i,%i,%i\n", r, g, b);fflush(stdout); if (color != 0) /* Ignore 0,0,0 as the transparent color */ { SDL_FillRect(image, NULL, color); SDL_SetColorKey(image, SDL_SRCCOLORKEY, color); /* use the first frames trans color */ } while (i < successCount) /* render our surfs and clear */ { if (image) { dbgout("Dimensions: %ix%i: %p\n", image->w, image->h, image);fflush(stdout); w = 0; SDL_Rect r2, r3; dbgout("Adding Frames[%i]: %p Disposal:%i TransIndex: %i Delay: %i Input:%i\n", i, frames[i].surf, frames[i].disposal, frames[i].transparent, frames[i].delayMs, frames[i].inputFlag); fflush(stdout); /* Print out the overlay at its offset coordinates */ r2.x = frames[i].x; r2.y = frames[i].y; r2.w = frames[i].surf->w; r2.h = frames[i].surf->h; dbgout("Drawing at: %i,%i\n", r2.x, r2.y);fflush(stdout); if (SDL_BlitSurface(frames[i].surf, NULL, image, &r2)) { /*something bad happened but ignore it for now. */ dbgout("Drawing Failed: %s\n", IMG_GetError());fflush(stdout); } dbgout("Setting Crap\n");fflush(stdout); //add image to our frames list framesArray[i].surf = image; framesArray[i].delay = frames[i].delayMs * 10; //HACK: All observed gifs have a delay of say.. 7, which means 70ms. framesArray[i].key = NULL; dbgout("i+1 crap\n");fflush(stdout); /*what to do in frame[i+1] before rendering*/ if (i + 1 < successCount) { //create next frame so we can do something to it nextImage = SDL_CreateRGBSurface(SDL_SWSURFACE, GifScreen.Width, GifScreen.Height, 32, RMASK, GMASK, BMASK, 0); color = SDL_MapRGB(nextImage->format, GifScreen.ColorMap[CM_RED][frames[0].transparent], GifScreen.ColorMap[CM_GREEN][frames[0].transparent], GifScreen.ColorMap[CM_BLUE][frames[0].transparent]); Uint8 r, g, b; SDL_GetRGB(color, nextImage->format, &r, &g, &b); dbgout("Final Transparency: %i,%i,%i\n", r, g, b);fflush(stdout); if (color != 0) /* Ignore 0,0,0 as the transparent color */ { SDL_FillRect(nextImage, NULL, color); SDL_SetColorKey(nextImage, SDL_SRCCOLORKEY, color); /* use the first frames trans color */ } dbgout("Disposal crap\n");fflush(stdout); switch (frames[i].disposal) { case DISPOSAL_PREVIOUSFRAME: /* 04h - Overwrite graphic with previous graphic */ dbgout("Doing previous frame\n");fflush(stdout); r2.x = 0; r2.y = 0; r2.w = GifScreen.Width; r2.h = GifScreen.Height; SDL_BlitSurface(frames[0].surf, NULL, nextImage, &r2); //Since I'm lazy, and haven't seen many gifs use this, it'll just render the original frame break; case DISPOSAL_UNSPECIFIED: /* DISPOSAL_UNSPECIFIED 00h - Let the viewer decide */ /*Drop down to donotdispose */ case DISPOSAL_DONOTDISPOSE: /* 01h - Leave graphic there */ dbgout("Doing nondispose\n");fflush(stdout); /*render a copy of the previous i-1 into i */ r2.w = GifScreen.Width; r2.h = GifScreen.Height; r2.x = 0; r2.y = 0; /* r3 = src, r2 = dst */ r3.w = GifScreen.Width; r3.h = GifScreen.Height; r3.x = 0; r3.y = 0; dbgout("r3:(%i,%i)%ix%i r2:(%i,%i)%ix%i\n", r3.x, r3.y, r3.w, r3.h, r2.x, r2.y, r2.w, r2.h);fflush(stdout); if (SDL_BlitSurface(image, &r3, nextImage, &r2)) { dbgout("Drawing Failed: %s\n", IMG_GetError());fflush(stdout); } break; default: /* This'll default to DISPOSAL_BGCOLORWIPE 02h - Overwrite graphic with background color do nothing, next rect is empty already*/ dbgout("Doing default %i\n", frames[i].disposal);fflush(stdout); break; } image = nextImage; } } i++; } i = 0; while (i < successCount) { SDL_FreeSurface(frames[i].surf); i++; } free(frames); frames = NULL; } else { image = NULL; } done: if (frames) { /* We didn't complete successfully, handle any leaks */ i = 0; while (i < successCount) { SDL_FreeSurface(frames[i].surf); i++; } free(frames); /*if (image) { SDL_FreeSurface(image); image = NULL; }*/ } /*if ( image == NULL ) { SDL_RWseek(src, start, SEEK_SET); } */ if (successCount > 0) { dst->frames = framesArray; dst->count = successCount; dst->format = IMG_FORMAT_GIF; return 1; } return 0; //return IMG_SurfaceToFrameset(image, sdlFrames, sdlFrameCount); }
ANIMATION* CreateAnimationFromGIF89a (HDC hdc, MG_RWops* area) { unsigned char c; int ok = 0; MYBITMAP mybmp; GIFSCREEN GifScreen; IMAGEDESC ImageDesc; ANIMATION* anim; ANIMATIONFRAME* frame, *current = NULL; anim = calloc (1, sizeof (ANIMATION)); if (anim == NULL) return NULL; anim->time_unit = 1; if (ReadGIFGlobal (area, &GifScreen) < 0) goto error; anim->width = GifScreen.Width; anim->height = GifScreen.Height; if (GifScreen.Background >= 0) { anim->bk = GifScreen.ColorMap [GifScreen.Background]; anim->bk.a = 1; } else { anim->bk.r = anim->bk.g = anim->bk.b = 255; anim->bk.a = 0; } _MG_PRINTF ("EX_CTRL>GIF89a: Background: %d, %d, %d.\n", anim->bk.r, anim->bk.g, anim->bk.b); if ((ok = ReadOK (area, &c, 1)) == 0) { _MG_PRINTF ("EX_CTRL>GIF89a: EOF on image data\n"); goto error; } while (c != ';' && ok > 0) { switch (c) { case '!': if ( (ok = ReadOK (area, &c, 1)) == 0) { _MG_PRINTF ("EX_CTRL>GIF89a: EOF on image data\n"); goto error; } DoExtension (area, c, &GifScreen); _MG_PRINTF ("EX_CTRL>GIF89a: Extension info: %d, %d, %d, %d, %d, %d\n", GifScreen.Width, GifScreen.Height, GifScreen.AspectRatio, GifScreen.delayTime, GifScreen.disposal, GifScreen.transparent); break; case ',': if (ReadImageDesc (area, &ImageDesc, &GifScreen) < 0) { goto error; } else { if (ReadImage (area, &mybmp, &ImageDesc, &GifScreen, 0) < 0) goto error; } _MG_PRINTF ("EX_CTRL>GIF89a: Image Descriptor: %d, %d, %d, %d, %d\n", ImageDesc.Top, ImageDesc.Left, ImageDesc.Width, ImageDesc.Height, ImageDesc.haveColorMap); frame = (ANIMATIONFRAME*) calloc (1, sizeof (ANIMATIONFRAME)); if (!frame) goto error; else { frame->next = NULL; frame->disposal = GifScreen.disposal; frame->off_y = ImageDesc.Left; frame->off_x = ImageDesc.Top; frame->width = mybmp.w; frame->height = mybmp.h; frame->delay_time = (GifScreen.delayTime>10)?GifScreen.delayTime:10; _MG_PRINTF ("EX_CTRL>GIF89a: frame info: %d, %d, %d, %d\n", frame->off_x, frame->off_y, frame->delay_time, GifScreen.transparent); if ((frame->mem_dc = CreateMemDCFromMyBitmap (&mybmp, ImageDesc.ColorMap)) == 0) { free (mybmp.bits); free (frame); _MG_PRINTF ("EX_CTRL>GIF89a: Error when expand frame bitmap.\n"); goto error; } frame->bits = mybmp.bits; if (anim->frames == NULL) { anim->frames = frame; current = frame; current->prev = NULL; } else { frame->prev = current; current->next = frame; current = current->next; } anim->nr_frames++ ; } break; } ok = ReadOK (area, &c, 1); } return anim; error: DestroyAnimation (anim, TRUE); return NULL; }
void ReadGIFInfo(FILE *fd,int *width,int *height) { unsigned char buf[16]; unsigned char c; char version[4]; char *str; if (!ReadOK(fd,buf,6)){ strcpy(str,"error reading magic number"); pm_error(str); } if (strncmp((char*)buf,"GIF",3) != 0){ strcpy(str,"not a GIF file"); pm_error(str); } strncpy(version,(char*)buf+3,3); version[3] = '\0'; if ((strcmp(version,"87a") != 0) && (strcmp(version,"89a") != 0)){ strcpy(str,"bad version number, not '87a' or '89a'"); pm_error(str); } /*read logical screen*/ if (!ReadOK(fd,buf,7)){ strcpy(str,"failed to read screen descriptor"); pm_error(str); } 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)){ if (ReadColorMap(fd,GifScreen.BitPixel,GifScreen.ColorMap)){ strcpy(str,"error reading global color map"); pm_error(str); } } if (!ReadOK(fd,&c,1)){ strcpy(str,"EOF / read error on image data"); pm_error(str); } if (c == ';'){/*0x3B, GIF terminator*/ return; } if (c == '!'){/*0x21, Extension*/ if (!ReadOK(fd,&c,1)){ strcpy(str,"OF / read error on extension function code"); pm_error(str); } DoExtension(fd,c); } if (!ReadOK(fd,buf,8)){ strcpy(str,"couldn't read left/top/width/height"); pm_error(str); } *width = LM_to_uint(buf[4],buf[5]); *height = LM_to_uint(buf[6],buf[7]); return; }
/***** * Name: _PLC_GIF_Init * Return Type: void * Description: image initializer for GIF images * In: * plc: current PLC * Returns: * Nothing but PLC is updated. * Note: * As this routine must be fully re-entrant, it needs a lot of checks * to make sure we have the data we want fully available. * The drawback is that if we are being suspended while doing this * initialization, everything must be reset and repeated the next time * this routine is called. *****/ void _PLC_GIF_Init(PLC *plc) { Byte buf[16], c; PLCImageGIF *gif; gif = &(plc->object->plc_gif_image); _XmHTMLDebug(15, ("plc.c: _PLC_GIF_Init for %s\n", plc->url)); /* this plc is active */ plc->plc_status = PLC_ACTIVE; /***** * When this routine is called, the init method of this PLC has already * been called to determine the type of this PLC Image object. Therefore * we already have data available and we need to rewind the input buffer * back to the beginning. *****/ _PLCRewindInputBuffer(plc); /* we know this is a gif image, so skip magic */ gif->info->type = IMAGE_GIF; (void)_PLCReadOK(plc, buf, 6); /* read logical screen descriptor */ (void)_PLCReadOK(plc, buf, 7); /* image dimensions */ gif->width = LM_to_uint(buf[0],buf[1]); gif->height = LM_to_uint(buf[2],buf[3]); /* set colorspace and allocate a colormap */ gif->colorclass = XmIMAGE_COLORSPACE_INDEXED; gif->cmapsize = 2<<(buf[4]&0x07); /* * We may have been called before (but returned 'cause not enough data * was available). */ if(gif->cmap == NULL) gif->cmap = (XCOLOR*)calloc(gif->cmapsize, sizeof(XCOLOR)); /* image is initially fully opaque */ gif->transparency = XmNONE; gif->bg_pixel = -1; /* * Incoming data buffer. This is *way* too much as the incoming data * will be compressed (but it does make sure there is enough room) */ gif->buf_size = gif->width*gif->height; gif->buf_pos = 0; /* current pos in data received so far */ gif->byte_count = 0; /* size of data received so far */ if(gif->buffer == NULL) gif->buffer = (Byte*)calloc(gif->buf_size + 1, sizeof(Byte)); /* check if a global colormap is available */ if(BitSet(buf[4], LOCALCOLORMAP)) { if(!(ReadColormap(plc, gif))) { /* premature end of data. */ if(plc->plc_data_status == STREAM_END) { _XmHTMLWarning(__WFUNC__(gif->owner, "_PLC_GIF_Init"), XMHTML_MSG_106, plc->url, "global"); plc->plc_status = PLC_ABORT; } return; /* no global colormap! */ } } /* process all extensions */ c = 0; while(c != ',') { if(!_PLCReadOK(plc, &c, 1)) return; if (c == ';') /* GIF terminator */ { _XmHTMLWarning(__WFUNC__(gif->owner, "_PLC_GIF_Init"), XMHTML_MSG_107, plc->url, "pixel data"); plc->plc_status = PLC_ABORT; return; } if(c == '!') /* Extension */ { if(!_PLCReadOK(plc,&c,1)) { if(plc->plc_data_status == STREAM_END) { _XmHTMLWarning(__WFUNC__(gif->owner, "_PLC_GIF_Init"), XMHTML_MSG_107, plc->url, "extension block type"); plc->plc_status = PLC_ABORT; } return; } if(!(DoExtension(plc, c))) { if(plc->plc_data_status == STREAM_END) { _XmHTMLWarning(__WFUNC__(gif->owner, "_PLC_GIF_Init"), XMHTML_MSG_107, plc->url, "extension block"); plc->plc_status = PLC_ABORT; } return; } continue; } if (c != ',') continue; /* Not a valid start character */ } /* get image descriptor */ if(!_PLCReadOK(plc, buf, 9)) return; /* see if we are to use a local colormap */ if(BitSet(buf[8], LOCALCOLORMAP)) { /* local colormap size */ gif->ncolors = 1<<((buf[8]&0x07)+1); /* do we also have a glocal colormap? */ if(gif->cmap) free(gif->cmap); gif->cmapsize = gif->ncolors; gif->cmap = (XCOLOR*)calloc(gif->cmapsize, sizeof(XCOLOR)); if(!(ReadColormap(plc, gif))) { /* premature end of data. */ if(plc->plc_data_status == STREAM_END) { _XmHTMLWarning(__WFUNC__(gif->owner, "_PLC_GIF_Init"), XMHTML_MSG_106, plc->url, "local"); plc->plc_status = PLC_ABORT; } return; /* no global colormap! */ } } gif->ncolors = gif->cmapsize; /* sanity check: image *must* have a colormap */ if(gif->cmap == NULL) { _XmHTMLWarning(__WFUNC__(gif->owner, "_PLC_GIF_Init"), XMHTML_MSG_106, plc->url, "global or local"); plc->plc_status = PLC_ABORT; return; /* no global colormap! */ } /* image depth (= codeSize in GIF images, unused in GZF images) */ if(!(_PLCReadOK(plc, &c, 1))) return; gif->depth = (int)(c & 0xff); /* check interlacing */ if(BitSet(buf[8], INTERLACE)) { /* interlaced gifs require 4 passes and use an initial rowstride of 8 */ gif->npasses = 4; gif->stride = 8; } else { /* regular gif, 1 pass will get us the entire image */ gif->npasses = 1; gif->stride = 0; } gif->curr_pass = 0; gif->curr_scanline = 0; /***** * This routine is also used for GZF images, so before initializing * the LZWStream object we need to make sure we have been called for * a true GIF image. *****/ if(plc->object->type == plcGIF) { XmHTMLWidget html = plc->object->plc_any.owner; if(HTML_ATTR(gif_proc) != NULL) { gif->external_codec = True; gif->inflate = HTML_ATTR(gif_proc); if((gif->gstream = (XmHTMLGIFStream*)malloc(sizeof(XmHTMLGIFStream))) == NULL) { /* out of memory, too bad then */ _XmHTMLWarning(__WFUNC__(gif->owner, "_PLC_GIF_Init"), XMHTML_MSG_113, plc->url, sizeof(XmHTMLGIFStream)); plc->plc_status = PLC_ABORT; return; } /* initialize GIFStream object */ memset(gif->gstream, 0, sizeof(XmHTMLGIFStream)); gif->gstream->codesize = (int)c; gif->gstream->state = GIF_STREAM_INIT; gif->gstream->next_out = gif->buffer; gif->gstream->avail_out = gif->buf_size + 1; gif->gstream->is_progressive = True; /* * and call external decoder so it can initialize its own data * structures */ if((gif->inflate(gif->gstream)) != GIF_STREAM_OK) { if(gif->gstream->msg != NULL) { _XmHTMLWarning(__WFUNC__(gif->owner, "_PLC_GIF_Init"), XMHTML_MSG_109, plc->url, gif->gstream->msg ? gif->gstream->msg : "(unknown error)"); } /* external decoder initalization failed, abort and return */ plc->plc_status = PLC_ABORT; return; } gif->gstream->state = GIF_STREAM_OK; } else { /* initialize local data buffer */ gif->ib.file = plc->url; gif->ib.buffer = gif->buffer; gif->ib.size = 0; gif->ib.next = 0; gif->ib.type = IMAGE_GIF; gif->ib.depth = gif->depth; gif->ib.may_free = False; /* initialize LZWStream object */ if(gif->lstream == NULL) { if((gif->lstream = LZWStreamCreate(&(gif->ib), html->html.zCmd)) == NULL) { /* couldn't create stream, abort and return */ plc->plc_status = PLC_ABORT; return; } /* set read functions */ gif->lstream->readOK = _XmHTMLGifReadOK; gif->lstream->getData = _XmHTMLGifGetDataBlock; } /* first byte in buffer is gif codesize */ gif->ib.buffer[0] = c; gif->ib.size = 1; } /* allocate room for final image data */ if(gif->data == NULL) { gif->data = (Byte*)calloc(gif->buf_size + 1, sizeof(Byte)); /* don't allocate clipmask yet, it's done in the plc code */ } gif->data_size = gif->buf_size; gif->data_pos = 0; } /* object has been initialized */ plc->initialized = True; plc->curr_obj_func = 0; /* move to GIF scanline reader */ return; }
static gint32 load_image (const gchar *filename, gboolean thumbnail, GError **error) { FILE *fd; guchar buf[16]; guchar c; CMap localColorMap; gint grayScale; gboolean useGlobalColormap; gint bitPixel; gint imageCount = 0; gchar version[4]; gint32 image_ID = -1; fd = g_fopen (filename, "rb"); if (! fd) { g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno), _("Could not open '%s' for reading: %s"), gimp_filename_to_utf8 (filename), g_strerror (errno)); return -1; } gimp_progress_init_printf (_("Opening '%s'"), gimp_filename_to_utf8 (filename)); if (! ReadOK (fd, buf, 6)) { g_message ("Error reading magic number"); return -1; } if (strncmp ((gchar *) buf, "GIF", 3) != 0) { g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "%s", _("This is not a GIF file")); return -1; } strncpy (version, (gchar *) buf + 3, 3); version[3] = '\0'; if ((strcmp (version, "87a") != 0) && (strcmp (version, "89a") != 0)) { g_message ("Bad version number, not '87a' or '89a'"); return -1; } if (! ReadOK (fd, buf, 7)) { g_message ("Failed to read screen descriptor"); return -1; } 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 (fd, GifScreen.BitPixel, GifScreen.ColorMap, &GifScreen.GrayScale)) { g_message ("Error reading global colormap"); return -1; } } if (GifScreen.AspectRatio != 0 && GifScreen.AspectRatio != 49) { g_message (_("Non-square pixels. Image might look squashed.")); } highest_used_index = 0; while (TRUE) { if (! ReadOK (fd, &c, 1)) { g_message ("EOF / read error on image data"); return image_ID; /* will be -1 if failed on first image! */ } if (c == ';') { /* GIF terminator */ return image_ID; } if (c == '!') { /* Extension */ if (! ReadOK (fd, &c, 1)) { g_message ("EOF / read error on extension function code"); return image_ID; /* will be -1 if failed on first image! */ } DoExtension (fd, c); continue; } if (c != ',') { /* Not a valid start character */ g_printerr ("GIF: bogus character 0x%02x, ignoring.\n", (int) c); continue; } ++imageCount; if (! ReadOK (fd, buf, 9)) { g_message ("Couldn't read left/top/width/height"); return image_ID; /* will be -1 if failed on first image! */ } useGlobalColormap = !BitSet (buf[8], LOCALCOLORMAP); bitPixel = 1 << ((buf[8] & 0x07) + 1); if (! useGlobalColormap) { if (! ReadColorMap (fd, bitPixel, localColorMap, &grayScale)) { g_message ("Error reading local colormap"); return image_ID; /* will be -1 if failed on first image! */ } image_ID = ReadImage (fd, filename, LM_to_uint (buf[4], buf[5]), LM_to_uint (buf[6], buf[7]), localColorMap, bitPixel, grayScale, BitSet (buf[8], INTERLACE), imageCount, (guint) LM_to_uint (buf[0], buf[1]), (guint) LM_to_uint (buf[2], buf[3]), GifScreen.Width, GifScreen.Height); } else { image_ID = ReadImage (fd, filename, LM_to_uint (buf[4], buf[5]), LM_to_uint (buf[6], buf[7]), GifScreen.ColorMap, GifScreen.BitPixel, GifScreen.GrayScale, BitSet (buf[8], INTERLACE), imageCount, (guint) LM_to_uint (buf[0], buf[1]), (guint) LM_to_uint (buf[2], buf[3]), GifScreen.Width, GifScreen.Height); } if (comment_parasite != NULL) { if (! thumbnail) gimp_image_attach_parasite (image_ID, comment_parasite); gimp_parasite_free (comment_parasite); comment_parasite = NULL; } /* If we are loading a thumbnail, we stop after the first frame. */ if (thumbnail) break; } return image_ID; }
/*--------------------------------------------------------------------------*/ int AG_LoadGIF_RW( SDL_RWops* src, AG_Frame* frames, int maxFrames ) { int start; unsigned char buf[16]; unsigned char c; int useGlobalColormap; int bitPixel; int iFrame = 0; char version[4]; SDL_Surface* image = NULL; gifdata* gd; if ( src == NULL ) return 0; gd = (gifdata *)malloc( sizeof(*gd) ); memset( gd, 0, sizeof(*gd) ); gd->src = src; start = SDL_RWtell( src ); if ( !SDL_RWread(src,buf,6,1) ) { SDL_SetError( "error reading magic number" ); goto done; } if ( strncmp((char*)buf,"GIF",3) != 0 ) { SDL_SetError( "not a GIF file" ); goto done; } strncpy( version, (char*)buf+3, 3 ); version[3] = '\0'; if ( (strcmp(version,"87a") != 0) && (strcmp(version,"89a") != 0) ) { SDL_SetError( "bad version number, not '87a' or '89a'" ); goto done; } gd->g89.transparent = -1; gd->g89.delayTime = -1; gd->g89.inputFlag = -1; gd->g89.disposal = AG_DISPOSE_NA; if ( !SDL_RWread(src,buf,7,1) ) { SDL_SetError( "failed to read screen descriptor" ); goto done; } gd->gs.Width = LM_to_uint(buf[0],buf[1]); gd->gs.Height = LM_to_uint(buf[2],buf[3]); gd->gs.BitPixel = 2 << (buf[4] & 0x07); gd->gs.ColorResolution = (((buf[4] & 0x70) >> 3) + 1); gd->gs.Background = buf[5]; gd->gs.AspectRatio = buf[6]; if ( BitSet(buf[4],LOCALCOLORMAP) ) /* Global Colormap */ { if ( ReadColorMap(gd,gd->gs.BitPixel,gd->gs.ColorMap) ) { SDL_SetError( "error reading global colormap" ); goto done; } } do { if ( !SDL_RWread(src,&c,1,1) ) { SDL_SetError( "EOF / read error on image data" ); goto done; } if ( c == ';' ) /* GIF terminator */ goto done; if ( c == '!' ) /* Extension */ { if ( !SDL_RWread(src,&c,1,1) ) { SDL_SetError( "EOF / read error on extention function code" ); goto done; } DoExtension( gd, c ); continue; } if ( c != ',' ) /* Not a valid start character */ continue; if ( !SDL_RWread(src,buf,9,1) ) { SDL_SetError( "couldn't read left/top/width/height" ); goto done; } useGlobalColormap = !BitSet(buf[8],LOCALCOLORMAP); bitPixel = 1 << ((buf[8] & 0x07) + 1); if ( !useGlobalColormap ) { if ( ReadColorMap(gd,bitPixel,gd->localColorMap) ) { SDL_SetError( "error reading local colormap" ); goto done; } image = ReadImage( gd, LM_to_uint(buf[4],buf[5]), LM_to_uint(buf[6],buf[7]), bitPixel, gd->localColorMap, BitSet(buf[8],INTERLACE), (frames==NULL) ); } else { image = ReadImage( gd, LM_to_uint(buf[4],buf[5]), LM_to_uint(buf[6],buf[7]), gd->gs.BitPixel, gd->gs.ColorMap, BitSet(buf[8],INTERLACE), (frames==NULL) ); } if ( frames ) { if ( image == NULL ) goto done; if ( gd->g89.transparent >= 0 ) SDL_SetColorKey( image, SDL_SRCCOLORKEY, gd->g89.transparent ); frames[iFrame].surface = image; frames[iFrame].x = LM_to_uint(buf[0], buf[1]); frames[iFrame].y = LM_to_uint(buf[2], buf[3]); frames[iFrame].disposal = gd->g89.disposal; frames[iFrame].delay = gd->g89.delayTime*10; /* gd->g89.transparent = -1; ** Hmmm, not sure if this should be reset for each frame? */ } iFrame++; } while ( iFrame < maxFrames || frames == NULL ); done: if ( image == NULL ) SDL_RWseek( src, start, SEEK_SET ); free( gd ); return iFrame; }