Home | History | Annotate | Download | only in giflib
      1 /*****************************************************************************
      2 
      3  GIF construction tools
      4 
      5 ****************************************************************************/
      6 
      7 #include <stdlib.h>
      8 #include <stdio.h>
      9 #include <string.h>
     10 
     11 #include "gif_lib.h"
     12 
     13 #define MAX(x, y)    (((x) > (y)) ? (x) : (y))
     14 
     15 /******************************************************************************
     16  Miscellaneous utility functions
     17 ******************************************************************************/
     18 
     19 /* return smallest bitfield size n will fit in */
     20 int
     21 GifBitSize(int n)
     22 {
     23     register int i;
     24 
     25     for (i = 1; i <= 8; i++)
     26         if ((1 << i) >= n)
     27             break;
     28     return (i);
     29 }
     30 
     31 /******************************************************************************
     32   Color map object functions
     33 ******************************************************************************/
     34 
     35 /*
     36  * Allocate a color map of given size; initialize with contents of
     37  * ColorMap if that pointer is non-NULL.
     38  */
     39 ColorMapObject *
     40 GifMakeMapObject(int ColorCount, const GifColorType *ColorMap)
     41 {
     42     ColorMapObject *Object;
     43 
     44     /*** FIXME: Our ColorCount has to be a power of two.  Is it necessary to
     45      * make the user know that or should we automatically round up instead? */
     46     if (ColorCount != (1 << GifBitSize(ColorCount))) {
     47         return ((ColorMapObject *) NULL);
     48     }
     49 
     50     Object = (ColorMapObject *)malloc(sizeof(ColorMapObject));
     51     if (Object == (ColorMapObject *) NULL) {
     52         return ((ColorMapObject *) NULL);
     53     }
     54 
     55     Object->Colors = (GifColorType *)calloc(ColorCount, sizeof(GifColorType));
     56     if (Object->Colors == (GifColorType *) NULL) {
     57 	free(Object);
     58         return ((ColorMapObject *) NULL);
     59     }
     60 
     61     Object->ColorCount = ColorCount;
     62     Object->BitsPerPixel = GifBitSize(ColorCount);
     63 
     64     if (ColorMap != NULL) {
     65         memcpy((char *)Object->Colors,
     66                (char *)ColorMap, ColorCount * sizeof(GifColorType));
     67     }
     68 
     69     return (Object);
     70 }
     71 
     72 /*******************************************************************************
     73 Free a color map object
     74 *******************************************************************************/
     75 void
     76 GifFreeMapObject(ColorMapObject *Object)
     77 {
     78     if (Object != NULL) {
     79         (void)free(Object->Colors);
     80         (void)free(Object);
     81     }
     82 }
     83 
     84 #ifdef DEBUG
     85 void
     86 DumpColorMap(ColorMapObject *Object,
     87              FILE * fp)
     88 {
     89     if (Object != NULL) {
     90         int i, j, Len = Object->ColorCount;
     91 
     92         for (i = 0; i < Len; i += 4) {
     93             for (j = 0; j < 4 && j < Len; j++) {
     94                 (void)fprintf(fp, "%3d: %02x %02x %02x   ", i + j,
     95 			      Object->Colors[i + j].Red,
     96 			      Object->Colors[i + j].Green,
     97 			      Object->Colors[i + j].Blue);
     98             }
     99             (void)fprintf(fp, "\n");
    100         }
    101     }
    102 }
    103 #endif /* DEBUG */
    104 
    105 /*******************************************************************************
    106  Compute the union of two given color maps and return it.  If result can't
    107  fit into 256 colors, NULL is returned, the allocated union otherwise.
    108  ColorIn1 is copied as is to ColorUnion, while colors from ColorIn2 are
    109  copied iff they didn't exist before.  ColorTransIn2 maps the old
    110  ColorIn2 into the ColorUnion color map table./
    111 *******************************************************************************/
    112 ColorMapObject *
    113 GifUnionColorMap(const ColorMapObject *ColorIn1,
    114               const ColorMapObject *ColorIn2,
    115               GifPixelType ColorTransIn2[])
    116 {
    117     int i, j, CrntSlot, RoundUpTo, NewGifBitSize;
    118     ColorMapObject *ColorUnion;
    119 
    120     /*
    121      * We don't worry about duplicates within either color map; if
    122      * the caller wants to resolve those, he can perform unions
    123      * with an empty color map.
    124      */
    125 
    126     /* Allocate table which will hold the result for sure. */
    127     ColorUnion = GifMakeMapObject(MAX(ColorIn1->ColorCount,
    128                                ColorIn2->ColorCount) * 2, NULL);
    129 
    130     if (ColorUnion == NULL)
    131         return (NULL);
    132 
    133     /*
    134      * Copy ColorIn1 to ColorUnion.
    135      */
    136     for (i = 0; i < ColorIn1->ColorCount; i++)
    137         ColorUnion->Colors[i] = ColorIn1->Colors[i];
    138     CrntSlot = ColorIn1->ColorCount;
    139 
    140     /*
    141      * Potentially obnoxious hack:
    142      *
    143      * Back CrntSlot down past all contiguous {0, 0, 0} slots at the end
    144      * of table 1.  This is very useful if your display is limited to
    145      * 16 colors.
    146      */
    147     while (ColorIn1->Colors[CrntSlot - 1].Red == 0
    148            && ColorIn1->Colors[CrntSlot - 1].Green == 0
    149            && ColorIn1->Colors[CrntSlot - 1].Blue == 0)
    150         CrntSlot--;
    151 
    152     /* Copy ColorIn2 to ColorUnion (use old colors if they exist): */
    153     for (i = 0; i < ColorIn2->ColorCount && CrntSlot <= 256; i++) {
    154         /* Let's see if this color already exists: */
    155         for (j = 0; j < ColorIn1->ColorCount; j++)
    156             if (memcmp (&ColorIn1->Colors[j], &ColorIn2->Colors[i],
    157                         sizeof(GifColorType)) == 0)
    158                 break;
    159 
    160         if (j < ColorIn1->ColorCount)
    161             ColorTransIn2[i] = j;    /* color exists in Color1 */
    162         else {
    163             /* Color is new - copy it to a new slot: */
    164             ColorUnion->Colors[CrntSlot] = ColorIn2->Colors[i];
    165             ColorTransIn2[i] = CrntSlot++;
    166         }
    167     }
    168 
    169     if (CrntSlot > 256) {
    170         GifFreeMapObject(ColorUnion);
    171         return ((ColorMapObject *) NULL);
    172     }
    173 
    174     NewGifBitSize = GifBitSize(CrntSlot);
    175     RoundUpTo = (1 << NewGifBitSize);
    176 
    177     if (RoundUpTo != ColorUnion->ColorCount) {
    178         register GifColorType *Map = ColorUnion->Colors;
    179 
    180         /*
    181          * Zero out slots up to next power of 2.
    182          * We know these slots exist because of the way ColorUnion's
    183          * start dimension was computed.
    184          */
    185         for (j = CrntSlot; j < RoundUpTo; j++)
    186             Map[j].Red = Map[j].Green = Map[j].Blue = 0;
    187 
    188         /* perhaps we can shrink the map? */
    189         if (RoundUpTo < ColorUnion->ColorCount)
    190             ColorUnion->Colors = (GifColorType *)realloc(Map,
    191                                  sizeof(GifColorType) * RoundUpTo);
    192     }
    193 
    194     ColorUnion->ColorCount = RoundUpTo;
    195     ColorUnion->BitsPerPixel = NewGifBitSize;
    196 
    197     return (ColorUnion);
    198 }
    199 
    200 /*******************************************************************************
    201  Apply a given color translation to the raster bits of an image
    202 *******************************************************************************/
    203 void
    204 GifApplyTranslation(SavedImage *Image, GifPixelType Translation[])
    205 {
    206     register int i;
    207     register int RasterSize = Image->ImageDesc.Height * Image->ImageDesc.Width;
    208 
    209     for (i = 0; i < RasterSize; i++)
    210         Image->RasterBits[i] = Translation[Image->RasterBits[i]];
    211 }
    212 
    213 /******************************************************************************
    214  Extension record functions
    215 ******************************************************************************/
    216 int
    217 GifAddExtensionBlock(int *ExtensionBlockCount,
    218 		     ExtensionBlock **ExtensionBlocks,
    219 		     int Function,
    220 		     unsigned int Len,
    221 		     unsigned char ExtData[])
    222 {
    223     ExtensionBlock *ep;
    224 
    225     if (*ExtensionBlocks == NULL)
    226         *ExtensionBlocks=(ExtensionBlock *)malloc(sizeof(ExtensionBlock));
    227     else
    228         *ExtensionBlocks = (ExtensionBlock *)realloc(*ExtensionBlocks,
    229                                       sizeof(ExtensionBlock) *
    230                                       (*ExtensionBlockCount + 1));
    231 
    232     if (*ExtensionBlocks == NULL)
    233         return (GIF_ERROR);
    234 
    235     ep = &(*ExtensionBlocks)[(*ExtensionBlockCount)++];
    236 
    237     ep->Function = Function;
    238     ep->ByteCount=Len;
    239     ep->Bytes = (GifByteType *)malloc(ep->ByteCount);
    240     if (ep->Bytes == NULL)
    241         return (GIF_ERROR);
    242 
    243     if (ExtData != NULL) {
    244         memcpy(ep->Bytes, ExtData, Len);
    245     }
    246 
    247     return (GIF_OK);
    248 }
    249 
    250 void
    251 GifFreeExtensions(int *ExtensionBlockCount,
    252 		  ExtensionBlock **ExtensionBlocks)
    253 {
    254     ExtensionBlock *ep;
    255 
    256     if (*ExtensionBlocks == NULL)
    257         return;
    258 
    259     for (ep = *ExtensionBlocks;
    260 	 ep < (*ExtensionBlocks + *ExtensionBlockCount);
    261 	 ep++)
    262         (void)free((char *)ep->Bytes);
    263     (void)free((char *)*ExtensionBlocks);
    264     *ExtensionBlocks = NULL;
    265     *ExtensionBlockCount = 0;
    266 }
    267 
    268 /******************************************************************************
    269  Image block allocation functions
    270 ******************************************************************************/
    271 
    272 /* Private Function:
    273  * Frees the last image in the GifFile->SavedImages array
    274  */
    275 void
    276 FreeLastSavedImage(GifFileType *GifFile)
    277 {
    278     SavedImage *sp;
    279 
    280     if ((GifFile == NULL) || (GifFile->SavedImages == NULL))
    281         return;
    282 
    283     /* Remove one SavedImage from the GifFile */
    284     GifFile->ImageCount--;
    285     sp = &GifFile->SavedImages[GifFile->ImageCount];
    286 
    287     /* Deallocate its Colormap */
    288     if (sp->ImageDesc.ColorMap != NULL) {
    289         GifFreeMapObject(sp->ImageDesc.ColorMap);
    290         sp->ImageDesc.ColorMap = NULL;
    291     }
    292 
    293     /* Deallocate the image data */
    294     if (sp->RasterBits != NULL)
    295         free((char *)sp->RasterBits);
    296 
    297     /* Deallocate any extensions */
    298     GifFreeExtensions(&sp->ExtensionBlockCount, &sp->ExtensionBlocks);
    299 
    300     /*** FIXME: We could realloc the GifFile->SavedImages structure but is
    301      * there a point to it? Saves some memory but we'd have to do it every
    302      * time.  If this is used in GifFreeSavedImages then it would be inefficient
    303      * (The whole array is going to be deallocated.)  If we just use it when
    304      * we want to free the last Image it's convenient to do it here.
    305      */
    306 }
    307 
    308 /*
    309  * Append an image block to the SavedImages array
    310  */
    311 SavedImage *
    312 GifMakeSavedImage(GifFileType *GifFile, const SavedImage *CopyFrom)
    313 {
    314     SavedImage *sp;
    315 
    316     if (GifFile->SavedImages == NULL)
    317         GifFile->SavedImages = (SavedImage *)malloc(sizeof(SavedImage));
    318     else
    319         GifFile->SavedImages = (SavedImage *)realloc(GifFile->SavedImages,
    320                                sizeof(SavedImage) * (GifFile->ImageCount + 1));
    321 
    322     if (GifFile->SavedImages == NULL)
    323         return ((SavedImage *)NULL);
    324     else {
    325         sp = &GifFile->SavedImages[GifFile->ImageCount++];
    326         memset((char *)sp, '\0', sizeof(SavedImage));
    327 
    328         if (CopyFrom != NULL) {
    329             memcpy((char *)sp, CopyFrom, sizeof(SavedImage));
    330 
    331             /*
    332              * Make our own allocated copies of the heap fields in the
    333              * copied record.  This guards against potential aliasing
    334              * problems.
    335              */
    336 
    337             /* first, the local color map */
    338             if (sp->ImageDesc.ColorMap != NULL) {
    339                 sp->ImageDesc.ColorMap = GifMakeMapObject(
    340                                          CopyFrom->ImageDesc.ColorMap->ColorCount,
    341                                          CopyFrom->ImageDesc.ColorMap->Colors);
    342                 if (sp->ImageDesc.ColorMap == NULL) {
    343                     FreeLastSavedImage(GifFile);
    344                     return (SavedImage *)(NULL);
    345                 }
    346             }
    347 
    348             /* next, the raster */
    349             sp->RasterBits = (unsigned char *)malloc(sizeof(GifPixelType) *
    350                                                    CopyFrom->ImageDesc.Height *
    351                                                    CopyFrom->ImageDesc.Width);
    352             if (sp->RasterBits == NULL) {
    353                 FreeLastSavedImage(GifFile);
    354                 return (SavedImage *)(NULL);
    355             }
    356             memcpy(sp->RasterBits, CopyFrom->RasterBits,
    357                    sizeof(GifPixelType) * CopyFrom->ImageDesc.Height *
    358                    CopyFrom->ImageDesc.Width);
    359 
    360             /* finally, the extension blocks */
    361             if (sp->ExtensionBlocks != NULL) {
    362                 sp->ExtensionBlocks = (ExtensionBlock *)malloc(
    363                                       sizeof(ExtensionBlock) *
    364                                       CopyFrom->ExtensionBlockCount);
    365                 if (sp->ExtensionBlocks == NULL) {
    366                     FreeLastSavedImage(GifFile);
    367                     return (SavedImage *)(NULL);
    368                 }
    369                 memcpy(sp->ExtensionBlocks, CopyFrom->ExtensionBlocks,
    370                        sizeof(ExtensionBlock) * CopyFrom->ExtensionBlockCount);
    371             }
    372         }
    373 
    374         return (sp);
    375     }
    376 }
    377 
    378 void
    379 GifFreeSavedImages(GifFileType *GifFile)
    380 {
    381     SavedImage *sp;
    382 
    383     if ((GifFile == NULL) || (GifFile->SavedImages == NULL)) {
    384         return;
    385     }
    386     for (sp = GifFile->SavedImages;
    387          sp < GifFile->SavedImages + GifFile->ImageCount; sp++) {
    388         if (sp->ImageDesc.ColorMap != NULL) {
    389             GifFreeMapObject(sp->ImageDesc.ColorMap);
    390             sp->ImageDesc.ColorMap = NULL;
    391         }
    392 
    393         if (sp->RasterBits != NULL)
    394             free((char *)sp->RasterBits);
    395 
    396 	GifFreeExtensions(&sp->ExtensionBlockCount, &sp->ExtensionBlocks);
    397     }
    398     free((char *)GifFile->SavedImages);
    399     GifFile->SavedImages = NULL;
    400 }
    401 
    402 /* end */
    403