📄 egif_lib.c
字号:
* Put an extension block (see GIF manual) into gif file. *******************************************************************************/int EGifPutExtension(GifFileType *GifFile, int ExtCode, int ExtLen, VoidPtr Extension){ GifByteType Buf[3]; GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private; if (!IS_WRITEABLE(Private)) { /* This file was NOT open for writing: */ _GifError = E_GIF_ERR_NOT_WRITEABLE; return GIF_ERROR; } if (ExtCode == 0) WRITE(GifFile, (GifByteType*)&ExtLen, 1); else { Buf[0] = '!'; Buf[1] = ExtCode; Buf[2] = ExtLen; WRITE(GifFile, Buf, 3); } WRITE(GifFile, Extension, ExtLen); Buf[0] = 0; WRITE(GifFile, Buf, 1); return GIF_OK;}/******************************************************************************* Put the image code in compressed form. This routine can be called if the ** information needed to be piped out as is. Obviously this is much faster ** than decoding and encoding again. This routine should be followed by calls ** to EGifPutCodeNext, until NULL block is given. ** The block should NOT be freed by the user (not dynamically allocated). *******************************************************************************/int EGifPutCode(GifFileType *GifFile, int CodeSize, GifByteType *CodeBlock){ GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private; if (!IS_WRITEABLE(Private)) { /* This file was NOT open for writing: */ _GifError = E_GIF_ERR_NOT_WRITEABLE; return GIF_ERROR; } /* No need to dump code size as Compression set up does any for us: */ /* Buf = CodeSize; if (WRITE(GifFile, &Buf, 1) != 1) { _GifError = E_GIF_ERR_WRITE_FAILED; return GIF_ERROR; } */ return EGifPutCodeNext(GifFile, CodeBlock);}/******************************************************************************* Continue to put the image code in compressed form. This routine should be ** called with blocks of code as read via DGifGetCode/DGifGetCodeNext. If ** given buffer pointer is NULL, empty block is written to mark end of code. *******************************************************************************/int EGifPutCodeNext(GifFileType *GifFile, GifByteType *CodeBlock){ GifByteType Buf; GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private; if (CodeBlock != NULL) { if (WRITE(GifFile, CodeBlock, CodeBlock[0] + 1) != (unsigned)(CodeBlock[0] + 1)) { _GifError = E_GIF_ERR_WRITE_FAILED; return GIF_ERROR; } } else { Buf = 0; if (WRITE(GifFile, &Buf, 1) != 1) { _GifError = E_GIF_ERR_WRITE_FAILED; return GIF_ERROR; } Private->PixelCount = 0; /* And local info. indicate image read. */ } return GIF_OK;}/******************************************************************************* This routine should be called last, to close GIF file. *******************************************************************************/int EGifCloseFile(GifFileType *GifFile){ GifByteType Buf; GifFilePrivateType *Private; FILE *File; if (GifFile == NULL) return GIF_ERROR; Private = (GifFilePrivateType *) GifFile->Private; if (!IS_WRITEABLE(Private)) { /* This file was NOT open for writing: */ _GifError = E_GIF_ERR_NOT_WRITEABLE; return GIF_ERROR; } File = Private->File; Buf = ';'; WRITE(GifFile, &Buf, 1); if (GifFile->Image.ColorMap) FreeMapObject(GifFile->Image.ColorMap); if (GifFile->SColorMap) FreeMapObject(GifFile->SColorMap); if (Private) { free((char *) Private); } free(GifFile); if (File && fclose(File) != 0) { _GifError = E_GIF_ERR_CLOSE_FAILED; return GIF_ERROR; } return GIF_OK;}/******************************************************************************* Put 2 bytes (word) into the given file: *******************************************************************************/static int EGifPutWord(int Word, GifFileType *GifFile){ char c[2]; c[0] = Word & 0xff; c[1] = (Word >> 8) & 0xff;#ifndef DEBUG_NO_PREFIX if (WRITE(GifFile, c, 2) == 2) return GIF_OK; else return GIF_ERROR;#else return GIF_OK;#endif /* DEBUG_NO_PREFIX */}/******************************************************************************* 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 { _GifError = E_GIF_ERR_NO_COLOR_MAP; return GIF_ERROR; } Buf = BitsPerPixel = (BitsPerPixel < 2 ? 2 : BitsPerPixel); WRITE(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 = 0; 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; /* Send Clear to make sure the encoder is initialized. */ if (EGifCompressOutput(GifFile, Private->ClearCode) == GIF_ERROR) { _GifError = E_GIF_ERR_DISK_IS_FULL; return GIF_ERROR; } return GIF_OK;}/******************************************************************************* The LZ compression routine: ** This version compress the given buffer Line of length LineLen. ** This routine can be called few times (one per scan line, for example), in ** order the complete the whole image. *******************************************************************************/static int EGifCompressLine(GifFileType *GifFile, GifPixelType *Line, int LineLen){ int i = 0, CrntCode, NewCode; unsigned long NewKey; GifPixelType Pixel; GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private; 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. */ if (EGifCompressOutput(GifFile, CrntCode) == GIF_ERROR) { _GifError = E_GIF_ERR_DISK_IS_FULL; return GIF_ERROR; } Private->RunningCode++; CrntCode = Pixel; if (Private->RunningCode >= (1 << (Private->BitsPerPixel)) - 2) { if (EGifCompressOutput(GifFile, Private->ClearCode) == GIF_ERROR) { _GifError = E_GIF_ERR_DISK_IS_FULL; return GIF_ERROR; } Private->RunningCode=0; } } /* 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) { _GifError = E_GIF_ERR_DISK_IS_FULL; return GIF_ERROR; } if (EGifCompressOutput(GifFile, Private->EOFCode) == GIF_ERROR) { _GifError = E_GIF_ERR_DISK_IS_FULL; return GIF_ERROR; } if (EGifCompressOutput(GifFile, FLUSH_OUTPUT) == GIF_ERROR) { _GifError = E_GIF_ERR_DISK_IS_FULL; return GIF_ERROR; } } return GIF_OK;}/******************************************************************************* The LZ compression output routine: ** This routine is responsible for the compression of the bit stream into ** 8 bits (bytes) packets. ** Returns GIF_OK if written succesfully. *******************************************************************************/static int EGifCompressOutput(GifFileType *GifFile, int Code){ GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private; int retval = GIF_OK; if (Code == FLUSH_OUTPUT) { while (Private->CrntShiftState > 0) { /* Get Rid of what is left in DWord, and flush it. */ if (EGifBufferedOutput(GifFile, Private->Buf, Private->CrntShiftDWord & 0xff) == GIF_ERROR) retval = GIF_ERROR; Private->CrntShiftDWord >>= 8; Private->CrntShiftState -= 8; } Private->CrntShiftState = 0; /* For next time. */ if (EGifBufferedOutput(GifFile, Private->Buf, FLUSH_OUTPUT) == GIF_ERROR) retval = GIF_ERROR; } else { Private->CrntShiftDWord |= ((long) Code) << Private->CrntShiftState; Private->CrntShiftState += Private->RunningBits; while (Private->CrntShiftState >= 8) { /* Dump out full bytes: */ if (EGifBufferedOutput(GifFile, Private->Buf, Private->CrntShiftDWord & 0xff) == GIF_ERROR) retval = GIF_ERROR; Private->CrntShiftDWord >>= 8; Private->CrntShiftState -= 8; } } return retval;}/******************************************************************************* This routines buffers the given characters until 255 characters are ready ** to be output. If Code is equal to -1 the buffer is flushed (EOF). ** The buffer is Dumped with first byte as its size, as GIF format requires. ** Returns GIF_OK if written succesfully. *******************************************************************************/static int EGifBufferedOutput(GifFileType *GifFile, GifByteType *Buf, int c){ if (c == FLUSH_OUTPUT) { /* Flush everything out. */ if (Buf[0] != 0 && WRITE(GifFile, Buf, Buf[0]+1) != (unsigned)(Buf[0] + 1)) { _GifError = E_GIF_ERR_WRITE_FAILED; return GIF_ERROR; } /* Mark end of compressed data, by an empty block (see GIF doc): */ Buf[0] = 0; if (WRITE(GifFile, Buf, 1) != 1) { _GifError = E_GIF_ERR_WRITE_FAILED; return GIF_ERROR; } } else { if (Buf[0] == 255) { /* Dump out this buffer - it is full: */ if (WRITE(GifFile, Buf, Buf[0] + 1) != (unsigned)(Buf[0] + 1)) { _GifError = E_GIF_ERR_WRITE_FAILED; return GIF_ERROR; } Buf[0] = 0; } Buf[++Buf[0]] = c; } return GIF_OK;}/******************************************************************************* This routine writes to disk an in-core representation of a GIF previously ** created by DGifSlurp(). *******************************************************************************/int EGifSpew(GifFileType *GifFileOut){ int i, j, gif89 = FALSE; char *SavedStamp; for (i = 0; i < GifFileOut->ImageCount; i++) { for (j = 0; j < GifFileOut->SavedImages[i].ExtensionBlockCount; j++) { int function=GifFileOut->SavedImages[i].ExtensionBlocks[j].Function; if (function == COMMENT_EXT_FUNC_CODE || function == GRAPHICS_EXT_FUNC_CODE || function == PLAINTEXT_EXT_FUNC_CODE || function == APPLICATION_EXT_FUNC_CODE) gif89 = TRUE; } } SavedStamp = GifVersionPrefix; GifVersionPrefix = gif89 ? GIF89_STAMP : GIF87_STAMP; if (EGifPutScreenDesc(GifFileOut, GifFileOut->SWidth, GifFileOut->SHeight, GifFileOut->SColorResolution, GifFileOut->SBackGroundColor, GifFileOut->SColorMap) == GIF_ERROR) { GifVersionPrefix = SavedStamp; return(GIF_ERROR); } GifVersionPrefix = SavedStamp; for (i = 0; i < GifFileOut->ImageCount; i++) { SavedImage *sp = &GifFileOut->SavedImages[i]; int SavedHeight = sp->ImageDesc.Height; int SavedWidth = sp->ImageDesc.Width; ExtensionBlock *ep; /* this allows us to delete images by nuking their rasters */ if (sp->RasterBits == NULL) continue; if (sp->ExtensionBlocks) { for ( j = 0; j < sp->ExtensionBlockCount; j++) { ep = &sp->ExtensionBlocks[j]; if (EGifPutExtension(GifFileOut, (ep->Function != 0) ? ep->Function : '\0', ep->ByteCount, ep->Bytes) == GIF_ERROR) return (GIF_ERROR); } } if (EGifPutImageDesc(GifFileOut, sp->ImageDesc.Left, sp->ImageDesc.Top, SavedWidth, SavedHeight, sp->ImageDesc.Interlace, sp->ImageDesc.ColorMap ) == GIF_ERROR) return(GIF_ERROR); for (j = 0; j < SavedHeight; j++) { if (EGifPutLine(GifFileOut, sp->RasterBits + j * SavedWidth, SavedWidth) == GIF_ERROR) return(GIF_ERROR); } } if (EGifCloseFile(GifFileOut) == GIF_ERROR) return(GIF_ERROR); return(GIF_OK);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -