📄 egif_lib.c
字号:
return GIF_OK;}/****************************************************************************** * This routine should be called last, to close GIF file. *****************************************************************************/intEGifCloseFile(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); GifFile->Image.ColorMap = NULL; } if (GifFile->SColorMap) { FreeMapObject(GifFile->SColorMap); GifFile->SColorMap = NULL; } 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 intEGifPutWord(int Word, GifFileType * GifFile) { unsigned 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 intEGifSetupCompress(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 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 intEGifCompressLine(GifFileType * GifFile, GifPixelType * Line, int LineLen) { int i = 0, CrntCode; 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 intEGifCompressOutput(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 intEGifBufferedOutput(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(). *****************************************************************************/intEGifSpew(GifFileType * GifFileOut) { int i, j, gif89 = FALSE; int bOff; /* Block Offset for adding sub blocks in Extensions */ char SavedStamp[GIF_STAMP_LEN + 1]; 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; } } strncpy(SavedStamp, GifVersionPrefix, GIF_STAMP_LEN); if (gif89) { strncpy(GifVersionPrefix, GIF89_STAMP, GIF_STAMP_LEN); } else { strncpy(GifVersionPrefix, GIF87_STAMP, GIF_STAMP_LEN); } if (EGifPutScreenDesc(GifFileOut, GifFileOut->SWidth, GifFileOut->SHeight, GifFileOut->SColorResolution, GifFileOut->SBackGroundColor, GifFileOut->SColorMap) == GIF_ERROR) { strncpy(GifVersionPrefix, SavedStamp, GIF_STAMP_LEN); return (GIF_ERROR); } strncpy(GifVersionPrefix, SavedStamp, GIF_STAMP_LEN); 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 (j == sp->ExtensionBlockCount - 1 || (ep+1)->Function != 0) { /*** FIXME: Must check whether outputting * <ExtLen><Extension> is ever valid or if we should just * drop anything with a 0 for the Function. (And whether * we should drop here or in EGifPutExtension) */ if (EGifPutExtension(GifFileOut, (ep->Function != 0) ? ep->Function : '\0', ep->ByteCount, ep->Bytes) == GIF_ERROR) { return (GIF_ERROR); } } else { EGifPutExtensionFirst(GifFileOut, ep->Function, ep->ByteCount, ep->Bytes); for (bOff = j+1; bOff < sp->ExtensionBlockCount; bOff++) { ep = &sp->ExtensionBlocks[bOff]; if (ep->Function != 0) { break; } EGifPutExtensionNext(GifFileOut, 0, ep->ByteCount, ep->Bytes); } EGifPutExtensionLast(GifFileOut, 0, 0, NULL); j = bOff-1; } } } 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 + -