10 #if GFX_USE_GDISP && GDISP_NEED_IMAGE && GDISP_NEED_IMAGE_PNG
21 typedef struct PNG_info {
23 #define PNG_FLG_HEADERDONE 0x01
24 #define PNG_FLG_TRANSPARENT 0x02
25 #define PNG_FLG_INTERLACE 0x04
26 #define PNG_FLG_BACKGROUND 0x08
29 #define PNG_COLORMODE_GRAY 0x00
30 #define PNG_COLORMODE_RGB 0x02
31 #define PNG_COLORMODE_PALETTE 0x03
32 #define PNG_COLORMODE_GRAYALPHA 0x04
33 #define PNG_COLORMODE_RGBA 0x06
39 void (*out)(
struct PNG_decode *);
41 #if GDISP_NEED_IMAGE_PNG_BACKGROUND
44 #if GDISP_NEED_IMAGE_PNG_TRANSPARENCY
49 #if GDISP_NEED_IMAGE_PNG_PALETTE_124 || GDISP_NEED_IMAGE_PNG_PALETTE_8
56 typedef struct PNG_input {
66 typedef struct PNG_output {
77 typedef struct PNG_filter {
85 typedef struct PNG_zTree {
90 typedef struct PNG_zinflate {
94 #define PNG_ZFLG_EOF 0x01
95 #define PNG_ZFLG_FINAL 0x02
96 #define PNG_ZFLG_RESUME_MASK 0x0C
97 #define PNG_ZFLG_RESUME_NEW 0x00
98 #define PNG_ZFLG_RESUME_COPY 0x04
99 #define PNG_ZFLG_RESUME_INFLATE 0x08
100 #define PNG_ZFLG_RESUME_OFFSET 0x0C
113 typedef struct PNG_decode {
127 static void PNG_iInit(PNG_decode *d) {
128 if (d->pinfo->cache) {
129 d->i.pbuf = d->pinfo->cache;
130 d->i.buflen = d->pinfo->cachesz;
141 static gBool PNG_iLoadData(PNG_decode *d) {
153 if (!d->i.chunklen) {
161 d->i.chunklen = gdispImageGetAlignedBE32(d->i.buf, 0);
162 d->i.chunknext += d->i.chunklen + 12;
165 switch (gdispImageGetAlignedBE32(d->i.buf, 4)) {
182 if (
gfileRead(d->i.f, d->i.buf, sz) != sz)
186 d->i.pbuf = d->i.buf;
191 static gU8 PNG_iGetByte(PNG_decode *d) {
214 static void PNG_oFlush(PNG_output *o) {
217 case 1:
gdispGDrawPixel(o->g, o->x+o->ix-o->sx, o->y+o->iy-o->sy, o->buf[0]);
break;
218 default:
gdispGBlitArea(o->g, o->x+o->ix-o->sx, o->y+o->iy-o->sy, o->cnt, 1, 0, 0, o->cnt, o->buf);
break;
225 static gBool PNG_oStartY(PNG_output *o,
gCoord y) {
226 if (y < o->sy || y >= o->sy+o->cy)
234 static void PNG_oColor(PNG_output *o,
gColor c) {
236 if (o->ix+(
gCoord)o->cnt < o->sx || o->ix+(
gCoord)o->cnt >= o->sx+o->cx) {
244 if (o->cnt >=
sizeof(o->buf)/
sizeof(o->buf[0]))
248 o->buf[o->cnt++] = c;
251 #if GDISP_NEED_IMAGE_PNG_TRANSPARENCY || GDISP_NEED_IMAGE_PNG_ALPHACLIFF > 0
253 static void PNG_oTransparent(PNG_output *o) {
267 #if (GDISP_IMAGE_PNG_Z_BUFFER_SIZE & ~(GDISP_IMAGE_PNG_Z_BUFFER_SIZE-1)) == GDISP_IMAGE_PNG_Z_BUFFER_SIZE
268 #define WRAP_ZBUF(x) { x &= GDISP_IMAGE_PNG_Z_BUFFER_SIZE-1; }
270 #if GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_DIRECT
271 #warning "PNG: GDISP_IMAGE_PNG_Z_BUFFER_SIZE is more efficient as a power of 2"
272 #elif GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_MACRO
273 COMPILER_WARNING(
"PNG: GDISP_IMAGE_PNG_Z_BUFFER_SIZE is more efficient as a power of 2")
275 #define WRAP_ZBUF(x) { if (x >= GDISP_IMAGE_PNG_Z_BUFFER_SIZE) x = 0; }
279 static void PNG_zInit(PNG_zinflate *z) {
282 z->bufpos = z->bufend = 0;
286 static gBool PNG_zGetHeader(PNG_decode *d) {
287 if (!PNG_iLoadData(d))
289 d->z.tmp[0] = PNG_iGetByte(d);
290 if (!PNG_iLoadData(d))
292 d->z.tmp[1] = PNG_iGetByte(d);
293 if (gdispImageGetAlignedBE16(d->z.tmp, 0) % 31 != 0
294 || (d->z.tmp[0] & 0x0F) != 8 || (d->z.tmp[0] & 0x80)
295 || (d->z.tmp[1] & 0x20))
301 static unsigned PNG_zGetBit(PNG_decode *d) {
305 if ((d->z.flags & PNG_ZFLG_EOF))
310 if (!PNG_iLoadData(d)) {
311 d->z.flags |= PNG_ZFLG_EOF;
314 d->z.data = PNG_iGetByte(d);
320 bit = d->z.data & 0x01;
326 static unsigned PNG_zGetBits(PNG_decode *d,
unsigned num) {
334 for (mask = 1; mask < limit; mask <<= 1)
341 static void PNG_zBuildTree(PNG_zTree *t,
const gU8 *lengths,
unsigned num) {
345 for (i = 0; i < 16; ++i)
347 for (i = 0; i < num; ++i)
348 t->table[lengths[i]]++;
352 for (sum = 0, i = 0; i < 16; ++i) {
356 for (i = 0; i < num; ++i) {
358 t->trans[offs[lengths[i]]++] = i;
363 static gU16 PNG_zGetSymbol(PNG_decode *d, PNG_zTree *t) {
371 cur += PNG_zGetBit(d);
372 if ((d->z.flags & PNG_ZFLG_EOF))
376 sum += t->table[len];
377 cur -= t->table[len];
380 return t->trans[sum + cur];
384 static void PNG_zBuildFixedTrees(PNG_decode *d) {
387 for (i = 0; i < 16; ++i) d->z.ltree.table[i] = 0;
388 d->z.ltree.table[7] = 24;
389 d->z.ltree.table[8] = 152;
390 d->z.ltree.table[9] = 112;
391 for (i = 0; i < 24; ++i) d->z.ltree.trans[i] = 256 + i;
392 for (i = 0; i < 144; ++i) d->z.ltree.trans[24 + i] = i;
393 for (i = 0; i < 8; ++i) d->z.ltree.trans[24 + 144 + i] = 280 + i;
394 for (i = 0; i < 112; ++i) d->z.ltree.trans[24 + 144 + 8 + i] = 144 + i;
396 for (i = 0; i < 16; ++i) d->z.dtree.table[i] = 0;
397 d->z.dtree.table[5] = 32;
398 for (i = 0; i < 32; ++i) d->z.dtree.trans[i] = i;
399 for ( ; i < 288; ++i) d->z.dtree.trans[i] = 0;
403 static gBool PNG_zDecodeTrees(PNG_decode *d) {
404 static const gU8 IndexLookup[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
405 unsigned hlit, hdist, hclen;
410 hlit = PNG_zGetBits(d, 5) + 257;
411 hdist = PNG_zGetBits(d, 5) + 1;
412 hclen = PNG_zGetBits(d, 4) + 4;
414 if ((d->z.flags & PNG_ZFLG_EOF))
417 for (i = 0; i < 19; ++i)
421 for (i = 0; i < hclen; ++i)
422 d->z.tmp[IndexLookup[i]] = PNG_zGetBits(d, 3);
424 if ((d->z.flags & PNG_ZFLG_EOF))
428 PNG_zBuildTree(&d->z.ltree, d->z.tmp, 19);
431 for (num = 0; num < hlit + hdist; ) {
432 symbol = PNG_zGetSymbol(d, &d->z.ltree);
433 if ((d->z.flags & PNG_ZFLG_EOF))
438 val = d->z.tmp[num - 1];
439 for (i = PNG_zGetBits(d, 2) + 3; i; i--)
440 d->z.tmp[num++] = val;
443 for (i = PNG_zGetBits(d, 3) + 3; i; i--)
447 for (i = PNG_zGetBits(d, 7) + 11; i; i--)
451 d->z.tmp[num++] = symbol;
457 PNG_zBuildTree(&d->z.ltree, d->z.tmp, hlit);
458 PNG_zBuildTree(&d->z.dtree, d->z.tmp + hlit, hdist);
463 static gBool PNG_zCopyInput(PNG_decode *d,
unsigned length) {
466 if (!PNG_iLoadData(d)) {
467 d->z.flags |= PNG_ZFLG_EOF;
470 d->z.buf[d->z.bufend++] = PNG_iGetByte(d);
471 WRAP_ZBUF(d->z.bufend);
472 if (d->z.bufend == d->z.bufpos) {
473 d->z.flags = (d->z.flags & ~PNG_ZFLG_RESUME_MASK) | PNG_ZFLG_RESUME_COPY;
474 ((
unsigned *)d->z.tmp)[0] = length;
480 d->z.flags = (d->z.flags & ~PNG_ZFLG_RESUME_MASK) | PNG_ZFLG_RESUME_NEW;
485 static gBool PNG_zUncompressedBlock(PNG_decode *d) {
492 for (length = 0; length < 4; length++) {
493 if (!PNG_iLoadData(d)) {
494 d->z.flags |= PNG_ZFLG_EOF;
497 d->z.tmp[length] = PNG_iGetByte(d);
501 length = gdispImageGetAlignedLE16(d->z.tmp, 0);
504 if ((gU16)length != (gU16)~gdispImageGetAlignedLE16(d->z.tmp, 2)) {
505 d->z.flags |= PNG_ZFLG_EOF;
510 return PNG_zCopyInput(d, length);
514 static gBool PNG_zInflateBlock(PNG_decode *d) {
515 static const gU8 lbits[30] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 6 };
516 static const gU16 lbase[30] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 323 };
517 static const gU8 dbits[30] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 };
518 static const gU16 dbase[30] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 };
519 unsigned length, dist, offset;
523 symbol = PNG_zGetSymbol(d, &d->z.ltree);
524 if ((d->z.flags & PNG_ZFLG_EOF))
529 d->z.flags = (d->z.flags & ~PNG_ZFLG_RESUME_MASK) | PNG_ZFLG_RESUME_NEW;
535 d->z.buf[d->z.bufend++] = (gU8)symbol;
536 WRAP_ZBUF(d->z.bufend);
537 if (d->z.bufend == d->z.bufpos) {
538 d->z.flags = (d->z.flags & ~PNG_ZFLG_RESUME_MASK) | PNG_ZFLG_RESUME_INFLATE;
547 if (symbol >=
sizeof(lbits))
551 length = PNG_zGetBits(d, lbits[symbol]) + lbase[symbol];
556 dist = PNG_zGetSymbol(d, &d->z.dtree);
557 if ((d->z.flags & PNG_ZFLG_EOF) || dist >=
sizeof(dbits))
561 offset = PNG_zGetBits(d, dbits[dist]) + dbase[dist];
566 if (offset > d->z.bufend)
568 offset = d->z.bufend - offset;
572 d->z.buf[d->z.bufend++] = d->z.buf[offset++];
573 WRAP_ZBUF(d->z.bufend);
575 if (d->z.bufend == d->z.bufpos) {
576 d->z.flags = (d->z.flags & ~PNG_ZFLG_RESUME_MASK) | PNG_ZFLG_RESUME_OFFSET;
577 ((
unsigned *)d->z.tmp)[0] = length;
578 ((
unsigned *)d->z.tmp)[1] = offset;
585 d->z.flags |= PNG_ZFLG_EOF;
590 static gBool PNG_zStartBlock(PNG_decode *d) {
592 if ((d->z.flags & (PNG_ZFLG_EOF|PNG_ZFLG_FINAL)))
597 d->z.flags |= PNG_ZFLG_FINAL;
600 switch (PNG_zGetBits(d, 2)) {
603 if (!PNG_zUncompressedBlock(d))
608 PNG_zBuildFixedTrees(d);
609 if (!PNG_zInflateBlock(d))
614 if (!PNG_zDecodeTrees(d))
616 if (!PNG_zInflateBlock(d))
622 d->z.flags |= PNG_ZFLG_EOF;
629 static gBool PNG_zResumeOffset(PNG_decode *d,
unsigned length,
unsigned offset) {
632 d->z.buf[d->z.bufend++] = d->z.buf[offset++];
633 WRAP_ZBUF(d->z.bufend);
635 if (d->z.bufend == d->z.bufpos) {
636 d->z.flags = (d->z.flags & ~PNG_ZFLG_RESUME_MASK) | PNG_ZFLG_RESUME_OFFSET;
637 ((
unsigned *)d->z.tmp)[0] = length;
638 ((
unsigned *)d->z.tmp)[1] = offset;
642 return PNG_zInflateBlock(d);
646 static gU8 PNG_zGetByte(PNG_decode *d) {
650 while (d->z.bufpos == d->z.bufend) {
654 switch((d->z.flags & PNG_ZFLG_RESUME_MASK)) {
655 case PNG_ZFLG_RESUME_NEW:
656 if (!PNG_zStartBlock(d))
659 case PNG_ZFLG_RESUME_COPY:
660 if (!PNG_zCopyInput(d, ((
unsigned *)d->z.tmp)[0]))
663 case PNG_ZFLG_RESUME_INFLATE:
664 if (!PNG_zInflateBlock(d))
667 case PNG_ZFLG_RESUME_OFFSET:
668 if (!PNG_zResumeOffset(d, ((
unsigned *)d->z.tmp)[0], ((
unsigned *)d->z.tmp)[1]))
675 if ((d->z.flags & PNG_ZFLG_RESUME_MASK) != PNG_ZFLG_RESUME_NEW)
680 data = d->z.buf[d->z.bufpos++];
681 WRAP_ZBUF(d->z.bufpos);
691 static void PNG_fInit(PNG_filter *f, gU8 *buf,
unsigned bytewidth,
unsigned scanbytes) {
692 f->scanbytes = scanbytes;
693 f->bytewidth = bytewidth;
699 static void PNG_fNext(PNG_filter *f) {
700 if (f->prev && f->line > f->prev) {
702 f->prev += f->scanbytes;
705 f->line += f->scanbytes;
710 static gU8 PNG_fCalcPath(gU16 a, gU16 b, gU16 c) {
711 gU16 pa = b > c ? (b - c) : (c - b);
712 gU16 pb = a > c ? (a - c) : (c - a);
713 gU16 pc = a + b > c + c ? (a + b - c - c) : (c + c - a - b);
715 if (pc < pa && pc < pb)
723 static gBool PNG_unfilter_type0(PNG_decode *d) {
728 ft = PNG_zGetByte(d);
733 for(i = 0; i < d->f.scanbytes; i++)
734 d->f.line[i] = PNG_zGetByte(d);
740 for(i = d->f.bytewidth; i < d->f.scanbytes; i++)
741 d->f.line[i] += d->f.line[i - d->f.bytewidth];
745 for(i = 0; i < d->f.scanbytes; i++)
746 d->f.line[i] += d->f.prev[i];
751 for(i = 0; i < d->f.bytewidth; i++)
752 d->f.line[i] += d->f.prev[i] / 2;
753 for( ; i < d->f.scanbytes; i++)
754 d->f.line[i] += (d->f.line[i - d->f.bytewidth] + d->f.prev[i]) / 2;
756 for(i = d->f.bytewidth; i < d->f.scanbytes; i++)
757 d->f.line[i] += d->f.line[i - d->f.bytewidth] / 2;
762 for(i = 0; i < d->f.bytewidth; i++)
763 d->f.line[i] += d->f.prev[i];
764 for( ; i < d->f.scanbytes; i++)
765 d->f.line[i] += PNG_fCalcPath(d->f.line[i - d->f.bytewidth], d->f.prev[i], d->f.prev[i - d->f.bytewidth]);
767 for(i = d->f.bytewidth; i < d->f.scanbytes; i++)
768 d->f.line[i] += d->f.line[i - d->f.bytewidth];
780 #if GDISP_NEED_IMAGE_PNG_GRAYSCALE_124
781 static void PNG_OutGRAY124(PNG_decode *d) {
788 for(i = 0; i < d->f.scanbytes; i++) {
789 for(bits = 8; bits; bits -= pinfo->bitdepth) {
790 px = (d->f.line[i] >> (bits - pinfo->bitdepth)) & ((1U << pinfo->bitdepth)-1);
791 #if GDISP_NEED_IMAGE_PNG_TRANSPARENCY
792 if ((pinfo->flags & PNG_FLG_TRANSPARENT) && (gU16)px == pinfo->trans_r) {
793 #if GDISP_NEED_IMAGE_PNG_BACKGROUND
794 if ((pinfo->flags & PNG_FLG_BACKGROUND)) {
795 PNG_oColor(&d->o, pinfo->bg);
799 PNG_oTransparent(&d->o);
803 px = px << (8-pinfo->bitdepth);
804 if (px >= 0x80) px += ((1U << (8-pinfo->bitdepth))-1);
810 #if GDISP_NEED_IMAGE_PNG_GRAYSCALE_8
811 static void PNG_OutGRAY8(PNG_decode *d) {
814 #if GDISP_NEED_IMAGE_PNG_TRANSPARENCY
815 PNG_info *pinfo = d->pinfo;
818 for(i = 0; i < d->f.scanbytes; i++) {
820 #if GDISP_NEED_IMAGE_PNG_TRANSPARENCY
821 if ((pinfo->flags & PNG_FLG_TRANSPARENT) && (gU16)px == pinfo->trans_r) {
822 #if GDISP_NEED_IMAGE_PNG_BACKGROUND
823 if ((pinfo->flags & PNG_FLG_BACKGROUND)) {
824 PNG_oColor(&d->o, pinfo->bg);
828 PNG_oTransparent(&d->o);
836 #if GDISP_NEED_IMAGE_PNG_GRAYSCALE_16
837 static void PNG_OutGRAY16(PNG_decode *d) {
840 #if GDISP_NEED_IMAGE_PNG_TRANSPARENCY
841 PNG_info *pinfo = d->pinfo;
844 for(i = 0; i < d->f.scanbytes; i+=2) {
846 #if GDISP_NEED_IMAGE_PNG_TRANSPARENCY
847 if ((pinfo->flags & PNG_FLG_TRANSPARENT) && gdispImageGetBE16(d->f.line, i) == pinfo->trans_r) {
848 #if GDISP_NEED_IMAGE_PNG_BACKGROUND
849 if ((pinfo->flags & PNG_FLG_BACKGROUND)) {
850 PNG_oColor(&d->o, pinfo->bg);
854 PNG_oTransparent(&d->o);
862 #if GDISP_NEED_IMAGE_PNG_RGB_8
863 static void PNG_OutRGB8(PNG_decode *d) {
865 #if GDISP_NEED_IMAGE_PNG_TRANSPARENCY
866 PNG_info *pinfo = d->pinfo;
869 for(i = 0; i < d->f.scanbytes; i+=3) {
870 #if GDISP_NEED_IMAGE_PNG_TRANSPARENCY
871 if ((pinfo->flags & PNG_FLG_TRANSPARENT)
872 && (gU16)d->f.line[i+0] == pinfo->trans_r
873 && (gU16)d->f.line[i+1] == pinfo->trans_g
874 && (gU16)d->f.line[i+2] == pinfo->trans_b) {
875 #if GDISP_NEED_IMAGE_PNG_BACKGROUND
876 if ((pinfo->flags & PNG_FLG_BACKGROUND)) {
877 PNG_oColor(&d->o, pinfo->bg);
881 PNG_oTransparent(&d->o);
885 PNG_oColor(&d->o,
RGB2COLOR(d->f.line[i+0], d->f.line[i+1], d->f.line[i+2]));
889 #if GDISP_NEED_IMAGE_PNG_RGB_16
890 static void PNG_OutRGB16(PNG_decode *d) {
892 #if GDISP_NEED_IMAGE_PNG_TRANSPARENCY
893 PNG_info *pinfo = d->pinfo;
896 for(i = 0; i < d->f.scanbytes; i+=6) {
897 #if GDISP_NEED_IMAGE_PNG_TRANSPARENCY
898 if ((pinfo->flags & PNG_FLG_TRANSPARENT)
899 && gdispImageGetBE16(d->f.line, i+0) == pinfo->trans_r
900 && gdispImageGetBE16(d->f.line, i+2) == pinfo->trans_g
901 && gdispImageGetBE16(d->f.line, i+4) == pinfo->trans_b) {
902 #if GDISP_NEED_IMAGE_PNG_BACKGROUND
903 if ((pinfo->flags & PNG_FLG_BACKGROUND)) {
904 PNG_oColor(&d->o, pinfo->bg);
908 PNG_oTransparent(&d->o);
912 PNG_oColor(&d->o,
RGB2COLOR(d->f.line[i+0], d->f.line[i+2], d->f.line[i+4]));
916 #if GDISP_NEED_IMAGE_PNG_PALETTE_124
917 static void PNG_OutPAL124(PNG_decode *d) {
924 for(i = 0; i < d->f.scanbytes; i++) {
925 for(bits = 8; bits; bits -= pinfo->bitdepth) {
926 idx = (d->f.line[i] >> (bits - pinfo->bitdepth)) & ((1U << pinfo->bitdepth)-1);
928 if ((gU16)idx >= pinfo->palsize) {
934 #define pix_color RGB2COLOR(pinfo->palette[idx], pinfo->palette[idx+1], pinfo->palette[idx+2])
935 #define pix_alpha pinfo->palette[idx+3]
937 #if GDISP_NEED_IMAGE_PNG_TRANSPARENCY
938 #if GDISP_NEED_IMAGE_PNG_BACKGROUND
939 if (pix_alpha != 255 && (pinfo->flags & PNG_FLG_BACKGROUND)) {
944 #if GDISP_NEED_IMAGE_PNG_ALPHACLIFF > 0
946 PNG_oTransparent(&d->o);
952 PNG_oColor(&d->o, pix_color);
960 #if GDISP_NEED_IMAGE_PNG_PALETTE_8
961 static void PNG_OutPAL8(PNG_decode *d) {
967 for(i = 0; i < d->f.scanbytes; i++) {
968 idx = (unsigned)d->f.line[i];
970 if ((gU16)idx >= pinfo->palsize) {
976 #define pix_color RGB2COLOR(pinfo->palette[idx], pinfo->palette[idx+1], pinfo->palette[idx+2])
977 #define pix_alpha pinfo->palette[idx+3]
979 #if GDISP_NEED_IMAGE_PNG_TRANSPARENCY
980 #if GDISP_NEED_IMAGE_PNG_BACKGROUND
981 if (pix_alpha != 255 && (pinfo->flags & PNG_FLG_BACKGROUND)) {
986 #if GDISP_NEED_IMAGE_PNG_ALPHACLIFF > 0
988 PNG_oTransparent(&d->o);
994 PNG_oColor(&d->o, pix_color);
1001 #if GDISP_NEED_IMAGE_PNG_GRAYALPHA_8
1002 static void PNG_OutGRAYA8(PNG_decode *d) {
1004 #if GDISP_NEED_IMAGE_PNG_BACKGROUND
1005 PNG_info *pinfo = d->pinfo;
1008 for(i = 0; i < d->f.scanbytes; i+=2) {
1009 #define pix_color LUMA2COLOR(d->f.line[i])
1010 #define pix_alpha d->f.line[i+1]
1012 #if GDISP_NEED_IMAGE_PNG_BACKGROUND
1013 if (pix_alpha != 255 && (pinfo->flags & PNG_FLG_BACKGROUND)) {
1018 #if GDISP_NEED_IMAGE_PNG_ALPHACLIFF > 0
1020 PNG_oTransparent(&d->o);
1025 PNG_oColor(&d->o, pix_color);
1032 #if GDISP_NEED_IMAGE_PNG_GRAYALPHA_16
1033 static void PNG_OutGRAYA16(PNG_decode *d) {
1035 #if GDISP_NEED_IMAGE_PNG_BACKGROUND
1036 PNG_info *pinfo = d->pinfo;
1039 for(i = 0; i < d->f.scanbytes; i+=4) {
1040 #define pix_color LUMA2COLOR(d->f.line[i])
1041 #define pix_alpha d->f.line[i+2]
1043 #if GDISP_NEED_IMAGE_PNG_BACKGROUND
1044 if (pix_alpha != 255 && (pinfo->flags & PNG_FLG_BACKGROUND)) {
1049 #if GDISP_NEED_IMAGE_PNG_ALPHACLIFF > 0
1051 PNG_oTransparent(&d->o);
1056 PNG_oColor(&d->o, pix_color);
1063 #if GDISP_NEED_IMAGE_PNG_RGBALPHA_8
1064 static void PNG_OutRGBA8(PNG_decode *d) {
1066 #if GDISP_NEED_IMAGE_PNG_BACKGROUND
1067 PNG_info *pinfo = d->pinfo;
1070 for(i = 0; i < d->f.scanbytes; i+=4) {
1071 #define pix_color RGB2COLOR(d->f.line[i+0], d->f.line[i+1], d->f.line[i+2])
1072 #define pix_alpha d->f.line[i+3]
1074 #if GDISP_NEED_IMAGE_PNG_BACKGROUND
1075 if (pix_alpha != 255 && (pinfo->flags & PNG_FLG_BACKGROUND)) {
1080 #if GDISP_NEED_IMAGE_PNG_ALPHACLIFF > 0
1082 PNG_oTransparent(&d->o);
1087 PNG_oColor(&d->o, pix_color);
1094 #if GDISP_NEED_IMAGE_PNG_RGBALPHA_16
1095 static void PNG_OutRGBA16(PNG_decode *d) {
1097 #if GDISP_NEED_IMAGE_PNG_BACKGROUND
1098 PNG_info *pinfo = d->pinfo;
1101 for(i = 0; i < d->f.scanbytes; i+=8) {
1102 #define pix_color RGB2COLOR(d->f.line[i+0], d->f.line[i+2], d->f.line[i+4])
1103 #define pix_alpha d->f.line[i+6]
1105 #if GDISP_NEED_IMAGE_PNG_BACKGROUND
1106 if (pix_alpha != 255 && (pinfo->flags & PNG_FLG_BACKGROUND)) {
1111 #if GDISP_NEED_IMAGE_PNG_ALPHACLIFF > 0
1113 PNG_oTransparent(&d->o);
1118 PNG_oColor(&d->o, pix_color);
1130 void gdispImageClose_PNG(
gImage *img) {
1133 pinfo = (PNG_info *)img->priv;
1136 gdispImageFree(img, (
void *)pinfo->palette, pinfo->palsize*4);
1138 gdispImageFree(img, (
void *)pinfo->cache, pinfo->cachesz);
1139 gdispImageFree(img, (
void *)pinfo,
sizeof(PNG_info));
1152 return GDISP_IMAGE_ERR_BADFORMAT;
1155 if(buf[0] != 137 || buf[1] != 80 || buf[2] != 78 || buf[3] != 71 || buf[4] != 13 || buf[5] != 10 || buf[6] != 26 || buf[7] != 10)
1156 return GDISP_IMAGE_ERR_BADFORMAT;
1161 img->type = GDISP_IMAGE_TYPE_PNG;
1164 if (!(img->priv = gdispImageAlloc(img,
sizeof(PNG_info))))
1165 return GDISP_IMAGE_ERR_NOMEMORY;
1168 pinfo = (PNG_info *)img->priv;
1180 for(pos = 8; ; pos += len+12,
gfileSetPos(img->f, pos)) {
1186 len = gdispImageGetAlignedBE32(buf, 0);
1189 switch (gdispImageGetAlignedBE32(buf, 4)) {
1193 if ((pinfo->flags & PNG_FLG_HEADERDONE))
1197 if (len < 13 ||
gfileRead(img->f, buf, 13) != 13)
1200 img->width = gdispImageGetAlignedBE16(buf, 2);
1201 img->height = gdispImageGetAlignedBE16(buf, 6);
1202 pinfo->bitdepth = gdispImageGetVar(gU8, buf, 8);
1203 pinfo->mode = gdispImageGetVar(gU8, buf, 9);
1204 if (gdispImageGetVar(gU8, buf, 12)) {
1205 pinfo->flags |= PNG_FLG_INTERLACE;
1206 #if !GDISP_NEED_IMAGE_PNG_INTERLACED
1207 goto exit_unsupported;
1212 if (gdispImageGetVar(gU16, buf, 0) != 0 || img->width <= 0
1213 || gdispImageGetVar(gU16, buf, 4) != 0 || img->height <= 0
1214 || gdispImageGetVar(gU8, buf, 10) != 0
1215 || gdispImageGetVar(gU8, buf, 11) != 0
1216 || gdispImageGetVar(gU8, buf, 12) > 1
1218 goto exit_unsupported;
1221 switch(pinfo->mode) {
1222 #if GDISP_NEED_IMAGE_PNG_GRAYSCALE_124 || GDISP_NEED_IMAGE_PNG_GRAYSCALE_8 || GDISP_NEED_IMAGE_PNG_GRAYSCALE_16
1223 case PNG_COLORMODE_GRAY:
1224 switch(pinfo->bitdepth) {
1225 #if GDISP_NEED_IMAGE_PNG_GRAYSCALE_124
1228 case 4: pinfo->out = PNG_OutGRAY124;
break;
1230 #if GDISP_NEED_IMAGE_PNG_GRAYSCALE_8
1231 case 8: pinfo->out = PNG_OutGRAY8;
break;
1233 #if GDISP_NEED_IMAGE_PNG_GRAYSCALE_16
1234 case 16: pinfo->out = PNG_OutGRAY16;
break;
1236 default:
goto exit_unsupported;
1238 pinfo->bpp = pinfo->bitdepth;
1241 #if GDISP_NEED_IMAGE_PNG_RGB_8 || GDISP_NEED_IMAGE_PNG_RGB_16
1242 case PNG_COLORMODE_RGB:
1243 switch(pinfo->bitdepth) {
1244 #if GDISP_NEED_IMAGE_PNG_RGB_8
1245 case 8: pinfo->out = PNG_OutRGB8;
break;
1247 #if GDISP_NEED_IMAGE_PNG_RGB_16
1248 case 16: pinfo->out = PNG_OutRGB16;
break;
1250 default:
goto exit_unsupported;
1252 pinfo->bpp = pinfo->bitdepth * 3;
1255 #if GDISP_NEED_IMAGE_PNG_PALETTE_124 || GDISP_NEED_IMAGE_PNG_PALETTE_8
1256 case PNG_COLORMODE_PALETTE:
1257 switch(pinfo->bitdepth) {
1258 #if GDISP_NEED_IMAGE_PNG_PALETTE_124
1261 case 4: pinfo->out = PNG_OutPAL124;
break;
1263 #if GDISP_NEED_IMAGE_PNG_PALETTE_8
1264 case 8: pinfo->out = PNG_OutPAL8;
break;
1266 default:
goto exit_unsupported;
1268 pinfo->bpp = pinfo->bitdepth;
1271 #if GDISP_NEED_IMAGE_PNG_GRAYALPHA_8 || GDISP_NEED_IMAGE_PNG_GRAYALPHA_16
1272 case PNG_COLORMODE_GRAYALPHA:
1273 switch(pinfo->bitdepth) {
1274 #if GDISP_NEED_IMAGE_PNG_GRAYALPHA_8
1275 case 8: pinfo->out = PNG_OutGRAYA8;
break;
1277 #if GDISP_NEED_IMAGE_PNG_GRAYALPHA_16
1278 case 16: pinfo->out = PNG_OutGRAYA16;
break;
1280 default:
goto exit_unsupported;
1282 pinfo->bpp = pinfo->bitdepth * 2;
1285 #if GDISP_NEED_IMAGE_PNG_RGBALPHA_8 || GDISP_NEED_IMAGE_PNG_RGBALPHA_16
1286 case PNG_COLORMODE_RGBA:
1287 switch(pinfo->bitdepth) {
1288 #if GDISP_NEED_IMAGE_PNG_RGBALPHA_8
1289 case 8: pinfo->out = PNG_OutRGBA8;
break;
1291 #if GDISP_NEED_IMAGE_PNG_RGBALPHA_16
1292 case 16: pinfo->out = PNG_OutRGBA16;
break;
1294 default:
goto exit_unsupported;
1296 pinfo->bpp = pinfo->bitdepth * 4;
1300 goto exit_unsupported;
1303 pinfo->flags |= PNG_FLG_HEADERDONE;
1312 if (!(pinfo->flags & PNG_FLG_HEADERDONE))
1315 #if GDISP_NEED_IMAGE_PNG_PALETTE_124 || GDISP_NEED_IMAGE_PNG_PALETTE_8
1317 if (pinfo->mode == PNG_COLORMODE_PALETTE && !pinfo->palette)
1322 return GDISP_IMAGE_ERR_OK;
1324 #if GDISP_NEED_IMAGE_PNG_PALETTE_124 || GDISP_NEED_IMAGE_PNG_PALETTE_8
1328 if (!(pinfo->flags & PNG_FLG_HEADERDONE))
1332 if (pinfo->mode != PNG_COLORMODE_PALETTE)
1336 if (len > 3 * 256 || pinfo->palette)
1340 pinfo->palsize = len / 3;
1341 if (!(pinfo->palette =
gfxAlloc(pinfo->palsize * 4)))
1349 for(idx=pinfo->palsize, p=pinfo->palette; idx; p += 4, idx--) {
1359 #if GDISP_NEED_IMAGE_PNG_TRANSPARENCY
1363 if (!(pinfo->flags & PNG_FLG_HEADERDONE))
1367 switch(pinfo->mode) {
1369 #if GDISP_NEED_IMAGE_PNG_PALETTE_124 || GDISP_NEED_IMAGE_PNG_PALETTE_8
1370 case PNG_COLORMODE_PALETTE:
1371 if (len > pinfo->palsize)
1379 for(idx=len, p=pinfo->palette+3; idx; p += 4, idx--) {
1387 #if GDISP_NEED_IMAGE_PNG_GRAYSCALE_124 || GDISP_NEED_IMAGE_PNG_GRAYSCALE_8 || GDISP_NEED_IMAGE_PNG_GRAYSCALE_16
1388 case PNG_COLORMODE_GRAY:
1390 if (len != 2 ||
gfileRead(img->f, buf, 2) != 2)
1393 pinfo->flags |= PNG_FLG_TRANSPARENT;
1394 pinfo->trans_r = gdispImageGetAlignedBE16(buf, 0);
1397 #if GDISP_NEED_IMAGE_PNG_RGB_8 || GDISP_NEED_IMAGE_PNG_RGB_16
1398 case PNG_COLORMODE_RGB:
1400 if (len != 6 ||
gfileRead(img->f, buf, 6) != 6)
1403 pinfo->flags |= PNG_FLG_TRANSPARENT;
1404 pinfo->trans_r = gdispImageGetAlignedBE16(buf, 0);
1405 pinfo->trans_g = gdispImageGetAlignedBE16(buf, 2);
1406 pinfo->trans_b = gdispImageGetAlignedBE16(buf, 4);
1410 goto exit_unsupported;
1416 #if GDISP_NEED_IMAGE_PNG_BACKGROUND
1420 if (!(pinfo->flags & PNG_FLG_HEADERDONE))
1423 pinfo->flags |= PNG_FLG_BACKGROUND;
1426 switch(pinfo->mode) {
1428 #if GDISP_NEED_IMAGE_PNG_PALETTE_124 || GDISP_NEED_IMAGE_PNG_PALETTE_8
1429 case PNG_COLORMODE_PALETTE:
1430 if (!pinfo->palette || len < 1 ||
gfileRead(img->f, buf, 1) != 1 || (gU16)buf[0] >= pinfo->palsize)
1432 pinfo->bg =
RGB2COLOR(pinfo->palette[((
unsigned)buf[0])*4+0],
1433 pinfo->palette[((
unsigned)buf[0])*4+1],
1434 pinfo->palette[((
unsigned)buf[0])*4+2]);
1438 #if GDISP_NEED_IMAGE_PNG_GRAYSCALE_124 || GDISP_NEED_IMAGE_PNG_GRAYSCALE_8 || GDISP_NEED_IMAGE_PNG_GRAYSCALE_16 || GDISP_NEED_IMAGE_PNG_GRAYALPHA_8 || GDISP_NEED_IMAGE_PNG_GRAYALPHA_16
1439 case PNG_COLORMODE_GRAY:
1440 case PNG_COLORMODE_GRAYALPHA:
1441 if (len < 2 ||
gfileRead(img->f, buf, 2) != 2)
1443 switch(pinfo->bitdepth) {
1444 #if GDISP_NEED_IMAGE_PNG_GRAYSCALE_124
1448 buf[1] <<= 8-pinfo->bitdepth;
1450 buf[1] += ((1U << (8-pinfo->bitdepth))-1);
1454 #if GDISP_NEED_IMAGE_PNG_GRAYSCALE_8 || GDISP_NEED_IMAGE_PNG_GRAYALPHA_8
1459 #if GDISP_NEED_IMAGE_PNG_GRAYSCALE_16 || GDISP_NEED_IMAGE_PNG_GRAYALPHA_16
1467 #if GDISP_NEED_IMAGE_PNG_RGB_8 || GDISP_NEED_IMAGE_PNG_RGB_16 || GDISP_NEED_IMAGE_PNG_RGBALPHA_8 || GDISP_NEED_IMAGE_PNG_RGBALPHA_16
1468 case PNG_COLORMODE_RGB:
1469 case PNG_COLORMODE_RGBA:
1470 if (len < 6 ||
gfileRead(img->f, buf, 6) != 6)
1473 #if GDISP_NEED_IMAGE_PNG_RGB_16 || GDISP_NEED_IMAGE_PNG_RGBALPHA_16
1474 if (pinfo->bitdepth == 16) {
1475 pinfo->bg =
RGB2COLOR(buf[0], buf[2], buf[4]);
1478 pinfo->bg =
RGB2COLOR(buf[1], buf[3], buf[5]);
1482 goto exit_unsupported;
1490 gdispImageClose_PNG(img);
1491 return GDISP_IMAGE_ERR_BADDATA;
1493 gdispImageClose_PNG(img);
1494 return GDISP_IMAGE_ERR_UNSUPPORTED;
1496 gdispImageClose_PNG(img);
1497 return GDISP_IMAGE_ERR_NOMEMORY;
1505 pinfo = (PNG_info *)img->priv;
1506 if (!(d = gdispImageAlloc(img,
sizeof(PNG_decode) + (img->width * pinfo->bpp + 7) / 4)))
1507 return GDISP_IMAGE_ERR_NOMEMORY;
1514 PNG_oInit(&d->o, g, x, y, cx, cy, sx, sy);
1518 if (!PNG_zGetHeader(d))
1521 #if GDISP_NEED_IMAGE_PNG_INTERLACED
1522 if ((pinfo->flags & PNG_FLG_INTERLACE)) {
1524 #error "PNG Decoder: Interlaced PNG's are not supported yet!"
1529 PNG_fInit(&d->f, (gU8 *)(d+1), (pinfo->bpp + 7) / 8, (img->width * pinfo->bpp + 7) / 8);
1530 for(y = 0; y < sy+cy; PNG_fNext(&d->f), y++) {
1531 if (!PNG_unfilter_type0(d))
1533 if (PNG_oStartY(&d->o, y)) {
1541 gdispImageFree(img, d,
sizeof(PNG_decode) + (img->width * pinfo->bpp + 7) / 4);
1542 return GDISP_IMAGE_ERR_OK;
1545 gdispImageFree(img, d,
sizeof(PNG_decode) + (img->width * pinfo->bpp + 7) / 4);
1546 return GDISP_IMAGE_ERR_BADDATA;
1557 pinfo = (PNG_info *)img->priv;
1559 return GDISP_IMAGE_ERR_OK;
1568 return GDISP_IMAGE_ERR_BADDATA;
1571 chunklen = gdispImageGetAlignedBE32(buf, 0);
1572 chunknext += chunklen + 12;
1575 switch (gdispImageGetAlignedBE32(buf, 4)) {
1577 pinfo->cachesz += chunklen;
1580 if (!pinfo->cachesz)
1581 return GDISP_IMAGE_ERR_BADDATA;
1588 if (!(pcache = gdispImageAlloc(img, pinfo->cachesz)))
1589 return GDISP_IMAGE_ERR_NOMEMORY;
1591 pinfo->cache = pcache;
1602 chunklen = gdispImageGetAlignedBE32(buf, 0);
1603 chunknext += chunklen + 12;
1606 switch (gdispImageGetAlignedBE32(buf, 4)) {
1608 if (
gfileRead(img->f, pcache, chunklen) != chunklen)
1613 return GDISP_IMAGE_ERR_OK;
1619 gdispImageFree(img, pinfo->cache, pinfo->cachesz);
1621 return GDISP_IMAGE_ERR_BADDATA;
1624 gDelay gdispImageNext_PNG(
gImage *img) {
1628 return gDelayForever;
GDISP image support routines header file.
#define LUMA2COLOR(l)
Convert a luminance (0 to 255) into a color value.
#define RGB2COLOR(r, g, b)
Convert red, green, blue (each 0 to 255) into a color value.
COLOR_TYPE gColor
The color type definition.
gColor gdispBlendColor(gColor fg, gColor bg, gU8 alpha)
Blend 2 colors according to the alpha.
void gdispGDrawPixel(GDisplay *g, gCoord x, gCoord y, gColor color)
Set a pixel in the specified color.
void gdispGBlitArea(GDisplay *g, gCoord x, gCoord y, gCoord cx, gCoord cy, gCoord srcx, gCoord srcy, gCoord srccx, const gPixel *buffer)
Fill an area using the supplied bitmap.
gColor gPixel
The pixel format.
#define GDISP_NEED_IMAGE_PNG_ALPHACLIFF
What is the cliff between non-blended alpha pixels being displayed or not.
#define GDISP_IMAGE_PNG_FILE_BUFFER_SIZE
The PNG input file buffer size in bytes.
#define GDISP_NEED_IMAGE_PNG_PALETTE_8
Is 8 bit PNG palettized image decoding required.
#define GDISP_NEED_IMAGE_PNG_PALETTE_124
Is 1, 2 and 4 bit PNG palettized image decoding required.
#define GDISP_IMAGE_PNG_BLIT_BUFFER_SIZE
The PNG blit buffer size in pixels.
gI16 gCoord
The type for a coordinate or length on the screen.
#define GDISP_IMAGE_PNG_Z_BUFFER_SIZE
The PNG inflate decompression buffer size in bytes.
gBool gfileSetPos(GFILE *f, gFileSize pos)
Set the position of the read/write cursor.
gMemSize gfileRead(GFILE *f, void *buf, gMemSize len)
Read from file.
struct GFILE GFILE
A file pointer.
void * gfxAlloc(gMemSize sz)
Allocate memory.
gU16 gdispImageError
An image error code.
The structure for an image.