int get_gif_saved_images( GifFileType *gif, int subimage, SavedImage **ret, int *ret_images ) { GifRecordType RecordType; GifByteType *ExtData; SavedImage temp_save; int curr_image = 0, ret_count = *ret_images ; int status = GIF_OK; memset( &temp_save, 0x00, sizeof( temp_save ) ); do { if ( (status = DGifGetRecordType(gif, &RecordType)) == GIF_ERROR) { break; } switch (RecordType) { case IMAGE_DESC_RECORD_TYPE: if ((status = get_gif_image_desc(gif, &temp_save)) == GIF_OK) { int size = temp_save.ImageDesc.Width*temp_save.ImageDesc.Height ; temp_save.RasterBits = realloc( temp_save.RasterBits, size ); status = DGifGetLine(gif, (unsigned char*)temp_save.RasterBits, size); if (status == GIF_OK) { if( curr_image == subimage || subimage < 0 ) { append_gif_saved_image( &temp_save, ret, &(ret_count)); } } ++curr_image ; } break; case EXTENSION_RECORD_TYPE: status = DGifGetExtension(gif,&temp_save.Function,&ExtData); while (ExtData != NULL && status == GIF_OK ) { /* Create an extension block with our data */ if ((status = AddExtensionBlock(&temp_save, ExtData[0], (char*)&(ExtData[1]))) == GIF_OK) status = DGifGetExtensionNext(gif, &ExtData); temp_save.Function = 0; } break; case TERMINATE_RECORD_TYPE: break; default: /* Should be trapped by DGifGetRecordType */ break; } }while( status == GIF_OK && RecordType != TERMINATE_RECORD_TYPE); /* if( status == GIF_OK && *ret == NULL ) append_gif_saved_image( &temp_save, ret, &(ret_count)); else */ free_gif_saved_image( &temp_save, True ); *ret_images = ret_count ; return status; }
/****************************************************************************** * This routine reads an entire GIF into core, hanging all its state info off * * the GifFileType pointer. Call DGifOpenFileName() or DGifOpenFileHandle() * * first to initialize I/O. Its inverse is EGifSpew(). * * ******************************************************************************/ int DGifSlurp(GifFileType *GifFile) { int i, j, Error, ImageSize; GifRecordType RecordType; SavedImage *sp; GifByteType *ExtData; SavedImage temp_save; temp_save.ExtensionBlocks=NULL; temp_save.ExtensionBlockCount=0; do { if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) return(GIF_ERROR); switch (RecordType) { case IMAGE_DESC_RECORD_TYPE: if (DGifGetImageDesc(GifFile) == GIF_ERROR) return(GIF_ERROR); sp = &GifFile->SavedImages[GifFile->ImageCount-1]; ImageSize = sp->ImageDesc.Width * sp->ImageDesc.Height; sp->RasterBits = (char *) malloc(ImageSize * sizeof(GifPixelType)); if (DGifGetLine(GifFile, (GifByteType*)sp->RasterBits, ImageSize) == GIF_ERROR) return(GIF_ERROR); if (temp_save.ExtensionBlocks) { sp->ExtensionBlocks = temp_save.ExtensionBlocks; sp->ExtensionBlockCount = temp_save.ExtensionBlockCount; temp_save.ExtensionBlocks = NULL; temp_save.ExtensionBlockCount=0; /* FIXME: The following is wrong. It is left in only for backwards * compatibility. Someday it should go away. Use the * sp->ExtensionBlocks->Function variable instead. */ sp->Function = sp->ExtensionBlocks[0].Function; } break; case EXTENSION_RECORD_TYPE: if (DGifGetExtension(GifFile,&temp_save.Function,&ExtData)==GIF_ERROR) return(GIF_ERROR); while (ExtData != NULL) { /* Create an extension block with our data */ if (AddExtensionBlock(&temp_save, ExtData[0], (char*)&ExtData[1]) == GIF_ERROR) return (GIF_ERROR); if (DGifGetExtensionNext(GifFile, &ExtData) == GIF_ERROR) return(GIF_ERROR); temp_save.Function = 0; } break; case TERMINATE_RECORD_TYPE: break; default: /* Should be trapped by DGifGetRecordType */ break; } } while (RecordType != TERMINATE_RECORD_TYPE); /* Just in case the Gif has an extension block without an associated * image... (Should we save this into a savefile structure with no image * instead? Have to check if the present writing code can handle that as * well.... */ if (temp_save.ExtensionBlocks) FreeExtension(&temp_save); return(GIF_OK); }
SkCodec::Result SkGifCodec::ReadUpToFirstImage(GifFileType* gif, uint32_t* transIndex) { // Use this as a container to hold information about any gif extension // blocks. This generally stores transparency and animation instructions. SavedImage saveExt; SkAutoTCallVProc<SavedImage, FreeExtension> autoFreeExt(&saveExt); saveExt.ExtensionBlocks = nullptr; saveExt.ExtensionBlockCount = 0; GifByteType* extData; int32_t extFunction; // We will loop over components of gif images until we find an image. Once // we find an image, we will decode and return it. While many gif files // contain more than one image, we will simply decode the first image. GifRecordType recordType; do { // Get the current record type if (GIF_ERROR == DGifGetRecordType(gif, &recordType)) { return gif_error("DGifGetRecordType failed.\n", kInvalidInput); } switch (recordType) { case IMAGE_DESC_RECORD_TYPE: { *transIndex = find_trans_index(saveExt); // FIXME: Gif files may have multiple images stored in a single // file. This is most commonly used to enable // animations. Since we are leaving animated gifs as a // TODO, we will return kSuccess after decoding the // first image in the file. This is the same behavior // as SkImageDecoder_libgif. // // Most times this works pretty well, but sometimes it // doesn't. For example, I have an animated test image // where the first image in the file is 1x1, but the // subsequent images are meaningful. This currently // displays the 1x1 image, which is not ideal. Right // now I am leaving this as an issue that will be // addressed when we implement animated gifs. // // It is also possible (not explicitly disallowed in the // specification) that gif files provide multiple // images in a single file that are all meant to be // displayed in the same frame together. I will // currently leave this unimplemented until I find a // test case that expects this behavior. return kSuccess; } // Extensions are used to specify special properties of the image // such as transparency or animation. case EXTENSION_RECORD_TYPE: // Read extension data if (GIF_ERROR == DGifGetExtension(gif, &extFunction, &extData)) { return gif_error("Could not get extension.\n", kIncompleteInput); } // Create an extension block with our data while (nullptr != extData) { // Add a single block #if GIFLIB_MAJOR < 5 if (AddExtensionBlock(&saveExt, extData[0], &extData[1]) == GIF_ERROR) { #else if (GIF_ERROR == GifAddExtensionBlock(&saveExt.ExtensionBlockCount, &saveExt.ExtensionBlocks, extFunction, extData[0], &extData[1])) { #endif return gif_error("Could not add extension block.\n", kIncompleteInput); } // Move to the next block if (GIF_ERROR == DGifGetExtensionNext(gif, &extData)) { return gif_error("Could not get next extension.\n", kIncompleteInput); } } break; // Signals the end of the gif file case TERMINATE_RECORD_TYPE: break; default: // DGifGetRecordType returns an error if the record type does // not match one of the above cases. This should not be // reached. SkASSERT(false); break; } } while (TERMINATE_RECORD_TYPE != recordType); return gif_error("Could not find any images to decode in gif file.\n", kInvalidInput); } bool SkGifCodec::GetDimensions(GifFileType* gif, SkISize* size, SkIRect* frameRect) { // Get the encoded dimension values SavedImage* image = &gif->SavedImages[gif->ImageCount - 1]; const GifImageDesc& desc = image->ImageDesc; int frameLeft = desc.Left; int frameTop = desc.Top; int frameWidth = desc.Width; int frameHeight = desc.Height; int width = gif->SWidth; int height = gif->SHeight; // Ensure that the decode dimensions are large enough to contain the frame width = SkTMax(width, frameWidth + frameLeft); height = SkTMax(height, frameHeight + frameTop); // All of these dimensions should be positive, as they are encoded as unsigned 16-bit integers. // It is unclear why giflib casts them to ints. We will go ahead and check that they are // in fact positive. if (frameLeft < 0 || frameTop < 0 || frameWidth < 0 || frameHeight < 0 || width <= 0 || height <= 0) { return false; } frameRect->setXYWH(frameLeft, frameTop, frameWidth, frameHeight); size->set(width, height); return true; }
static void Icon2Gif(char *FileName, FILE *txtin, int fdout) { unsigned int ExtCode, ColorMapSize = 0; GifColorType GlobalColorMap[256], LocalColorMap[256], *ColorMap = GlobalColorMap; char GlobalColorKeys[PRINTABLES], LocalColorKeys[PRINTABLES], *KeyTable = GlobalColorKeys; int red, green, blue; char buf[BUFSIZ * 2], InclusionFile[64]; GifFileType *GifFileOut; SavedImage *NewImage = NULL; int n, LineNum = 0; if ((GifFileOut = EGifOpenFileHandle(fdout)) == NULL) { (void) HandleGifError(GifFileOut); } /* OK, interpret directives */ while (fgets(buf, sizeof(buf), txtin) != (char *)NULL) { char *cp; ++LineNum; /* * Skip lines consisting only of whitespace and comments */ for (cp = buf; isspace((int)(*cp)); cp++) continue; if (*cp == '#' || *cp == '\0') continue; /* * If there's a trailing comment, nuke it and all preceding whitespace. * But preserve the EOL. */ if ((cp = strchr(buf, '#')) && (cp == strrchr(cp, '#'))) { while (isspace((int)(*--cp))) continue; *++cp = '\n'; *++cp = '\0'; } /* * Explicit header declarations */ if (sscanf(buf, "screen width %d\n", &GifFileOut->SWidth) == 1) continue; else if (sscanf(buf, "screen height %d\n", &GifFileOut->SHeight) == 1) continue; else if (sscanf(buf, "screen colors %d\n", &n) == 1) { int ResBits = BitSize(n); if (n > 256 || n < 0 || n != (1 << ResBits)) { PARSE_ERROR("Invalid color resolution value."); exit(EXIT_FAILURE); } GifFileOut->SColorResolution = ResBits; continue; } else if (sscanf(buf, "screen background %d\n", &GifFileOut->SBackGroundColor) == 1) continue; /* * Color table parsing */ else if (strcmp(buf, "screen map\n") == 0) { if (GifFileOut->SColorMap != NULL) { PARSE_ERROR("You've already declared a global color map."); exit(EXIT_FAILURE); } ColorMapSize = 0; ColorMap = GlobalColorMap; KeyTable = GlobalColorKeys; memset(GlobalColorKeys, '\0', sizeof(GlobalColorKeys)); } else if (strcmp(buf, "image map\n") == 0) { if (NewImage == NULL) { PARSE_ERROR("No previous image declaration."); exit(EXIT_FAILURE); } ColorMapSize = 0; ColorMap = LocalColorMap; KeyTable = LocalColorKeys; memset(LocalColorKeys, '\0', sizeof(LocalColorKeys)); } else if (sscanf(buf, " rgb %d %d %d is %c", &red, &green, &blue, &KeyTable[ColorMapSize]) == 4) { ColorMap[ColorMapSize].Red = red; ColorMap[ColorMapSize].Green = green; ColorMap[ColorMapSize].Blue = blue; ColorMapSize++; } else if (strcmp(buf, "end\n") == 0) { ColorMapObject *NewMap; NewMap = MakeMapObject(1 << BitSize(ColorMapSize), ColorMap); if (NewMap == (ColorMapObject *)NULL) { PARSE_ERROR("Out of memory while allocating new color map."); exit(EXIT_FAILURE); } if (NewImage) NewImage->ImageDesc.ColorMap = NewMap; else GifFileOut->SColorMap = NewMap; } /* GIF inclusion */ else if (sscanf(buf, "include %s", InclusionFile) == 1) { GifBooleanType DoTranslation; GifPixelType Translation[256]; GifFileType *Inclusion; SavedImage *NewImage, *CopyFrom; if ((Inclusion = DGifOpenFileName(InclusionFile)) == NULL || DGifSlurp(Inclusion) == GIF_ERROR) { PARSE_ERROR("Inclusion read failed."); QuitGifError(Inclusion, GifFileOut); } if ((DoTranslation = (GifFileOut->SColorMap!=(ColorMapObject*)NULL))) { ColorMapObject *UnionMap; UnionMap = UnionColorMap(GifFileOut->SColorMap, Inclusion->SColorMap, Translation); if (UnionMap == NULL) { PARSE_ERROR("Inclusion failed --- global map conflict."); QuitGifError(Inclusion, GifFileOut); } FreeMapObject(GifFileOut->SColorMap); GifFileOut->SColorMap = UnionMap; } for (CopyFrom = Inclusion->SavedImages; CopyFrom < Inclusion->SavedImages + Inclusion->ImageCount; CopyFrom++) { if ((NewImage = MakeSavedImage(GifFileOut, CopyFrom)) == NULL) { PARSE_ERROR("Inclusion failed --- out of memory."); QuitGifError(Inclusion, GifFileOut); } else if (DoTranslation) ApplyTranslation(NewImage, Translation); GifQprintf( "%s: Image %d at (%d, %d) [%dx%d]: from %s\n", PROGRAM_NAME, GifFileOut->ImageCount, NewImage->ImageDesc.Left, NewImage->ImageDesc.Top, NewImage->ImageDesc.Width, NewImage->ImageDesc.Height, InclusionFile); } (void) DGifCloseFile(Inclusion); } /* * Explicit image declarations */ else if (strcmp(buf, "image\n") == 0) { if ((NewImage = MakeSavedImage(GifFileOut, NULL)) == (SavedImage *)NULL) { PARSE_ERROR("Out of memory while allocating image block."); exit(EXIT_FAILURE); } /* use global table unless user specifies a local one */ ColorMap = GlobalColorMap; KeyTable = GlobalColorKeys; } /* * Nothing past this point is valid unless we've seen a previous * image declaration. */ else if (NewImage == (SavedImage *)NULL) { (void) fputs(buf, stderr); PARSE_ERROR("Syntax error in header block."); exit(EXIT_FAILURE); } /* * Accept image attributes */ else if (sscanf(buf, "image top %d\n", &NewImage->ImageDesc.Top) == 1) continue; else if (sscanf(buf, "image left %d\n", &NewImage->ImageDesc.Left)== 1) continue; else if (strcmp(buf, "image interlaced\n") == 0) { NewImage->ImageDesc.Interlace = TRUE; continue; } else if (sscanf(buf, "image bits %d by %d\n", &NewImage->ImageDesc.Width, &NewImage->ImageDesc.Height) == 2) { int i, j; static GifPixelType *Raster, *cp; int c; if ((Raster = (GifPixelType *) malloc(sizeof(GifPixelType) * NewImage->ImageDesc.Width * NewImage->ImageDesc.Height)) == NULL) { PARSE_ERROR("Failed to allocate raster block, aborted."); exit(EXIT_FAILURE); } if (!GifQuietPrint) fprintf(stderr, "%s: Image %d at (%d, %d) [%dx%d]: ", PROGRAM_NAME, GifFileOut->ImageCount, NewImage->ImageDesc.Left, NewImage->ImageDesc.Top, NewImage->ImageDesc.Width, NewImage->ImageDesc.Height); cp = Raster; for (i = 0; i < NewImage->ImageDesc.Height; i++) { char *dp; for (j = 0; j < NewImage->ImageDesc.Width; j++) if ((c = fgetc(txtin)) == EOF) { PARSE_ERROR("input file ended prematurely."); exit(EXIT_FAILURE); } else if (c == '\n') { --j; ++LineNum; } else if (isspace(c)) --j; else if ((dp = strchr(KeyTable, c))) *cp++ = (dp - KeyTable); else { PARSE_ERROR("Invalid pixel value."); exit(EXIT_FAILURE); } if (!GifQuietPrint) fprintf(stderr, "\b\b\b\b%-4d", i); } if (!GifQuietPrint) putc('\n', stderr); NewImage->RasterBits = (unsigned char *) Raster; } else if (sscanf(buf, "comment")) { MakeExtension(NewImage, COMMENT_EXT_FUNC_CODE); while (fgets(buf, sizeof(buf), txtin) != (char *)NULL) if (strcmp(buf, "end\n") == 0) break; else { int Len; buf[strlen(buf) - 1] = '\0'; Len = EscapeString(buf, buf); if (AddExtensionBlock(NewImage, Len, (unsigned char *)buf) == GIF_ERROR) { PARSE_ERROR("out of memory while adding comment block."); exit(EXIT_FAILURE); } } } else if (sscanf(buf, "plaintext")) { MakeExtension(NewImage, PLAINTEXT_EXT_FUNC_CODE); while (fgets(buf, sizeof(buf), txtin) != (char *)NULL) if (strcmp(buf, "end\n") == 0) break; else { int Len; buf[strlen(buf) - 1] = '\0'; Len = EscapeString(buf, buf); if (AddExtensionBlock(NewImage, Len, (unsigned char *)buf) == GIF_ERROR) { PARSE_ERROR("out of memory while adding plaintext block."); exit(EXIT_FAILURE); } } } else if (sscanf(buf, "extension %02x", &ExtCode)) { MakeExtension(NewImage, ExtCode); while (fgets(buf, sizeof(buf), txtin) != (char *)NULL) if (strcmp(buf, "end\n") == 0) break; else { int Len; buf[strlen(buf) - 1] = '\0'; Len = EscapeString(buf, buf); if (AddExtensionBlock(NewImage, Len, (unsigned char *)buf) == GIF_ERROR) { PARSE_ERROR("out of memory while adding extension block."); exit(EXIT_FAILURE); } } } else { (void) fputs(buf, stderr); PARSE_ERROR("Syntax error in image description."); exit(EXIT_FAILURE); } } if (EGifSpew(GifFileOut) == GIF_ERROR) HandleGifError(GifFileOut); }
int image_gif_load(image *im) { int x, y, ofs; GifRecordType RecordType; GifPixelType *line = NULL; int ExtFunction = 0; GifByteType *ExtData; SavedImage *sp; SavedImage temp_save; int BackGround = 0; int trans_index = 0; // transparent index if any ColorMapObject *ColorMap; GifColorType *ColorMapEntry; temp_save.ExtensionBlocks = NULL; temp_save.ExtensionBlockCount = 0; // If reusing the object a second time, start over if (im->used) { DEBUG_TRACE("Recreating giflib objects\n"); image_gif_finish(im); if (im->fh != NULL) { // reset file to begining of image PerlIO_seek(im->fh, im->image_offset, SEEK_SET); } else { // reset SV read im->sv_offset = im->image_offset; } buffer_clear(im->buf); image_gif_read_header(im); } do { if (DGifGetRecordType(im->gif, &RecordType) == GIF_ERROR) { warn("Image::Scale unable to read GIF file (%s)\n", SvPVX(im->path)); image_gif_finish(im); return 0; } switch (RecordType) { case IMAGE_DESC_RECORD_TYPE: if (DGifGetImageDesc(im->gif) == GIF_ERROR) { warn("Image::Scale unable to read GIF file (%s)\n", SvPVX(im->path)); image_gif_finish(im); return 0; } sp = &im->gif->SavedImages[im->gif->ImageCount - 1]; im->width = sp->ImageDesc.Width; im->height = sp->ImageDesc.Height; BackGround = im->gif->SBackGroundColor; // XXX needed? ColorMap = im->gif->Image.ColorMap ? im->gif->Image.ColorMap : im->gif->SColorMap; if (ColorMap == NULL) { warn("Image::Scale GIF image has no colormap (%s)\n", SvPVX(im->path)); image_gif_finish(im); return 0; } // Allocate storage for decompressed image image_alloc(im, im->width, im->height); New(0, line, im->width, GifPixelType); if (im->gif->Image.Interlace) { int i; for (i = 0; i < 4; i++) { for (x = InterlacedOffset[i]; x < im->height; x += InterlacedJumps[i]) { ofs = x * im->width; if (DGifGetLine(im->gif, line, 0) != GIF_OK) { warn("Image::Scale unable to read GIF file (%s)\n", SvPVX(im->path)); image_gif_finish(im); return 0; } for (y = 0; y < im->width; y++) { ColorMapEntry = &ColorMap->Colors[line[y]]; im->pixbuf[ofs++] = COL_FULL( ColorMapEntry->Red, ColorMapEntry->Green, ColorMapEntry->Blue, trans_index == line[y] ? 0 : 255 ); } } } } else { ofs = 0; for (x = 0; x < im->height; x++) { if (DGifGetLine(im->gif, line, 0) != GIF_OK) { warn("Image::Scale unable to read GIF file (%s)\n", SvPVX(im->path)); image_gif_finish(im); return 0; } for (y = 0; y < im->width; y++) { ColorMapEntry = &ColorMap->Colors[line[y]]; im->pixbuf[ofs++] = COL_FULL( ColorMapEntry->Red, ColorMapEntry->Green, ColorMapEntry->Blue, trans_index == line[y] ? 0 : 255 ); } } } Safefree(line); break; case EXTENSION_RECORD_TYPE: if (DGifGetExtension(im->gif, &ExtFunction, &ExtData) == GIF_ERROR) { warn("Image::Scale unable to read GIF file (%s)\n", SvPVX(im->path)); image_gif_finish(im); return 0; } if (ExtFunction == 0xF9) { // transparency info if (ExtData[1] & 1) trans_index = ExtData[4]; else trans_index = -1; im->has_alpha = 1; DEBUG_TRACE("GIF transparency index: %d\n", trans_index); } while (ExtData != NULL) { /* Create an extension block with our data */ #ifdef GIFLIB_API_50 if (GifAddExtensionBlock(&im->gif->ExtensionBlockCount, &im->gif->ExtensionBlocks, ExtFunction, ExtData[0], &ExtData[1]) == GIF_ERROR) { #else temp_save.Function = ExtFunction; if (AddExtensionBlock(&temp_save, ExtData[0], &ExtData[1]) == GIF_ERROR) { #endif #ifdef GIFLIB_API_41 PrintGifError(); #endif warn("Image::Scale unable to read GIF file (%s)\n", SvPVX(im->path)); image_gif_finish(im); return 0; } if (DGifGetExtensionNext(im->gif, &ExtData) == GIF_ERROR) { #ifdef GIFLIB_API_41 PrintGifError(); #endif warn("Image::Scale unable to read GIF file (%s)\n", SvPVX(im->path)); image_gif_finish(im); return 0; } ExtFunction = 0; // CONTINUE_EXT_FUNC_CODE } break; case TERMINATE_RECORD_TYPE: default: break; } } while (RecordType != TERMINATE_RECORD_TYPE); return 1; } void image_gif_finish(image *im) { if (im->gif != NULL) { #ifdef GIFLIB_API_51 if (DGifCloseFile(im->gif, NULL) != GIF_OK) { #else if (DGifCloseFile(im->gif) != GIF_OK) { #endif #ifdef GIFLIB_API_41 PrintGifError(); #endif warn("Image::Scale unable to close GIF file (%s)\n", SvPVX(im->path)); } im->gif = NULL; DEBUG_TRACE("image_gif_finish\n"); } }
/****************************************************************************** * This routine reads an entire GIF into core, hanging all its state info off * the GifFileType pointer. Call DGifOpenFileName() or DGifOpenFileHandle() * first to initialize I/O. Its inverse is EGifSpew(). ******************************************************************************/ int DGifSlurp(GifFileType * GifFile) { int ImageSize; GifRecordType RecordType; SavedImage *sp; GifByteType *ExtData; Extensions temp_save; temp_save.ExtensionBlocks = NULL; temp_save.ExtensionBlockCount = 0; do { if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) return (GIF_ERROR); switch (RecordType) { case IMAGE_DESC_RECORD_TYPE: if (DGifGetImageDesc(GifFile) == GIF_ERROR) return (GIF_ERROR); sp = &GifFile->SavedImages[GifFile->ImageCount - 1]; ImageSize = sp->ImageDesc.Width * sp->ImageDesc.Height; sp->RasterBits = ungif_alloc(ImageSize * sizeof(GifPixelType)); if (sp->RasterBits == NULL) { return GIF_ERROR; } if (DGifGetLine(GifFile, sp->RasterBits, ImageSize) == GIF_ERROR) return (GIF_ERROR); if (temp_save.ExtensionBlocks) { sp->Extensions.ExtensionBlocks = temp_save.ExtensionBlocks; sp->Extensions.ExtensionBlockCount = temp_save.ExtensionBlockCount; temp_save.ExtensionBlocks = NULL; temp_save.ExtensionBlockCount = 0; /* FIXME: The following is wrong. It is left in only for * backwards compatibility. Someday it should go away. Use * the sp->ExtensionBlocks->Function variable instead. */ sp->Extensions.Function = sp->Extensions.ExtensionBlocks[0].Function; } break; case EXTENSION_RECORD_TYPE: { int Function; Extensions *Extensions; if (DGifGetExtension(GifFile, &Function, &ExtData) == GIF_ERROR) return (GIF_ERROR); if (GifFile->ImageCount || Function == GRAPHICS_EXT_FUNC_CODE) Extensions = &temp_save; else Extensions = &GifFile->Extensions; Extensions->Function = Function; /* Create an extension block with our data */ if (AddExtensionBlock(Extensions, ExtData[0], &ExtData[1]) == GIF_ERROR) return (GIF_ERROR); while (ExtData != NULL) { int Len; GifByteType *Data; if (DGifGetExtensionNext(GifFile, &ExtData) == GIF_ERROR) return (GIF_ERROR); if (ExtData) { Len = ExtData[0]; Data = &ExtData[1]; } else { Len = 0; Data = NULL; } if (AppendExtensionBlock(Extensions, Len, Data) == GIF_ERROR) return (GIF_ERROR); } break; } case TERMINATE_RECORD_TYPE: break; default: /* Should be trapped by DGifGetRecordType */ break; } } while (RecordType != TERMINATE_RECORD_TYPE); /* Just in case the Gif has an extension block without an associated * image... (Should we save this into a savefile structure with no image * instead? Have to check if the present writing code can handle that as * well.... */ if (temp_save.ExtensionBlocks) FreeExtension(&temp_save); return (GIF_OK); }