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