Home | History | Annotate | Download | only in giflib
      1 /*****************************************************************************
      2  *   "Gif-Lib" - Yet another gif library.
      3  *
      4  * Written by:  Gershon Elber                Ver 0.1, Jun. 1989
      5  * Extensively hacked by: Eric S. Raymond        Ver 1.?, Sep 1992
      6  *****************************************************************************
      7  * GIF construction tools
      8  *****************************************************************************
      9  * History:
     10  * 15 Sep 92 - Version 1.0 by Eric Raymond.
     11  ****************************************************************************/
     12 
     13 #ifdef HAVE_CONFIG_H
     14 #include <config.h>
     15 #endif
     16 
     17 #include <stdlib.h>
     18 #include <stdio.h>
     19 #include <string.h>
     20 #include "gif_lib.h"
     21 
     22 #define MAX(x, y)    (((x) > (y)) ? (x) : (y))
     23 
     24 /******************************************************************************
     25  * Miscellaneous utility functions
     26  *****************************************************************************/
     27 
     28 /* return smallest bitfield size n will fit in */
     29 int
     30 BitSize(int n) {
     31 
     32     register int i;
     33 
     34     for (i = 1; i <= 8; i++)
     35         if ((1 << i) >= n)
     36             break;
     37     return (i);
     38 }
     39 
     40 /******************************************************************************
     41  * Color map object functions
     42  *****************************************************************************/
     43 
     44 /*
     45  * Allocate a color map of given size; initialize with contents of
     46  * ColorMap if that pointer is non-NULL.
     47  */
     48 ColorMapObject *
     49 MakeMapObject(int ColorCount,
     50               const GifColorType * ColorMap) {
     51 
     52     ColorMapObject *Object;
     53 
     54     /*** FIXME: Our ColorCount has to be a power of two.  Is it necessary to
     55      * make the user know that or should we automatically round up instead? */
     56     if (ColorCount != (1 << BitSize(ColorCount))) {
     57         return ((ColorMapObject *) NULL);
     58     }
     59 
     60     Object = (ColorMapObject *)malloc(sizeof(ColorMapObject));
     61     if (Object == (ColorMapObject *) NULL) {
     62         return ((ColorMapObject *) NULL);
     63     }
     64 
     65     Object->Colors = (GifColorType *)calloc(ColorCount, sizeof(GifColorType));
     66     if (Object->Colors == (GifColorType *) NULL) {
     67         return ((ColorMapObject *) NULL);
     68     }
     69 
     70     Object->ColorCount = ColorCount;
     71     Object->BitsPerPixel = BitSize(ColorCount);
     72 
     73     if (ColorMap) {
     74         memcpy((char *)Object->Colors,
     75                (char *)ColorMap, ColorCount * sizeof(GifColorType));
     76     }
     77 
     78     return (Object);
     79 }
     80 
     81 /*
     82  * Free a color map object
     83  */
     84 void
     85 FreeMapObject(ColorMapObject * Object) {
     86 
     87     if (Object != NULL) {
     88         free(Object->Colors);
     89         free(Object);
     90         /*** FIXME:
     91          * When we are willing to break API we need to make this function
     92          * FreeMapObject(ColorMapObject **Object)
     93          * and do this assignment to NULL here:
     94          * *Object = NULL;
     95          */
     96     }
     97 }
     98 
     99 #ifdef DEBUG
    100 void
    101 DumpColorMap(ColorMapObject * Object,
    102              FILE * fp) {
    103 
    104     if (Object) {
    105         int i, j, Len = Object->ColorCount;
    106 
    107         for (i = 0; i < Len; i += 4) {
    108             for (j = 0; j < 4 && j < Len; j++) {
    109                 fprintf(fp, "%3d: %02x %02x %02x   ", i + j,
    110                         Object->Colors[i + j].Red,
    111                         Object->Colors[i + j].Green,
    112                         Object->Colors[i + j].Blue);
    113             }
    114             fprintf(fp, "\n");
    115         }
    116     }
    117 }
    118 #endif /* DEBUG */
    119 
    120 /*
    121  * Compute the union of two given color maps and return it.  If result can't
    122  * fit into 256 colors, NULL is returned, the allocated union otherwise.
    123  * ColorIn1 is copied as is to ColorUnion, while colors from ColorIn2 are
    124  * copied iff they didn't exist before.  ColorTransIn2 maps the old
    125  * ColorIn2 into ColorUnion color map table.
    126  */
    127 ColorMapObject *
    128 UnionColorMap(const ColorMapObject * ColorIn1,
    129               const ColorMapObject * ColorIn2,
    130               GifPixelType ColorTransIn2[]) {
    131 
    132     int i, j, CrntSlot, RoundUpTo, NewBitSize;
    133     ColorMapObject *ColorUnion;
    134 
    135     /*
    136      * Allocate table which will hold the result for sure.
    137      */
    138     ColorUnion = MakeMapObject(MAX(ColorIn1->ColorCount,
    139                                ColorIn2->ColorCount) * 2, NULL);
    140 
    141     if (ColorUnion == NULL)
    142         return (NULL);
    143 
    144     /* Copy ColorIn1 to ColorUnionSize; */
    145     /*** FIXME: What if there are duplicate entries into the colormap to begin
    146      * with? */
    147     for (i = 0; i < ColorIn1->ColorCount; i++)
    148         ColorUnion->Colors[i] = ColorIn1->Colors[i];
    149     CrntSlot = ColorIn1->ColorCount;
    150 
    151     /*
    152      * Potentially obnoxious hack:
    153      *
    154      * Back CrntSlot down past all contiguous {0, 0, 0} slots at the end
    155      * of table 1.  This is very useful if your display is limited to
    156      * 16 colors.
    157      */
    158     while (ColorIn1->Colors[CrntSlot - 1].Red == 0
    159            && ColorIn1->Colors[CrntSlot - 1].Green == 0
    160            && ColorIn1->Colors[CrntSlot - 1].Blue == 0)
    161         CrntSlot--;
    162 
    163     /* Copy ColorIn2 to ColorUnionSize (use old colors if they exist): */
    164     for (i = 0; i < ColorIn2->ColorCount && CrntSlot <= 256; i++) {
    165         /* Let's see if this color already exists: */
    166         /*** FIXME: Will it ever occur that ColorIn2 will contain duplicate
    167          * entries?  So we should search from 0 to CrntSlot rather than
    168          * ColorIn1->ColorCount?
    169          */
    170         for (j = 0; j < ColorIn1->ColorCount; j++)
    171             if (memcmp (&ColorIn1->Colors[j], &ColorIn2->Colors[i],
    172                         sizeof(GifColorType)) == 0)
    173                 break;
    174 
    175         if (j < ColorIn1->ColorCount)
    176             ColorTransIn2[i] = j;    /* color exists in Color1 */
    177         else {
    178             /* Color is new - copy it to a new slot: */
    179             ColorUnion->Colors[CrntSlot] = ColorIn2->Colors[i];
    180             ColorTransIn2[i] = CrntSlot++;
    181         }
    182     }
    183 
    184     if (CrntSlot > 256) {
    185         FreeMapObject(ColorUnion);
    186         return ((ColorMapObject *) NULL);
    187     }
    188 
    189     NewBitSize = BitSize(CrntSlot);
    190     RoundUpTo = (1 << NewBitSize);
    191 
    192     if (RoundUpTo != ColorUnion->ColorCount) {
    193         register GifColorType *Map = ColorUnion->Colors;
    194 
    195         /*
    196          * Zero out slots up to next power of 2.
    197          * We know these slots exist because of the way ColorUnion's
    198          * start dimension was computed.
    199          */
    200         for (j = CrntSlot; j < RoundUpTo; j++)
    201             Map[j].Red = Map[j].Green = Map[j].Blue = 0;
    202 
    203         /* perhaps we can shrink the map? */
    204         if (RoundUpTo < ColorUnion->ColorCount)
    205             ColorUnion->Colors = (GifColorType *)realloc(Map,
    206                                  sizeof(GifColorType) * RoundUpTo);
    207     }
    208 
    209     ColorUnion->ColorCount = RoundUpTo;
    210     ColorUnion->BitsPerPixel = NewBitSize;
    211 
    212     return (ColorUnion);
    213 }
    214 
    215 /*
    216  * Apply a given color translation to the raster bits of an image
    217  */
    218 void
    219 ApplyTranslation(SavedImage * Image,
    220                  GifPixelType Translation[]) {
    221 
    222     register int i;
    223     register int RasterSize = Image->ImageDesc.Height * Image->ImageDesc.Width;
    224 
    225     for (i = 0; i < RasterSize; i++)
    226         Image->RasterBits[i] = Translation[Image->RasterBits[i]];
    227 }
    228 
    229 /******************************************************************************
    230  * Extension record functions
    231  *****************************************************************************/
    232 
    233 void
    234 MakeExtension(SavedImage * New,
    235               int Function) {
    236 
    237     New->Function = Function;
    238     /*** FIXME:
    239      * Someday we might have to deal with multiple extensions.
    240      * ??? Was this a note from Gershon or from me?  Does the multiple
    241      * extension blocks solve this or do we need multiple Functions?  Or is
    242      * this an obsolete function?  (People should use AddExtensionBlock
    243      * instead?)
    244      * Looks like AddExtensionBlock needs to take the int Function argument
    245      * then it can take the place of this function.  Right now people have to
    246      * use both.  Fix AddExtensionBlock and add this to the deprecation list.
    247      */
    248 }
    249 
    250 int
    251 AddExtensionBlock(SavedImage * New,
    252                   int Len,
    253                   unsigned char ExtData[]) {
    254 
    255     ExtensionBlock *ep;
    256 
    257     if (New->ExtensionBlocks == NULL)
    258         New->ExtensionBlocks=(ExtensionBlock *)malloc(sizeof(ExtensionBlock));
    259     else
    260         New->ExtensionBlocks = (ExtensionBlock *)realloc(New->ExtensionBlocks,
    261                                       sizeof(ExtensionBlock) *
    262                                       (New->ExtensionBlockCount + 1));
    263 
    264     if (New->ExtensionBlocks == NULL)
    265         return (GIF_ERROR);
    266 
    267     ep = &New->ExtensionBlocks[New->ExtensionBlockCount++];
    268 
    269     ep->ByteCount=Len;
    270     ep->Bytes = (char *)malloc(ep->ByteCount);
    271     if (ep->Bytes == NULL)
    272         return (GIF_ERROR);
    273 
    274     if (ExtData) {
    275         memcpy(ep->Bytes, ExtData, Len);
    276         ep->Function = New->Function;
    277     }
    278 
    279     return (GIF_OK);
    280 }
    281 
    282 void
    283 FreeExtension(SavedImage * Image)
    284 {
    285     ExtensionBlock *ep;
    286 
    287     if ((Image == NULL) || (Image->ExtensionBlocks == NULL)) {
    288         return;
    289     }
    290     for (ep = Image->ExtensionBlocks;
    291          ep < (Image->ExtensionBlocks + Image->ExtensionBlockCount); ep++)
    292         (void)free((char *)ep->Bytes);
    293     free((char *)Image->ExtensionBlocks);
    294     Image->ExtensionBlocks = NULL;
    295 }
    296 
    297 /******************************************************************************
    298  * Image block allocation functions
    299 ******************************************************************************/
    300 
    301 /* Private Function:
    302  * Frees the last image in the GifFile->SavedImages array
    303  */
    304 void
    305 FreeLastSavedImage(GifFileType *GifFile) {
    306 
    307     SavedImage *sp;
    308 
    309     if ((GifFile == NULL) || (GifFile->SavedImages == NULL))
    310         return;
    311 
    312     /* Remove one SavedImage from the GifFile */
    313     GifFile->ImageCount--;
    314     sp = &GifFile->SavedImages[GifFile->ImageCount];
    315 
    316     /* Deallocate its Colormap */
    317     if (sp->ImageDesc.ColorMap) {
    318         FreeMapObject(sp->ImageDesc.ColorMap);
    319         sp->ImageDesc.ColorMap = NULL;
    320     }
    321 
    322     /* Deallocate the image data */
    323     if (sp->RasterBits)
    324         free((char *)sp->RasterBits);
    325 
    326     /* Deallocate any extensions */
    327     if (sp->ExtensionBlocks)
    328         FreeExtension(sp);
    329 
    330     /*** FIXME: We could realloc the GifFile->SavedImages structure but is
    331      * there a point to it? Saves some memory but we'd have to do it every
    332      * time.  If this is used in FreeSavedImages then it would be inefficient
    333      * (The whole array is going to be deallocated.)  If we just use it when
    334      * we want to free the last Image it's convenient to do it here.
    335      */
    336 }
    337 
    338 /*
    339  * Append an image block to the SavedImages array
    340  */
    341 SavedImage *
    342 MakeSavedImage(GifFileType * GifFile,
    343                const SavedImage * CopyFrom) {
    344 
    345     SavedImage *sp;
    346 
    347     if (GifFile->SavedImages == NULL)
    348         GifFile->SavedImages = (SavedImage *)malloc(sizeof(SavedImage));
    349     else
    350         GifFile->SavedImages = (SavedImage *)realloc(GifFile->SavedImages,
    351                                sizeof(SavedImage) * (GifFile->ImageCount + 1));
    352 
    353     if (GifFile->SavedImages == NULL)
    354         return ((SavedImage *)NULL);
    355     else {
    356         sp = &GifFile->SavedImages[GifFile->ImageCount++];
    357         memset((char *)sp, '\0', sizeof(SavedImage));
    358 
    359         if (CopyFrom) {
    360             memcpy((char *)sp, CopyFrom, sizeof(SavedImage));
    361 
    362             /*
    363              * Make our own allocated copies of the heap fields in the
    364              * copied record.  This guards against potential aliasing
    365              * problems.
    366              */
    367 
    368             /* first, the local color map */
    369             if (sp->ImageDesc.ColorMap) {
    370                 sp->ImageDesc.ColorMap = MakeMapObject(
    371                                          CopyFrom->ImageDesc.ColorMap->ColorCount,
    372                                          CopyFrom->ImageDesc.ColorMap->Colors);
    373                 if (sp->ImageDesc.ColorMap == NULL) {
    374                     FreeLastSavedImage(GifFile);
    375                     return (SavedImage *)(NULL);
    376                 }
    377             }
    378 
    379             /* next, the raster */
    380             sp->RasterBits = (unsigned char *)malloc(sizeof(GifPixelType) *
    381                                                    CopyFrom->ImageDesc.Height *
    382                                                    CopyFrom->ImageDesc.Width);
    383             if (sp->RasterBits == NULL) {
    384                 FreeLastSavedImage(GifFile);
    385                 return (SavedImage *)(NULL);
    386             }
    387             memcpy(sp->RasterBits, CopyFrom->RasterBits,
    388                    sizeof(GifPixelType) * CopyFrom->ImageDesc.Height *
    389                    CopyFrom->ImageDesc.Width);
    390 
    391             /* finally, the extension blocks */
    392             if (sp->ExtensionBlocks) {
    393                 sp->ExtensionBlocks = (ExtensionBlock *)malloc(
    394                                       sizeof(ExtensionBlock) *
    395                                       CopyFrom->ExtensionBlockCount);
    396                 if (sp->ExtensionBlocks == NULL) {
    397                     FreeLastSavedImage(GifFile);
    398                     return (SavedImage *)(NULL);
    399                 }
    400                 memcpy(sp->ExtensionBlocks, CopyFrom->ExtensionBlocks,
    401                        sizeof(ExtensionBlock) * CopyFrom->ExtensionBlockCount);
    402 
    403                 /*
    404                  * For the moment, the actual blocks can take their
    405                  * chances with free().  We'll fix this later.
    406                  *** FIXME: [Better check this out... Toshio]
    407                  * 2004 May 27: Looks like this was an ESR note.
    408                  * It means the blocks are shallow copied from InFile to
    409                  * OutFile.  However, I don't see that in this code....
    410                  * Did ESR fix it but never remove this note (And other notes
    411                  * in gifspnge?)
    412                  */
    413             }
    414         }
    415 
    416         return (sp);
    417     }
    418 }
    419 
    420 void
    421 FreeSavedImages(GifFileType * GifFile) {
    422 
    423     SavedImage *sp;
    424 
    425     if ((GifFile == NULL) || (GifFile->SavedImages == NULL)) {
    426         return;
    427     }
    428     for (sp = GifFile->SavedImages;
    429          sp < GifFile->SavedImages + GifFile->ImageCount; sp++) {
    430         if (sp->ImageDesc.ColorMap) {
    431             FreeMapObject(sp->ImageDesc.ColorMap);
    432             sp->ImageDesc.ColorMap = NULL;
    433         }
    434 
    435         if (sp->RasterBits)
    436             free((char *)sp->RasterBits);
    437 
    438         if (sp->ExtensionBlocks)
    439             FreeExtension(sp);
    440     }
    441     free((char *)GifFile->SavedImages);
    442     GifFile->SavedImages=NULL;
    443 }
    444