void image_finish(image *im) { // Called at DESTROY-time to release all memory if needed. // Items here may be freed elsewhere so must check that they aren't NULL DEBUG_TRACE("image_finish\n"); switch (im->type) { #ifdef HAVE_JPEG case JPEG: image_jpeg_finish(im); break; #endif #ifdef HAVE_PNG case PNG: image_png_finish(im); break; #endif #ifdef HAVE_GIF case GIF: image_gif_finish(im); break; #endif case BMP: image_bmp_finish(im); break; } if (im->buf != NULL) { buffer_free(im->buf); Safefree(im->buf); im->buf = NULL; } if (im->pixbuf != NULL && im->pixbuf != im->outbuf) { // pixbuf = outbuf if resizing to same dimensions Safefree(im->pixbuf); im->pixbuf = NULL; } if (im->outbuf != NULL) { Safefree(im->outbuf); im->outbuf = NULL; im->outbuf_size = 0; } if (im->path != NULL) { SvREFCNT_dec(im->path); im->path = NULL; } DEBUG_TRACE("Freed all memory, total used: %d\n", im->memory_used); im->memory_used = 0; }
int image_gif_read_header(image *im) { #ifdef GIFLIB_API_50 im->gif = DGifOpen(im, image_gif_read_buf, NULL); #else im->gif = DGifOpen(im, image_gif_read_buf); #endif if (im->gif == NULL) { #ifdef GIFLIB_API_41 PrintGifError(); #endif warn("Image::Scale unable to open GIF file (%s)\n", SvPVX(im->path)); image_gif_finish(im); return 0; } im->width = im->gif->SWidth; im->height = im->gif->SHeight; return 1; }
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"); } }