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