ESP32-HUB75-MatrixPanel-DMA/examples/AnimatedGIF/LzwDecoder_Impl.h
2018-10-25 23:49:41 +01:00

169 lines
5.2 KiB
C++

/*
* This file contains code to decompress the LZW encoded animated GIF data
*
* Written by: Craig A. Lindley, Fabrice Bellard and Steven A. Bennett
* See my book, "Practical Image Processing in C", John Wiley & Sons, Inc.
*
* Copyright (c) 2014 Craig A. Lindley
* Minor modifications by Louis Beaudoin (pixelmatix)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#define LZWDEBUG 0
#include "GifDecoder.h"
template <int maxGifWidth, int maxGifHeight, int lzwMaxBits>
void GifDecoder<maxGifWidth, maxGifHeight, lzwMaxBits>::lzw_setTempBuffer(uint8_t * tempBuffer) {
temp_buffer = tempBuffer;
}
// Initialize LZW decoder
// csize initial code size in bits
// buf input data
template <int maxGifWidth, int maxGifHeight, int lzwMaxBits>
void GifDecoder<maxGifWidth, maxGifHeight, lzwMaxBits>::lzw_decode_init (int csize) {
// Initialize read buffer variables
bbuf = 0;
bbits = 0;
bs = 0;
bcnt = 0;
// Initialize decoder variables
codesize = csize;
cursize = codesize + 1;
curmask = mask[cursize];
top_slot = 1 << cursize;
clear_code = 1 << codesize;
end_code = clear_code + 1;
slot = newcodes = clear_code + 2;
oc = fc = -1;
sp = stack;
}
// Get one code of given number of bits from stream
template <int maxGifWidth, int maxGifHeight, int lzwMaxBits>
int GifDecoder<maxGifWidth, maxGifHeight, lzwMaxBits>::lzw_get_code() {
while (bbits < cursize) {
if (bcnt == bs) {
// get number of bytes in next block
readIntoBuffer(temp_buffer, 1);
bs = temp_buffer[0];
readIntoBuffer(temp_buffer, bs);
bcnt = 0;
}
bbuf |= temp_buffer[bcnt] << bbits;
bbits += 8;
bcnt++;
}
int c = bbuf;
bbuf >>= cursize;
bbits -= cursize;
return c & curmask;
}
// Decode given number of bytes
// buf 8 bit output buffer
// len number of pixels to decode
// returns the number of bytes decoded
template <int maxGifWidth, int maxGifHeight, int lzwMaxBits>
int GifDecoder<maxGifWidth, maxGifHeight, lzwMaxBits>::lzw_decode(uint8_t *buf, int len, uint8_t *bufend) {
int l, c, code;
#if LZWDEBUG == 1
unsigned char debugMessagePrinted = 0;
#endif
if (end_code < 0) {
return 0;
}
l = len;
for (;;) {
while (sp > stack) {
// load buf with data if we're still within bounds
if(buf < bufend) {
*buf++ = *(--sp);
} else {
// out of bounds, keep incrementing the pointers, but don't use the data
#if LZWDEBUG == 1
// only print this message once per call to lzw_decode
if(buf == bufend)
Serial.println("****** LZW imageData buffer overrun *******");
#endif
}
if ((--l) == 0) {
return len;
}
}
c = lzw_get_code();
if (c == end_code) {
break;
}
else if (c == clear_code) {
cursize = codesize + 1;
curmask = mask[cursize];
slot = newcodes;
top_slot = 1 << cursize;
fc= oc= -1;
}
else {
code = c;
if ((code == slot) && (fc >= 0)) {
*sp++ = fc;
code = oc;
}
else if (code >= slot) {
break;
}
while (code >= newcodes) {
*sp++ = suffix[code];
code = prefix[code];
}
*sp++ = code;
if ((slot < top_slot) && (oc >= 0)) {
suffix[slot] = code;
prefix[slot++] = oc;
}
fc = code;
oc = c;
if (slot >= top_slot) {
if (cursize < lzwMaxBits) {
top_slot <<= 1;
curmask = mask[++cursize];
} else {
#if LZWDEBUG == 1
if(!debugMessagePrinted) {
debugMessagePrinted = 1;
Serial.println("****** cursize >= lzwMaxBits *******");
}
#endif
}
}
}
}
end_code = -1;
return len - l;
}