snapshot
This commit is contained in:
@@ -60,41 +60,21 @@ static const uint16_t usGrayTo565[] = {0x0000,0x0000,0x0000,0x0000,0x0020,0x0020
|
||||
// C interface
|
||||
//
|
||||
#ifndef __cplusplus
|
||||
// Forward references
|
||||
PNG_STATIC int32_t readFLASH(PNGFILE *pFile, uint8_t *pBuf, int32_t iLen);
|
||||
PNG_STATIC int32_t seekMem(PNGFILE *pFile, int32_t iPosition);
|
||||
PNG_STATIC int PNGInit(PNGIMAGE *pPNG);
|
||||
|
||||
// C API
|
||||
int PNG_openRAM(PNGIMAGE *pPNG, uint8_t *pData, int iDataSize, PNG_DRAW_CALLBACK *pfnDraw)
|
||||
{
|
||||
pPNG->iError = PNG_SUCCESS;
|
||||
pPNG->pfnRead = readFLASH;
|
||||
pPNG->pfnRead = readMem;
|
||||
pPNG->pfnSeek = seekMem;
|
||||
pPNG->pfnDraw = pfnDraw;
|
||||
pPNG->pfnOpen = NULL;
|
||||
pPNG->pfnClose = NULL;
|
||||
pPNG->PNGFile.iSize = iDataSize;
|
||||
pPNG->PNGFile.pData = pData;
|
||||
pPNG->PNGFile.iPos = 0;
|
||||
return PNGInit(pPNG);
|
||||
} /* PNG_openRAM() */
|
||||
|
||||
#ifdef __LINUX__
|
||||
int32_t readFile(PNGFILE *handle, uint8_t *buffer, int32_t length) {
|
||||
if (!handle->fHandle) return 0;
|
||||
return (int32_t)fread(buffer, 1, length, (FILE *)handle->fHandle);
|
||||
}
|
||||
int32_t seekFile(PNGFILE *handle, int32_t position) {
|
||||
if (!handle->fHandle) return 0;
|
||||
return fseek((FILE *)handle->fHandle, position, SEEK_SET);
|
||||
}
|
||||
void closeFile(void *handle) {
|
||||
if (handle) {
|
||||
FILE *f = (FILE *)handle;
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
int PNG_openFile(PNGIMAGE *pPNG, const char *szFilename, PNG_DRAW_CALLBACK *pfnDraw)
|
||||
{
|
||||
pPNG->iError = PNG_SUCCESS;
|
||||
@@ -239,15 +219,6 @@ PNG_STATIC uint8_t PNGMakeMask(PNGDRAW *pDraw, uint8_t *pMask, uint8_t ucThresho
|
||||
} // switch on pixel type
|
||||
return cHasOpaque; // let the caller know if any pixels are opaque
|
||||
} /* PNGMakeMask() */
|
||||
#ifdef ARDUINO_ESP32S3_DEV
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
void s3_rgb565(uint8_t *pSrc, uint8_t *pDest, int iCount, bool bBigEndian);
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
//
|
||||
// Convert a line of native PNG pixels into RGB565
|
||||
// handles all standard pixel types
|
||||
@@ -257,39 +228,18 @@ PNG_STATIC void PNGRGB565(PNGDRAW *pDraw, uint16_t *pPixels, int iEndiannes, uin
|
||||
{
|
||||
int x, j;
|
||||
uint16_t usPixel, *pDest = pPixels;
|
||||
uint8_t c=0, a, *pPal, *s = pDraw->pPixels;
|
||||
uint8_t c, a, *pPal, *s = pDraw->pPixels;
|
||||
|
||||
switch (pDraw->iPixelType) {
|
||||
case PNG_PIXEL_GRAY_ALPHA:
|
||||
if (u32Bkgd != 0xffffffff) {
|
||||
// gray level of background color choice
|
||||
uint8_t u8BG = (uint8_t)(((u32Bkgd & 0xff) + ((u32Bkgd >> 7) & 0x1fe) + ((u32Bkgd >> 16) & 0xff)) / 4);
|
||||
uint16_t usBG = usGrayTo565[u8BG];
|
||||
for (x=0; x<pDraw->iWidth; x++) {
|
||||
c = *s++; // gray level
|
||||
a = *s++;
|
||||
if (a == 0) {
|
||||
usPixel = usBG;
|
||||
} else if (a == 255) { // fully opaque
|
||||
usPixel = usGrayTo565[c];
|
||||
} else { // mix the colors
|
||||
usPixel = (c * a) + (u8BG * (255-a));
|
||||
usPixel = usGrayTo565[(usPixel >> 8)];
|
||||
}
|
||||
if (iEndiannes == PNG_RGB565_BIG_ENDIAN)
|
||||
usPixel = __builtin_bswap16(usPixel);
|
||||
*pDest++ = usPixel;
|
||||
} // for x
|
||||
} else {
|
||||
for (x=0; x<pDraw->iWidth; x++) {
|
||||
c = *s++; // gray level
|
||||
a = *s++;
|
||||
j = (a * c) >> 8; // multiply by the alpha
|
||||
usPixel = usGrayTo565[j];
|
||||
if (iEndiannes == PNG_RGB565_BIG_ENDIAN)
|
||||
usPixel = __builtin_bswap16(usPixel);
|
||||
*pDest++ = usPixel;
|
||||
}
|
||||
for (x=0; x<pDraw->iWidth; x++) {
|
||||
c = *s++; // gray level
|
||||
a = *s++;
|
||||
j = (a * c) >> 8; // multiply by the alpha
|
||||
usPixel = usGrayTo565[j];
|
||||
if (iEndiannes == PNG_RGB565_BIG_ENDIAN)
|
||||
usPixel = __builtin_bswap16(usPixel);
|
||||
*pDest++ = usPixel;
|
||||
}
|
||||
break;
|
||||
case PNG_PIXEL_GRAYSCALE:
|
||||
@@ -387,49 +337,18 @@ PNG_STATIC void PNGRGB565(PNGDRAW *pDraw, uint16_t *pPixels, int iEndiannes, uin
|
||||
switch (pDraw->iBpp) {
|
||||
case 8: // 8-bit palette also supports palette alpha
|
||||
if (pDraw->iHasAlpha) { // use the alpha to modify the palette
|
||||
if (u32Bkgd != 0xffffffff) { // user wants to blend it with a background color
|
||||
uint32_t b_r, b_g, b_b;
|
||||
b_r = u32Bkgd & 0xff; b_g = (u32Bkgd & 0xff00) >> 8;
|
||||
b_b = (u32Bkgd >> 16) & 0xff;
|
||||
uint16_t u16Clr = (u32Bkgd & 0xf8) << 8;
|
||||
u16Clr |= ((u32Bkgd & 0xfc00) >> 5);
|
||||
u16Clr |= ((u32Bkgd & 0xf80000) >> 19);
|
||||
for (x=0; x<pDraw->iWidth; x++) {
|
||||
int a;
|
||||
c = *s++;
|
||||
a = pDraw->pPalette[768+c]; // get alpha
|
||||
if (a == 0) { // pure BGColor
|
||||
usPixel = u16Clr;
|
||||
} else if (a == 255) { // opaque
|
||||
pPal = &pDraw->pPalette[c * 3];
|
||||
usPixel = ((pPal[2] * a) >> 11); // blue
|
||||
usPixel |= (((pPal[1] * a) >> 10) << 5); // green
|
||||
usPixel |= (((pPal[0] * a) >> 11) << 11); // red
|
||||
} else { // need to mix the bg & fg colors
|
||||
|
||||
pPal = &pDraw->pPalette[c * 3];
|
||||
usPixel = ((((pPal[2] * a) + (b_b * (255-a)))) >> 11); // blue
|
||||
usPixel |= ((((pPal[1] * a) + (b_g * (255-a)))>> 10) << 5); // green
|
||||
usPixel |= ((((pPal[0] * a) + (b_r * (255-a)))>> 11) << 11); // red
|
||||
} // need to mix with alpha
|
||||
if (iEndiannes == PNG_RGB565_BIG_ENDIAN)
|
||||
usPixel = __builtin_bswap16(usPixel);
|
||||
*pDest++ = usPixel;
|
||||
} // for x
|
||||
} else { // alpha 0 = black
|
||||
for (x=0; x<pDraw->iWidth; x++) {
|
||||
int a;
|
||||
c = *s++;
|
||||
a = pDraw->pPalette[768+c]; // get alpha
|
||||
pPal = &pDraw->pPalette[c * 3];
|
||||
usPixel = ((pPal[2] * a) >> 11); // blue
|
||||
usPixel |= (((pPal[1] * a) >> 10) << 5); // green
|
||||
usPixel |= (((pPal[0] * a) >> 11) << 11); // red
|
||||
if (iEndiannes == PNG_RGB565_BIG_ENDIAN)
|
||||
usPixel = __builtin_bswap16(usPixel);
|
||||
*pDest++ = usPixel;
|
||||
} // for x
|
||||
}
|
||||
for (x=0; x<pDraw->iWidth; x++) {
|
||||
int a;
|
||||
c = *s++;
|
||||
a = pDraw->pPalette[768+c]; // get alpha
|
||||
pPal = &pDraw->pPalette[c * 3];
|
||||
usPixel = ((pPal[2] * a) >> 11); // blue
|
||||
usPixel |= (((pPal[1] * a) >> 10) << 5); // green
|
||||
usPixel |= (((pPal[0] * a) >> 11) << 11); // red
|
||||
if (iEndiannes == PNG_RGB565_BIG_ENDIAN)
|
||||
usPixel = __builtin_bswap16(usPixel);
|
||||
*pDest++ = usPixel;
|
||||
} // for x
|
||||
} else {
|
||||
for (x=0; x<pDraw->iWidth; x++) {
|
||||
c = *s++;
|
||||
@@ -525,9 +444,6 @@ PNG_STATIC void PNGRGB565(PNGDRAW *pDraw, uint16_t *pPixels, int iEndiannes, uin
|
||||
s += 4; // skip alpha
|
||||
}
|
||||
} else { // ignore alpha
|
||||
#ifdef ARDUINO_ESP32S3_DEV
|
||||
s3_rgb565(s, (uint8_t *)pDest, pDraw->iWidth, (iEndiannes == PNG_RGB565_BIG_ENDIAN));
|
||||
#else
|
||||
for (x=0; x<pDraw->iWidth; x++) {
|
||||
usPixel = (s[2] >> 3); // blue
|
||||
usPixel |= ((s[1] >> 2) << 5); // green
|
||||
@@ -537,7 +453,6 @@ PNG_STATIC void PNGRGB565(PNGDRAW *pDraw, uint16_t *pPixels, int iEndiannes, uin
|
||||
*pDest++ = usPixel;
|
||||
s += 4; // skip alpha
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -591,8 +506,8 @@ PNG_STATIC int PNGParseInfo(PNGIMAGE *pPage)
|
||||
|
||||
pPage->iHasAlpha = pPage->iInterlaced = 0;
|
||||
// Read a few bytes to just parse the size/pixel info
|
||||
iBytesRead = (*pPage->pfnRead)(&pPage->PNGFile, s, 33);
|
||||
if (iBytesRead < 33) { // a PNG file this tiny? probably bad
|
||||
iBytesRead = (*pPage->pfnRead)(&pPage->PNGFile, s, 32);
|
||||
if (iBytesRead < 32) { // a PNG file this tiny? probably bad
|
||||
pPage->iError = PNG_INVALID_FILE;
|
||||
return pPage->iError;
|
||||
}
|
||||
@@ -602,17 +517,6 @@ PNG_STATIC int PNGParseInfo(PNGIMAGE *pPage)
|
||||
return pPage->iError;
|
||||
}
|
||||
if (MOTOLONG(&s[12]) == 0x49484452/*'IHDR'*/) {
|
||||
int len = MOTOLONG(&s[8]);
|
||||
if (len != 13) {
|
||||
pPage->iError = PNG_INVALID_FILE;
|
||||
return pPage->iError;
|
||||
}
|
||||
int crc = (int)crc32(0, &s[12], len+4);
|
||||
int hdrcrc = MOTOLONG(&s[16+len]);
|
||||
if (len != 13 || crc != hdrcrc) {
|
||||
pPage->iError = PNG_INVALID_FILE;
|
||||
return pPage->iError;
|
||||
}
|
||||
pPage->iWidth = MOTOLONG(&s[16]);
|
||||
pPage->iHeight = MOTOLONG(&s[20]);
|
||||
pPage->ucBpp = s[24]; // bits per pixel
|
||||
@@ -725,7 +629,7 @@ PNG_STATIC void DeFilter(uint8_t *pCurr, uint8_t *pPrev, int iWidth, int iPitch)
|
||||
b = *pPrev++;
|
||||
p = b - c;
|
||||
pc = a - c;
|
||||
// assume no native ABS() instruction
|
||||
// asume no native ABS() instruction
|
||||
pa = p < 0 ? -p : p;
|
||||
pb = pc < 0 ? -pc : pc;
|
||||
pc = (p + pc) < 0 ? -(p + pc) : p + pc;
|
||||
@@ -773,13 +677,8 @@ PNG_STATIC int DecodePNG(PNGIMAGE *pPage, void *pUser, int iOptions)
|
||||
return 0;
|
||||
}
|
||||
// Use internal buffer to maintain the current and previous lines
|
||||
y = (int)(intptr_t)&pPage->ucPixels[0];
|
||||
y &= 15; // make sure we're 16-byte aligned, -1 for filter byte
|
||||
y += (15 - y);
|
||||
pCurr = &pPage->ucPixels[y]; // so that the pixels are 16-byte aligned
|
||||
y += pPage->iPitch + 1; // both lines are 16-byte (minus 1)
|
||||
y += (15 - (y & 15));
|
||||
pPrev = &pPage->ucPixels[y];
|
||||
pCurr = pPage->ucPixels;
|
||||
pPrev = &pPage->ucPixels[pPage->iPitch+1];
|
||||
pPage->iError = PNG_SUCCESS;
|
||||
// Start decoding the image
|
||||
bDone = FALSE;
|
||||
@@ -792,7 +691,7 @@ PNG_STATIC int DecodePNG(PNGIMAGE *pPage, void *pUser, int iOptions)
|
||||
// Insert the memory pointer here to avoid having to use malloc() inside zlib
|
||||
state = (struct inflate_state FAR *)pPage->ucZLIB;
|
||||
d_stream.state = (struct internal_state FAR *)state;
|
||||
state->window = &pPage->ucZLIB[sizeof(struct inflate_state)]; // point to 32k dictionary buffer
|
||||
state->window = &pPage->ucZLIB[sizeof(inflate_state)]; // point to 32k dictionary buffer
|
||||
err = inflateInit(&d_stream);
|
||||
#ifdef FUTURE
|
||||
// if (inpage->cCompression == PIL_COMP_IPHONE_FLATE)
|
||||
@@ -803,27 +702,18 @@ PNG_STATIC int DecodePNG(PNGIMAGE *pPage, void *pUser, int iOptions)
|
||||
|
||||
iFileOffset = 8; // skip PNG file signature
|
||||
iOffset = 0; // internal buffer offset starts at 0
|
||||
iBytesRead = 0; // We haven't read yet anything
|
||||
// Read some data to start
|
||||
(*pPage->pfnSeek)(&pPage->PNGFile, iFileOffset);
|
||||
iBytesRead = (*pPage->pfnRead)(&pPage->PNGFile, s, PNG_FILE_BUF_SIZE);
|
||||
iFileOffset += iBytesRead;
|
||||
y = 0;
|
||||
d_stream.avail_out = 0;
|
||||
d_stream.next_out = pPage->pImage;
|
||||
|
||||
// continue until fully decoded
|
||||
// parse the markers until the next data block
|
||||
while (!bDone && y < pPage->iHeight)
|
||||
while (y < pPage->iHeight) { // continue until fully decoded
|
||||
// parse the markers until the next data block
|
||||
while (!bDone)
|
||||
{
|
||||
if (iOffset > iBytesRead-8) { // need to read more data
|
||||
iFileOffset += (iOffset - iBytesRead);
|
||||
(*pPage->pfnSeek)(&pPage->PNGFile, iFileOffset);
|
||||
iBytesRead = (*pPage->pfnRead)(&pPage->PNGFile, s, PNG_FILE_BUF_SIZE);
|
||||
if (iBytesRead < 8) {
|
||||
pPage->iError = PNG_DECODE_ERROR;
|
||||
return 1;
|
||||
}
|
||||
iFileOffset += iBytesRead;
|
||||
iOffset = 0;
|
||||
}
|
||||
|
||||
iLen = MOTOLONG(&s[iOffset]); // chunk length
|
||||
if (iLen < 0 || iLen + (iFileOffset - iBytesRead) > pPage->PNGFile.iSize) // invalid data
|
||||
{
|
||||
@@ -931,10 +821,7 @@ PNG_STATIC int DecodePNG(PNGIMAGE *pPage, void *pUser, int iOptions)
|
||||
pngd.iHasAlpha = pPage->iHasAlpha;
|
||||
pngd.iBpp = pPage->ucBpp;
|
||||
pngd.y = y;
|
||||
if (!(*pPage->pfnDraw)(&pngd)) { // user code returned 0 from PNGDraw
|
||||
pPage->iError = PNG_QUIT_EARLY;
|
||||
return pPage->iError;
|
||||
}
|
||||
(*pPage->pfnDraw)(&pngd);
|
||||
} else {
|
||||
// copy to destination bitmap
|
||||
memcpy(&pPage->pImage[y * pPage->iPitch], &pCurr[1], pPage->iPitch);
|
||||
@@ -959,14 +846,17 @@ PNG_STATIC int DecodePNG(PNGIMAGE *pPage, void *pUser, int iOptions)
|
||||
y |= 0; // need more data
|
||||
}
|
||||
} // while (iLen)
|
||||
if (iBytesRead) { // data remaining in buffer
|
||||
// Restore iBytesRead to be total ucFileBuf bytes, not remainder
|
||||
iBytesRead += iOffset;
|
||||
} else {
|
||||
// We consumed everything, so move the pointer to the zero.
|
||||
// We haven't read CRC for the block, but it doesn't matter as
|
||||
// pfnSeek will move past it to the next chunk.
|
||||
iOffset = 0;
|
||||
if (y != pPage->iHeight && iFileOffset < pPage->PNGFile.iSize) {
|
||||
// need to read more IDAT chunks
|
||||
if (iBytesRead) { // data remaining in buffer
|
||||
// move the data down
|
||||
memmove(pPage->ucFileBuf, &pPage->ucFileBuf[iOffset], iBytesRead);
|
||||
iOffset = 0;
|
||||
} else {
|
||||
iBytesRead = (*pPage->pfnRead)(&pPage->PNGFile, pPage->ucFileBuf, PNG_FILE_BUF_SIZE);
|
||||
iFileOffset += iBytesRead;
|
||||
iOffset = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
// case 0x69545874: //'iTXt'
|
||||
@@ -999,6 +889,14 @@ PNG_STATIC int DecodePNG(PNGIMAGE *pPage, void *pUser, int iOptions)
|
||||
#endif
|
||||
} // switch
|
||||
iOffset += (iLen + 4); // skip data + CRC
|
||||
if (iOffset > iBytesRead-8) { // need to read more data
|
||||
iFileOffset += (iOffset - iBytesRead);
|
||||
(*pPage->pfnSeek)(&pPage->PNGFile, iFileOffset);
|
||||
iBytesRead = (*pPage->pfnRead)(&pPage->PNGFile, s, PNG_FILE_BUF_SIZE);
|
||||
iFileOffset += iBytesRead;
|
||||
iOffset = 0;
|
||||
}
|
||||
} // while !bDone
|
||||
} // while y < height
|
||||
err = inflateEnd(&d_stream);
|
||||
return pPage->iError;
|
||||
|
||||
Reference in New Issue
Block a user