summaryrefslogtreecommitdiffstats
path: root/gifalloc.c
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:29:32 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:29:32 -0800
commitc2eacaec90baee57fdbbdbad935d161638894ee7 (patch)
tree93693412a6d49782f7bf07ac44fba0b6d15575e8 /gifalloc.c
parentf015ec9ad03a8c22f423638c5338da0a185c5235 (diff)
downloadandroid_external_giflib-c2eacaec90baee57fdbbdbad935d161638894ee7.tar.gz
android_external_giflib-c2eacaec90baee57fdbbdbad935d161638894ee7.tar.bz2
android_external_giflib-c2eacaec90baee57fdbbdbad935d161638894ee7.zip
auto import from //depot/cupcake/@135843
Diffstat (limited to 'gifalloc.c')
-rw-r--r--gifalloc.c443
1 files changed, 443 insertions, 0 deletions
diff --git a/gifalloc.c b/gifalloc.c
new file mode 100644
index 0000000..79d2332
--- /dev/null
+++ b/gifalloc.c
@@ -0,0 +1,443 @@
+/*****************************************************************************
+ * "Gif-Lib" - Yet another gif library.
+ *
+ * Written by: Gershon Elber Ver 0.1, Jun. 1989
+ * Extensively hacked by: Eric S. Raymond Ver 1.?, Sep 1992
+ *****************************************************************************
+ * GIF construction tools
+ *****************************************************************************
+ * History:
+ * 15 Sep 92 - Version 1.0 by Eric Raymond.
+ ****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "gif_lib.h"
+
+#define MAX(x, y) (((x) > (y)) ? (x) : (y))
+
+/******************************************************************************
+ * Miscellaneous utility functions
+ *****************************************************************************/
+
+/* return smallest bitfield size n will fit in */
+int
+BitSize(int n) {
+
+ register int i;
+
+ for (i = 1; i <= 8; i++)
+ if ((1 << i) >= n)
+ break;
+ return (i);
+}
+
+/******************************************************************************
+ * Color map object functions
+ *****************************************************************************/
+
+/*
+ * Allocate a color map of given size; initialize with contents of
+ * ColorMap if that pointer is non-NULL.
+ */
+ColorMapObject *
+MakeMapObject(int ColorCount,
+ const GifColorType * ColorMap) {
+
+ ColorMapObject *Object;
+
+ /*** FIXME: Our ColorCount has to be a power of two. Is it necessary to
+ * make the user know that or should we automatically round up instead? */
+ if (ColorCount != (1 << BitSize(ColorCount))) {
+ return ((ColorMapObject *) NULL);
+ }
+
+ Object = (ColorMapObject *)malloc(sizeof(ColorMapObject));
+ if (Object == (ColorMapObject *) NULL) {
+ return ((ColorMapObject *) NULL);
+ }
+
+ Object->Colors = (GifColorType *)calloc(ColorCount, sizeof(GifColorType));
+ if (Object->Colors == (GifColorType *) NULL) {
+ return ((ColorMapObject *) NULL);
+ }
+
+ Object->ColorCount = ColorCount;
+ Object->BitsPerPixel = BitSize(ColorCount);
+
+ if (ColorMap) {
+ memcpy((char *)Object->Colors,
+ (char *)ColorMap, ColorCount * sizeof(GifColorType));
+ }
+
+ return (Object);
+}
+
+/*
+ * Free a color map object
+ */
+void
+FreeMapObject(ColorMapObject * Object) {
+
+ if (Object != NULL) {
+ free(Object->Colors);
+ free(Object);
+ /*** FIXME:
+ * When we are willing to break API we need to make this function
+ * FreeMapObject(ColorMapObject **Object)
+ * and do this assignment to NULL here:
+ * *Object = NULL;
+ */
+ }
+}
+
+#ifdef DEBUG
+void
+DumpColorMap(ColorMapObject * Object,
+ FILE * fp) {
+
+ if (Object) {
+ int i, j, Len = Object->ColorCount;
+
+ for (i = 0; i < Len; i += 4) {
+ for (j = 0; j < 4 && j < Len; j++) {
+ fprintf(fp, "%3d: %02x %02x %02x ", i + j,
+ Object->Colors[i + j].Red,
+ Object->Colors[i + j].Green,
+ Object->Colors[i + j].Blue);
+ }
+ fprintf(fp, "\n");
+ }
+ }
+}
+#endif /* DEBUG */
+
+/*
+ * 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 != 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);
+}
+
+/*
+ * Apply a given color translation to the raster bits of an image
+ */
+void
+ApplyTranslation(SavedImage * Image,
+ GifPixelType Translation[]) {
+
+ register int i;
+ register int RasterSize = Image->ImageDesc.Height * Image->ImageDesc.Width;
+
+ for (i = 0; i < RasterSize; i++)
+ Image->RasterBits[i] = Translation[Image->RasterBits[i]];
+}
+
+/******************************************************************************
+ * Extension record functions
+ *****************************************************************************/
+
+void
+MakeExtension(SavedImage * New,
+ int Function) {
+
+ New->Function = Function;
+ /*** FIXME:
+ * Someday we might have to deal with multiple extensions.
+ * ??? Was this a note from Gershon or from me? Does the multiple
+ * extension blocks solve this or do we need multiple Functions? Or is
+ * this an obsolete function? (People should use AddExtensionBlock
+ * instead?)
+ * Looks like AddExtensionBlock needs to take the int Function argument
+ * then it can take the place of this function. Right now people have to
+ * use both. Fix AddExtensionBlock and add this to the deprecation list.
+ */
+}
+
+int
+AddExtensionBlock(SavedImage * New,
+ int Len,
+ unsigned char ExtData[]) {
+
+ ExtensionBlock *ep;
+
+ if (New->ExtensionBlocks == NULL)
+ New->ExtensionBlocks=(ExtensionBlock *)malloc(sizeof(ExtensionBlock));
+ else
+ New->ExtensionBlocks = (ExtensionBlock *)realloc(New->ExtensionBlocks,
+ sizeof(ExtensionBlock) *
+ (New->ExtensionBlockCount + 1));
+
+ if (New->ExtensionBlocks == NULL)
+ return (GIF_ERROR);
+
+ ep = &New->ExtensionBlocks[New->ExtensionBlockCount++];
+
+ ep->ByteCount=Len;
+ ep->Bytes = (char *)malloc(ep->ByteCount);
+ if (ep->Bytes == NULL)
+ return (GIF_ERROR);
+
+ if (ExtData) {
+ memcpy(ep->Bytes, ExtData, Len);
+ ep->Function = New->Function;
+ }
+
+ return (GIF_OK);
+}
+
+void
+FreeExtension(SavedImage * Image)
+{
+ ExtensionBlock *ep;
+
+ if ((Image == NULL) || (Image->ExtensionBlocks == NULL)) {
+ return;
+ }
+ for (ep = Image->ExtensionBlocks;
+ ep < (Image->ExtensionBlocks + Image->ExtensionBlockCount); ep++)
+ (void)free((char *)ep->Bytes);
+ free((char *)Image->ExtensionBlocks);
+ Image->ExtensionBlocks = NULL;
+}
+
+/******************************************************************************
+ * Image block allocation functions
+******************************************************************************/
+
+/* Private Function:
+ * Frees the last image in the GifFile->SavedImages array
+ */
+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.
+ */
+}
+
+/*
+ * Append an image block to the SavedImages array
+ */
+SavedImage *
+MakeSavedImage(GifFileType * GifFile,
+ const SavedImage * CopyFrom) {
+
+ SavedImage *sp;
+
+ if (GifFile->SavedImages == NULL)
+ GifFile->SavedImages = (SavedImage *)malloc(sizeof(SavedImage));
+ else
+ GifFile->SavedImages = (SavedImage *)realloc(GifFile->SavedImages,
+ sizeof(SavedImage) * (GifFile->ImageCount + 1));
+
+ if (GifFile->SavedImages == NULL)
+ return ((SavedImage *)NULL);
+ else {
+ sp = &GifFile->SavedImages[GifFile->ImageCount++];
+ memset((char *)sp, '\0', sizeof(SavedImage));
+
+ if (CopyFrom) {
+ memcpy((char *)sp, CopyFrom, sizeof(SavedImage));
+
+ /*
+ * Make our own allocated copies of the heap fields in the
+ * copied record. This guards against potential aliasing
+ * problems.
+ */
+
+ /* first, the local color map */
+ if (sp->ImageDesc.ColorMap) {
+ sp->ImageDesc.ColorMap = MakeMapObject(
+ CopyFrom->ImageDesc.ColorMap->ColorCount,
+ CopyFrom->ImageDesc.ColorMap->Colors);
+ if (sp->ImageDesc.ColorMap == NULL) {
+ FreeLastSavedImage(GifFile);
+ return (SavedImage *)(NULL);
+ }
+ }
+
+ /* next, the raster */
+ sp->RasterBits = (unsigned char *)malloc(sizeof(GifPixelType) *
+ CopyFrom->ImageDesc.Height *
+ CopyFrom->ImageDesc.Width);
+ if (sp->RasterBits == NULL) {
+ FreeLastSavedImage(GifFile);
+ return (SavedImage *)(NULL);
+ }
+ memcpy(sp->RasterBits, CopyFrom->RasterBits,
+ sizeof(GifPixelType) * CopyFrom->ImageDesc.Height *
+ CopyFrom->ImageDesc.Width);
+
+ /* finally, the extension blocks */
+ if (sp->ExtensionBlocks) {
+ sp->ExtensionBlocks = (ExtensionBlock *)malloc(
+ sizeof(ExtensionBlock) *
+ CopyFrom->ExtensionBlockCount);
+ if (sp->ExtensionBlocks == NULL) {
+ FreeLastSavedImage(GifFile);
+ return (SavedImage *)(NULL);
+ }
+ memcpy(sp->ExtensionBlocks, CopyFrom->ExtensionBlocks,
+ sizeof(ExtensionBlock) * CopyFrom->ExtensionBlockCount);
+
+ /*
+ * For the moment, the actual blocks can take their
+ * chances with free(). We'll fix this later.
+ *** FIXME: [Better check this out... Toshio]
+ * 2004 May 27: Looks like this was an ESR note.
+ * It means the blocks are shallow copied from InFile to
+ * OutFile. However, I don't see that in this code....
+ * Did ESR fix it but never remove this note (And other notes
+ * in gifspnge?)
+ */
+ }
+ }
+
+ return (sp);
+ }
+}
+
+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)
+ free((char *)sp->RasterBits);
+
+ if (sp->ExtensionBlocks)
+ FreeExtension(sp);
+ }
+ free((char *)GifFile->SavedImages);
+ GifFile->SavedImages=NULL;
+}