Skip to content

Commit 0d09816

Browse files
Laurence BankLaurence Bank
authored andcommitted
Added more support in RGB565 output for alpha blending of grayscale and indexed color. Added more functional tests for those features
1 parent 0d1a4cb commit 0d09816

File tree

4 files changed

+1815
-27
lines changed

4 files changed

+1815
-27
lines changed

MacOS/PNG_Test/PNG_Test/main.cpp

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,16 @@
2020
#include "../../../src/PNGdec.cpp"
2121

2222
#include "../../../test_images/octocat_8bpp.h"
23+
#include "../../../test_images/octocat.h"
2324
PNG png;
2425
int xoff, yoff, iBpp;
2526
int iWidth, iLines;
2627
uint32_t palentry24;
2728
uint16_t palentry16;
29+
uint32_t u32BG;
30+
uint16_t u16Out;
31+
uint8_t ucPixelType;
32+
2833
//
2934
// Return the current time in microseconds
3035
//
@@ -47,11 +52,17 @@ typedef struct my_private_struct
4752
{
4853
int xoff, yoff; // corner offset
4954
} PRIVATE;
50-
55+
// Second draw callback for testing conversion to RGB565
56+
void PNGDraw2(PNGDRAW *pDraw)
57+
{
58+
uint16_t usPixels[320];
59+
png.getLineAsRGB565(pDraw, usPixels, ucPixelType, u32BG);
60+
if (pDraw->y == 0) { // get first pixel of first line for testing
61+
u16Out = usPixels[0];
62+
}
63+
} /* PNGDraw2() */
5164
void PNGDraw(PNGDRAW *pDraw)
5265
{
53-
//uint16_t usPixels[320];
54-
//uint8_t ucMask[40];
5566
PRIVATE *pPriv = (PRIVATE *)pDraw->pUser;
5667

5768
if (pPriv) {
@@ -66,10 +77,6 @@ PRIVATE *pPriv = (PRIVATE *)pDraw->pUser;
6677
iBpp = pDraw->iBpp;
6778
iWidth = pDraw->iWidth;
6879
iLines++;
69-
// png.getLineAsRGB565(pDraw, usPixels, PNG_RGB565_BIG_ENDIAN, 0xffffffff);
70-
// if (png.getAlphaMask(pDraw, ucMask, 255)) { // if any pixels are opaque, draw them
71-
// spilcdWritePixelsMasked(&lcd, pPriv->xoff, pPriv->yoff + pDraw->y, (uint8_t *)usPixels, ucMask, pDraw->iWidth, DRAW_TO_LCD);
72-
// }
7380
} /* PNGDraw() */
7481

7582
//
@@ -215,6 +222,43 @@ int main(int argc, const char * argv[]) {
215222
PNGLOG(__LINE__, szTestName, " - FAILED");
216223
}
217224
free(pFrameBuffer);
225+
// Test 8 - check 8-bit to RGB565 conversion and alpha blending
226+
ucPixelType = PNG_RGB565_BIG_ENDIAN;
227+
u32BG = 0x00ff00; // set background color to pure green
228+
szTestName = (char *)"PNG Verify 8-bit to RGB565 output";
229+
iTotal++;
230+
PNGLOG(__LINE__, szTestName, szStart);
231+
u16Out = 0xffff;
232+
png.openFLASH((uint8_t *)octocat_8bpp, sizeof(octocat_8bpp), PNGDraw2);
233+
png.setBuffer(NULL);
234+
png.decode(NULL, 0);
235+
png.close();
236+
if (u16Out == 0xe007) { // check transparnet pixel (0,0) to see if it matches the 32-bit BG color we asked for
237+
iTotalPass++;
238+
PNGLOG(__LINE__, szTestName, " - PASSED");
239+
} else {
240+
iTotalFail++;
241+
PNGLOG(__LINE__, szTestName, " - FAILED");
242+
}
243+
// Test 9 - check 32-bit to RGB565 conversion and alpha blending
244+
ucPixelType = PNG_RGB565_BIG_ENDIAN;
245+
u32BG = 0xff0000; // set background color to pure blue
246+
szTestName = (char *)"PNG Verify 32-bit to RGB565 output";
247+
iTotal++;
248+
PNGLOG(__LINE__, szTestName, szStart);
249+
u16Out = 0xffff;
250+
png.openFLASH((uint8_t *)octocat_8bpp, sizeof(octocat_8bpp), PNGDraw2);
251+
png.setBuffer(NULL);
252+
png.decode(NULL, 0);
253+
png.close();
254+
if (u16Out == 0x1f00) { // check transparnet pixel (0,0) to see if it matches the 32-bit BG color we asked for
255+
iTotalPass++;
256+
PNGLOG(__LINE__, szTestName, " - PASSED");
257+
} else {
258+
iTotalFail++;
259+
PNGLOG(__LINE__, szTestName, " - FAILED");
260+
}
261+
218262
// FUZZ testing
219263
// Randomize the input data (file header and compressed data) and confirm that the library returns an error code
220264
// and doesn't have an invalid pointer exception

src/png.inl

Lines changed: 73 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -241,14 +241,35 @@ PNG_STATIC void PNGRGB565(PNGDRAW *pDraw, uint16_t *pPixels, int iEndiannes, uin
241241

242242
switch (pDraw->iPixelType) {
243243
case PNG_PIXEL_GRAY_ALPHA:
244-
for (x=0; x<pDraw->iWidth; x++) {
245-
c = *s++; // gray level
246-
a = *s++;
247-
j = (a * c) >> 8; // multiply by the alpha
248-
usPixel = usGrayTo565[j];
249-
if (iEndiannes == PNG_RGB565_BIG_ENDIAN)
250-
usPixel = __builtin_bswap16(usPixel);
251-
*pDest++ = usPixel;
244+
if (u32Bkgd != 0xffffffff) {
245+
// gray level of background color choice
246+
uint8_t u8BG = (uint8_t)(((u32Bkgd & 0xff) + ((u32Bkgd >> 7) & 0x1fe) + ((u32Bkgd >> 16) & 0xff)) / 4);
247+
uint16_t usBG = usGrayTo565[u8BG];
248+
for (x=0; x<pDraw->iWidth; x++) {
249+
c = *s++; // gray level
250+
a = *s++;
251+
if (a == 0) {
252+
usPixel = usBG;
253+
} else if (a == 255) { // fully opaque
254+
usPixel = usGrayTo565[c];
255+
} else { // mix the colors
256+
usPixel = (c * a) + (u8BG * (255-a));
257+
usPixel = usGrayTo565[(usPixel >> 8)];
258+
}
259+
if (iEndiannes == PNG_RGB565_BIG_ENDIAN)
260+
usPixel = __builtin_bswap16(usPixel);
261+
*pDest++ = usPixel;
262+
} // for x
263+
} else {
264+
for (x=0; x<pDraw->iWidth; x++) {
265+
c = *s++; // gray level
266+
a = *s++;
267+
j = (a * c) >> 8; // multiply by the alpha
268+
usPixel = usGrayTo565[j];
269+
if (iEndiannes == PNG_RGB565_BIG_ENDIAN)
270+
usPixel = __builtin_bswap16(usPixel);
271+
*pDest++ = usPixel;
272+
}
252273
}
253274
break;
254275
case PNG_PIXEL_GRAYSCALE:
@@ -346,18 +367,50 @@ PNG_STATIC void PNGRGB565(PNGDRAW *pDraw, uint16_t *pPixels, int iEndiannes, uin
346367
switch (pDraw->iBpp) {
347368
case 8: // 8-bit palette also supports palette alpha
348369
if (pDraw->iHasAlpha) { // use the alpha to modify the palette
349-
for (x=0; x<pDraw->iWidth; x++) {
350-
int a;
351-
c = *s++;
352-
a = pDraw->pPalette[768+c]; // get alpha
353-
pPal = &pDraw->pPalette[c * 3];
354-
usPixel = ((pPal[2] * a) >> 11); // blue
355-
usPixel |= (((pPal[1] * a) >> 10) << 5); // green
356-
usPixel |= (((pPal[0] * a) >> 11) << 11); // red
357-
if (iEndiannes == PNG_RGB565_BIG_ENDIAN)
358-
usPixel = __builtin_bswap16(usPixel);
359-
*pDest++ = usPixel;
360-
} // for x
370+
if (u32Bkgd != 0xffffffff) { // user wants to blend it with a background color
371+
uint32_t r, g, b, a;
372+
uint32_t b_r, b_g, b_b;
373+
b_r = u32Bkgd & 0xff; b_g = (u32Bkgd & 0xff00) >> 8;
374+
b_b = (u32Bkgd >> 16) & 0xff;
375+
uint16_t u16Clr = (u32Bkgd & 0xf8) << 8;
376+
u16Clr |= ((u32Bkgd & 0xfc00) >> 5);
377+
u16Clr |= ((u32Bkgd & 0xf80000) >> 19);
378+
for (x=0; x<pDraw->iWidth; x++) {
379+
int a;
380+
c = *s++;
381+
a = pDraw->pPalette[768+c]; // get alpha
382+
if (a == 0) { // pure BGColor
383+
usPixel = u16Clr;
384+
} else if (a == 255) { // opaque
385+
pPal = &pDraw->pPalette[c * 3];
386+
usPixel = ((pPal[2] * a) >> 11); // blue
387+
usPixel |= (((pPal[1] * a) >> 10) << 5); // green
388+
usPixel |= (((pPal[0] * a) >> 11) << 11); // red
389+
} else { // need to mix the bg & fg colors
390+
391+
pPal = &pDraw->pPalette[c * 3];
392+
usPixel = ((((pPal[2] * a) + (b_b * (255-a)))) >> 11); // blue
393+
usPixel |= ((((pPal[1] * a) + (b_g * (255-a)))>> 10) << 5); // green
394+
usPixel |= ((((pPal[0] * a) + (b_r * (255-a)))>> 11) << 11); // red
395+
} // need to mix with alpha
396+
if (iEndiannes == PNG_RGB565_BIG_ENDIAN)
397+
usPixel = __builtin_bswap16(usPixel);
398+
*pDest++ = usPixel;
399+
} // for x
400+
} else { // alpha 0 = black
401+
for (x=0; x<pDraw->iWidth; x++) {
402+
int a;
403+
c = *s++;
404+
a = pDraw->pPalette[768+c]; // get alpha
405+
pPal = &pDraw->pPalette[c * 3];
406+
usPixel = ((pPal[2] * a) >> 11); // blue
407+
usPixel |= (((pPal[1] * a) >> 10) << 5); // green
408+
usPixel |= (((pPal[0] * a) >> 11) << 11); // red
409+
if (iEndiannes == PNG_RGB565_BIG_ENDIAN)
410+
usPixel = __builtin_bswap16(usPixel);
411+
*pDest++ = usPixel;
412+
} // for x
413+
}
361414
} else {
362415
for (x=0; x<pDraw->iWidth; x++) {
363416
c = *s++;

0 commit comments

Comments
 (0)