1277 lines
39 KiB
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 = ¶m;
|
|
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 ****************************/
|
|
|
|
|