You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
754 lines
23 KiB
754 lines
23 KiB
/*++
|
|
|
|
Copyright (c) 1990-1992 Microsoft Corporation
|
|
|
|
|
|
Module Name:
|
|
|
|
htuigif.c
|
|
|
|
|
|
Abstract:
|
|
|
|
This module contains GIF file decompression to generate a memory DIB type
|
|
bitmap for the GIF
|
|
|
|
Author:
|
|
|
|
21-Apr-1992 Tue 11:38:11 created -by- Daniel Chou (danielc)
|
|
|
|
|
|
[Environment:]
|
|
|
|
GDI Device Driver - Halftone.
|
|
|
|
|
|
[Notes:]
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
|
|
|
|
#include <stddef.h>
|
|
#include <windows.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <ht.h>
|
|
|
|
#include "htuidlg.h"
|
|
#include "htuimain.h"
|
|
#include "htuigif.h"
|
|
|
|
extern HMODULE hHTUIModule;
|
|
|
|
|
|
//
|
|
// Following structures and #defines are only used in this C file
|
|
//
|
|
|
|
|
|
#pragma pack(1)
|
|
typedef struct _GIFRGB { /* gifrgb */
|
|
BYTE Red;
|
|
BYTE Green;
|
|
BYTE Blue;
|
|
} GIFRGB, FAR *PGIFRGB;
|
|
#pragma pack()
|
|
|
|
typedef struct _GIFMAP {
|
|
SHORT CurX;
|
|
SHORT CurY;
|
|
SHORT Width;
|
|
SHORT Height;
|
|
} GIFMAP;
|
|
|
|
#pragma pack(1)
|
|
typedef struct _GIFHEADER {
|
|
BYTE Signature[3]; /* This is the 'GIF' signature */
|
|
BYTE Version[3]; /* version number such as '89a' */
|
|
WORD Width; /* Width of the picture in pels */
|
|
WORD Height; /* Height of the picture in pels */
|
|
BYTE Flags; /* GIFH_xxxx flags */
|
|
BYTE BColorIndex; /* background color index */
|
|
BYTE AspectRatio; /* w/h ratio = (x + 15) / 64 */
|
|
} GIFHEADER, *PGIFHEADER;
|
|
#pragma pack()
|
|
|
|
#define GIFH_GLOBAL_COLOR_TABLE 0x80
|
|
#define GIFH_PRIMARY_COLOR_BITS 0xe0
|
|
#define GIFH_SORTED_COLORS 0x08
|
|
#define GIFH_SIZE_COLOR_TABLE 0x07
|
|
|
|
#define GIFMAP_INTERLACE 0x40
|
|
|
|
typedef struct _GIF2DIBINFO {
|
|
LPSHORT pLineIncVec;
|
|
LPBYTE pDIBLine1;
|
|
LPBYTE pDIBCurLine;
|
|
LPBYTE pDIBNow;
|
|
LPBYTE pGIFBuf;
|
|
DWORD SizeGIFBuf;
|
|
GIFMAP Map;
|
|
WORD cx;
|
|
WORD cy;
|
|
WORD cxBytes;
|
|
WORD LinesDone;
|
|
WORD RemainXPels;
|
|
WORD PelMask;
|
|
} GIF2DIBINFO, *PGIF2DIBINFO;
|
|
|
|
|
|
typedef VOID (*PFNOUTPUTPELS)(PGIF2DIBINFO pGIF2DIBInfo, UINT TotalPels);
|
|
|
|
#define SET_NEXT_DIB_PBUF \
|
|
{ \
|
|
SHORT LineInc; \
|
|
\
|
|
GIF2DIBInfo.pDIBCurLine -= \
|
|
(LONG)(LineInc = *(GIF2DIBInfo.pLineIncVec)) * \
|
|
(LONG)GIF2DIBInfo.cxBytes; \
|
|
\
|
|
if ((GIF2DIBInfo.Map.CurY += LineInc) >= GIF2DIBInfo.Map.Height) { \
|
|
\
|
|
GIF2DIBInfo.pLineIncVec++; \
|
|
\
|
|
if (*(GIF2DIBInfo.pLineIncVec) >= 0) { \
|
|
\
|
|
GIF2DIBInfo.Map.CurY = *(GIF2DIBInfo.pLineIncVec++); \
|
|
GIF2DIBInfo.pDIBCurLine = GIF2DIBInfo.pDIBLine1 - \
|
|
((LONG)GIF2DIBInfo.Map.CurX * \
|
|
(LONG)GIF2DIBInfo.Map.CurY); \
|
|
} \
|
|
} \
|
|
\
|
|
++GIF2DIBInfo.LinesDone; \
|
|
\
|
|
GIF2DIBInfo.pDIBNow = GIF2DIBInfo.pDIBCurLine; \
|
|
GIF2DIBInfo.RemainXPels = GIF2DIBInfo.cx; \
|
|
GIF2DIBInfo.PelMask = 0; \
|
|
} \
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// LZW DeCompression //
|
|
// //
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
#define MAXBITS 12
|
|
#define SIZE_GIF_BUF (60 * 1024)
|
|
#define SIZE_LZW_LASTCHAR (1 << MAXBITS)
|
|
#define SIZE_LZW_RASTERBLOCK 256
|
|
#define SIZE_LZW_PREFIX ((1 << MAXBITS) * 2)
|
|
#define SIZE_LZW_BUFS (SIZE_LZW_LASTCHAR + SIZE_LZW_RASTERBLOCK + \
|
|
SIZE_LZW_PREFIX)
|
|
|
|
typedef struct _LZWINFO {
|
|
LPBYTE pLastChar;
|
|
LPBYTE pRasterBlock;
|
|
LPSHORT pPrefix;
|
|
SHORT EODCode;
|
|
SHORT CSMask;
|
|
SHORT CodeSize;
|
|
SHORT BitsLeft;
|
|
DWORD CodeBuf;
|
|
SHORT GetCodeRet;
|
|
BYTE RBIndex;
|
|
BYTE RBLen;
|
|
} LZWINFO;
|
|
|
|
|
|
|
|
#define GET_GIF_CODE \
|
|
{ \
|
|
BOOL EODCodeBreak = FALSE; \
|
|
\
|
|
while (LZWInfo.BitsLeft < LZWInfo.CodeSize) { \
|
|
\
|
|
if (LZWInfo.RBIndex >= LZWInfo.RBLen) { \
|
|
\
|
|
if ((!ReadFile(hFile, &LZWInfo.RBLen, 1, &cbRead, NULL)) || \
|
|
(cbRead != 1) || \
|
|
(LZWInfo.RBLen < 1) || \
|
|
(!ReadFile(hFile, LZWInfo.pRasterBlock, LZWInfo.RBLen, \
|
|
&cbRead, NULL)) || \
|
|
(cbRead != (DWORD)LZWInfo.RBLen)) { \
|
|
\
|
|
EODCodeBreak = TRUE; \
|
|
break; \
|
|
} \
|
|
\
|
|
LZWInfo.RBIndex = 0; \
|
|
} \
|
|
\
|
|
LZWInfo.CodeBuf |= (DWORD)*(LZWInfo.pRasterBlock + \
|
|
LZWInfo.RBIndex++) << LZWInfo.BitsLeft; \
|
|
LZWInfo.BitsLeft += 8; \
|
|
} \
|
|
\
|
|
if (EODCodeBreak) { \
|
|
\
|
|
LZWInfo.GetCodeRet = LZWInfo.EODCode; \
|
|
\
|
|
} else { \
|
|
\
|
|
LZWInfo.GetCodeRet = (SHORT)(LZWInfo.CodeBuf & \
|
|
(DWORD)LZWInfo.CSMask); \
|
|
LZWInfo.CodeBuf >>= LZWInfo.CodeSize; \
|
|
LZWInfo.BitsLeft -= LZWInfo.CodeSize; \
|
|
} \
|
|
} \
|
|
|
|
|
|
BOOL
|
|
DeCompressGIFFileToDIB(
|
|
HANDLE hFile,
|
|
PGIF2DIBINFO pGIF2DIBInfo,
|
|
LPBYTE pLZWBuf,
|
|
PFNOUTPUTPELS pfnOutputPels,
|
|
WORD BitCount
|
|
)
|
|
{
|
|
LPBYTE pGIFBufBeg;
|
|
LPBYTE pGIFBufEnd;
|
|
LPBYTE pOutBufTail;
|
|
LPBYTE pOutBufHead;
|
|
LZWINFO LZWInfo;
|
|
UINT SizeGIFBuf;
|
|
DWORD cbRead;
|
|
WORD BytesMove;
|
|
SHORT FinalChar;
|
|
SHORT OldCode;
|
|
SHORT CurCode;
|
|
SHORT InitialCodeSize;
|
|
SHORT ClearCode;
|
|
SHORT MaxCode;
|
|
SHORT MaxCol;
|
|
SHORT NextCode;
|
|
BYTE bCh;
|
|
|
|
|
|
//
|
|
// First initialize all the local buffer
|
|
//
|
|
|
|
LZWInfo.pLastChar = pLZWBuf;
|
|
LZWInfo.pRasterBlock = pLZWBuf + SIZE_LZW_LASTCHAR;
|
|
LZWInfo.pPrefix = (LPSHORT)(LZWInfo.pRasterBlock +
|
|
SIZE_LZW_RASTERBLOCK);
|
|
LZWInfo.BitsLeft = 0;
|
|
LZWInfo.CodeBuf = 0;
|
|
LZWInfo.GetCodeRet = 0;
|
|
LZWInfo.RBIndex =
|
|
LZWInfo.RBLen = 0;
|
|
*(LZWInfo.pLastChar) = (BYTE)0;
|
|
*(LZWInfo.pPrefix) =
|
|
FinalChar =
|
|
OldCode = 0;
|
|
|
|
if ((!ReadFile(hFile, &bCh, 1, &cbRead, NULL)) ||
|
|
(cbRead != 1)) {
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
pGIFBufBeg = pGIF2DIBInfo->pGIFBuf;
|
|
SizeGIFBuf = (UINT)pGIF2DIBInfo->SizeGIFBuf;
|
|
pGIFBufEnd = pGIFBufBeg + SizeGIFBuf;
|
|
|
|
InitialCodeSize = (SHORT)bCh;
|
|
LZWInfo.CodeSize = ++InitialCodeSize;
|
|
|
|
if (LZWInfo.CodeSize < 3 || LZWInfo.CodeSize > 9) {
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
MaxCol = (SHORT)((1 << BitCount) - 1);
|
|
ClearCode = (SHORT)(1 << (LZWInfo.CodeSize - 1));
|
|
LZWInfo.EODCode = (SHORT)(ClearCode + 1);
|
|
NextCode = (SHORT)(ClearCode + 2);
|
|
MaxCode = (SHORT)(ClearCode << 1);
|
|
LZWInfo.CSMask = (SHORT)(MaxCode - 1);
|
|
pOutBufHead = pGIFBufBeg;
|
|
|
|
|
|
while (TRUE) {
|
|
|
|
//
|
|
// GET_GIF_CODE will reeurn from this function if _ReadFile() failed,
|
|
// otherwise it set the curretn read code into LZWInfo.GetCodeRet
|
|
//
|
|
|
|
GET_GIF_CODE;
|
|
|
|
if (LZWInfo.GetCodeRet == LZWInfo.EODCode) {
|
|
|
|
break; // Done
|
|
}
|
|
|
|
//
|
|
// Write out the color data if the buffer is full
|
|
//
|
|
|
|
if (pOutBufHead >= pGIFBufEnd) {
|
|
|
|
pfnOutputPels(pGIF2DIBInfo, (UINT)SizeGIFBuf);
|
|
pOutBufHead = pGIFBufBeg;
|
|
}
|
|
|
|
if (LZWInfo.GetCodeRet == ClearCode) {
|
|
|
|
LZWInfo.CodeSize = InitialCodeSize;
|
|
NextCode = (SHORT)(ClearCode + (SHORT)2);
|
|
MaxCode = (SHORT)(1 << LZWInfo.CodeSize);
|
|
LZWInfo.CSMask = (SHORT)(MaxCode - 1);
|
|
|
|
do {
|
|
|
|
GET_GIF_CODE;
|
|
|
|
} while (LZWInfo.GetCodeRet == ClearCode);
|
|
|
|
|
|
if (LZWInfo.GetCodeRet == LZWInfo.EODCode) {
|
|
|
|
break;
|
|
|
|
} else if (LZWInfo.GetCodeRet >= NextCode) {
|
|
|
|
LZWInfo.GetCodeRet = 0;
|
|
}
|
|
|
|
*pOutBufHead++ = (BYTE)(OldCode = FinalChar = LZWInfo.GetCodeRet);
|
|
|
|
} else {
|
|
|
|
CurCode = LZWInfo.GetCodeRet;
|
|
|
|
//
|
|
// At here, we guranteed that at least one byte in the buffer
|
|
// is available
|
|
//
|
|
|
|
pOutBufTail = pGIFBufEnd;
|
|
|
|
if (CurCode == NextCode) {
|
|
|
|
*--pOutBufTail = (BYTE)FinalChar;
|
|
CurCode = OldCode;
|
|
|
|
} else if (CurCode > NextCode) {
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
while (CurCode > MaxCol) {
|
|
|
|
if (pOutBufTail <= pOutBufHead) {
|
|
|
|
//
|
|
// Output some when buffer full
|
|
//
|
|
|
|
pfnOutputPels(pGIF2DIBInfo, (UINT)(pOutBufHead-pGIFBufBeg));
|
|
pOutBufHead = pGIFBufBeg;
|
|
}
|
|
|
|
*--pOutBufTail = *(LZWInfo.pLastChar + CurCode);
|
|
CurCode = *(LZWInfo.pPrefix + CurCode);
|
|
}
|
|
|
|
if (pOutBufTail <= pOutBufHead) {
|
|
|
|
pfnOutputPels(pGIF2DIBInfo, (UINT)(pOutBufHead - pGIFBufBeg));
|
|
pOutBufHead = pGIFBufBeg;
|
|
}
|
|
|
|
*--pOutBufTail = (BYTE)(FinalChar = CurCode);
|
|
|
|
//
|
|
// Need to move little bit, we guranteed that we minimum
|
|
// has one byte generated in this ELSE()
|
|
//
|
|
|
|
if (pOutBufTail > pOutBufHead) {
|
|
|
|
memmove(pOutBufHead,
|
|
pOutBufTail,
|
|
BytesMove = (WORD)(pGIFBufEnd - pOutBufTail));
|
|
|
|
pOutBufHead += BytesMove;
|
|
|
|
} else {
|
|
|
|
//
|
|
// We are exactly fill up the buffer, so do not need to
|
|
// move but just advance the pointer
|
|
//
|
|
|
|
pOutBufHead = pGIFBufEnd;
|
|
}
|
|
|
|
if (NextCode < MaxCode) {
|
|
|
|
*(LZWInfo.pPrefix + NextCode) = OldCode;
|
|
*(LZWInfo.pLastChar + NextCode) = (BYTE)(FinalChar = CurCode);
|
|
OldCode = LZWInfo.GetCodeRet;
|
|
}
|
|
|
|
if ((++NextCode >= MaxCode) &&
|
|
(LZWInfo.CodeSize < MAXBITS)) {
|
|
|
|
++LZWInfo.CodeSize;
|
|
MaxCode <<= 1;
|
|
LZWInfo.CSMask = (SHORT)(MaxCode - 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pOutBufHead > pGIFBufBeg) {
|
|
|
|
pfnOutputPels(pGIF2DIBInfo, (UINT)(pOutBufHead - pGIFBufBeg));
|
|
pOutBufHead = pGIFBufBeg;
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
Output8BPP(
|
|
PGIF2DIBINFO pGIF2DIBInfo,
|
|
UINT TotalPels
|
|
)
|
|
{
|
|
GIF2DIBINFO GIF2DIBInfo;
|
|
LPBYTE pGIFBuf;
|
|
UINT CopySize;
|
|
|
|
|
|
GIF2DIBInfo = *pGIF2DIBInfo;
|
|
pGIFBuf = GIF2DIBInfo.pGIFBuf;
|
|
|
|
while (TotalPels) {
|
|
|
|
CopySize = (TotalPels > (UINT)GIF2DIBInfo.RemainXPels) ?
|
|
(UINT)GIF2DIBInfo.RemainXPels : TotalPels;
|
|
|
|
CopyMemory(GIF2DIBInfo.pDIBNow, pGIFBuf, CopySize);
|
|
|
|
GIF2DIBInfo.pDIBNow += CopySize;
|
|
pGIFBuf += CopySize;
|
|
TotalPels -= CopySize;
|
|
|
|
if (!(GIF2DIBInfo.RemainXPels -= (WORD)CopySize)) {
|
|
|
|
SET_NEXT_DIB_PBUF;
|
|
}
|
|
}
|
|
|
|
*pGIF2DIBInfo = GIF2DIBInfo;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
Output4BPP(
|
|
PGIF2DIBINFO pGIF2DIBInfo,
|
|
UINT TotalPels
|
|
)
|
|
{
|
|
GIF2DIBINFO GIF2DIBInfo;
|
|
LPBYTE pGIFBuf;
|
|
UINT CopySize;
|
|
|
|
|
|
GIF2DIBInfo = *pGIF2DIBInfo;
|
|
pGIFBuf = GIF2DIBInfo.pGIFBuf;
|
|
|
|
|
|
while (TotalPels) {
|
|
|
|
CopySize = (TotalPels > (UINT)GIF2DIBInfo.RemainXPels) ?
|
|
(UINT)GIF2DIBInfo.RemainXPels : TotalPels;
|
|
|
|
TotalPels -= (WORD)CopySize;
|
|
GIF2DIBInfo.RemainXPels -= (WORD)CopySize;
|
|
|
|
while (CopySize--) {
|
|
|
|
if (GIF2DIBInfo.PelMask ^= 0x01) {
|
|
|
|
*GIF2DIBInfo.pDIBNow++ |= (BYTE)(*pGIFBuf++ & 0x0f);
|
|
|
|
} else {
|
|
|
|
*GIF2DIBInfo.pDIBNow = (BYTE)(*pGIFBuf++ << 4);
|
|
}
|
|
}
|
|
|
|
if (!GIF2DIBInfo.RemainXPels) {
|
|
|
|
SET_NEXT_DIB_PBUF;
|
|
}
|
|
}
|
|
|
|
*pGIF2DIBInfo = GIF2DIBInfo;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
Output1BPP(
|
|
PGIF2DIBINFO pGIF2DIBInfo,
|
|
UINT TotalPels
|
|
)
|
|
{
|
|
GIF2DIBINFO GIF2DIBInfo;
|
|
LPBYTE pGIFBuf;
|
|
UINT CopySize;
|
|
BYTE bPel;
|
|
|
|
|
|
GIF2DIBInfo = *pGIF2DIBInfo;
|
|
pGIFBuf = GIF2DIBInfo.pGIFBuf;
|
|
|
|
|
|
while (TotalPels) {
|
|
|
|
CopySize = (TotalPels > (UINT)GIF2DIBInfo.RemainXPels) ?
|
|
(UINT)GIF2DIBInfo.RemainXPels : TotalPels;
|
|
|
|
TotalPels -= CopySize;
|
|
GIF2DIBInfo.RemainXPels -= (WORD)CopySize;
|
|
|
|
bPel = (BYTE)((GIF2DIBInfo.PelMask) ? *GIF2DIBInfo.pDIBNow : 0);
|
|
|
|
while (CopySize--) {
|
|
|
|
bPel = (BYTE)((bPel << 1) | ((*pGIFBuf++) & 0x01));
|
|
|
|
if (++GIF2DIBInfo.PelMask == 8) {
|
|
|
|
*GIF2DIBInfo.pDIBNow++ = bPel;
|
|
bPel = 0;
|
|
GIF2DIBInfo.PelMask = 0;
|
|
|
|
}
|
|
}
|
|
|
|
if (GIF2DIBInfo.PelMask) {
|
|
|
|
*(GIF2DIBInfo.pDIBNow) = bPel;
|
|
}
|
|
|
|
if (!GIF2DIBInfo.RemainXPels) {
|
|
|
|
SET_NEXT_DIB_PBUF;
|
|
}
|
|
}
|
|
|
|
*pGIF2DIBInfo = GIF2DIBInfo;
|
|
}
|
|
|
|
|
|
|
|
HANDLE
|
|
ReadGIFFile(
|
|
HANDLE hFile
|
|
)
|
|
{
|
|
static SHORT NotInterleaved[] = { 0, 1, -1, -1};
|
|
static SHORT Interleaved[] = { 0, 8, 4, 8, 2, 4, 1, 2, -1, -1};
|
|
PFNOUTPUTPELS pfnOutputPels;
|
|
LPBYTE pLZWBuf;
|
|
LPBYTE pDIB;
|
|
HANDLE hDIB;
|
|
PGIFRGB pGIFRGB;
|
|
RGBQUAD FAR *pRGBQUAD;
|
|
GIFHEADER GIFHeader;
|
|
BITMAPINFOHEADER biGIF;
|
|
GIF2DIBINFO GIF2DIBInfo;
|
|
DWORD cbRead;
|
|
DWORD GIFPalSize;
|
|
WORD BitCount;
|
|
WORD ColorCount;
|
|
WORD Loop;
|
|
BOOL Ok = TRUE;
|
|
BYTE Seperator;
|
|
BYTE iFlags;
|
|
|
|
|
|
|
|
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
|
|
|
|
if ((!ReadFile(hFile, &GIFHeader, sizeof(GIFHEADER), &cbRead, NULL)) ||
|
|
(cbRead != sizeof(GIFHEADER)) ||
|
|
(strncmp(GIFHeader.Signature, "GIF", 3))) {
|
|
|
|
return(NULL); // non-gif
|
|
}
|
|
|
|
biGIF.biSize = sizeof(BITMAPINFOHEADER);
|
|
biGIF.biWidth = (DWORD)(GIF2DIBInfo.cx = (WORD)GIFHeader.Width);
|
|
biGIF.biHeight = (DWORD)(GIF2DIBInfo.cy = (WORD)GIFHeader.Height);
|
|
biGIF.biPlanes = 1;
|
|
BitCount =
|
|
biGIF.biBitCount = (WORD)((GIFHeader.Flags & 0x07) + 1);
|
|
biGIF.biCompression = (DWORD)BI_RGB;
|
|
biGIF.biXPelsPerMeter = 0;
|
|
biGIF.biYPelsPerMeter = 0;
|
|
|
|
if (BitCount == 1) {
|
|
|
|
pfnOutputPels = Output1BPP;
|
|
|
|
} else if (BitCount <= 4) {
|
|
|
|
pfnOutputPels = Output4BPP;
|
|
biGIF.biBitCount = 4;
|
|
|
|
} else if (BitCount <= 8) {
|
|
|
|
pfnOutputPels = Output8BPP;
|
|
biGIF.biBitCount = 8;
|
|
|
|
} else {
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
biGIF.biClrUsed =
|
|
biGIF.biClrImportant = (DWORD)1 << biGIF.biBitCount;
|
|
|
|
GIFPalSize = (DWORD)sizeof(RGBQUAD) * (DWORD)biGIF.biClrUsed;
|
|
GIF2DIBInfo.cxBytes = (WORD)ALIGN_BPP_DW(GIF2DIBInfo.cx,
|
|
biGIF.biBitCount);
|
|
|
|
biGIF.biSizeImage = (DWORD)GIF2DIBInfo.cxBytes * (DWORD)GIF2DIBInfo.cy;
|
|
|
|
if (!(hDIB = GlobalAlloc(GHND, (DWORD)sizeof(BITMAPINFOHEADER) +
|
|
GIFPalSize + (DWORD)biGIF.biSizeImage))) {
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
GIF2DIBInfo.SizeGIFBuf = (DWORD)SIZE_GIF_BUF;
|
|
|
|
if (!(GIF2DIBInfo.pGIFBuf = (LPBYTE)LocalAlloc(LPTR,
|
|
GIF2DIBInfo.SizeGIFBuf))) {
|
|
|
|
GlobalFree(hDIB);
|
|
return(NULL); // no memory for decompress
|
|
}
|
|
|
|
if (!(pLZWBuf = (LPBYTE)LocalAlloc(LPTR, SIZE_LZW_BUFS))) {
|
|
|
|
GlobalFree(hDIB);
|
|
LocalFree((HANDLE)GIF2DIBInfo.pGIFBuf);
|
|
return(NULL);
|
|
}
|
|
|
|
pDIB = GlobalLock(hDIB);
|
|
*(LPBITMAPINFOHEADER)pDIB = biGIF;
|
|
|
|
if (GIFHeader.Flags & GIFH_GLOBAL_COLOR_TABLE) {
|
|
|
|
ColorCount = (WORD)(1 << BitCount);
|
|
|
|
pGIFRGB = (PGIFRGB)(pDIB + sizeof(BITMAPINFOHEADER) +
|
|
((sizeof(RGBQUAD) - sizeof(GIFRGB)) * ColorCount));
|
|
|
|
pRGBQUAD = (RGBQUAD FAR *)(pDIB + sizeof(BITMAPINFOHEADER));
|
|
|
|
if ((!ReadFile(hFile,
|
|
pGIFRGB,
|
|
sizeof(GIFRGB) * ColorCount,
|
|
&cbRead,
|
|
NULL)) ||
|
|
(cbRead != sizeof(GIFRGB) * ColorCount)) {
|
|
|
|
Ok = FALSE;
|
|
|
|
} else {
|
|
|
|
for (Loop = 0; Loop < ColorCount; Loop++) {
|
|
|
|
pRGBQUAD->rgbRed = pGIFRGB->Red;
|
|
pRGBQUAD->rgbGreen = pGIFRGB->Green;
|
|
pRGBQUAD->rgbBlue = pGIFRGB->Blue;
|
|
pRGBQUAD->rgbReserved = 0;
|
|
|
|
++pRGBQUAD;
|
|
++pGIFRGB;
|
|
}
|
|
|
|
if (Loop = (WORD)(biGIF.biClrUsed - ColorCount)) {
|
|
|
|
ZeroMemory((LPVOID)pRGBQUAD, Loop * sizeof(RGBQUAD));
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((!Ok) ||
|
|
(!ReadFile(hFile, &Seperator, sizeof(Seperator), &cbRead, NULL)) ||
|
|
(cbRead != sizeof(Seperator)) ||
|
|
(!ReadFile(hFile,
|
|
&(GIF2DIBInfo.Map),
|
|
sizeof(GIFMAP),
|
|
&cbRead,
|
|
NULL)) ||
|
|
(cbRead != sizeof(GIFMAP)) ||
|
|
(!ReadFile(hFile, &iFlags, sizeof(iFlags), &cbRead, NULL)) ||
|
|
(cbRead != sizeof(iFlags))) {
|
|
|
|
Ok = FALSE;
|
|
|
|
} else {
|
|
|
|
GIF2DIBInfo.pLineIncVec = (LPSHORT)((iFlags & GIFMAP_INTERLACE) ?
|
|
Interleaved : NotInterleaved);
|
|
GIF2DIBInfo.Map.CurY = *(GIF2DIBInfo.pLineIncVec++);
|
|
GIF2DIBInfo.Map.CurX = 0;
|
|
GIF2DIBInfo.PelMask =
|
|
GIF2DIBInfo.LinesDone = 0;
|
|
GIF2DIBInfo.RemainXPels = GIF2DIBInfo.cx;
|
|
GIF2DIBInfo.pDIBLine1 =
|
|
GIF2DIBInfo.pDIBCurLine =
|
|
GIF2DIBInfo.pDIBNow = pDIB +
|
|
(DWORD)sizeof(BITMAPINFOHEADER) +
|
|
(DWORD)GIFPalSize +
|
|
((DWORD)(GIF2DIBInfo.cy - 1) *
|
|
(DWORD)GIF2DIBInfo.cxBytes);
|
|
|
|
Ok = DeCompressGIFFileToDIB(hFile,
|
|
&GIF2DIBInfo,
|
|
pLZWBuf,
|
|
pfnOutputPels,
|
|
BitCount);
|
|
}
|
|
|
|
LocalFree((HANDLE)GIF2DIBInfo.pGIFBuf);
|
|
LocalFree((HANDLE)pLZWBuf);
|
|
GlobalUnlock(hDIB);
|
|
|
|
if (!Ok) {
|
|
|
|
GlobalFree(hDIB);
|
|
hDIB = NULL;
|
|
}
|
|
|
|
return(hDIB);
|
|
}
|