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