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