/****************************************************************************** * This routine should be called last, to close the GIF file. *****************************************************************************/ int DGifCloseFile(GifFileType * GifFile) { GifFilePrivateType *Private; if (GifFile == NULL) return GIF_ERROR; Private = GifFile->Private; if (GifFile->Image.ColorMap) { FreeMapObject(GifFile->Image.ColorMap); GifFile->Image.ColorMap = NULL; } if (GifFile->SColorMap) { FreeMapObject(GifFile->SColorMap); GifFile->SColorMap = NULL; } ungif_free(Private); Private = NULL; if (GifFile->SavedImages) { FreeSavedImages(GifFile); GifFile->SavedImages = NULL; } FreeExtension(&GifFile->Extensions); ungif_free(GifFile); return GIF_OK; }
/****************************************************************************** * This routine should be called last, to close the GIF file. * ******************************************************************************/ int DGifCloseFile(GifFileType *GifFile) { GifFilePrivateType *Private; FILE *File; if (GifFile == NULL) return GIF_ERROR; Private = (GifFilePrivateType *) GifFile->Private; if (!IS_READABLE(Private)) { /* This file was NOT open for reading: */ _GifError = D_GIF_ERR_NOT_READABLE; return GIF_ERROR; } File = Private->File; if (GifFile->Image.ColorMap) FreeMapObject(GifFile->Image.ColorMap); if (GifFile->SColorMap) FreeMapObject(GifFile->SColorMap); if (Private) free((char *) Private); if (GifFile->SavedImages) FreeSavedImages(GifFile); free(GifFile); if ( File && (fclose(File) != 0)) { _GifError = D_GIF_ERR_CLOSE_FAILED; return GIF_ERROR; } return GIF_OK; }
static int DGifCloseFile(GifFileType * GifFile) { GifFilePrivateType *Private; FILE *File; if (GifFile == NULL) return GIF_ERROR; Private = (GifFilePrivateType *) GifFile->Private; if (!IS_READABLE(Private)) { _GifError = D_GIF_ERR_NOT_READABLE; return GIF_ERROR; } File = Private->File; if (GifFile->Image.ColorMap) { FreeMapObject(GifFile->Image.ColorMap); GifFile->Image.ColorMap = NULL; } if (GifFile->SColorMap) { FreeMapObject(GifFile->SColorMap); GifFile->SColorMap = NULL; } if (Private) { gif_free((char *) Private); Private = NULL; } if (GifFile->SavedImages) { FreeSavedImages(GifFile); GifFile->SavedImages = NULL; } gif_free(GifFile); if (File && (fclose(File) != 0)) { _GifError = D_GIF_ERR_CLOSE_FAILED; return GIF_ERROR; } return GIF_OK; }
/****************************************************************************** * This routine should be called last, to close the GIF file. * ******************************************************************************/ int DGifCloseFile(GifFileType *GifFile) { GifFilePrivateType *Private; FILE *File; int ret = GIF_OK; if (GifFile == NULL) return GIF_ERROR; Private = (GifFilePrivateType *) GifFile->Private; if (!IS_READABLE(Private)) { /* This file was NOT open for reading: */ _GifError = D_GIF_ERR_NOT_READABLE; ret = GIF_ERROR; /* we have to free everything regardless */ } File = Private->File; if (GifFile->Image.ColorMap) { FreeMapObject(GifFile->Image.ColorMap); GifFile->Image.ColorMap = NULL; } if (GifFile->SColorMap) { FreeMapObject(GifFile->SColorMap); GifFile->SColorMap = NULL; } if (Private) { free((char *) Private); GifFile->Private = NULL; } if (GifFile->SavedImages) { FreeSavedImages(GifFile); GifFile->SavedImages = NULL; } free(GifFile); if ( File && (fclose(File) != 0)) { _GifError = D_GIF_ERR_CLOSE_FAILED; ret = GIF_ERROR; } return ret; }
static void FreeSavedImages(GifFileType * GifFile) { SavedImage *sp; if ((GifFile == NULL) || (GifFile->SavedImages == NULL)) { return; } for (sp = GifFile->SavedImages; sp < GifFile->SavedImages + GifFile->ImageCount; sp++) { if (sp->ImageDesc.ColorMap) { FreeMapObject(sp->ImageDesc.ColorMap); sp->ImageDesc.ColorMap = NULL; } if (sp->RasterBits) gif_free((char *) sp->RasterBits); if (sp->ExtensionBlocks) FreeExtension(sp); } gif_free((char *) GifFile->SavedImages); GifFile->SavedImages = NULL; }
/* Private Function: * Frees the last image in the GifFile->SavedImages array */ static void FreeLastSavedImage(GifFileType *GifFile) { SavedImage *sp; if ((GifFile == NULL) || (GifFile->SavedImages == NULL)) return; /* Remove one SavedImage from the GifFile */ GifFile->ImageCount--; sp = &GifFile->SavedImages[GifFile->ImageCount]; /* Deallocate its Colormap */ if (sp->ImageDesc.ColorMap) { FreeMapObject(sp->ImageDesc.ColorMap); sp->ImageDesc.ColorMap = NULL; } /* Deallocate the image data */ if (sp->RasterBits) free((char *)sp->RasterBits); /* Deallocate any extensions */ if (sp->ExtensionBlocks) FreeExtension(sp); /*** FIXME: We could realloc the GifFile->SavedImages structure but is * there a point to it? Saves some memory but we'd have to do it every * time. If this is used in FreeSavedImages then it would be inefficient * (The whole array is going to be deallocated.) If we just use it when * we want to free the last Image it's convenient to do it here. */ }
static int DGifGetScreenDesc(GifFileType * GifFile) { int i, BitsPerPixel; GifByteType Buf[3]; GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private; if (!IS_READABLE(Private)) { _GifError = D_GIF_ERR_NOT_READABLE; return GIF_ERROR; } if (DGifGetWord(GifFile, &GifFile->SWidth) == GIF_ERROR || DGifGetWord(GifFile, &GifFile->SHeight) == GIF_ERROR) return GIF_ERROR; if (READ(GifFile, Buf, 3) != 3) { _GifError = D_GIF_ERR_READ_FAILED; return GIF_ERROR; } GifFile->SColorResolution = (((Buf[0] & 0x70) + 1) >> 4) + 1; BitsPerPixel = (Buf[0] & 0x07) + 1; GifFile->SBackGroundColor = Buf[1]; if (Buf[0] & 0x80) { GifFile->SColorMap = MakeMapObject(1 << BitsPerPixel, NULL); if (GifFile->SColorMap == NULL) { _GifError = D_GIF_ERR_NOT_ENOUGH_MEM; return GIF_ERROR; } for (i = 0; i < GifFile->SColorMap->ColorCount; i++) { if (READ(GifFile, Buf, 3) != 3) { FreeMapObject(GifFile->SColorMap); GifFile->SColorMap = NULL; _GifError = D_GIF_ERR_READ_FAILED; return GIF_ERROR; } GifFile->SColorMap->Colors[i].Red = Buf[0]; GifFile->SColorMap->Colors[i].Green = Buf[1]; GifFile->SColorMap->Colors[i].Blue = Buf[2]; } } else { GifFile->SColorMap = NULL; } return GIF_OK; }
/****************************************************************************** * This routine should be called before any other DGif calls. Note that * this routine is called automatically from DGif file open routines. *****************************************************************************/ int DGifGetScreenDesc(GifFileType * GifFile) { int BitsPerPixel; GifByteType Buf[3]; GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private; if (!IS_READABLE(Private)) { /* This file was NOT open for reading: */ _GifError = D_GIF_ERR_NOT_READABLE; return GIF_ERROR; } /* Put the screen descriptor into the file: */ if (DGifGetWord(GifFile, &GifFile->SWidth) == GIF_ERROR || DGifGetWord(GifFile, &GifFile->SHeight) == GIF_ERROR) return GIF_ERROR; if (READ(GifFile, Buf, 3) != 3) { _GifError = D_GIF_ERR_READ_FAILED; return GIF_ERROR; } GifFile->SColorResolution = (((Buf[0] & 0x70) + 1) >> 4) + 1; BitsPerPixel = (Buf[0] & 0x07) + 1; GifFile->SBackGroundColor = Buf[1]; if (Buf[0] & 0x80) { /* Do we have global color map? */ int i; GifFile->SColorMap = MakeMapObject(1 << BitsPerPixel, NULL); if (GifFile->SColorMap == NULL) { _GifError = D_GIF_ERR_NOT_ENOUGH_MEM; return GIF_ERROR; } /* Get the global color map: */ for (i = 0; i < GifFile->SColorMap->ColorCount; i++) { if (READ(GifFile, Buf, 3) != 3) { FreeMapObject(GifFile->SColorMap); GifFile->SColorMap = NULL; _GifError = D_GIF_ERR_READ_FAILED; return GIF_ERROR; } GifFile->SColorMap->Colors[i].Red = Buf[0]; GifFile->SColorMap->Colors[i].Green = Buf[1]; GifFile->SColorMap->Colors[i].Blue = Buf[2]; } } else { GifFile->SColorMap = NULL; } return GIF_OK; }
void GifFree(GifFileType * GifFile) { GifFilePrivateType *Private; if (GifFile == NULL) return; Private = (GifFilePrivateType *) GifFile->Private; if (GifFile->SavedImages) FreeSavedImages(GifFile); if (GifFile->Image.ColorMap) FreeMapObject(GifFile->Image.ColorMap); if (GifFile->SColorMap) FreeMapObject(GifFile->SColorMap); if (Private) { free(Private); } if (GifFile->GifIO) free(GifFile->GifIO); free(GifFile); }
/****************************************************************************** * This routine should be called before any attemp to read an image. * * Note it is assumed the Image desc. header (',') has been read. * ******************************************************************************/ int DGifGetImageDesc(GifFileType *GifFile) { int i, BitsPerPixel; GifByteType Buf[3]; GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private; if (!IS_READABLE(Private)) { /* This file was NOT open for reading: */ _GifError = D_GIF_ERR_NOT_READABLE; return GIF_ERROR; } if (DGifGetWord(Private, &GifFile->Image.Left) == GIF_ERROR || DGifGetWord(Private, &GifFile->Image.Top) == GIF_ERROR || DGifGetWord(Private, &GifFile->Image.Width) == GIF_ERROR || DGifGetWord(Private, &GifFile->Image.Height) == GIF_ERROR) return GIF_ERROR; if (my_fread(Buf, 1, 1, Private) != 1) { _GifError = D_GIF_ERR_READ_FAILED; return GIF_ERROR; } BitsPerPixel = (Buf[0] & 0x07) + 1; GifFile->Image.Interlace = (Buf[0] & 0x40); if (Buf[0] & 0x80) { /* Does this image have local color map? */ if (GifFile->Image.ColorMap) FreeMapObject(GifFile->Image.ColorMap); GifFile->Image.ColorMap = MakeMapObject(1 << BitsPerPixel, NULL); /* Get the image local color map: */ for (i = 0; i < GifFile->Image.ColorMap->ColorCount; i++) { if (my_fread(Buf, 1, 3, Private) != 3) { _GifError = D_GIF_ERR_READ_FAILED; return GIF_ERROR; } GifFile->Image.ColorMap->Colors[i].Red = Buf[0]; GifFile->Image.ColorMap->Colors[i].Green = Buf[1]; GifFile->Image.ColorMap->Colors[i].Blue = Buf[2]; } } GifFile->ImageCount++; Private->PixelCount = (s32) GifFile->Image.Width * (s32) GifFile->Image.Height; DGifSetupDecompress(GifFile); /* Reset decompress algorithm parameters. */ return GIF_OK; }
/****************************************************************************** * This routine should be called last, to close the GIF file. * ******************************************************************************/ int DGifCloseFile(GifFileType *GifFile) { GifFilePrivateType *Private; if (GifFile == NULL) return GIF_ERROR; Private = (GifFilePrivateType *) GifFile->Private; if (!IS_READABLE(Private)) { /* This file was NOT open for reading: */ _GifError = D_GIF_ERR_NOT_READABLE; return GIF_ERROR; } if (GifFile->Image.ColorMap) FreeMapObject(GifFile->Image.ColorMap); if (GifFile->SColorMap) FreeMapObject(GifFile->SColorMap); if (Private) free((char *) Private); free(GifFile); return GIF_OK; }
void free_gif_saved_image( SavedImage *sp, Bool reusable ) { if( sp ) { if (sp->ImageDesc.ColorMap) FreeMapObject(sp->ImageDesc.ColorMap); if (sp->RasterBits) free((char *)sp->RasterBits); if (sp->ExtensionBlocks) FreeExtension(sp); if( !reusable ) free( sp ); } }
/****************************************************************************** * This routine should be called before any other DGif calls. Note that * this routine is called automatically from DGif file open routines. *****************************************************************************/ static int DGifGetScreenDesc(GifFileType * GifFile) { int i, BitsPerPixel, SortFlag; GifByteType Buf[3]; /* Put the screen descriptor into the file: */ if (DGifGetWord(GifFile, &GifFile->SWidth) == GIF_ERROR || DGifGetWord(GifFile, &GifFile->SHeight) == GIF_ERROR) return GIF_ERROR; if (READ(GifFile, Buf, 3) != 3) { return GIF_ERROR; } GifFile->SColorResolution = (((Buf[0] & 0x70) + 1) >> 4) + 1; SortFlag = (Buf[0] & 0x08) != 0; BitsPerPixel = (Buf[0] & 0x07) + 1; GifFile->SBackGroundColor = Buf[1]; GifFile->SAspectRatio = Buf[2]; if (Buf[0] & 0x80) { /* Do we have global color map? */ GifFile->SColorMap = MakeMapObject(1 << BitsPerPixel, NULL); if (GifFile->SColorMap == NULL) { return GIF_ERROR; } /* Get the global color map: */ GifFile->SColorMap->SortFlag = SortFlag; for (i = 0; i < GifFile->SColorMap->ColorCount; i++) { if (READ(GifFile, Buf, 3) != 3) { FreeMapObject(GifFile->SColorMap); GifFile->SColorMap = NULL; return GIF_ERROR; } GifFile->SColorMap->Colors[i].Red = Buf[0]; GifFile->SColorMap->Colors[i].Green = Buf[1]; GifFile->SColorMap->Colors[i].Blue = Buf[2]; } } else { GifFile->SColorMap = NULL; } return GIF_OK; }
void FreeSavedImages(GifFileType *GifFile) { SavedImage *sp; for (sp = GifFile->SavedImages; sp < GifFile->SavedImages + GifFile->ImageCount; sp++) { if (sp->ImageDesc.ColorMap) FreeMapObject(sp->ImageDesc.ColorMap); if (sp->RasterBits) free((char *)sp->RasterBits); if (sp->ExtensionBlocks) FreeExtension(sp); } free((char *) GifFile->SavedImages); }
/* * Compute the union of two given color maps and return it. If result can't * fit into 256 colors, NULL is returned, the allocated union otherwise. * ColorIn1 is copied as is to ColorUnion, while colors from ColorIn2 are * copied iff they didn't exist before. ColorTransIn2 maps the old * ColorIn2 into ColorUnion color map table. */ ColorMapObject * UnionColorMap(const ColorMapObject * ColorIn1, const ColorMapObject * ColorIn2, GifPixelType ColorTransIn2[]) { int i, j, CrntSlot, RoundUpTo, NewBitSize; ColorMapObject *ColorUnion; /* * Allocate table which will hold the result for sure. */ ColorUnion = MakeMapObject(MAX(ColorIn1->ColorCount, ColorIn2->ColorCount) * 2, NULL); if (ColorUnion == NULL) return (NULL); /* Copy ColorIn1 to ColorUnionSize; */ /*** FIXME: What if there are duplicate entries into the colormap to begin * with? */ for (i = 0; i < ColorIn1->ColorCount; i++) ColorUnion->Colors[i] = ColorIn1->Colors[i]; CrntSlot = ColorIn1->ColorCount; /* * Potentially obnoxious hack: * * Back CrntSlot down past all contiguous {0, 0, 0} slots at the end * of table 1. This is very useful if your display is limited to * 16 colors. */ while (ColorIn1->Colors[CrntSlot - 1].Red == 0 && ColorIn1->Colors[CrntSlot - 1].Green == 0 && ColorIn1->Colors[CrntSlot - 1].Blue == 0) CrntSlot--; /* Copy ColorIn2 to ColorUnionSize (use old colors if they exist): */ for (i = 0; i < ColorIn2->ColorCount && CrntSlot <= 256; i++) { /* Let's see if this color already exists: */ /*** FIXME: Will it ever occur that ColorIn2 will contain duplicate * entries? So we should search from 0 to CrntSlot rather than * ColorIn1->ColorCount? */ for (j = 0; j < ColorIn1->ColorCount; j++) if (memcmp (&ColorIn1->Colors[j], &ColorIn2->Colors[i], sizeof(GifColorType)) == 0) break; if (j < ColorIn1->ColorCount) ColorTransIn2[i] = j; /* color exists in Color1 */ else { /* Color is new - copy it to a new slot: */ ColorUnion->Colors[CrntSlot] = ColorIn2->Colors[i]; ColorTransIn2[i] = CrntSlot++; } } if (CrntSlot > 256) { FreeMapObject(ColorUnion); return ((ColorMapObject *) NULL); } NewBitSize = BitSize(CrntSlot); RoundUpTo = (1 << NewBitSize); if (RoundUpTo > 0 && RoundUpTo != ColorUnion->ColorCount) { register GifColorType *Map = ColorUnion->Colors; /* * Zero out slots up to next power of 2. * We know these slots exist because of the way ColorUnion's * start dimension was computed. */ for (j = CrntSlot; j < RoundUpTo; j++) Map[j].Red = Map[j].Green = Map[j].Blue = 0; /* perhaps we can shrink the map? */ if (RoundUpTo < ColorUnion->ColorCount) { GifColorType *new_map = (GifColorType *)realloc(Map, RoundUpTo * sizeof(GifColorType)); if( new_map == NULL ) { FreeMapObject(ColorUnion); return ((ColorMapObject *) NULL); } ColorUnion->Colors = new_map; } } ColorUnion->ColorCount = RoundUpTo; ColorUnion->BitsPerPixel = NewBitSize; return (ColorUnion); }
static int encode_gif_data(psx_image_header* header, psx_image_frame* frame, int idx, const ps_byte* buffer, size_t buffer_len, int* ret) { int x, y; ColorMapObject *output_map = NULL; int map_size = 256; struct gif_image_ctx* ctx = (struct gif_image_ctx*)header->priv; if ((output_map = MakeMapObject(map_size, NULL)) == NULL) { if (ret) *ret = S_FAILURE; return -1; } for (y = 0; y < header->height; y++) { ps_byte* row = (ps_byte*)(buffer + header->pitch * y); for (x = 0; x < header->width; x++) { uint32_t rgba[4] = {0}; // r, g, b, a gif_get_pixel_rgba_premultiply(header->format, row, x, rgba); ctx->red_buf[header->width * y + x] = rgba[0]; ctx->green_buf[header->width * y + x] = rgba[1]; ctx->blue_buf[header->width * y + x] = rgba[2]; } } if (QuantizeBuffer(header->width, header->height, &map_size, ctx->red_buf, ctx->green_buf, ctx->blue_buf, ctx->output_buffer, output_map->Colors) == GIF_ERROR) { FreeMapObject(output_map); if (ret) *ret = S_FAILURE; return -1; } if (frame->duration > 0) { GifByteType extension[4]; #if GIFLIB_MAJOR >= 5 GraphicsControlBlock gcb; gcb.DisposalMode = DISPOSAL_UNSPECIFIED; // FIXME: need specified ? gcb.UserInputFlag = false; gcb.DelayTime = frame->duration / 10; gcb.TransparentColor = -1; // FIXME: need specified ? EGifGCBToExtension(&gcb, extension); #else int delay = frame->duration / 10; extension[0] = 0; extension[1] = LOBYTE(delay); extension[2] = HIBYTE(delay); extension[3] = (char)-1; #endif if (EGifPutExtension(ctx->gif, GRAPHICS_EXT_FUNC_CODE, 4, extension) == GIF_ERROR) { FreeMapObject(output_map); if (ret) *ret = S_FAILURE; return -1; } } if (EGifPutImageDesc(ctx->gif, 0, 0, header->width, header->height, FALSE, output_map) == GIF_ERROR) { FreeMapObject(output_map); if (ret) *ret = S_FAILURE; return -1; } for (y = 0; y < header->height; y++) { EGifPutLine(ctx->gif, ctx->output_buffer + y * header->width, header->width); } FreeMapObject(output_map); return 0; }
/****************************************************************************** * This routine should be called before any attemp to read an image. * * Note it is assumed the Image desc. header (',') has been read. * ******************************************************************************/ int DGifGetImageDesc(GifFileType *GifFile) { int i, BitsPerPixel; GifByteType Buf[3]; GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private; SavedImage *sp; if (!IS_READABLE(Private)) { /* This file was NOT open for reading: */ _GifError = D_GIF_ERR_NOT_READABLE; return GIF_ERROR; } if (DGifGetWord(GifFile, &GifFile->Image.Left) == GIF_ERROR || DGifGetWord(GifFile, &GifFile->Image.Top) == GIF_ERROR || DGifGetWord(GifFile, &GifFile->Image.Width) == GIF_ERROR || DGifGetWord(GifFile, &GifFile->Image.Height) == GIF_ERROR) return GIF_ERROR; if (READ(GifFile,Buf, 1) != 1) { _GifError = D_GIF_ERR_READ_FAILED; return GIF_ERROR; } BitsPerPixel = (Buf[0] & 0x07) + 1; GifFile->Image.Interlace = (Buf[0] & 0x40); if (Buf[0] & 0x80) { /* Does this image have local color map? */ if (GifFile->Image.ColorMap && GifFile->SavedImages == NULL) FreeMapObject(GifFile->Image.ColorMap); GifFile->Image.ColorMap = MakeMapObject(1 << BitsPerPixel, NULL); /* Get the image local color map: */ for (i = 0; i < GifFile->Image.ColorMap->ColorCount; i++) { if (READ(GifFile,Buf, 3) != 3) { _GifError = D_GIF_ERR_READ_FAILED; return GIF_ERROR; } GifFile->Image.ColorMap->Colors[i].Red = Buf[0]; GifFile->Image.ColorMap->Colors[i].Green = Buf[1]; GifFile->Image.ColorMap->Colors[i].Blue = Buf[2]; } } if (GifFile->SavedImages) { if ((GifFile->SavedImages = (SavedImage *)realloc(GifFile->SavedImages, sizeof(SavedImage) * (GifFile->ImageCount + 1))) == NULL) { _GifError = D_GIF_ERR_NOT_ENOUGH_MEM; return GIF_ERROR; } } else { if ((GifFile->SavedImages = (SavedImage *)malloc(sizeof(SavedImage))) == NULL) { _GifError = D_GIF_ERR_NOT_ENOUGH_MEM; return GIF_ERROR; } } sp = &GifFile->SavedImages[GifFile->ImageCount]; memcpy(&sp->ImageDesc, &GifFile->Image, sizeof(GifImageDesc)); if (GifFile->Image.ColorMap != NULL) { sp->ImageDesc.ColorMap = MakeMapObject( GifFile->Image.ColorMap->ColorCount, GifFile->Image.ColorMap->Colors); } sp->RasterBits = (char *)NULL; sp->ExtensionBlockCount = 0; sp->ExtensionBlocks = (ExtensionBlock *)NULL; GifFile->ImageCount++; Private->PixelCount = (long) GifFile->Image.Width * (long) GifFile->Image.Height; DGifSetupDecompress(GifFile); /* Reset decompress algorithm parameters. */ return GIF_OK; }
bool CxImageGIF::Encode(CxFile * fp) { if (EncodeSafeCheck(fp)) return false; GifFileType *GifFile = NULL; ColorMapObject *OutputColorMap = NULL; int i, ColorMapSize; if(head.biBitCount != 8) { if(head.biBitCount < 8)IncreaseBpp(8); else DecreaseBpp(8, true); } try { GifFile = EGifOpen(fp, writeCxFile); ColorMapSize = head.biClrUsed; OutputColorMap = MakeMapObject(ColorMapSize, NULL); RGBQUAD* pPal = GetPalette(); for(i=0; i<ColorMapSize; ++i) { OutputColorMap->Colors[i].Red = pPal[i].rgbRed; OutputColorMap->Colors[i].Green = pPal[i].rgbGreen; OutputColorMap->Colors[i].Blue = pPal[i].rgbBlue; } EGifPutScreenDesc(GifFile, head.biWidth, head.biHeight, OutputColorMap->ColorCount, info.nBkgndIndex== -1 ? 0 : info.nBkgndIndex, OutputColorMap); FreeMapObject(OutputColorMap); OutputColorMap = NULL; if(info.nBkgndIndex != -1) { unsigned char ExtStr[4] = { 1, 0, 0, info.nBkgndIndex }; EGifPutExtension(GifFile, GRAPHICS_EXT_FUNC_CODE, 4, ExtStr); } EGifPutImageDesc(GifFile, 0, 0, head.biWidth, head.biHeight, FALSE, NULL); for (i = 0; i < head.biHeight; i++) EGifPutLine(GifFile, GetBits(head.biHeight - i - 1), head.biWidth); EGifCloseFile(GifFile); GifFile = NULL; } catch (int errid) { strncpy(info.szLastError,GifGetErrorMessage(errid),255); if(OutputColorMap) { FreeMapObject(OutputColorMap); OutputColorMap = NULL; } if(GifFile) { EGifCloseFile(GifFile); GifFile = NULL; } return false; } catch (char *message) { strncpy(info.szLastError,message,255); if(OutputColorMap) { FreeMapObject(OutputColorMap); OutputColorMap = NULL; } if(GifFile) { EGifCloseFile(GifFile); GifFile = NULL; } return false; } return true; }
static int DGifGetImageDesc(GifFileType * GifFile) { int i, BitsPerPixel; GifByteType Buf[3]; GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private; SavedImage *sp; if (!IS_READABLE(Private)) { _GifError = D_GIF_ERR_NOT_READABLE; return GIF_ERROR; } if (DGifGetWord(GifFile, &GifFile->Image.Left) == GIF_ERROR || DGifGetWord(GifFile, &GifFile->Image.Top) == GIF_ERROR || DGifGetWord(GifFile, &GifFile->Image.Width) == GIF_ERROR || DGifGetWord(GifFile, &GifFile->Image.Height) == GIF_ERROR) return GIF_ERROR; if (READ(GifFile, Buf, 1) != 1) { _GifError = D_GIF_ERR_READ_FAILED; return GIF_ERROR; } BitsPerPixel = (Buf[0] & 0x07) + 1; GifFile->Image.Interlace = (Buf[0] & 0x40); if (Buf[0] & 0x80) { if (GifFile->Image.ColorMap && GifFile->SavedImages == NULL) FreeMapObject(GifFile->Image.ColorMap); GifFile->Image.ColorMap = MakeMapObject(1 << BitsPerPixel, NULL); if (GifFile->Image.ColorMap == NULL) { _GifError = D_GIF_ERR_NOT_ENOUGH_MEM; return GIF_ERROR; } for (i = 0; i < GifFile->Image.ColorMap->ColorCount; i++) { if (READ(GifFile, Buf, 3) != 3) { FreeMapObject(GifFile->Image.ColorMap); _GifError = D_GIF_ERR_READ_FAILED; GifFile->Image.ColorMap = NULL; return GIF_ERROR; } GifFile->Image.ColorMap->Colors[i].Red = Buf[0]; GifFile->Image.ColorMap->Colors[i].Green = Buf[1]; GifFile->Image.ColorMap->Colors[i].Blue = Buf[2]; } } else if (GifFile->Image.ColorMap) { FreeMapObject(GifFile->Image.ColorMap); GifFile->Image.ColorMap = NULL; } if (GifFile->SavedImages) { if ((GifFile->SavedImages = (SavedImage *) realloc(GifFile->SavedImages, sizeof(SavedImage) * (GifFile->ImageCount + 1))) == NULL) { _GifError = D_GIF_ERR_NOT_ENOUGH_MEM; return GIF_ERROR; } } else { if ((GifFile->SavedImages = (SavedImage *) gif_malloc(sizeof(SavedImage))) == NULL) { _GifError = D_GIF_ERR_NOT_ENOUGH_MEM; return GIF_ERROR; } } sp = &GifFile->SavedImages[GifFile->ImageCount]; memcpy(&sp->ImageDesc, &GifFile->Image, sizeof(GifImageDesc)); if (GifFile->Image.ColorMap != NULL) { sp->ImageDesc.ColorMap = MakeMapObject(GifFile->Image.ColorMap->ColorCount, GifFile->Image.ColorMap->Colors); if (sp->ImageDesc.ColorMap == NULL) { _GifError = D_GIF_ERR_NOT_ENOUGH_MEM; return GIF_ERROR; } } sp->RasterBits = (unsigned char *) NULL; sp->ExtensionBlockCount = 0; sp->ExtensionBlocks = (ExtensionBlock *) NULL; GifFile->ImageCount++; Private->PixelCount = (long) GifFile->Image.Width * (long) GifFile->Image.Height; DGifSetupDecompress(GifFile); return GIF_OK; }
void * gif_encode(Image *image, int single, int *size) { int width = image->columns; int height = image->rows; int total = width * height; GifByteType output[total]; GifByteType red[total]; GifByteType green[total]; GifByteType blue[total]; // Quantize the images using IM/GM first, to reduce // their number of colors to 256. int count = GetImageListLength(image); QuantizeInfo info; GetQuantizeInfo(&info); info.dither = 1; info.number_colors = NCOLORS; QuantizeImage(&info, image); if (count > 1) { #ifdef _MAGICK_USES_IM RemapImages(&info, image->next, image); #else MapImages(image->next, image, 0); #endif } if (!acquire_image_pixels(image, red, green, blue)) { return NULL; } Frame *frames = calloc(count, sizeof(*frames)); ColorMapObject *palette = MakeMapObject(NCOLORS, NULL); int palette_size = NCOLORS; // Quantize again using giflib, since it yields a palette which produces // better compression, reducing the file size by 20%. Note that this second // quantization is very fast, because the image already has 256 colors, so // its effect on performance is negligible. if (QuantizeBuffer(width, height, &palette_size, red, green, blue, output, palette->Colors) == GIF_ERROR) { FreeMapObject(palette); gif_frames_free(frames, count); return NULL; } frames[0].data = malloc(total); memcpy(frames[0].data, output, total); frames[0].width = width; frames[0].height = height; frames[0].duration = image->delay; GifColorType *colors = palette->Colors; Image *cur = image->next; PixelCache *cache = pixel_cache_new(); int ii; for (ii = 1; ii < count; ii++, cur = cur->next) { frames[ii].width = width; frames[ii].height = height; frames[ii].duration = cur->delay; GifPixelType *data = malloc(total); frames[ii].data = data; if (!aprox_image_pixels(cur, colors, palette_size, cache, data)) { FreeMapObject(palette); gif_frames_free(frames, count); pixel_cache_free(cache); return NULL; } } pixel_cache_free(cache); void *ret = gif_save(image, palette, frames, count, size); FreeMapObject(palette); gif_frames_free(frames, count); return ret; }
/*! * pixWriteStreamGif() * * Input: stream * pix (1, 2, 4, 8, 16 or 32 bpp) * Return: 0 if OK, 1 on error * * Notes: * (1) All output gif have colormaps. If the pix is 32 bpp rgb, * this quantizes the colors and writes out 8 bpp. * If the pix is 16 bpp grayscale, it converts to 8 bpp first. * (2) We can't write to memory using open_memstream() because * the gif functions write through a file descriptor, not a * file stream. */ l_int32 pixWriteStreamGif(FILE *fp, PIX *pix) { char *text; l_int32 fd, wpl, i, j, w, h, d, ncolor, rval, gval, bval; l_int32 gif_ncolor = 0; l_uint32 *data, *line; PIX *pixd; PIXCMAP *cmap; GifFileType *gif; ColorMapObject *gif_cmap; GifByteType *gif_line; PROCNAME("pixWriteStreamGif"); if (!fp) return ERROR_INT("stream not open", procName, 1); if (!pix) return ERROR_INT("pix not defined", procName, 1); rewind(fp); if ((fd = fileno(fp)) < 0) return ERROR_INT("invalid file descriptor", procName, 1); d = pixGetDepth(pix); if (d == 32) { pixd = pixConvertRGBToColormap(pix, 1); } else if (d > 1) { pixd = pixConvertTo8(pix, TRUE); } else { /* d == 1; make sure there's a colormap */ pixd = pixClone(pix); if (!pixGetColormap(pixd)) { cmap = pixcmapCreate(1); pixcmapAddColor(cmap, 255, 255, 255); pixcmapAddColor(cmap, 0, 0, 0); pixSetColormap(pixd, cmap); } } if (!pixd) return ERROR_INT("failed to convert image to indexed", procName, 1); d = pixGetDepth(pixd); if ((cmap = pixGetColormap(pixd)) == NULL) { pixDestroy(&pixd); return ERROR_INT("cmap is missing", procName, 1); } /* 'Round' the number of gif colors up to a power of 2 */ ncolor = pixcmapGetCount(cmap); for (i = 0; i <= 8; i++) { if ((1 << i) >= ncolor) { gif_ncolor = (1 << i); break; } } if (gif_ncolor < 1) { pixDestroy(&pixd); return ERROR_INT("number of colors is invalid", procName, 1); } /* Save the cmap colors in a gif_cmap */ if ((gif_cmap = MakeMapObject(gif_ncolor, NULL)) == NULL) { pixDestroy(&pixd); return ERROR_INT("failed to create GIF color map", procName, 1); } for (i = 0; i < gif_ncolor; i++) { rval = gval = bval = 0; if (ncolor > 0) { if (pixcmapGetColor(cmap, i, &rval, &gval, &bval) != 0) { pixDestroy(&pixd); FreeMapObject(gif_cmap); return ERROR_INT("failed to get color from color map", procName, 1); } ncolor--; } gif_cmap->Colors[i].Red = rval; gif_cmap->Colors[i].Green = gval; gif_cmap->Colors[i].Blue = bval; } /* Get the gif file handle */ if ((gif = EGifOpenFileHandle(fd)) == NULL) { pixDestroy(&pixd); FreeMapObject(gif_cmap); return ERROR_INT("failed to create GIF image handle", procName, 1); } pixGetDimensions(pixd, &w, &h, NULL); if (EGifPutScreenDesc(gif, w, h, gif_cmap->BitsPerPixel, 0, gif_cmap) != GIF_OK) { pixDestroy(&pixd); FreeMapObject(gif_cmap); EGifCloseFile(gif); return ERROR_INT("failed to write screen description", procName, 1); } FreeMapObject(gif_cmap); /* not needed after this point */ if (EGifPutImageDesc(gif, 0, 0, w, h, FALSE, NULL) != GIF_OK) { pixDestroy(&pixd); EGifCloseFile(gif); return ERROR_INT("failed to image screen description", procName, 1); } data = pixGetData(pixd); wpl = pixGetWpl(pixd); if (d != 1 && d != 2 && d != 4 && d != 8) { pixDestroy(&pixd); EGifCloseFile(gif); return ERROR_INT("image depth is not in {1, 2, 4, 8}", procName, 1); } if ((gif_line = (GifByteType *)CALLOC(sizeof(GifByteType), w)) == NULL) { pixDestroy(&pixd); EGifCloseFile(gif); return ERROR_INT("mem alloc fail for data line", procName, 1); } for (i = 0; i < h; i++) { line = data + i * wpl; /* Gif's way of setting the raster line up for compression */ for (j = 0; j < w; j++) { switch(d) { case 8: gif_line[j] = GET_DATA_BYTE(line, j); break; case 4: gif_line[j] = GET_DATA_QBIT(line, j); break; case 2: gif_line[j] = GET_DATA_DIBIT(line, j); break; case 1: gif_line[j] = GET_DATA_BIT(line, j); break; } } /* Compress and save the line */ if (EGifPutLine(gif, gif_line, w) != GIF_OK) { FREE(gif_line); pixDestroy(&pixd); EGifCloseFile(gif); return ERROR_INT("failed to write data line into GIF", procName, 1); } } /* Write a text comment. This must be placed after writing the * data (!!) Note that because libgif does not provide a function * for reading comments from file, you will need another way * to read comments. */ if ((text = pixGetText(pix)) != NULL) { if (EGifPutComment(gif, text) != GIF_OK) L_WARNING("gif comment not written", procName); } FREE(gif_line); pixDestroy(&pixd); EGifCloseFile(gif); return 0; }
ColorMapObject *UnionColorMap( ColorMapObject *ColorIn1, ColorMapObject *ColorIn2, GifPixelType ColorTransIn2[]) /* * Compute the union of two given color maps and return it. If result can't * fit into 256 colors, NULL is returned, the allocated union otherwise. * ColorIn1 is copied as is to ColorUnion, while colors from ColorIn2 are * copied iff they didn't exist before. ColorTransIn2 maps the old * ColorIn2 into ColorUnion color map table. */ { int i, j, CrntSlot, RoundUpTo, NewBitSize; ColorMapObject *ColorUnion; /* * Allocate table which will hold the result for sure. */ ColorUnion = MakeMapObject(MAX(ColorIn1->ColorCount,ColorIn2->ColorCount)*2,NULL); if (ColorUnion == NULL) return(NULL); /* Copy ColorIn1 to ColorUnionSize; */ for (i = 0; i < ColorIn1->ColorCount; i++) ColorUnion->Colors[i] = ColorIn1->Colors[i]; CrntSlot = ColorIn1->ColorCount; /* * Potentially obnoxious hack: * * Back CrntSlot down past all contiguous {0, 0, 0} slots at the end * of table 1. This is very useful if your display is limited to * 16 colors. */ while (ColorIn1->Colors[CrntSlot-1].Red == 0 && ColorIn1->Colors[CrntSlot-1].Green == 0 && ColorIn1->Colors[CrntSlot-1].Red == 0) CrntSlot--; /* Copy ColorIn2 to ColorUnionSize (use old colors if they exist): */ for (i = 0; i < ColorIn2->ColorCount && CrntSlot<=256; i++) { /* Let's see if this color already exists: */ for (j = 0; j < ColorIn1->ColorCount; j++) if (memcmp(&ColorIn1->Colors[j], &ColorIn2->Colors[i], sizeof(GifColorType)) == 0) break; if (j < ColorIn1->ColorCount) ColorTransIn2[i] = j; /* color exists in Color1 */ else { /* Color is new - copy it to a new slot: */ ColorUnion->Colors[CrntSlot] = ColorIn2->Colors[i]; ColorTransIn2[i] = CrntSlot++; } } if (CrntSlot > 256) { FreeMapObject(ColorUnion); return((ColorMapObject *)NULL); } NewBitSize = BitSize(CrntSlot); RoundUpTo = (1 << NewBitSize); if (RoundUpTo != ColorUnion->ColorCount) { register GifColorType *Map = ColorUnion->Colors; /* * Zero out slots up to next power of 2. * We know these slots exist because of the way ColorUnion's * start dimension was computed. */ for (j = CrntSlot; j < RoundUpTo; j++) Map[j].Red = Map[j].Green = Map[j].Blue = 0; /* perhaps we can shrink the map? */ if (RoundUpTo < ColorUnion->ColorCount) ColorUnion->Colors = (GifColorType *)realloc(Map, sizeof(GifColorType)*RoundUpTo); } ColorUnion->ColorCount = RoundUpTo; ColorUnion->BitsPerPixel = NewBitSize; return(ColorUnion); }
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); }
/****************************************************************************** * This routine should be called before any attempt to read an image. * Note it is assumed the Image desc. header (',') has been read. *****************************************************************************/ static int DGifGetImageDesc(GifFileType * GifFile) { int i, BitsPerPixel, SortFlag; GifByteType Buf[3]; GifFilePrivateType *Private = GifFile->Private; SavedImage *sp; if (DGifGetWord(GifFile, &GifFile->Image.Left) == GIF_ERROR || DGifGetWord(GifFile, &GifFile->Image.Top) == GIF_ERROR || DGifGetWord(GifFile, &GifFile->Image.Width) == GIF_ERROR || DGifGetWord(GifFile, &GifFile->Image.Height) == GIF_ERROR) return GIF_ERROR; if (READ(GifFile, Buf, 1) != 1) { return GIF_ERROR; } BitsPerPixel = (Buf[0] & 0x07) + 1; SortFlag = (Buf[0] & 0x20) != 0; GifFile->Image.Interlace = (Buf[0] & 0x40); if (Buf[0] & 0x80) { /* Does this image have local color map? */ FreeMapObject(GifFile->Image.ColorMap); GifFile->Image.ColorMap = MakeMapObject(1 << BitsPerPixel, NULL); if (GifFile->Image.ColorMap == NULL) { return GIF_ERROR; } /* Get the image local color map: */ GifFile->Image.ColorMap->SortFlag = SortFlag; for (i = 0; i < GifFile->Image.ColorMap->ColorCount; i++) { if (READ(GifFile, Buf, 3) != 3) { FreeMapObject(GifFile->Image.ColorMap); GifFile->Image.ColorMap = NULL; return GIF_ERROR; } GifFile->Image.ColorMap->Colors[i].Red = Buf[0]; GifFile->Image.ColorMap->Colors[i].Green = Buf[1]; GifFile->Image.ColorMap->Colors[i].Blue = Buf[2]; } } else if (GifFile->Image.ColorMap) { FreeMapObject(GifFile->Image.ColorMap); GifFile->Image.ColorMap = NULL; } if (GifFile->SavedImages) { if ((GifFile->SavedImages = ungif_realloc(GifFile->SavedImages, sizeof(SavedImage) * (GifFile->ImageCount + 1))) == NULL) { return GIF_ERROR; } } else { if ((GifFile->SavedImages = ungif_alloc(sizeof(SavedImage))) == NULL) { return GIF_ERROR; } } sp = &GifFile->SavedImages[GifFile->ImageCount]; sp->ImageDesc = GifFile->Image; if (GifFile->Image.ColorMap != NULL) { sp->ImageDesc.ColorMap = MakeMapObject( GifFile->Image.ColorMap->ColorCount, GifFile->Image.ColorMap->Colors); if (sp->ImageDesc.ColorMap == NULL) { return GIF_ERROR; } sp->ImageDesc.ColorMap->SortFlag = GifFile->Image.ColorMap->SortFlag; } sp->RasterBits = NULL; sp->Extensions.ExtensionBlockCount = 0; sp->Extensions.ExtensionBlocks = NULL; GifFile->ImageCount++; Private->PixelCount = (long)GifFile->Image.Width * (long)GifFile->Image.Height; DGifSetupDecompress(GifFile); /* Reset decompress algorithm parameters. */ return GIF_OK; }
GDALDataset * GIFDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS, int bStrict, char ** papszOptions, GDALProgressFunc pfnProgress, void * pProgressData ) { int nBands = poSrcDS->GetRasterCount(); int nXSize = poSrcDS->GetRasterXSize(); int nYSize = poSrcDS->GetRasterYSize(); int bInterlace = FALSE; /* -------------------------------------------------------------------- */ /* Check for interlaced option. */ /* -------------------------------------------------------------------- */ bInterlace = CSLFetchBoolean(papszOptions, "INTERLACING", FALSE); /* -------------------------------------------------------------------- */ /* Some some rudimentary checks */ /* -------------------------------------------------------------------- */ if( nBands != 1 ) { CPLError( CE_Failure, CPLE_NotSupported, "GIF driver only supports one band images.\n" ); return NULL; } if (nXSize > 65535 || nYSize > 65535) { CPLError( CE_Failure, CPLE_NotSupported, "GIF driver only supports datasets up to 65535x65535 size.\n" ); return NULL; } if( poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte && bStrict ) { CPLError( CE_Failure, CPLE_NotSupported, "GIF driver doesn't support data type %s. " "Only eight bit bands supported.\n", GDALGetDataTypeName( poSrcDS->GetRasterBand(1)->GetRasterDataType()) ); return NULL; } /* -------------------------------------------------------------------- */ /* Open the output file. */ /* -------------------------------------------------------------------- */ GifFileType *hGifFile; VSILFILE *fp; fp = VSIFOpenL( pszFilename, "wb" ); if( fp == NULL ) { CPLError( CE_Failure, CPLE_OpenFailed, "Failed to create %s:\n%s", pszFilename, VSIStrerror( errno ) ); return NULL; } hGifFile = EGifOpen( fp, VSIGIFWriteFunc ); if( hGifFile == NULL ) { VSIFCloseL( fp ); CPLError( CE_Failure, CPLE_OpenFailed, "EGifOpenFilename(%s) failed. Does file already exist?", pszFilename ); return NULL; } /* -------------------------------------------------------------------- */ /* Prepare colortable. */ /* -------------------------------------------------------------------- */ GDALRasterBand *poBand = poSrcDS->GetRasterBand(1); ColorMapObject *psGifCT; int iColor; if( poBand->GetColorTable() == NULL ) { psGifCT = MakeMapObject( 256, NULL ); for( iColor = 0; iColor < 256; iColor++ ) { psGifCT->Colors[iColor].Red = (GifByteType) iColor; psGifCT->Colors[iColor].Green = (GifByteType) iColor; psGifCT->Colors[iColor].Blue = (GifByteType) iColor; } } else { GDALColorTable *poCT = poBand->GetColorTable(); int nFullCount = 1; while( nFullCount < poCT->GetColorEntryCount() ) nFullCount = nFullCount * 2; psGifCT = MakeMapObject( nFullCount, NULL ); for( iColor = 0; iColor < poCT->GetColorEntryCount(); iColor++ ) { GDALColorEntry sEntry; poCT->GetColorEntryAsRGB( iColor, &sEntry ); psGifCT->Colors[iColor].Red = (GifByteType) sEntry.c1; psGifCT->Colors[iColor].Green = (GifByteType) sEntry.c2; psGifCT->Colors[iColor].Blue = (GifByteType) sEntry.c3; } for( ; iColor < nFullCount; iColor++ ) { psGifCT->Colors[iColor].Red = 0; psGifCT->Colors[iColor].Green = 0; psGifCT->Colors[iColor].Blue = 0; } } /* -------------------------------------------------------------------- */ /* Setup parameters. */ /* -------------------------------------------------------------------- */ if (EGifPutScreenDesc(hGifFile, nXSize, nYSize, psGifCT->ColorCount, 255, psGifCT) == GIF_ERROR) { FreeMapObject(psGifCT); PrintGifError(); CPLError( CE_Failure, CPLE_AppDefined, "Error writing gif file." ); EGifCloseFile(hGifFile); VSIFCloseL( fp ); return NULL; } FreeMapObject(psGifCT); psGifCT = NULL; /* Support for transparency */ int bNoDataValue; double noDataValue = poBand->GetNoDataValue(&bNoDataValue); if (bNoDataValue && noDataValue >= 0 && noDataValue <= 255) { unsigned char extensionData[4]; extensionData[0] = 1; /* Transparent Color Flag */ extensionData[1] = 0; extensionData[2] = 0; extensionData[3] = (unsigned char)noDataValue; EGifPutExtension(hGifFile, 0xf9, 4, extensionData); } if (EGifPutImageDesc(hGifFile, 0, 0, nXSize, nYSize, bInterlace, NULL) == GIF_ERROR ) { PrintGifError(); CPLError( CE_Failure, CPLE_AppDefined, "Error writing gif file." ); EGifCloseFile(hGifFile); VSIFCloseL( fp ); return NULL; } /* -------------------------------------------------------------------- */ /* Loop over image, copying image data. */ /* -------------------------------------------------------------------- */ CPLErr eErr; GDALPamDataset *poDS; GByte *pabyScanline; pabyScanline = (GByte *) CPLMalloc( nXSize ); if( !pfnProgress( 0.0, NULL, pProgressData ) ) eErr = CE_Failure; if( !bInterlace ) { for( int iLine = 0; iLine < nYSize; iLine++ ) { eErr = poBand->RasterIO( GF_Read, 0, iLine, nXSize, 1, pabyScanline, nXSize, 1, GDT_Byte, nBands, nBands * nXSize ); if( eErr != CE_None || EGifPutLine( hGifFile, pabyScanline, nXSize ) == GIF_ERROR ) { CPLError( CE_Failure, CPLE_AppDefined, "Error writing gif file." ); goto error; } if( !pfnProgress( (iLine + 1) * 1.0 / nYSize, NULL, pProgressData ) ) { goto error; } } } else { int i, j; int nLinesRead = 0; int nLinesToRead = 0; for ( i = 0; i < 4; i++) { for (j = InterlacedOffset[i]; j < nYSize; j += InterlacedJumps[i]) { nLinesToRead ++; } } /* Need to perform 4 passes on the images: */ for ( i = 0; i < 4; i++) { for (j = InterlacedOffset[i]; j < nYSize; j += InterlacedJumps[i]) { eErr= poBand->RasterIO( GF_Read, 0, j, nXSize, 1, pabyScanline, nXSize, 1, GDT_Byte, 1, nXSize ); if (eErr != CE_None || EGifPutLine(hGifFile, pabyScanline, nXSize) == GIF_ERROR) { CPLError( CE_Failure, CPLE_AppDefined, "Error writing gif file." ); goto error; } nLinesRead ++; if( !pfnProgress( nLinesRead * 1.0 / nYSize, NULL, pProgressData ) ) { goto error; } } } } CPLFree( pabyScanline ); pabyScanline = NULL; /* -------------------------------------------------------------------- */ /* cleanup */ /* -------------------------------------------------------------------- */ if (EGifCloseFile(hGifFile) == GIF_ERROR) { CPLError( CE_Failure, CPLE_AppDefined, "EGifCloseFile() failed.\n" ); hGifFile = NULL; goto error; } hGifFile = NULL; VSIFCloseL( fp ); fp = NULL; /* -------------------------------------------------------------------- */ /* Do we need a world file? */ /* -------------------------------------------------------------------- */ if( CSLFetchBoolean( papszOptions, "WORLDFILE", FALSE ) ) { double adfGeoTransform[6]; if( poSrcDS->GetGeoTransform( adfGeoTransform ) == CE_None ) GDALWriteWorldFile( pszFilename, "wld", adfGeoTransform ); } /* -------------------------------------------------------------------- */ /* Re-open dataset, and copy any auxilary pam information. */ /* -------------------------------------------------------------------- */ /* If outputing to stdout, we can't reopen it, so we'll return */ /* a fake dataset to make the caller happy */ CPLPushErrorHandler(CPLQuietErrorHandler); poDS = (GDALPamDataset*) GDALOpen(pszFilename, GA_ReadOnly); CPLPopErrorHandler(); if (poDS) { poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT ); return poDS; } else { CPLErrorReset(); GIFDataset* poGIF_DS = new GIFDataset(); poGIF_DS->nRasterXSize = nXSize; poGIF_DS->nRasterYSize = nYSize; for(int i=0;i<nBands;i++) poGIF_DS->SetBand( i+1, new GIFRasterBand( poGIF_DS, i+1, NULL, 0 ) ); return poGIF_DS; } error: if (hGifFile) EGifCloseFile(hGifFile); if (fp) VSIFCloseL( fp ); if (pabyScanline) CPLFree( pabyScanline ); return NULL; }