Skip to content

Commit

Permalink
Added user pointer to GIDraw callback and animated digit example
Browse files Browse the repository at this point in the history
  • Loading branch information
bitbank2 committed May 31, 2021
1 parent e665ca4 commit d3a0bd2
Show file tree
Hide file tree
Showing 15 changed files with 10,059 additions and 30 deletions.
1,274 changes: 1,274 additions & 0 deletions examples/gif_animated_digits/digit_0.h

Large diffs are not rendered by default.

433 changes: 433 additions & 0 deletions examples/gif_animated_digits/digit_1.h

Large diffs are not rendered by default.

1,378 changes: 1,378 additions & 0 deletions examples/gif_animated_digits/digit_2.h

Large diffs are not rendered by default.

876 changes: 876 additions & 0 deletions examples/gif_animated_digits/digit_3.h

Large diffs are not rendered by default.

563 changes: 563 additions & 0 deletions examples/gif_animated_digits/digit_4.h

Large diffs are not rendered by default.

1,004 changes: 1,004 additions & 0 deletions examples/gif_animated_digits/digit_5.h

Large diffs are not rendered by default.

1,093 changes: 1,093 additions & 0 deletions examples/gif_animated_digits/digit_6.h

Large diffs are not rendered by default.

867 changes: 867 additions & 0 deletions examples/gif_animated_digits/digit_7.h

Large diffs are not rendered by default.

1,457 changes: 1,457 additions & 0 deletions examples/gif_animated_digits/digit_8.h

Large diffs are not rendered by default.

849 changes: 849 additions & 0 deletions examples/gif_animated_digits/digit_9.h

Large diffs are not rendered by default.

237 changes: 237 additions & 0 deletions examples/gif_animated_digits/gif_animated_digits.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
//
// Animated GIF digit demo
// written by Larry Bank
// May 30, 2021
//
#ifdef ESP_PLATFORM
#include <M5Core2.h>
#define tft M5.Lcd
#endif

#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

#include <AnimatedGIF.h>
// animated digit images
#include "digit_0.h"
#include "digit_1.h"
#include "digit_2.h"
#include "digit_3.h"
#include "digit_4.h"
#include "digit_5.h"
#include "digit_6.h"
#include "digit_7.h"
#include "digit_8.h"
#include "digit_9.h"

// Display settings for Adafruit PyPortal
#define TFT_RESET 24
#define TFT_BACKLIGHT 25
#define TFT_D0 34 // Data bit 0 pin (MUST be on PORT byte boundary)
#define TFT_WR 26 // Write-strobe pin (CCL-inverted timer output)
#define TFT_DC 10 // Data/command pin
#define TFT_CS 11 // Chip-select pin
#define TFT_RST 24 // Reset pin
#define TFT_RD 9 // Read-strobe pin
#define TFT_BACKLIGHT 25

#define DISPLAY_WIDTH 320
#define DISPLAY_HEIGHT 240
#ifndef ESP_PLATFORM
Adafruit_ILI9341 tft = Adafruit_ILI9341(tft8bitbus, TFT_D0, TFT_WR, TFT_DC, TFT_CS, TFT_RST, TFT_RD);
#endif
AnimatedGIF gif[4]; // we need 4 independent instances of the class to animate the 4 digits simultaneously
typedef struct my_private_struct
{
int xoff, yoff; // corner offset
} PRIVATE;

// Draw a line of image directly on the LCD
void GIFDraw(GIFDRAW *pDraw)
{
uint8_t *s;
uint16_t *d, *usPalette, usTemp[320];
int x, y, iWidth;
PRIVATE *pPriv = (PRIVATE *)pDraw->pUser;

iWidth = pDraw->iWidth;
if (iWidth + pDraw->iX > DISPLAY_WIDTH)
iWidth = DISPLAY_WIDTH - pDraw->iX;
usPalette = pDraw->pPalette;
y = pPriv->yoff + pDraw->iY + pDraw->y; // current line
if (y >= DISPLAY_HEIGHT || pDraw->iX >= DISPLAY_WIDTH || iWidth < 1)
return;
s = pDraw->pPixels;
if (pDraw->ucDisposalMethod == 2) // restore to background color
{
for (x=0; x<iWidth; x++)
{
if (s[x] == pDraw->ucTransparent)
s[x] = pDraw->ucBackground;
}
pDraw->ucHasTransparency = 0;
}

// Apply the new pixels to the main image
if (pDraw->ucHasTransparency) // if transparency used
{
uint8_t *pEnd, c, ucTransparent = pDraw->ucTransparent;
int x, iCount;
pEnd = s + iWidth;
x = 0;
iCount = 0; // count non-transparent pixels
while(x < iWidth)
{
c = ucTransparent-1;
d = usTemp;
while (c != ucTransparent && s < pEnd)
{
c = *s++;
if (c == ucTransparent) // done, stop
{
s--; // back up to treat it like transparent
}
else // opaque
{
*d++ = usPalette[c];
iCount++;
}
} // while looking for opaque pixels
if (iCount) // any opaque pixels?
{
tft.startWrite();
tft.setAddrWindow(pPriv->xoff + pDraw->iX + x, y, iCount, 1);
#ifdef ESP_PLATFORM
tft.pushColors(usTemp, iCount, true);
#else
tft.writePixels(usTemp, iCount, false, false);
#endif
tft.endWrite();
x += iCount;
iCount = 0;
}
// no, look for a run of transparent pixels
c = ucTransparent;
while (c == ucTransparent && s < pEnd)
{
c = *s++;
if (c == ucTransparent)
iCount++;
else
s--;
}
if (iCount)
{
x += iCount; // skip these
iCount = 0;
}
}
}
else
{
s = pDraw->pPixels;
// Translate the 8-bit pixels through the RGB565 palette (already byte reversed)
for (x=0; x<iWidth; x++)
usTemp[x] = usPalette[*s++];
tft.startWrite();
tft.setAddrWindow(pPriv->xoff + pDraw->iX, y, iWidth, 1);
#ifdef ESP_PLATFORM
tft.pushColors(usTemp, iWidth, true);
#else
tft.writePixels(usTemp, iWidth, false, false);
#endif
tft.endWrite();
}
} /* GIFDraw() */

const uint8_t * digits[10] = {digit_0, digit_1, digit_2, digit_3, digit_4, digit_5, digit_6, digit_7, digit_8, digit_9};
const size_t lengths[10] = {sizeof(digit_0), sizeof(digit_1), sizeof(digit_2), sizeof(digit_3), sizeof(digit_4), sizeof(digit_5),
sizeof(digit_6), sizeof(digit_7), sizeof(digit_8), sizeof(digit_9)};
//
// Display 4 animated digits (80 pixels wide each)
// only animate the digits which change from one iteration to the next
//
void ShowDigits(int iValue, int iOldValue)
{
int i, rc, iBusy;
PRIVATE priv;
int jn, jo, t0, t1;
long lTime;

priv.yoff = 72; // center digits vertically
iBusy = 0;
// mark digitis which need to change with a single bit flag
jn = iValue; jo = iOldValue;
for (i=3; i>=0; i--) { // compare old and new values
t0 = jn % 10; t1 = jo % 10;
if (t0 != t1) {
iBusy |= (1 << i);
gif[i].open((uint8_t *)digits[t0], lengths[t0], GIFDraw); // prepare the right digit animated file
}
jn /= 10;
jo /= 10; // next digit
}
while (iBusy) {
// Draw each frame of each changing digit together so that they animate together
lTime = millis() + 40; // play the frames at a rate of 25fps (40ms per frame)
for (i=0; i<4; i++) {
if (iBusy & (1 << i)) {
// Advance this animation one frame
priv.xoff = 80 * i; // each digit is 80 pixels wide
rc = gif[i].playFrame(false, NULL, (void *)&priv); // draw it and return immediately
if (!rc) { // animation has ended
iBusy &= ~(1<<i); // clear the bit indicating this digit is busy
gif[i].close();
}
}
} // for each digit
delay(25);
// while ((millis() - lTime) < 0)
// {
// delay(1);
// };
} // while digits still changing
} /* ShowDigits() */

void setup() {
Serial.begin(115200);
// while (!Serial);

#ifdef ESP_PLATFORM
M5.begin(true, true, true, true);
// if (!SD.begin()) {
// M5.Lcd.println("Card failed, or not present");
// while (1);
// }
#else
// put your setup code here, to run once:
pinMode(TFT_BACKLIGHT, OUTPUT);
digitalWrite(TFT_BACKLIGHT, HIGH);

pinMode(TFT_RESET, OUTPUT);
digitalWrite(TFT_RESET, HIGH);
delay(10);
digitalWrite(TFT_RESET, LOW);
delay(10);
digitalWrite(TFT_RESET, HIGH);
delay(10);
tft.begin();
tft.setRotation(1);
#endif
tft.fillScreen(ILI9341_WHITE);
// tft.setTextColor(ILI9341_YELLOW);
// tft.setTextSize(2);
for (int i=0; i<4; i++)
gif[i].begin(GIF_PALETTE_RGB565_LE);
} /* setup() */

void loop() {
int i, iOld;
iOld = 9999; // force every digit to be drawn the first time
for (i=0; i<9999; i++) {
ShowDigits(i, iOld);
iOld = i;
delay(250);
}
} /* loop() */
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=AnimatedGIF
version=1.3.2
version=1.4.0
author=Larry Bank
maintainer=Larry Bank
sentence=Universal GIF player for MCUs with at least 32K of RAM.
Expand Down
12 changes: 5 additions & 7 deletions src/AnimatedGIF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ int AnimatedGIF::getCanvasHeight()

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

int AnimatedGIF::getLastError()
Expand Down Expand Up @@ -154,14 +154,11 @@ void AnimatedGIF::reset()
(*_gif.pfnSeek)(&_gif.GIFFile, 0);
} /* reset() */

void AnimatedGIF::begin(int iEndian, unsigned char ucPaletteType)
void AnimatedGIF::begin(unsigned char ucPaletteType)

This comment has been minimized.

Copy link
@embedded-creations

embedded-creations Jun 3, 2021

This is a large API change, and I believe along with deleting the definition for LITTLE_ENDIAN_PIXELS broke a bunch of your example code. Maybe you should keep the endian definitions and the two-argument begin() calls around for backwards compatibility? I'm not sure how to support this change with my GifDecoder library. I'd probably have to note that earlier versions of my library are only compatible with AnimatedGIF <1.4.0 and later versions are only compatible with >=1.4.0

{
memset(&_gif, 0, sizeof(_gif));
if (iEndian != LITTLE_ENDIAN_PIXELS && iEndian != BIG_ENDIAN_PIXELS)
if (ucPaletteType != GIF_PALETTE_RGB565_LE && ucPaletteType != GIF_PALETTE_RGB565_BE && ucPaletteType != GIF_PALETTE_RGB888)
_gif.iError = GIF_INVALID_PARAMETER;
if (ucPaletteType != GIF_PALETTE_RGB565 && ucPaletteType != GIF_PALETTE_RGB888)
_gif.iError = GIF_INVALID_PARAMETER;
_gif.ucLittleEndian = (iEndian == LITTLE_ENDIAN_PIXELS);
_gif.ucPaletteType = ucPaletteType;
_gif.ucDrawType = GIF_DRAW_RAW; // assume RAW pixel handling
_gif.pFrameBuffer = NULL;
Expand All @@ -172,7 +169,7 @@ void AnimatedGIF::begin(int iEndian, unsigned char ucPaletteType)
// 1 = good result and more frames exist
// 0 = no more frames exist, a frame may or may not have been played: use getLastError() and look for GIF_SUCCESS to know if a frame was played
// -1 = error
int AnimatedGIF::playFrame(bool bSync, int *delayMilliseconds)
int AnimatedGIF::playFrame(bool bSync, int *delayMilliseconds, void *pUser)
{
int rc;
#if !defined( __MACH__ ) && !defined( __LINUX__ )
Expand All @@ -185,6 +182,7 @@ long lTime = millis();
}
if (GIFParseInfo(&_gif, 0))
{
_gif.pUser = pUser;
rc = DecodeLZW(&_gif, 0);
if (rc != 0) // problem
return -1;
Expand Down
21 changes: 10 additions & 11 deletions src/AnimatedGIF.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,10 @@
#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_PALETTE_RGB565 = 0, // default
GIF_PALETTE_RGB888
GIF_PALETTE_RGB565_LE = 0, // little endian (default)
GIF_PALETTE_RGB565_BE, // big endian
GIF_PALETTE_RGB888 // original 24-bpp entries
};
//
// Draw callback pixel type
Expand Down Expand Up @@ -98,6 +95,7 @@ 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
void *pUser; // user supplied pointer
uint8_t *pPixels; // 8-bit source pixels for this line
uint16_t *pPalette; // little or big-endian RGB565 palette entries (default)
uint8_t *pPalette24; // RGB888 palette (optional)
Expand Down Expand Up @@ -136,6 +134,7 @@ typedef struct gif_image_tag
GIF_OPEN_CALLBACK *pfnOpen;
GIF_CLOSE_CALLBACK *pfnClose;
GIFFILE GIFFile;
void *pUser;
unsigned char *pFrameBuffer;
unsigned char *pPixels, *pOldPixels;
unsigned char ucLineBuf[MAX_WIDTH]; // current line
Expand All @@ -146,7 +145,7 @@ typedef struct gif_image_tag
unsigned short usGIFTable[4096];
unsigned char ucGIFPixels[8192];
unsigned char bEndOfFrame;
unsigned char ucGIFBits, ucBackground, ucTransparent, ucCodeStart, ucMap, bUseLocalPalette, ucLittleEndian;
unsigned char ucGIFBits, ucBackground, ucTransparent, ucCodeStart, ucMap, bUseLocalPalette;
unsigned char ucPaletteType; // RGB565 or RGB888
unsigned char ucDrawType; // RAW or COOKED
} GIFIMAGE;
Expand All @@ -162,8 +161,8 @@ class AnimatedGIF
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, unsigned char ucPaletteType = GIF_PALETTE_RGB565);
int playFrame(bool bSync, int *delayMilliseconds);
void begin(unsigned char ucPaletteType = GIF_PALETTE_RGB565_LE);
int playFrame(bool bSync, int *delayMilliseconds, void *pUser = NULL);
int getCanvasWidth();
int allocFrameBuf(GIF_ALLOC_CALLBACK *pfnAlloc);
int setDrawType(int iType);
Expand All @@ -182,9 +181,9 @@ class AnimatedGIF
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 , unsigned char ucPaletteType);
void GIF_begin(GIFIMAGE *pGIF, unsigned char ucPaletteType);
void GIF_reset(GIFIMAGE *pGIF);
int GIF_playFrame(GIFIMAGE *pGIF, int *delayMilliseconds);
int GIF_playFrame(GIFIMAGE *pGIF, int *delayMilliseconds, void *pUser);
int GIF_getCanvasWidth(GIFIMAGE *pGIF);
int GIF_getCanvasHeight(GIFIMAGE *pGIF);
int GIF_getComment(GIFIMAGE *pGIF, char *destBuffer);
Expand Down
Loading

0 comments on commit d3a0bd2

Please sign in to comment.