Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
cmake_minimum_required(VERSION 3.8)
project (examples)
include (../32blit.cmake)
add_subdirectory(animated_gif)
add_subdirectory(another-world)
add_subdirectory(audio-test)
add_subdirectory(audio-wave)
Expand Down
149 changes: 149 additions & 0 deletions examples/animated_gif/AnimatedGIF.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
//
// GIF Animator
// written by Larry Bank
// [email protected]
// Arduino port started 7/5/2020
// Original GIF code written 20+ years ago :)
// The goal of this code is to decode images up to 480x320
// using no more than 22K of RAM (if sent directly to an LCD display)
//
// Copyright 2020 BitBank Software, Inc. All Rights Reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//===========================================================================
#include "AnimatedGIF.h"

// Here is all of the actual code...
#include "gif.c"

//
// Memory initialization
//
int AnimatedGIF::open(uint8_t *pData, int iDataSize, GIF_DRAW_CALLBACK *pfnDraw)
{
_gif.pfnRead = readMem;
_gif.pfnSeek = seekMem;
_gif.pfnDraw = pfnDraw;
_gif.pfnOpen = NULL;
_gif.pfnClose = NULL;
_gif.GIFFile.iSize = iDataSize;
_gif.GIFFile.pData = pData;
return GIFInit(&_gif);
} /* open() */

//
// Returns the first comment block found (if any)
int AnimatedGIF::getComment(char *pDest)
{
int32_t iOldPos;

iOldPos = _gif.GIFFile.iPos; // keep old position
(*_gif.pfnSeek)(&_gif.GIFFile, _gif.iCommentPos);
(*_gif.pfnRead)(&_gif.GIFFile, (uint8_t *)pDest, _gif.sCommentLen);
(*_gif.pfnSeek)(&_gif.GIFFile, iOldPos);
pDest[_gif.sCommentLen] = 0; // zero terminate the string
return (int)_gif.sCommentLen;
} /* getComment() */

int AnimatedGIF::getCanvasWidth()
{
return _gif.iCanvasWidth;
} /* getCanvasWidth() */

int AnimatedGIF::getCanvasHeight()
{
return _gif.iCanvasHeight;
} /* getCanvasHeight() */

int AnimatedGIF::getInfo(GIFINFO *pInfo)
{
return GIFGetInfo(&_gif, pInfo);
} /* getInfo() */

int AnimatedGIF::getLastError()
{
return _gif.iError;
} /* getLastError() */

//
// File (SD/MMC) based initialization
//
int AnimatedGIF::open(const char *szFilename, GIF_OPEN_CALLBACK *pfnOpen, GIF_CLOSE_CALLBACK *pfnClose, GIF_READ_CALLBACK *pfnRead, GIF_SEEK_CALLBACK *pfnSeek, GIF_DRAW_CALLBACK *pfnDraw)
{
_gif.pfnRead = pfnRead;
_gif.pfnSeek = pfnSeek;
_gif.pfnDraw = pfnDraw;
_gif.pfnOpen = pfnOpen;
_gif.pfnClose = pfnClose;
_gif.GIFFile.fHandle = (*pfnOpen)(szFilename, &_gif.GIFFile.iSize);
if (_gif.GIFFile.fHandle == NULL)
return 0;
return GIFInit(&_gif);

} /* open() */

void AnimatedGIF::close()
{
if (_gif.pfnClose)
(*_gif.pfnClose)(_gif.GIFFile.fHandle);
} /* close() */

void AnimatedGIF::reset()
{
(*_gif.pfnSeek)(&_gif.GIFFile, 0);
} /* reset() */

void AnimatedGIF::begin(int iEndian)
{
memset(&_gif, 0, sizeof(_gif));
if (iEndian < LITTLE_ENDIAN_PIXELS || iEndian > BIG_ENDIAN_PIXELS)
_gif.iError = GIF_INVALID_PARAMETER;
_gif.ucLittleEndian = (iEndian == LITTLE_ENDIAN_PIXELS);
}
//
// Play a single frame
// returns:
// 1 = good result and more frames exist
// 0 = good result and no more frames exist
// -1 = error
int AnimatedGIF::playFrame(bool bSync, int *delayMilliseconds)
{
int rc;
//#if !defined( __MACH__ ) && !defined( __LINUX__ ) && !defined( TARGET_32BLIT_HW )
//long lTime = millis();
//#endif

if (_gif.GIFFile.iPos >= _gif.GIFFile.iSize-1) // no more data exists
{
(*_gif.pfnSeek)(&_gif.GIFFile, 0); // seek to start
}
if (GIFParseInfo(&_gif, 0))
{
rc = DecodeLZW(&_gif, 0);
if (rc != 0) // problem
return 0;
}
else
{
return 0; // error parsing the frame info, we may be at the end of the file
}
// Return 1 for more frames or 0 if this was the last frame
if (bSync)
{
//#if !defined( __MACH__ ) && !defined( __LINUX__ ) && !defined( TARGET_32BLIT_HW )
// lTime = millis() - lTime;
// if (lTime < _gif.iFrameDelay) // need to pause a bit
// delay(_gif.iFrameDelay - lTime);
//#endif // __LINUX__
}
if (delayMilliseconds) // if not NULL, return the frame delay time
*delayMilliseconds = _gif.iFrameDelay;
return (_gif.GIFFile.iPos < _gif.GIFFile.iSize-1);
} /* playFrame() */
172 changes: 172 additions & 0 deletions examples/animated_gif/AnimatedGIF.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
// Copyright 2020 BitBank Software, Inc. All Rights Reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//===========================================================================

#ifndef __ANIMATEDGIF__
#define __ANIMATEDGIF__
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#define memcpy_P memcpy
#define PROGMEM
//
// GIF Animator
// Written by Larry Bank
// Copyright (c) 2020 BitBank Software, Inc.
// [email protected]
//
// Designed to decode images up to 480x320
// using less than 22K of RAM
//

/* GIF Defines and variables */
#define MAX_CHUNK_SIZE 255
#define LZW_BUF_SIZE (6*MAX_CHUNK_SIZE)
#define LZW_HIGHWATER (4*MAX_CHUNK_SIZE)
#define MAX_WIDTH 320
#define FILE_BUF_SIZE 4096

#define PIXEL_FIRST 0
#define PIXEL_LAST 4096
#define LINK_UNUSED 5911 // 0x1717 to use memset
#define LINK_END 5912
#define MAX_HASH 5003
#define MAXMAXCODE 4096

// RGB565 pixel byte order in the palette
#define BIG_ENDIAN_PIXELS 0
#define LITTLE_ENDIAN_PIXELS 1

enum {
GIF_SUCCESS = 0,
GIF_DECODE_ERROR,
GIF_TOO_WIDE,
GIF_INVALID_PARAMETER,
GIF_UNSUPPORTED_FEATURE
};

typedef struct gif_file_tag
{
int32_t iPos; // current file position
int32_t iSize; // file size
uint8_t *pData; // memory file pointer
void * fHandle; // class pointer to File/SdFat or whatever you want
} GIFFILE;

typedef struct gif_info_tag
{
int32_t iFrameCount; // total frames in file
int32_t iDuration; // duration of animation in milliseconds
int32_t iMaxDelay; // maximum frame delay
int32_t iMinDelay; // minimum frame delay
} GIFINFO;

typedef struct gif_draw_tag
{
int iX, iY; // Corner offset of this frame on the canvas
int y; // current line being drawn (0 = top line of image)
int iWidth, iHeight; // size of this frame
uint8_t *pPixels; // 8-bit source pixels for this line
uint16_t *pPalette; // little or big-endian RGB565 palette entries
uint8_t ucTransparent; // transparent color
uint8_t ucHasTransparency; // flag indicating the transparent color is in use
uint8_t ucDisposalMethod; // frame disposal method
uint8_t ucBackground; // background color
} GIFDRAW;

// Callback function prototypes
typedef int32_t (GIF_READ_CALLBACK)(GIFFILE *pFile, uint8_t *pBuf, int32_t iLen);
typedef int32_t (GIF_SEEK_CALLBACK)(GIFFILE *pFile, int32_t iPosition);
typedef void (GIF_DRAW_CALLBACK)(GIFDRAW *pDraw);
typedef void * (GIF_OPEN_CALLBACK)(const char *szFilename, int32_t *pFileSize);
typedef void (GIF_CLOSE_CALLBACK)(void *pHandle);

//
// our private structure to hold a GIF image decode state
//
typedef struct gif_image_tag
{
int iWidth, iHeight, iCanvasWidth, iCanvasHeight;
int iX, iY; // GIF corner offset
int iBpp;
int iError; // last error
int iFrameDelay; // delay in milliseconds for this frame
int iXCount, iYCount; // decoding position in image (countdown values)
int iLZWOff; // current LZW data offset
int iLZWSize; // current quantity of data in the LZW buffer
int iCommentPos; // file offset of start of comment data
short sCommentLen; // length of comment
GIF_READ_CALLBACK *pfnRead;
GIF_SEEK_CALLBACK *pfnSeek;
GIF_DRAW_CALLBACK *pfnDraw;
GIF_OPEN_CALLBACK *pfnOpen;
GIF_CLOSE_CALLBACK *pfnClose;
GIFFILE GIFFile;
unsigned char *pPixels, *pOldPixels;
unsigned char ucLineBuf[MAX_WIDTH]; // current line
unsigned char ucFileBuf[FILE_BUF_SIZE]; // holds temp data and pixel stack
unsigned short pPalette[256];
unsigned short pLocalPalette[256]; // color palettes for GIF images
unsigned char ucLZW[LZW_BUF_SIZE]; // holds 6 chunks (6x255) of GIF LZW data packed together
unsigned short usGIFTable[4096];
unsigned char ucGIFPixels[8192];
unsigned char bEndOfFrame;
unsigned char ucGIFBits, ucBackground, ucTransparent, ucCodeStart, ucMap, bUseLocalPalette, ucLittleEndian;
} GIFIMAGE;

#ifdef __cplusplus
//
// The GIF class wraps portable C code which does the actual work
//
class AnimatedGIF
{
public:
int open(uint8_t *pData, int iDataSize, GIF_DRAW_CALLBACK *pfnDraw);
int open(const char *szFilename, GIF_OPEN_CALLBACK *pfnOpen, GIF_CLOSE_CALLBACK *pfnClose, GIF_READ_CALLBACK *pfnRead, GIF_SEEK_CALLBACK *pfnSeek, GIF_DRAW_CALLBACK *pfnDraw);
void close();
void reset();
void begin(int iEndian);
int playFrame(bool bSync, int *delayMilliseconds);
int getCanvasWidth();
int getCanvasHeight();
int getInfo(GIFINFO *pInfo);
int getLastError();
int getComment(char *destBuffer);

private:
GIFIMAGE _gif;
};
#else
// C interface
int GIF_openRAM(GIFIMAGE *pGIF, uint8_t *pData, int iDataSize, GIF_DRAW_CALLBACK *pfnDraw);
int GIF_openFile(GIFIMAGE *pGIF, const char *szFilename, GIF_DRAW_CALLBACK *pfnDraw);
void GIF_close(GIFIMAGE *pGIF);
void GIF_begin(GIFIMAGE *pGIF, int iEndian);
void GIF_reset(GIFIMAGE *pGIF);
int GIF_playFrame(GIFIMAGE *pGIF, int *delayMilliseconds);
int GIF_getCanvasWidth(GIFIMAGE *pGIF);
int GIF_getCanvasHeight(GIFIMAGE *pGIF);
int GIF_getComment(GIFIMAGE *pGIF, char *destBuffer);
int GIF_getInfo(GIFIMAGE *pGIF, GIFINFO *pInfo);
int GIF_getLastError(GIFIMAGE *pGIF);
#endif // __cplusplus

// Due to unaligned memory causing an exception, we have to do these macros the slow way
#define INTELSHORT(p) ((*p) + (*(p+1)<<8))
#define INTELLONG(p) ((*p) + (*(p+1)<<8) + (*(p+2)<<16) + (*(p+3)<<24))
#define MOTOSHORT(p) (((*(p))<<8) + (*(p+1)))
#define MOTOLONG(p) (((*p)<<24) + ((*(p+1))<<16) + ((*(p+2))<<8) + (*(p+3)))

// Must be a 32-bit target processor
#define REGISTER_WIDTH 32

#endif // __ANIMATEDGIF__
4 changes: 4 additions & 0 deletions examples/animated_gif/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
cmake_minimum_required(VERSION 3.8)
project (animated_gif)
include (../../32blit.cmake)
blit_executable (animated_gif animated_gif.cpp AnimatedGIF.cpp)
Loading