doubao_chat/apps/common/ui/GUI_GIF.c

1277 lines
39 KiB
C

/*********************************************************************
* SEGGER Microcontroller GmbH & Co. KG *
* Solutions for real time microcontroller applications *
**********************************************************************
* *
* (c) 1996 - 2010 SEGGER Microcontroller GmbH & Co. KG *
* *
* Internet: www.segger.com Support: support@segger.com *
* *
**********************************************************************
** emWin V5.06 - Graphical user interface for embedded applications **
emWin is protected by international copyright laws. Knowledge of the
source code may not be used to write a similar product. This file may
only be used in accordance with a license and should not be re-
distributed in any way. We appreciate your understanding and fairness.
----------------------------------------------------------------------
File : GUI_GIF.c
Purpose : Implementation of rendering GIF images
---------------------------END-OF-HEADER------------------------------
*/
#include <stdlib.h>
#include <string.h>
#ifdef CONFIG_UI_ENABLE
#include "GUI_GIF_Private.h"
/*********************************************************************
*
* Defines
*
**********************************************************************
*/
/* Input buffer configuration */
#ifndef GUI_GIF_INPUT_BUFFER_SIZE
#define GUI_GIF_INPUT_BUFFER_SIZE 0
#endif
/* Constants for reading GIFs */
#define GIF_INTRO_TERMINATOR ';'
#define GIF_INTRO_EXTENSION '!'
#define GIF_INTRO_IMAGE ','
#define GIF_COMMENT 0xFE
#define GIF_APPLICATION 0xFF
#define GIF_PLAINTEXT 0x01
#define GIF_GRAPHICCTL 0xF9
/*********************************************************************
*
* Static const data
*
**********************************************************************
*/
#if GUI_GIF_INPUT_BUFFER_SIZE
static u8 _aInputBuffer[GUI_GIF_INPUT_BUFFER_SIZE];
#endif
static const int _aMaskTbl[16] = {
0x0000, 0x0001, 0x0003, 0x0007,
0x000f, 0x001f, 0x003f, 0x007f,
0x00ff, 0x01ff, 0x03ff, 0x07ff,
0x0fff, 0x1fff, 0x3fff, 0x7fff,
};
/*********************************************************************
*
* Static data
*
**********************************************************************
*/
static u8 _aBuffer[256];
/*********************************************************************
*
* Private data
*
**********************************************************************
*/
const int GUI_GIF__aInterlaceOffset[4] = { 8, 8, 4, 2 };
const int GUI_GIF__aInterlaceYPos[4] = { 0, 4, 2, 1 };
GUI_GIF_CONTEXT pContext;
/*********************************************************************
*
* Static code
*
**********************************************************************
*//*********************************************************************
*
* GUI__Read16
*/
static u16 GUI__Read16(const u8 **ppData)
{
const u8 *pData;
u16 Value;
pData = *ppData;
Value = *pData;
Value |= (u16)(*(pData + 1) << 8);
pData += 2;
*ppData = pData;
return Value;
}
/*********************************************************************
*
* GUI__Read32
*/
static u32 GUI__Read32(const u8 **ppData)
{
const u8 *pData;
u32 Value;
pData = *ppData;
Value = *pData;
Value |= ((u32) * (pData + 1) << 8);
Value |= ((u32) * (pData + 2) << 16);
Value |= ((u32) * (pData + 3) << 24);
pData += 4;
*ppData = pData;
return Value;
}
/*********************************************************************
*
* _ReadBytes
*
* Purpose:
* Reads a string from the given pointer if possible and increments the pointer
*/
static void _ReadBytes(GUI_GIF_CONTEXT *pContext, u8 *pBuffer, int Len)
{
const u8 *pData;
if (GUI_GIF__ReadData(pContext, Len, &pData, 0)) {
return; /* Error */
}
memcpy(pBuffer, pData, Len);
}
/*********************************************************************
*
* _GetDataBlock
*
* Purpose:
* Reads a LZW data block. The first byte contains the length of the block,
* so the maximum length is 256 byte
*
* Return value:
* Length of the data block
*/
static int _GetDataBlock(GUI_GIF_CONTEXT *pContext, u8 *pBuffer)
{
u8 Count;
const u8 *pData;
if (GUI_GIF__ReadData(pContext, 1, &pData, 0)) {
return 0; /* Error */
}
Count = *pData; /* Read the length of the data block */
if (Count) {
if (pBuffer) {
_ReadBytes(pContext, pBuffer, Count);
} else {
if (GUI_GIF__ReadData(pContext, Count, &pData, 0)) {
return 0; /* Error */
}
}
}
return ((int)Count);
}
/*********************************************************************
*
* _GetNextCode
*
* Purpose:
* Returns the next LZW code from the LZW stack. One LZW code contains up to 12 bits.
*
* Return value:
* >= 0 if succeed
* < 0 if not succeed
*/
static int _GetNextCode(GUI_GIF_CONTEXT *pContext)
{
int i, j, End;
long Result;
if (pContext->ReturnClear) {
/* The first code should be a clear code. */
pContext->ReturnClear = 0;
return pContext->ClearCode;
}
End = pContext->CurBit + pContext->CodeSize;
if (End >= pContext->LastBit) {
int Count;
if (pContext->GetDone) {
return -1; /* Error */
}
pContext->aBuffer[0] = pContext->aBuffer[pContext->LastByte - 2];
pContext->aBuffer[1] = pContext->aBuffer[pContext->LastByte - 1];
if ((Count = _GetDataBlock(pContext, &pContext->aBuffer[2])) == 0) {
pContext->GetDone = 1;
}
if (Count < 0) {
return -1; /* Error */
}
pContext->LastByte = 2 + Count;
pContext->CurBit = (pContext->CurBit - pContext->LastBit) + 16;
pContext->LastBit = (2 + Count) * 8 ;
End = pContext->CurBit + pContext->CodeSize;
}
j = End >> 3;
i = pContext->CurBit >> 3;
if (i == j) {
Result = (long)pContext->aBuffer[i];
} else if (i + 1 == j) {
Result = (long)pContext->aBuffer[i] | ((long)pContext->aBuffer[i + 1] << 8);
} else {
Result = (long)pContext->aBuffer[i] | ((long)pContext->aBuffer[i + 1] << 8) | ((long)pContext->aBuffer[i + 2] << 16);
}
Result = (Result >> (pContext->CurBit & 0x7)) & _aMaskTbl[pContext->CodeSize];
pContext->CurBit += pContext->CodeSize;
return (int)Result;
}
/*********************************************************************
*
* _ReadExtension
*
* Purpose:
* Reads an extension block. One extension block can consist of several data blocks.
* If an unknown extension block occures, the routine failes.
*/
static int _ReadExtension(GUI_GIF_CONTEXT *pContext, int *pTransIndex, GUI_GIF_IMAGE_INFO *pInfo, u8 *pDisposal)
{
u8 Label;
const u8 *pData;
if (GUI_GIF__ReadData(pContext, 1, &pData, 0)) {
return 1; /* Error */
}
Label = *pData;
switch (Label) {
case GIF_PLAINTEXT:
case GIF_APPLICATION:
case GIF_COMMENT:
while (_GetDataBlock(pContext, _aBuffer) > 0);
return 0;
case GIF_GRAPHICCTL:
if (_GetDataBlock(pContext, _aBuffer) != 4) { /* Length of a graphic control block must be 4 */
return 1;
}
if (pInfo) {
pInfo->Delay = (_aBuffer[2] << 8) | _aBuffer[1];
}
if (pDisposal) {
*pDisposal = (_aBuffer[0] >> 2) & 0x7;
}
if (pTransIndex) {
*pTransIndex = -1;
if ((_aBuffer[0] & 0x1) != 0) {
*pTransIndex = _aBuffer[3];
}
}
/* Skip block terminator, must be 0 */
if (GUI_GIF__ReadData(pContext, 1, &pData, 0)) {
return 1; /* Error */
}
if (*pData) {
return 1; /* Error */
}
return 0;
}
return 1; /* Error */
}
/*********************************************************************
*
* _ReadComment
*
* Purpose:
* Reads a comment from the extension block if available and returns the number
* of comment bytes.
*/
static int _ReadComment(GUI_GIF_CONTEXT *pContext, u8 *pBuffer, int MaxSize, int *pSize)
{
u8 Label;
int Size;
const u8 *pData;
if (GUI_GIF__ReadData(pContext, 1, &pData, 0)) {
return 1; /* Error */
}
Label = *pData;
switch (Label) {
case GIF_PLAINTEXT:
case GIF_APPLICATION:
while (_GetDataBlock(pContext, _aBuffer) > 0);
return 0;
case GIF_COMMENT:
Size = _GetDataBlock(pContext, _aBuffer);
if (Size > MaxSize) {
Size = MaxSize;
}
if (pBuffer) {
*pSize = Size;
memcpy(pBuffer, _aBuffer, Size);
}
return 0;
case GIF_GRAPHICCTL:
if (_GetDataBlock(pContext, _aBuffer) != 4) { /* Length of a graphic control block must be 4 */
return 1;
}
/* Skip block terminator, must be 0 */
if (GUI_GIF__ReadData(pContext, 1, &pData, 0)) {
return 1; /* Error */
}
if (*pData) {
return 1; /* Error */
}
return 0;
}
return 1; /* Error */
}
/*********************************************************************
*
* _ReadColorMap
*/
static int _ReadColorMap(GUI_GIF_CONTEXT *pContext, int NumColors)
{
int i;
for (i = 0; i < NumColors; i++) {
u8 r, g, b;
const u8 *pData;
if (GUI_GIF__ReadData(pContext, 3, &pData, 0)) {
return 1; /* Error */
}
r = *(pData + 0);
g = *(pData + 1);
b = *(pData + 2);
pContext->aColorTable[i] = r | ((u16)g << 8) | ((u32)b << 16);
}
return 0;
}
/*********************************************************************
*
* _InitGIFDecoding
*
* Purpose:
* The routine initializes the static SOURCE structure and checks
* if the file is a legal GIF file.
*
* Return value:
* 0 on success, 1 on error
*/
static int _InitGIFDecoding(GUI_GIF_CONTEXT *pContext)
{
const u8 *pData;
if (GUI_GIF__ReadData(pContext, 6, &pData, 1)) {
return 1; /* Error */
}
/* Check if the file is a legal GIF file by checking the 6 byte file header */
if ((*(pData + 0) != 'G') ||
(*(pData + 1) != 'I') ||
(*(pData + 2) != 'F') ||
(*(pData + 3) != '8') ||
((*(pData + 4) != '7') && (*(pData + 4) != '9')) ||
(*(pData + 5) != 'a')) {
return 1;
}
return 0;
}
/*********************************************************************
*
* _GetImageDimension
*
* Purpose:
* Reads the image dimension from the logical screen descriptor
*
* Return value:
* 0 on success, 1 on error
*/
static int _GetImageDimension(GUI_GIF_CONTEXT *pContext, int *pxSize, int *pySize)
{
int XSize, YSize;
const u8 *pData;
/* Initialize decoding */
if (_InitGIFDecoding(pContext)) {
return 1; /* Error */
}
/* Get data */
if (GUI_GIF__ReadData(pContext, 4, &pData, 0)) {
return 1; /* Error */
}
/* Read image size */
XSize = GUI__Read16(&pData);
YSize = GUI__Read16(&pData);
if ((XSize > 2000) || (YSize > 2000)) {
return 1; /* Error if image is too large */
}
if (pxSize) {
*pxSize = XSize;
}
if (pySize) {
*pySize = YSize;
}
return 0;
}
/*********************************************************************
*
* _GetGlobalColorTable
*
* Purpose:
* Reads the global color table if there is one. Returns the number of
* available colors over the pointer pNumColors (can be NULL).
*
* Return value:
* 0 on success, 1 on error
*/
static int _GetGlobalColorTable(GUI_GIF_CONTEXT *pContext, int *pNumColors)
{
u8 Flags;
int NumColors;
const u8 *pData;
if (GUI_GIF__ReadData(pContext, 3, &pData, 0)) {
return 1; /* Error */
}
/* Read flags from logical screen descriptor */
Flags = *pData;
NumColors = 2 << (Flags & 0x7);
if (Flags & 0x80) {
pContext->pBuffer = pData + 1;
/* Read global color table */
if (_ReadColorMap(pContext, NumColors)) {
return 1; /* Error */
}
pContext->BkColorIndex = pContext->aColorTable[pContext->pBuffer[0]];
}
if (pNumColors) {
*pNumColors = NumColors;
}
return 0;
}
/*********************************************************************
*
* _GetSizeAndColorTable
*/
static int _GetSizeAndColorTable(GUI_GIF_CONTEXT *pContext, int *pxSize, int *pySize, int *pNumColors)
{
/* Get image size */
if (_GetImageDimension(pContext, pxSize, pySize)) {
return 1; /* Error */
}
/* Get global color table (if available) */
if (_GetGlobalColorTable(pContext, pNumColors)) {
return 1; /* Error */
}
return 0;
}
/*********************************************************************
*
* _SkipLocalColorTable
*/
static void _SkipLocalColorTable(GUI_GIF_CONTEXT *pContext)
{
u8 Flags;
const u8 *pData;
if (GUI_GIF__ReadData(pContext, 9, &pData, 0)) {
return; /* Error */
}
Flags = *(pData + 8); /* Skip the first 8 bytes of the image descriptor, only 'Flags' are intresting */
if (Flags & 0x80) {
/* Skip local color table */
int NumBytes, RemBytes, NumColors;
NumColors = 2 << (Flags & 0x7);
RemBytes = NumColors * 3 + 1; /* Skip colors (Number of colors * 3) and the codesize byte */
while (RemBytes) {
if (RemBytes > 256) {
NumBytes = 256;
} else {
NumBytes = RemBytes;
}
if (GUI_GIF__ReadData(pContext, NumBytes, &pData, 0)) {
return; /* Error */
}
RemBytes -= NumBytes;
}
} else {
/* Skip codesize */
if (GUI_GIF__ReadData(pContext, 1, &pData, 0)) {
return; /* Error */
}
}
}
/*********************************************************************
*
* _GetImageInfo
*/
static int _GetImageInfo(GUI_GIF_CONTEXT *pContext, GUI_GIF_IMAGE_INFO *pInfo, int Index)
{
u8 Introducer;
int NumColors, ImageCnt;
const u8 *pData;
/* Initialize decoding and get size and global color table */
if (_GetSizeAndColorTable(pContext, NULL, NULL, &NumColors)) {
return 1; /* Error */
}
ImageCnt = 0;
/* Iterate over the blocks */
do {
if (GUI_GIF__ReadData(pContext, 1, &pData, 0)) {
return 1; /* Error */
}
Introducer = *pData;
switch (Introducer) {
case GIF_INTRO_IMAGE:
if (Index == ImageCnt) {
if (GUI_GIF__ReadData(pContext, 8, &pData, 0)) {
return 1; /* Error */
}
pInfo->xPos = GUI__Read16(&pData);
pInfo->xPos = GUI__Read16(&pData);
pInfo->xSize = GUI__Read16(&pData);
pInfo->ySize = GUI__Read16(&pData);
return 0;
}
_SkipLocalColorTable(pContext);
while (_GetDataBlock(pContext, 0) > 0); /* Skip data blocks */
ImageCnt++;
break;
case GIF_INTRO_TERMINATOR:
break;
case GIF_INTRO_EXTENSION:
if (_ReadExtension(pContext, NULL, (Index == ImageCnt) ? pInfo : NULL, NULL)) {
return 1;
}
break;
default:
return 1;
}
} while (Introducer != GIF_INTRO_TERMINATOR); /* We do not support more than one image, so stop when the first terminator has been read */
return 0;
}
/*********************************************************************
*
* _GetGIFComment
*
* Purpose:
* Returns the given comment of the GIF image.
*
* Parameters:
* pData - Pointer to start of the GIF file
* NumBytes - Number of bytes in the file
* pBuffer - Pointer to buffer to be filled by the routine
* MaxSize - Number of bytes in buffer
* Index - Index of the comment to be returned
*
* Return value:
* 0 on success, 1 on error
*/
static int _GetGIFComment(GUI_GIF_CONTEXT *pContext, u8 *pBuffer, int MaxSize, int Index)
{
u8 Introducer;
int NumColors, CommentCnt, Size;
const u8 *pData;
/* Initialize decoding and skip size and global color table */
if (_GetSizeAndColorTable(pContext, NULL, NULL, &NumColors)) {
return 1; /* Error */
}
CommentCnt = Size = 0;
/* Iterate over the blocks */
do {
if (GUI_GIF__ReadData(pContext, 1, &pData, 0)) {
return 1; /* Error */
}
Introducer = *pData;
switch (Introducer) {
case GIF_INTRO_IMAGE:
_SkipLocalColorTable(pContext);
while (_GetDataBlock(pContext, 0) > 0); /* Skip data blocks */
break;
case GIF_INTRO_TERMINATOR:
break;
case GIF_INTRO_EXTENSION:
_ReadComment(pContext, (Index == CommentCnt) ? pBuffer : NULL, MaxSize, &Size);
if ((Size) && (Index == CommentCnt)) {
return 0;
}
break;
default:
return 1;
}
} while (Introducer != GIF_INTRO_TERMINATOR); /* We do not support more than one image, so stop when the first terminator has been read */
return 1;
}
/*********************************************************************
*
* Private code
*
**********************************************************************
*/
/*********************************************************************
*
* GUI_GIF__GetNextByte
*
* Purpose:
* Reads the next LZW code from the LZW stack and returns the first byte from the LZW code.
*
* Return value:
* >= 0 if succeed
* -1 if not succeed
* -2 if end code has been read
*/
static int GUI_GIF__GetNextByte(GUI_GIF_CONTEXT *pContext)
{
int i, Code, Incode;
while ((Code = _GetNextCode(pContext)) >= 0) {
if (Code == pContext->ClearCode) {
/* Corrupt GIFs can make this happen */
if (pContext->ClearCode >= (1 << MAX_NUM_LWZ_BITS)) {
return -1; /* Error */
}
/* Clear the tables */
memset((u8 *)pContext->aCode, 0, sizeof(pContext->aCode));
for (i = 0; i < pContext->ClearCode; ++i) {
pContext->aPrefix[i] = i;
}
/* Calculate the 'special codes' in dependence of the initial code size
and initialize the stack pointer */
pContext->CodeSize = pContext->SetCodeSize + 1;
pContext->MaxCodeSize = pContext->ClearCode << 1;
pContext->MaxCode = pContext->ClearCode + 2;
pContext->sp = pContext->aDecompBuffer;
/* Read the first code from the stack after clearing and initializing */
do {
pContext->FirstCode = _GetNextCode(pContext);
} while (pContext->FirstCode == pContext->ClearCode);
pContext->OldCode = pContext->FirstCode;
return pContext->FirstCode;
}
if (Code == pContext->EndCode) {
return -2; /* End code */
}
Incode = Code;
if (Code >= pContext->MaxCode) {
*(pContext->sp)++ = pContext->FirstCode;
Code = pContext->OldCode;
}
while (Code >= pContext->ClearCode) {
*(pContext->sp)++ = pContext->aPrefix[Code];
if (Code == pContext->aCode[Code]) {
return Code;
}
if ((pContext->sp - pContext->aDecompBuffer) >= sizeof(pContext->aDecompBuffer)) {
return Code;
}
Code = pContext->aCode[Code];
}
*(pContext->sp)++ = pContext->FirstCode = pContext->aPrefix[Code];
if ((Code = pContext->MaxCode) < (1 << MAX_NUM_LWZ_BITS)) {
pContext->aCode [Code] = pContext->OldCode;
pContext->aPrefix[Code] = pContext->FirstCode;
++pContext->MaxCode;
if ((pContext->MaxCode >= pContext->MaxCodeSize) && (pContext->MaxCodeSize < (1 << MAX_NUM_LWZ_BITS))) {
pContext->MaxCodeSize <<= 1;
++pContext->CodeSize;
}
}
pContext->OldCode = Incode;
if (pContext->sp > pContext->aDecompBuffer) {
return *--(pContext->sp);
}
}
return Code;
}
/*********************************************************************
*
* GUI_GIF__InitLZW
*
* Purpose:
* Initializes the given LZW with the input code size
*/
static void GUI_GIF__InitLZW(GUI_GIF_CONTEXT *pContext, int InputCodeSize)
{
pContext->SetCodeSize = InputCodeSize;
pContext->CodeSize = InputCodeSize + 1;
pContext->ClearCode = (1 << InputCodeSize);
pContext->EndCode = (1 << InputCodeSize) + 1;
pContext->MaxCode = (1 << InputCodeSize) + 2;
pContext->MaxCodeSize = (1 << InputCodeSize) << 1;
pContext->ReturnClear = 1;
pContext->LastByte = 2;
pContext->sp = pContext->aDecompBuffer;
}
/*********************************************************************
*
* GUI_GIF__ReadData
*/
static int GUI_GIF__ReadData(GUI_GIF_CONTEXT *pContext, unsigned NumBytesReq, const u8 **ppData, unsigned StartOfFile)
{
#if GUI_GIF_INPUT_BUFFER_SIZE
if (StartOfFile) {
pContext->NumBytesInBuffer = 0;
}
/* Check if there are sufficient bytes in buffer */
if (pContext->NumBytesInBuffer < NumBytesReq) {
/* Fill up to maximum size */
unsigned NumBytesRead;
NumBytesRead = GUI_GIF_INPUT_BUFFER_SIZE - pContext->NumBytesInBuffer;
if (pContext->NumBytesInBuffer) {
memmove(_aInputBuffer, pContext->pBuffer, pContext->NumBytesInBuffer); /* Shift the remaining few bytes from top to bottom */
}
pContext->pBuffer = _aInputBuffer + pContext->NumBytesInBuffer;
if ((pContext->NumBytesInBuffer += pContext->pfGetData(pContext->pParam, NumBytesRead, ppData, StartOfFile)) < NumBytesReq) {
return 1;
}
memcpy((void *)pContext->pBuffer, (const void *)*ppData, NumBytesRead);
pContext->pBuffer = _aInputBuffer;
}
*ppData = pContext->pBuffer;
pContext->pBuffer += NumBytesReq;
pContext->NumBytesInBuffer -= NumBytesReq;
return 0;
#else
if (StartOfFile) {
pContext->Offset = 0;
}
if ((unsigned)pContext->pfGetData(pContext->pParam, ppData, NumBytesReq, pContext->Offset) != NumBytesReq) {
return 1;
}
pContext->Offset += NumBytesReq;
/*
if ((unsigned)pContext->pfGetData(pConte Points to a IMAGE_DESCRIPTOR structure, which contains infos about size, colors and interlacing.
* x0, y0 - Obvious.xt->pParam, NumBytesReq, ppData, StartOfFile) != NumBytesReq) {
return 1;
}
*/
return 0;
#endif
}
/*********************************************************************
*
* GUI_GIF__GetData
*/
static int GUI_GIF__GetData(void *p, const u8 **ppData, unsigned NumBytesReq, u32 Offset)
{
int RemBytes, NumBytes;
GUI_GIF_PARAM *pParam;
pParam = (GUI_GIF_PARAM *)p;
RemBytes = pParam->FileSize - Offset;
NumBytes = 0;
if (RemBytes > 0) {
NumBytes = ((unsigned)RemBytes > NumBytesReq) ? NumBytesReq : RemBytes;
*ppData = pParam->pFileData + Offset;
}
return NumBytes;
}
/*********************************************************************
*
* Public code
*
**********************************************************************/
/*********************************************************************
*
* _GetGIFInfo
*/
static int _GetGIFInfo(GUI_GIF_CONTEXT *pContext, GUI_GIF_IMAGE_INFO *pInfo)
{
u8 Introducer;
int NumColors, ImageCnt;
const u8 *pData;
/* Initialize decoding and get size and global color table */
if (_GetSizeAndColorTable(pContext, &pInfo->xSize, &pInfo->ySize, &NumColors)) {
return 1; /* Error */
}
ImageCnt = 0;
/* Iterate over the blocks */
do {
if (GUI_GIF__ReadData(pContext, 1, &pData, 0)) {
return 1; /* Error */
}
Introducer = *pData;
switch (Introducer) {
case GIF_INTRO_IMAGE: // , 2C
_SkipLocalColorTable(pContext);
while (_GetDataBlock(pContext, 0) > 0); /* Skip data blocks */
ImageCnt++;
pInfo->NumImages = ImageCnt;
break;
case GIF_INTRO_TERMINATOR: // ; 3B
break;
case GIF_INTRO_EXTENSION: // ! 21
if (_ReadExtension(pContext, NULL, (ImageCnt == 0) ? pInfo : NULL, NULL)) { /* Skip image extension */
return 1;
}
break;
default:
return 1;
}
} while (Introducer != GIF_INTRO_TERMINATOR); /* We do not support more than one image, so stop when the first terminator has been read */
pInfo->NumImages = ImageCnt;
return 0;
}
/*********************************************************************
*
* GUI_GIF_GetInfo
*/
int GUI_GIF_GetInfo(const void *pGIF, u32 NumBytes, GUI_GIF_IMAGE_INFO *pInfo)
{
int r = 1;
GUI_GIF_PARAM param = {0};
param.pFileData = (const u8 *)pGIF;
param.FileSize = NumBytes;
memset(&pContext, 0, sizeof(pContext));
pContext.pfGetData = GUI_GIF__GetData;
pContext.pParam = &param;
r = _GetGIFInfo(&pContext, pInfo);
return r;
}
/*******************添加自定义函数******************************/
/***做动图***/
static char *Gif_DrawFromData(GUI_GIF_CONTEXT *pContext, IMAGE_DESCRIPTOR *pDescriptor, GUI_GIF_IMAGE_INFO *Info, int Transparency, int Disposal, char *inbuf, int type)
{
int Codesize, Index, XPos, YPos, YCnt, XCnt, XEnd, YEnd, Pass = 0, Interlace, type_cnt;
int XSize, YSize, Width, Height, NumColors, BkColorIndex, ColorIndex;
const int *pTrans;
const u8 *pData;
Width = Info->xSize;
Height = Info->ySize;
XPos = pDescriptor->XPos;
YPos = pDescriptor->YPos;
XSize = pDescriptor->XSize;
YSize = pDescriptor->YSize;
NumColors = pDescriptor->NumColors;
XEnd = XSize + XPos;
YEnd = YSize + YPos ;
char *buf = inbuf;
if (type == 1) {
type_cnt = 3;
}
else if (type == 2) {
type_cnt = 2;
} else {
printf("type not match\r\n");
return NULL;
}
char *out_buf = (char *)calloc(1, XSize * YSize * type_cnt + 1);
if (!out_buf) {
printf("out_buf malloc failed\r\n");
return NULL;
}
char *tmp_buf = out_buf;
pTrans = pContext->aColorTable; //颜色表起始地址
BkColorIndex = pContext->BkColorIndex;
if (GUI_GIF__ReadData(pContext, 1, &pData, 0)) {
return NULL; /* Error */
}
Codesize = *pData; /* Read the LZW codesize */
GUI_GIF__InitLZW(pContext, Codesize); /* Initialize the LZW stack with the LZW codesize */
Interlace = (pDescriptor->Flags & 0x40) ? 1 : 0; /* Evaluate if image is interlaced */
for (YCnt = 0; YCnt < YEnd; YCnt++) {
if (YCnt < YPos) {
buf = inbuf + Width * YPos * type_cnt;
YCnt = YPos;
}
if (XPos > 0) {
buf += XPos * type_cnt;
}
for (XCnt = 0; XCnt < XSize; XCnt++) {
if (pContext->sp > pContext->aDecompBuffer) {
Index = *--(pContext->sp);
} else {
Index = GUI_GIF__GetNextByte(pContext);
}
if (Index == -2) {
printf("Index == -2\n");
return NULL; /* End code */
}
if ((Index < 0) || (Index >= NumColors)) {
printf("Index <0 || > NumColors\n");
return NULL; /* If Index out of legal range stop decompressing, error */
}
//将读到的索引引向颜色表
if (Index != Transparency || Disposal == 2) {
if (Index != Transparency) {
ColorIndex = *(pTrans + Index);
} else {
ColorIndex = BkColorIndex;
}
if (type == 1) {
*(buf + 0) = (ColorIndex >> 0) & 0xff; //R
*(buf + 1) = (ColorIndex >> 8) & 0xff; //G
*(buf + 2) = (ColorIndex >> 16) & 0xff; //B
} else if (type == 2) {
*(buf + 0) = ((ColorIndex >> 0) & 0xf8) | (((ColorIndex >> 8) & 0xe0) >> 5);
*(buf + 1) = (((ColorIndex >> 8) & 0x1c) << 3) | (((ColorIndex >> 16) & 0xf8) >> 3);
}
}
buf += type_cnt;
}//end X
if (Width > (XSize + XPos)) {
buf += (Width - XSize - XPos) * type_cnt;
}
if (Interlace) {
buf += (GUI_GIF__aInterlaceOffset[Pass] - 1) * Width * type_cnt;
if ((buf - inbuf) >= type_cnt * Width * YEnd) {
++Pass;
buf = inbuf + (GUI_GIF__aInterlaceYPos[Pass]) * Width * type_cnt;
}
}
}//end Y
buf = inbuf; //init buf address
buf = inbuf + Width * YPos * type_cnt;
buf += XPos * type_cnt;
/* for(YCnt = YPos; YCnt < YEnd; YCnt++) */
/* { */
/* memcpy(out_buf,inbuf+Width*YCnt*type_cnt+XPos*type_cnt,XSize*type_cnt); */
/* out_buf += XSize*type_cnt; */
/* } */
for (YCnt = YPos; YCnt < YEnd; YCnt++) {
memcpy(tmp_buf, buf, XSize * type_cnt);
buf += Width * type_cnt;
tmp_buf += XSize * type_cnt;
}
return out_buf;
}
/****做图片***/
static int Picture_DrawFromData(GUI_GIF_CONTEXT *pContext, IMAGE_DESCRIPTOR *pDescriptor, GUI_GIF_IMAGE_INFO *Info, int Transparency, int Disposal, char *inbuf, int type)
{
int Codesize, Index, XPos, YPos, YCnt, XCnt, XEnd, YEnd, Pass = 0, Interlace, type_cnt;
int XSize, YSize, Width, Height, NumColors, BkColorIndex, ColorIndex;
const int *pTrans;
const u8 *pData;
Width = Info->xSize;
Height = Info->ySize;
XPos = pDescriptor->XPos;
YPos = pDescriptor->YPos;
XSize = pDescriptor->XSize;
YSize = pDescriptor->YSize;
NumColors = pDescriptor->NumColors;
XEnd = XSize + XPos;
YEnd = YSize + YPos ;
char *buf = inbuf;
if (type == 1) {
type_cnt = 3;
}
else if (type == 2) {
type_cnt = 2;
} else {
return -1;
}
pTrans = pContext->aColorTable; //颜色表起始地址
BkColorIndex = pContext->BkColorIndex;
if (GUI_GIF__ReadData(pContext, 1, &pData, 0)) {
return -1; /* Error */
}
Codesize = *pData; /* Read the LZW codesize */
GUI_GIF__InitLZW(pContext, Codesize); /* Initialize the LZW stack with the LZW codesize */
Interlace = (pDescriptor->Flags & 0x40) ? 1 : 0; /* Evaluate if image is interlaced */
for (YCnt = 0; YCnt < YEnd; YCnt++) {
if (YCnt < YPos) {
buf = inbuf + Width * YPos * type_cnt;
YCnt = YPos;
}
if (XPos > 0) {
buf += XPos * type_cnt;
}
for (XCnt = 0; XCnt < XSize; XCnt++) {
if (pContext->sp > pContext->aDecompBuffer) {
Index = *--(pContext->sp);
} else {
Index = GUI_GIF__GetNextByte(pContext);
}
if (Index == -2) {
printf("Index == -2\n");
return -2; /* End code */
}
if ((Index < 0) || (Index >= NumColors)) {
printf("Index <0 || > NumColors\n");
return -3; /* If Index out of legal range stop decompressing, error */
}
if (XCnt == 31 && YCnt == 60) {
XCnt = XCnt;
}
//将读到的索引引向颜色表
if (Index != Transparency || Disposal == 2) {
if (Index != Transparency) {
ColorIndex = *(pTrans + Index);
} else {
ColorIndex = BkColorIndex;
}
if (type == 1) {
*(buf + 0) = (ColorIndex >> 0) & 0xff; //R
*(buf + 1) = (ColorIndex >> 8) & 0xff; //G
*(buf + 2) = (ColorIndex >> 16) & 0xff; //B
} else if (type == 2) {
*(buf + 0) = ((ColorIndex >> 0) & 0xf8) | (((ColorIndex >> 8) & 0xe0) >> 5);
*(buf + 1) = (((ColorIndex >> 8) & 0x1c) << 3) | (((ColorIndex >> 16) & 0xf8) >> 3);
}
}
buf += type_cnt;
}//end X
if (Width > (XSize + XPos)) {
buf += (Width - XSize - XPos) * type_cnt;
}
if (Interlace) {
buf += (GUI_GIF__aInterlaceOffset[Pass] - 1) * Width * type_cnt;
if ((buf - inbuf) >= type_cnt * Width * YEnd) {
++Pass;
buf = inbuf + (GUI_GIF__aInterlaceYPos[Pass] + YPos) * Width * type_cnt;
}
}
}//end Y
/* free(pContext); */
return 0;
}
/**这个做gif动图***/
static char *Gif_Maker(GUI_GIF_CONTEXT *pContext, GUI_GIF_IMAGE_INFO *Info1, GUI_GIF_IMAGE_INFO *Info2, char *inbuf, int type, int Index)
{
u8 Disposal = 0;
int XSize, YSize, TransIndex = 0, ImageCnt = 0 ;
IMAGE_DESCRIPTOR Descriptor = {0};
u8 Introducer;
const u8 *pData;
/* Initialize decoding and get size and global color table */
if (_GetSizeAndColorTable(pContext, &XSize, &YSize, &Descriptor.NumColors)) {
return NULL; /* Error */
}
/* Iterate over the blocks */
do {
if (GUI_GIF__ReadData(pContext, 1, &pData, 0)) {
return NULL; /* Error */
}
Introducer = *pData;
switch (Introducer) {
case GIF_INTRO_IMAGE: // , 2C
/* Read image descriptor */
if (GUI_GIF__ReadData(pContext, 9, &pData, 0)) {
return NULL; /* Error */
}
Info2->xPos = Descriptor.XPos = GUI__Read16(&pData);
Info2->yPos = Descriptor.YPos = GUI__Read16(&pData);
Info2->xSize = Descriptor.XSize = GUI__Read16(&pData);
Info2->ySize = Descriptor.YSize = GUI__Read16(&pData);
Descriptor.Flags = *pData;
if (Descriptor.Flags & 0x80) {
/* Read local color table */
Descriptor.NumColors = 2 << (Descriptor.Flags & 0x7);
if (_ReadColorMap(pContext, Descriptor.NumColors)) {
return NULL; /* Error */
}
}
if (Index == ImageCnt) {
char *out_buf;
out_buf = Gif_DrawFromData(pContext, &Descriptor, Info1, TransIndex, Disposal, inbuf, type);
/* Skip block terminator, must be 0 */
if (GUI_GIF__ReadData(pContext, 1, &pData, 0)) {
return NULL; /* Error */
}
return out_buf;
} else {
/* Skip codesize */
if (GUI_GIF__ReadData(pContext, 1, &pData, 0)) {
return NULL; /* Error */
}
while (_GetDataBlock(pContext, 0) > 0); /* Skip data blocks */
}
ImageCnt++;
break;
case GIF_INTRO_TERMINATOR: // ; 3B
break;
case GIF_INTRO_EXTENSION: // ! 21
/* Read image extension */
if (_ReadExtension(pContext, &TransIndex, (Index == ImageCnt) ? Info1 : NULL, (Index == ImageCnt) ? &Disposal : NULL)) {
return NULL;
}
break;
default:
return NULL;
}
} while (Introducer != GIF_INTRO_TERMINATOR); /* We do not support more than one image, so stop when the first terminator has been read */
return NULL;
}
/****这个做图片获取***/
static int Picture_Maker(GUI_GIF_CONTEXT *pContext, GUI_GIF_IMAGE_INFO *Info, char *inbuf, int type, int Index)
{
u8 Disposal = 0;
int XSize, YSize, TransIndex = 0, ImageCnt = 0, ret = 0;
IMAGE_DESCRIPTOR Descriptor = {0};
u8 Introducer;
const u8 *pData;
/* Initialize decoding and get size and global color table */
if (_GetSizeAndColorTable(pContext, &XSize, &YSize, &Descriptor.NumColors)) {
return -1; /* Error */
}
/* Iterate over the blocks */
do {
if (GUI_GIF__ReadData(pContext, 1, &pData, 0)) {
return -1; /* Error */
}
Introducer = *pData;
switch (Introducer) {
case GIF_INTRO_IMAGE: // , 2C
/* Read image descriptor */
if (GUI_GIF__ReadData(pContext, 9, &pData, 0)) {
return -1; /* Error */
}
Descriptor.XPos = GUI__Read16(&pData);
Descriptor.YPos = GUI__Read16(&pData);
Descriptor.XSize = GUI__Read16(&pData);
Descriptor.YSize = GUI__Read16(&pData);
Descriptor.Flags = *pData;
if (Descriptor.Flags & 0x80) {
/* Read local color table */
Descriptor.NumColors = 2 << (Descriptor.Flags & 0x7);
if (_ReadColorMap(pContext, Descriptor.NumColors)) {
return -1; /* Error */
}
}
if (Index == ImageCnt) {
if (Picture_DrawFromData(pContext, &Descriptor, Info, TransIndex, Disposal, inbuf, type)) {
return -1;
}
/* Skip block terminator, must be 0 */
if (GUI_GIF__ReadData(pContext, 1, &pData, 0)) {
return -1; /* Error */
}
return 0;
} else {
/* Skip codesize */
if (GUI_GIF__ReadData(pContext, 1, &pData, 0)) {
return -1; /* Error */
}
while (_GetDataBlock(pContext, 0) > 0); /* Skip data blocks */
}
ImageCnt++;
break;
case GIF_INTRO_TERMINATOR: // ; 3B
break;
case GIF_INTRO_EXTENSION: // ! 21
/* Read image extension */
if (_ReadExtension(pContext, &TransIndex, NULL, NULL)) {
return -1;
}
break;
default:
return -1;
}
} while (Introducer != GIF_INTRO_TERMINATOR); /* We do not support more than one image, so stop when the first terminator has been read */
return 0;
}
char *Gif_to_Gif(const void *pGIF, u32 NumBytes, GUI_GIF_IMAGE_INFO *in_Info, GUI_GIF_IMAGE_INFO *out_Info, char *inbuf, int type, int Index)
{
GUI_GIF_PARAM Param = {0};
Param.pFileData = (const u8 *)pGIF;
Param.FileSize = NumBytes;
memset(&pContext, 0, sizeof(pContext));
pContext.pfGetData = GUI_GIF__GetData;
pContext.pParam = &Param;
return Gif_Maker(&pContext, in_Info, out_Info, inbuf, type, Index);
}
int Gif_to_Picture(const void *pGIF, u32 NumBytes, GUI_GIF_IMAGE_INFO *Info, char *inbuf, int type, int Index)
{
GUI_GIF_PARAM Param = {0};
Param.pFileData = (const u8 *)pGIF;
Param.FileSize = NumBytes;
memset(&pContext, 0, sizeof(pContext));
pContext.pfGetData = GUI_GIF__GetData;
pContext.pParam = &Param;
if (Picture_Maker(&pContext, Info, inbuf, type, Index)) {
return -1;
}
return 0;
}
#endif
/*************************** End of file ****************************/