/****************************************************************************** Initialize HashTable - allocate the memory needed and clear it. * ******************************************************************************/ GifHashTableType *_InitHashTable(void) { GifHashTableType *HashTable; if ((HashTable = (GifHashTableType *) malloc(sizeof(GifHashTableType))) == NULL) return NULL; _ClearHashTable(HashTable); return HashTable; }
/****************************************************************************** * Initialize HashTable - allocate the memory needed and clear it. * ******************************************************************************/ GifHashTableType *_InitHashTable(void) { GifHashTableType *HashTable; if ((HashTable = (GifHashTableType *) IMAGE_MALLOC(sizeof(GifHashTableType))) == NULL) return NULL; _ClearHashTable(HashTable); return HashTable; }
/****************************************************************************** Setup the LZ compression for this image: ******************************************************************************/ static int EGifSetupCompress(GifFileType *GifFile) { int BitsPerPixel; GifByteType Buf; GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private; /* Test and see what color map to use, and from it # bits per pixel: */ if (GifFile->Image.ColorMap) BitsPerPixel = GifFile->Image.ColorMap->BitsPerPixel; else if (GifFile->SColorMap) BitsPerPixel = GifFile->SColorMap->BitsPerPixel; else { GifFile->Error = E_GIF_ERR_NO_COLOR_MAP; return GIF_ERROR; } Buf = BitsPerPixel = (BitsPerPixel < 2 ? 2 : BitsPerPixel); InternalWrite(GifFile, &Buf, 1); /* Write the Code size to file. */ Private->Buf[0] = 0; /* Nothing was output yet. */ Private->BitsPerPixel = BitsPerPixel; Private->ClearCode = (1 << BitsPerPixel); Private->EOFCode = Private->ClearCode + 1; Private->RunningCode = Private->EOFCode + 1; Private->RunningBits = BitsPerPixel + 1; /* Number of bits per code. */ Private->MaxCode1 = 1 << Private->RunningBits; /* Max. code + 1. */ Private->CrntCode = FIRST_CODE; /* Signal that this is first one! */ Private->CrntShiftState = 0; /* No information in CrntShiftDWord. */ Private->CrntShiftDWord = 0; /* Clear hash table and send Clear to make sure the decoder do the same. */ _ClearHashTable(Private->HashTable); if (EGifCompressOutput(GifFile, Private->ClearCode) == GIF_ERROR) { GifFile->Error = E_GIF_ERR_DISK_IS_FULL; return GIF_ERROR; } return GIF_OK; }
/****************************************************************************** The LZ compression routine: This version compresses the given buffer Line of length LineLen. This routine can be called a few times (one per scan line, for example), in order to complete the whole image. ******************************************************************************/ static int EGifCompressLine(GifFileType *GifFile, GifPixelType *Line, const int LineLen) { int i = 0, CrntCode, NewCode; unsigned long NewKey; GifPixelType Pixel; GifHashTableType *HashTable; GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private; HashTable = Private->HashTable; if (Private->CrntCode == FIRST_CODE) /* Its first time! */ CrntCode = Line[i++]; else CrntCode = Private->CrntCode; /* Get last code in compression. */ while (i < LineLen) { /* Decode LineLen items. */ Pixel = Line[i++]; /* Get next pixel from stream. */ /* Form a new unique key to search hash table for the code combines * CrntCode as Prefix string with Pixel as postfix char. */ NewKey = (((uint32_t) CrntCode) << 8) + Pixel; if ((NewCode = _ExistsHashTable(HashTable, NewKey)) >= 0) { /* This Key is already there, or the string is old one, so * simple take new code as our CrntCode: */ CrntCode = NewCode; } else { /* Put it in hash table, output the prefix code, and make our * CrntCode equal to Pixel. */ if (EGifCompressOutput(GifFile, CrntCode) == GIF_ERROR) { GifFile->Error = E_GIF_ERR_DISK_IS_FULL; return GIF_ERROR; } CrntCode = Pixel; /* If however the HashTable if full, we send a clear first and * Clear the hash table. */ if (Private->RunningCode >= LZ_MAX_CODE) { /* Time to do some clearance: */ if (EGifCompressOutput(GifFile, Private->ClearCode) == GIF_ERROR) { GifFile->Error = E_GIF_ERR_DISK_IS_FULL; return GIF_ERROR; } Private->RunningCode = Private->EOFCode + 1; Private->RunningBits = Private->BitsPerPixel + 1; Private->MaxCode1 = 1 << Private->RunningBits; _ClearHashTable(HashTable); } else { /* Put this unique key with its relative Code in hash table: */ _InsertHashTable(HashTable, NewKey, Private->RunningCode++); } } } /* Preserve the current state of the compression algorithm: */ Private->CrntCode = CrntCode; if (Private->PixelCount == 0) { /* We are done - output last Code and flush output buffers: */ if (EGifCompressOutput(GifFile, CrntCode) == GIF_ERROR) { GifFile->Error = E_GIF_ERR_DISK_IS_FULL; return GIF_ERROR; } if (EGifCompressOutput(GifFile, Private->EOFCode) == GIF_ERROR) { GifFile->Error = E_GIF_ERR_DISK_IS_FULL; return GIF_ERROR; } if (EGifCompressOutput(GifFile, FLUSH_OUTPUT) == GIF_ERROR) { GifFile->Error = E_GIF_ERR_DISK_IS_FULL; return GIF_ERROR; } } return GIF_OK; }