µGFX  2.9
version 2.9
gdisp_image_png.c
1 /*
2  * This file is subject to the terms of the GFX License. If a copy of
3  * the license was not distributed with this file, you can obtain one at:
4  *
5  * http://ugfx.io/license.html
6  */
7 
8 #include "../../gfx.h"
9 
10 #if GFX_USE_GDISP && GDISP_NEED_IMAGE && GDISP_NEED_IMAGE_PNG
11 
12 #include "gdisp_image_support.h"
13 
14 /*-----------------------------------------------------------------
15  * Structure definitions
16  *---------------------------------------------------------------*/
17 
18 struct PNG_decode;
19 
20 // PNG info (comes from the PNG header)
21 typedef struct PNG_info {
22  gU8 flags; // Flags (global)
23  #define PNG_FLG_HEADERDONE 0x01 // The header has been processed
24  #define PNG_FLG_TRANSPARENT 0x02 // Has transparency
25  #define PNG_FLG_INTERLACE 0x04 // Is Interlaced
26  #define PNG_FLG_BACKGROUND 0x08 // Has a specified background color
27  gU8 bitdepth; // 1, 2, 4, 8, 16
28  gU8 mode; // The PNG color-mode
29  #define PNG_COLORMODE_GRAY 0x00 // Grayscale
30  #define PNG_COLORMODE_RGB 0x02 // RGB
31  #define PNG_COLORMODE_PALETTE 0x03 // Pallete
32  #define PNG_COLORMODE_GRAYALPHA 0x04 // Grayscale with Alpha
33  #define PNG_COLORMODE_RGBA 0x06 // RGBA
34  gU8 bpp; // Bits per pixel
35 
36  gU8 *cache; // The image cache
37  unsigned cachesz; // The image cache size
38 
39  void (*out)(struct PNG_decode *); // The scan line output function
40 
41  #if GDISP_NEED_IMAGE_PNG_BACKGROUND
42  gColor bg; // The background color
43  #endif
44  #if GDISP_NEED_IMAGE_PNG_TRANSPARENCY
45  gU16 trans_r; // Red/grayscale component of the transparent color (PNG_COLORMODE_GRAY and PNG_COLORMODE_RGB only)
46  gU16 trans_g; // Green component of the transparent color (PNG_COLORMODE_RGB only)
47  gU16 trans_b; // Blue component of the transparent color (PNG_COLORMODE_RGB only)
48  #endif
49  #if GDISP_NEED_IMAGE_PNG_PALETTE_124 || GDISP_NEED_IMAGE_PNG_PALETTE_8
50  gU16 palsize; // palette size in number of colors
51  gU8 *palette; // palette in RGBA RGBA... order (4 bytes per entry - PNG_COLORMODE_PALETTE only)
52  #endif
53  } PNG_info;
54 
55 // Handle the PNG file stream
56 typedef struct PNG_input {
57  GFILE * f; // The gfile to retrieve data from
58  unsigned buflen; // The number of bytes left in the buffer
59  gU8 *pbuf; // The pointer to the next byte
60  gU32 chunklen; // The number of bytes left in the current PNG chunk
61  gU32 chunknext; // The file position of the next PNG chunk
62  gU8 buf[GDISP_IMAGE_PNG_FILE_BUFFER_SIZE]; // Must be a minimum of 8 bytes to hold a chunk header
63  } PNG_input;
64 
65 // Handle the display output and windowing
66 typedef struct PNG_output {
67  GDisplay *g;
68  gCoord x, y;
69  gCoord cx, cy;
70  gCoord sx, sy;
71  gCoord ix, iy;
72  unsigned cnt;
74  } PNG_output;
75 
76 // Handle the PNG scan line filter
77 typedef struct PNG_filter {
78  unsigned scanbytes;
79  unsigned bytewidth;
80  gU8 *line;
81  gU8 *prev;
82  } PNG_filter;
83 
84 // Handle the PNG inflate decompression
85 typedef struct PNG_zTree {
86  gU16 table[16]; // Table of code length counts
87  gU16 trans[288]; // Code to symbol translation table
88  } PNG_zTree;
89 
90 typedef struct PNG_zinflate {
91  gU8 data; // The current input stream data byte
92  gU8 bits; // The number of bits left in the data byte
93  gU8 flags; // Decompression flags
94  #define PNG_ZFLG_EOF 0x01 // No more input data
95  #define PNG_ZFLG_FINAL 0x02 // This is the final block
96  #define PNG_ZFLG_RESUME_MASK 0x0C // The mask of bits for the resume state
97  #define PNG_ZFLG_RESUME_NEW 0x00 // Process a new block
98  #define PNG_ZFLG_RESUME_COPY 0x04 // Resume a byte copy from the input stream (length in tmp)
99  #define PNG_ZFLG_RESUME_INFLATE 0x08 // Resume using the specified symbol (symbol in tmp[0])
100  #define PNG_ZFLG_RESUME_OFFSET 0x0C // Resume a byte offset copy from the buffer (length and offset in tmp)
101 
102  unsigned bufpos; // The current buffer output position
103  unsigned bufend; // The current buffer end position (wraps)
104 
105  PNG_zTree ltree; // The dynamic length tree
106  PNG_zTree dtree; // The dynamic distance tree
107  gU8 tmp[288+32]; // Temporary space for decoding dynamic trees and other temporary uses
108  gU8 buf[GDISP_IMAGE_PNG_Z_BUFFER_SIZE]; // The decoding buffer and sliding window
109  } PNG_zinflate;
110 
111 // Put all the decoding structures together.
112 // Note this is immediately followed by 2 scan lines of uncompressed image data for filtering (dynamic size).
113 typedef struct PNG_decode {
114  gImage *img;
115  PNG_info *pinfo;
116  PNG_input i;
117  PNG_output o;
118  PNG_filter f;
119  PNG_zinflate z;
120  } PNG_decode;
121 
122 /*-----------------------------------------------------------------
123  * PNG input data stream functions
124  *---------------------------------------------------------------*/
125 
126 // Input initialization
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;
131  d->i.f = 0;
132  } else {
133  d->i.buflen = 0;
134  d->i.chunklen = 0;
135  d->i.chunknext = 8;
136  d->i.f = d->img->f;
137  }
138 }
139 
140 // Load the next byte of image data from the PNG file
141 static gBool PNG_iLoadData(PNG_decode *d) {
142  gU32 sz;
143 
144  // Is there data still left in the buffer?
145  if (d->i.buflen)
146  return gTrue;
147 
148  // If we are cached then we have no more data
149  if (!d->i.f)
150  return gFalse;
151 
152  // Have we finished the current chunk?
153  if (!d->i.chunklen) {
154  while(1) {
155  // Find a new chunk
156  gfileSetPos(d->i.f, d->i.chunknext);
157  if (gfileRead(d->i.f, d->i.buf, 8) != 8)
158  return gFalse;
159 
160  // Calculate the chunk length and next chunk
161  d->i.chunklen = gdispImageGetAlignedBE32(d->i.buf, 0);
162  d->i.chunknext += d->i.chunklen + 12;
163 
164  // Process only image data chunks
165  switch (gdispImageGetAlignedBE32(d->i.buf, 4)) {
166  case 0x49444154: // "IDAT" - Image Data
167  if (!d->i.chunklen)
168  break;
169  goto gotchunk;
170  case 0x49454E44: // "IEND" - All done
171  return gFalse;
172  }
173  }
174  }
175 
176 gotchunk:
177 
178  // Try to read data some from the chunk
179  sz = d->i.chunklen;
182  if (gfileRead(d->i.f, d->i.buf, sz) != sz)
183  return gFalse;
184  d->i.chunklen -= sz;
185  d->i.buflen = sz;
186  d->i.pbuf = d->i.buf;
187  return gTrue;
188 }
189 
190 // Get the last loaded byte of image data from the PNG file
191 static gU8 PNG_iGetByte(PNG_decode *d) {
192  d->i.buflen--;
193  return *d->i.pbuf++;
194 }
195 
196 /*-----------------------------------------------------------------
197  * Display output and windowing functions
198  *---------------------------------------------------------------*/
199 
200 // Initialize the display output window
201 static void PNG_oInit(PNG_output *o, GDisplay *g, gCoord x, gCoord y, gCoord cx, gCoord cy, gCoord sx, gCoord sy) {
202  o->g = g;
203  o->x = x;
204  o->y = y;
205  o->cx = cx;
206  o->cy = cy;
207  o->sx = sx;
208  o->sy = sy;
209  o->ix = o->iy = 0;
210  o->cnt = 0;
211 }
212 
213 // Flush the output buffer to the display
214 static void PNG_oFlush(PNG_output *o) {
215  switch(o->cnt) {
216  case 0: return;
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;
219  }
220  o->ix += o->cnt;
221  o->cnt = 0;
222 }
223 
224 // Start a new image line
225 static gBool PNG_oStartY(PNG_output *o, gCoord y) {
226  if (y < o->sy || y >= o->sy+o->cy)
227  return gFalse;
228  o->ix = 0;
229  o->iy = y;
230  return gTrue;
231 }
232 
233 // Feed a pixel color to the display buffer
234 static void PNG_oColor(PNG_output *o, gColor c) {
235  // Is it in the window
236  if (o->ix+(gCoord)o->cnt < o->sx || o->ix+(gCoord)o->cnt >= o->sx+o->cx) {
237  // No - just skip the pixel
238  PNG_oFlush(o);
239  o->ix++;
240  return;
241  }
242 
243  // Is the buffer full
244  if (o->cnt >= sizeof(o->buf)/sizeof(o->buf[0]))
245  PNG_oFlush(o);
246 
247  // Save the pixel
248  o->buf[o->cnt++] = c;
249 }
250 
251 #if GDISP_NEED_IMAGE_PNG_TRANSPARENCY || GDISP_NEED_IMAGE_PNG_ALPHACLIFF > 0
252  // Feed a transparent pixel to the display buffer
253  static void PNG_oTransparent(PNG_output *o) {
254  // Flush any existing pixels
255  PNG_oFlush(o);
256 
257  // Just skip the pixel
258  o->ix++;
259  }
260 #endif
261 
262 /*-----------------------------------------------------------------
263  * Inflate uncompress functions
264  *---------------------------------------------------------------*/
265 
266 // Wrap the zInflate buffer position (after increment)
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; }
269 #else
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")
274  #endif
275  #define WRAP_ZBUF(x) { if (x >= GDISP_IMAGE_PNG_Z_BUFFER_SIZE) x = 0; }
276 #endif
277 
278 // Initialize the inflate decompressor
279 static void PNG_zInit(PNG_zinflate *z) {
280  z->bits = 0;
281  z->flags = 0;
282  z->bufpos = z->bufend = 0;
283 }
284 
285 // Get the inflate header (slightly customized for PNG validity testing)
286 static gBool PNG_zGetHeader(PNG_decode *d) {
287  if (!PNG_iLoadData(d))
288  return gFalse;
289  d->z.tmp[0] = PNG_iGetByte(d);
290  if (!PNG_iLoadData(d))
291  return gFalse;
292  d->z.tmp[1] = PNG_iGetByte(d);
293  if (gdispImageGetAlignedBE16(d->z.tmp, 0) % 31 != 0 // Must be modulo 31, the FCHECK value is made that way
294  || (d->z.tmp[0] & 0x0F) != 8 || (d->z.tmp[0] & 0x80) // only method 8: inflate 32k sliding window
295  || (d->z.tmp[1] & 0x20)) // no preset dictionary
296  return gFalse;
297  return gTrue;
298 }
299 
300 // Get a bit from the input (treated as a LSB first stream)
301 static unsigned PNG_zGetBit(PNG_decode *d) {
302  unsigned bit;
303 
304  // Check for EOF
305  if ((d->z.flags & PNG_ZFLG_EOF))
306  return 1;
307 
308  // Check if data is empty
309  if (!d->z.bits) {
310  if (!PNG_iLoadData(d)) {
311  d->z.flags |= PNG_ZFLG_EOF;
312  return 1;
313  }
314  d->z.data = PNG_iGetByte(d);
315  d->z.bits = 8;
316  }
317 
318  // Get the next bit
319  d->z.bits--;
320  bit = d->z.data & 0x01;
321  d->z.data >>= 1;
322  return bit;
323 }
324 
325 // Get multiple bits from the input (treated as a LSB first stream with bit order retained)
326 static unsigned PNG_zGetBits(PNG_decode *d, unsigned num) {
327  unsigned val;
328  unsigned limit;
329  unsigned mask;
330 
331  val = 0;
332  limit = 1 << num;
333 
334  for (mask = 1; mask < limit; mask <<= 1)
335  if (PNG_zGetBit(d))
336  val += mask;
337  return val;
338 }
339 
340 // Build an inflate dynamic tree using a string of byte lengths
341 static void PNG_zBuildTree(PNG_zTree *t, const gU8 *lengths, unsigned num) {
342  unsigned i, sum;
343  gU16 offs[16];
344 
345  for (i = 0; i < 16; ++i)
346  t->table[i] = 0;
347  for (i = 0; i < num; ++i)
348  t->table[lengths[i]]++;
349 
350  t->table[0] = 0;
351 
352  for (sum = 0, i = 0; i < 16; ++i) {
353  offs[i] = sum;
354  sum += t->table[i];
355  }
356  for (i = 0; i < num; ++i) {
357  if (lengths[i])
358  t->trans[offs[lengths[i]]++] = i;
359  }
360 }
361 
362 // Get an inflate decode symbol
363 static gU16 PNG_zGetSymbol(PNG_decode *d, PNG_zTree *t) {
364  int sum, cur;
365  unsigned len;
366 
367  sum = cur = 0;
368  len = 0;
369  do {
370  cur <<= 1;
371  cur += PNG_zGetBit(d);
372  if ((d->z.flags & PNG_ZFLG_EOF))
373  return 0;
374  len++;
375 
376  sum += t->table[len];
377  cur -= t->table[len];
378  } while (cur >= 0);
379 
380  return t->trans[sum + cur];
381 }
382 
383 // Build inflate fixed length and distance trees
384 static void PNG_zBuildFixedTrees(PNG_decode *d) {
385  unsigned i;
386 
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;
395 
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;
400 }
401 
402 // Build inflate dynamic length and distance trees
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;
406  unsigned i, num;
407  gU16 symbol;
408  gU8 val;
409 
410  hlit = PNG_zGetBits(d, 5) + 257; // 257 - 286
411  hdist = PNG_zGetBits(d, 5) + 1; // 1 - 32
412  hclen = PNG_zGetBits(d, 4) + 4; // 4 - 19
413 
414  if ((d->z.flags & PNG_ZFLG_EOF))
415  return gFalse;
416 
417  for (i = 0; i < 19; ++i)
418  d->z.tmp[i] = 0;
419 
420  // Get code lengths for the code length alphabet
421  for (i = 0; i < hclen; ++i)
422  d->z.tmp[IndexLookup[i]] = PNG_zGetBits(d, 3);
423 
424  if ((d->z.flags & PNG_ZFLG_EOF))
425  return gFalse;
426 
427  // Build the code length tree
428  PNG_zBuildTree(&d->z.ltree, d->z.tmp, 19);
429 
430  // Decode code lengths
431  for (num = 0; num < hlit + hdist; ) {
432  symbol = PNG_zGetSymbol(d, &d->z.ltree);
433  if ((d->z.flags & PNG_ZFLG_EOF))
434  return gFalse;
435 
436  switch(symbol) {
437  case 16: // Copy the previous code length 3-6 times
438  val = d->z.tmp[num - 1];
439  for (i = PNG_zGetBits(d, 2) + 3; i; i--)
440  d->z.tmp[num++] = val;
441  break;
442  case 17: // Repeat code length 0 for 3-10 times
443  for (i = PNG_zGetBits(d, 3) + 3; i; i--)
444  d->z.tmp[num++] = 0;
445  break;
446  case 18: // Repeat code length 0 for 11-138 times
447  for (i = PNG_zGetBits(d, 7) + 11; i; i--)
448  d->z.tmp[num++] = 0;
449  break;
450  default: // symbols 0-15 are the actual code lengths
451  d->z.tmp[num++] = symbol;
452  break;
453  }
454  }
455 
456  // Build the trees
457  PNG_zBuildTree(&d->z.ltree, d->z.tmp, hlit);
458  PNG_zBuildTree(&d->z.dtree, d->z.tmp + hlit, hdist);
459  return gTrue;
460 }
461 
462 // Copy bytes from the input stream. Completing the copy completes the block.
463 static gBool PNG_zCopyInput(PNG_decode *d, unsigned length) {
464  // Copy the block
465  while(length--) {
466  if (!PNG_iLoadData(d)) { // EOF?
467  d->z.flags |= PNG_ZFLG_EOF;
468  return gFalse;
469  }
470  d->z.buf[d->z.bufend++] = PNG_iGetByte(d);
471  WRAP_ZBUF(d->z.bufend);
472  if (d->z.bufend == d->z.bufpos) { // Buffer full?
473  d->z.flags = (d->z.flags & ~PNG_ZFLG_RESUME_MASK) | PNG_ZFLG_RESUME_COPY;
474  ((unsigned *)d->z.tmp)[0] = length;
475  return gTrue;
476  }
477  }
478 
479  // The block is done
480  d->z.flags = (d->z.flags & ~PNG_ZFLG_RESUME_MASK) | PNG_ZFLG_RESUME_NEW;
481  return gTrue;
482 }
483 
484 // Copy an uncompressed inflate block into the output
485 static gBool PNG_zUncompressedBlock(PNG_decode *d) {
486  unsigned length;
487 
488  // This block works on byte boundaries
489  d->z.bits = 0;
490 
491  // Get 4 byte header
492  for (length = 0; length < 4; length++) {
493  if (!PNG_iLoadData(d)) { // EOF?
494  d->z.flags |= PNG_ZFLG_EOF;
495  return gFalse;
496  }
497  d->z.tmp[length] = PNG_iGetByte(d);
498  }
499 
500  // Get length
501  length = gdispImageGetAlignedLE16(d->z.tmp, 0);
502 
503  // Check length
504  if ((gU16)length != (gU16)~gdispImageGetAlignedLE16(d->z.tmp, 2)) {
505  d->z.flags |= PNG_ZFLG_EOF;
506  return gFalse;
507  }
508 
509  // Copy the block
510  return PNG_zCopyInput(d, length);
511 }
512 
513 // Inflate a compressed inflate block into the output
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;
520  gU16 symbol;
521 
522  while(1) {
523  symbol = PNG_zGetSymbol(d, &d->z.ltree); // EOF?
524  if ((d->z.flags & PNG_ZFLG_EOF))
525  goto iserror;
526 
527  // Is the block done?
528  if (symbol == 256) {
529  d->z.flags = (d->z.flags & ~PNG_ZFLG_RESUME_MASK) | PNG_ZFLG_RESUME_NEW;
530  return gTrue;
531  }
532 
533  if (symbol < 256) {
534  // The symbol is the data
535  d->z.buf[d->z.bufend++] = (gU8)symbol;
536  WRAP_ZBUF(d->z.bufend);
537  if (d->z.bufend == d->z.bufpos) { // Buffer full?
538  d->z.flags = (d->z.flags & ~PNG_ZFLG_RESUME_MASK) | PNG_ZFLG_RESUME_INFLATE;
539  return gTrue;
540  }
541  continue;
542  }
543 
544  // Shift the symbol down into an index
545  symbol -= 257;
546 
547  if (symbol >= sizeof(lbits)) // Bad index?
548  goto iserror;
549 
550  // Get more bits from length code
551  length = PNG_zGetBits(d, lbits[symbol]) + lbase[symbol];
552  if ((d->z.flags & PNG_ZFLG_EOF) || length >= GDISP_IMAGE_PNG_Z_BUFFER_SIZE) // Bad length?
553  goto iserror;
554 
555  // Get the distance code
556  dist = PNG_zGetSymbol(d, &d->z.dtree); // Bad distance?
557  if ((d->z.flags & PNG_ZFLG_EOF) || dist >= sizeof(dbits))
558  goto iserror;
559 
560  // Get more bits from distance code
561  offset = PNG_zGetBits(d, dbits[dist]) + dbase[dist];
562  if ((d->z.flags & PNG_ZFLG_EOF) || offset >= GDISP_IMAGE_PNG_Z_BUFFER_SIZE) // Bad offset?
563  goto iserror;
564 
565  // Work out the source buffer position allowing for wrapping
566  if (offset > d->z.bufend)
568  offset = d->z.bufend - offset;
569 
570  // Copy the matching string
571  while (length--) {
572  d->z.buf[d->z.bufend++] = d->z.buf[offset++];
573  WRAP_ZBUF(d->z.bufend);
574  WRAP_ZBUF(offset);
575  if (d->z.bufend == d->z.bufpos) { // Buffer full?
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;
579  return gTrue;
580  }
581  }
582  }
583 
584 iserror:
585  d->z.flags |= PNG_ZFLG_EOF;
586  return gFalse;
587 }
588 
589 // Start a new uncompressed/inflate block
590 static gBool PNG_zStartBlock(PNG_decode *d) {
591  // Check for previous error, EOF or no more blocks
592  if ((d->z.flags & (PNG_ZFLG_EOF|PNG_ZFLG_FINAL)))
593  return gFalse;
594 
595  // Is this the final inflate block?
596  if (PNG_zGetBit(d))
597  d->z.flags |= PNG_ZFLG_FINAL;
598 
599  // Get the block type
600  switch (PNG_zGetBits(d, 2)) {
601 
602  case 0: // Decompress uncompressed block
603  if (!PNG_zUncompressedBlock(d))
604  return gFalse;
605  break;
606 
607  case 1: // Decompress block with fixed huffman trees
608  PNG_zBuildFixedTrees(d);
609  if (!PNG_zInflateBlock(d))
610  return gFalse;
611  break;
612 
613  case 2: // Decompress block with dynamic huffman trees
614  if (!PNG_zDecodeTrees(d))
615  return gFalse;
616  if (!PNG_zInflateBlock(d))
617  return gFalse;
618  break;
619 
620  default: // Bad block type
621  // Mark it as an error
622  d->z.flags |= PNG_ZFLG_EOF;
623  return gFalse;
624  }
625  return gTrue;
626 }
627 
628 // Resume an offset copy
629 static gBool PNG_zResumeOffset(PNG_decode *d, unsigned length, unsigned offset) {
630  // Copy the matching string
631  while (length--) {
632  d->z.buf[d->z.bufend++] = d->z.buf[offset++];
633  WRAP_ZBUF(d->z.bufend);
634  WRAP_ZBUF(offset);
635  if (d->z.bufend == d->z.bufpos) { // Buffer full?
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;
639  return gTrue;
640  }
641  }
642  return PNG_zInflateBlock(d);
643 }
644 
645 // Get a fully decompressed byte from the inflate data stream
646 static gU8 PNG_zGetByte(PNG_decode *d) {
647  gU8 data;
648 
649  // Do we have any data in the buffers
650  while (d->z.bufpos == d->z.bufend) {
651 
652  // No, get some more data
653 
654  switch((d->z.flags & PNG_ZFLG_RESUME_MASK)) {
655  case PNG_ZFLG_RESUME_NEW: // Start a new inflate block
656  if (!PNG_zStartBlock(d))
657  return 0xFF;
658  break;
659  case PNG_ZFLG_RESUME_COPY: // Resume uncompressed block copy for length bytes
660  if (!PNG_zCopyInput(d, ((unsigned *)d->z.tmp)[0]))
661  return 0xFF;
662  break;
663  case PNG_ZFLG_RESUME_INFLATE: // Resume compressed block
664  if (!PNG_zInflateBlock(d))
665  return 0xFF;
666  break;
667  case PNG_ZFLG_RESUME_OFFSET: // Resume compressed block using offset copy for length bytes
668  if (!PNG_zResumeOffset(d, ((unsigned *)d->z.tmp)[0], ((unsigned *)d->z.tmp)[1]))
669  return 0xFF;
670  break;
671  }
672 
673  // Check for no data being provided
674  // A resume code means the buffer is completely full so the test must be skipped
675  if ((d->z.flags & PNG_ZFLG_RESUME_MASK) != PNG_ZFLG_RESUME_NEW)
676  break;
677  }
678 
679  // Get the next data byte
680  data = d->z.buf[d->z.bufpos++];
681  WRAP_ZBUF(d->z.bufpos);
682 
683  return data;
684 }
685 
686 /*-----------------------------------------------------------------
687  * Scan-line filter functions
688  *---------------------------------------------------------------*/
689 
690 // Initialise the scan-line engine
691 static void PNG_fInit(PNG_filter *f, gU8 *buf, unsigned bytewidth, unsigned scanbytes) {
692  f->scanbytes = scanbytes;
693  f->bytewidth = bytewidth;
694  f->line = buf;
695  f->prev = 0;
696 }
697 
698 // Get ready for the next scan-line
699 static void PNG_fNext(PNG_filter *f) {
700  if (f->prev && f->line > f->prev) {
701  f->line = f->prev;
702  f->prev += f->scanbytes;
703  } else {
704  f->prev = f->line;
705  f->line += f->scanbytes;
706  }
707 }
708 
709 // Predictor function for filter0 mode 4
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);
714 
715  if (pc < pa && pc < pb)
716  return (gU8)c;
717  if (pb < pa)
718  return (gU8)b;
719  return (gU8)a;
720 }
721 
722 // Scan-line filter type 0
723 static gBool PNG_unfilter_type0(PNG_decode *d) { // PNG filter method 0
724  gU8 ft;
725  unsigned i;
726 
727  // Get the filter type and check for validity (eg not EOF)
728  ft = PNG_zGetByte(d);
729  if (ft > 0x04)
730  return gFalse;
731 
732  // Uncompress the scan line
733  for(i = 0; i < d->f.scanbytes; i++)
734  d->f.line[i] = PNG_zGetByte(d);
735 
736  // Adjust the scan line based on the filter type
737  // 0 = no adjustment
738  switch(ft) {
739  case 1:
740  for(i = d->f.bytewidth; i < d->f.scanbytes; i++)
741  d->f.line[i] += d->f.line[i - d->f.bytewidth];
742  break;
743  case 2:
744  if (d->f.prev) {
745  for(i = 0; i < d->f.scanbytes; i++)
746  d->f.line[i] += d->f.prev[i];
747  }
748  break;
749  case 3:
750  if (d->f.prev) {
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;
755  } else {
756  for(i = d->f.bytewidth; i < d->f.scanbytes; i++)
757  d->f.line[i] += d->f.line[i - d->f.bytewidth] / 2;
758  }
759  break;
760  case 4:
761  if (d->f.prev) {
762  for(i = 0; i < d->f.bytewidth; i++)
763  d->f.line[i] += d->f.prev[i]; // PNG_fCalcPath(0, val, 0) is always val
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]);
766  } else {
767  for(i = d->f.bytewidth; i < d->f.scanbytes; i++)
768  d->f.line[i] += d->f.line[i - d->f.bytewidth]; // PNG_fCalcPath(val, 0, 0) is always val
769  }
770  break;
771  }
772 
773  return gTrue;
774 }
775 
776 /*-----------------------------------------------------------------
777  * Scan-line output and color conversion functions
778  *---------------------------------------------------------------*/
779 
780 #if GDISP_NEED_IMAGE_PNG_GRAYSCALE_124
781  static void PNG_OutGRAY124(PNG_decode *d) {
782  unsigned i;
783  PNG_info *pinfo;
784  gU8 px;
785  gU8 bits;
786 
787  pinfo = d->pinfo;
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);
796  continue;
797  }
798  #endif
799  PNG_oTransparent(&d->o);
800  continue;
801  }
802  #endif
803  px = px << (8-pinfo->bitdepth);
804  if (px >= 0x80) px += ((1U << (8-pinfo->bitdepth))-1);
805  PNG_oColor(&d->o, LUMA2COLOR(px));
806  }
807  }
808  }
809 #endif
810 #if GDISP_NEED_IMAGE_PNG_GRAYSCALE_8
811  static void PNG_OutGRAY8(PNG_decode *d) {
812  unsigned i;
813  gU8 px;
814  #if GDISP_NEED_IMAGE_PNG_TRANSPARENCY
815  PNG_info *pinfo = d->pinfo;
816  #endif
817 
818  for(i = 0; i < d->f.scanbytes; i++) {
819  px = d->f.line[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);
825  continue;
826  }
827  #endif
828  PNG_oTransparent(&d->o);
829  continue;
830  }
831  #endif
832  PNG_oColor(&d->o, LUMA2COLOR(px));
833  }
834  }
835 #endif
836 #if GDISP_NEED_IMAGE_PNG_GRAYSCALE_16
837  static void PNG_OutGRAY16(PNG_decode *d) {
838  unsigned i;
839  gU8 px;
840  #if GDISP_NEED_IMAGE_PNG_TRANSPARENCY
841  PNG_info *pinfo = d->pinfo;
842  #endif
843 
844  for(i = 0; i < d->f.scanbytes; i+=2) {
845  px = d->f.line[i];
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);
851  continue;
852  }
853  #endif
854  PNG_oTransparent(&d->o);
855  continue;
856  }
857  #endif
858  PNG_oColor(&d->o, LUMA2COLOR(px));
859  }
860  }
861 #endif
862 #if GDISP_NEED_IMAGE_PNG_RGB_8
863  static void PNG_OutRGB8(PNG_decode *d) {
864  unsigned i;
865  #if GDISP_NEED_IMAGE_PNG_TRANSPARENCY
866  PNG_info *pinfo = d->pinfo;
867  #endif
868 
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);
878  continue;
879  }
880  #endif
881  PNG_oTransparent(&d->o);
882  continue;
883  }
884  #endif
885  PNG_oColor(&d->o, RGB2COLOR(d->f.line[i+0], d->f.line[i+1], d->f.line[i+2]));
886  }
887  }
888 #endif
889 #if GDISP_NEED_IMAGE_PNG_RGB_16
890  static void PNG_OutRGB16(PNG_decode *d) {
891  unsigned i;
892  #if GDISP_NEED_IMAGE_PNG_TRANSPARENCY
893  PNG_info *pinfo = d->pinfo;
894  #endif
895 
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);
905  continue;
906  }
907  #endif
908  PNG_oTransparent(&d->o);
909  continue;
910  }
911  #endif
912  PNG_oColor(&d->o, RGB2COLOR(d->f.line[i+0], d->f.line[i+2], d->f.line[i+4]));
913  }
914  }
915 #endif
916 #if GDISP_NEED_IMAGE_PNG_PALETTE_124
917  static void PNG_OutPAL124(PNG_decode *d) {
918  unsigned i;
919  PNG_info *pinfo;
920  unsigned idx;
921  gU8 bits;
922 
923  pinfo = d->pinfo;
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);
927 
928  if ((gU16)idx >= pinfo->palsize) {
929  PNG_oColor(&d->o, RGB2COLOR(0, 0, 0));
930  continue;
931  }
932  idx *= 4;
933 
934  #define pix_color RGB2COLOR(pinfo->palette[idx], pinfo->palette[idx+1], pinfo->palette[idx+2])
935  #define pix_alpha pinfo->palette[idx+3]
936 
937  #if GDISP_NEED_IMAGE_PNG_TRANSPARENCY
938  #if GDISP_NEED_IMAGE_PNG_BACKGROUND
939  if (pix_alpha != 255 && (pinfo->flags & PNG_FLG_BACKGROUND)) {
940  PNG_oColor(&d->o, gdispBlendColor(pix_color, pinfo->bg, pix_alpha));
941  continue;
942  }
943  #endif
944  #if GDISP_NEED_IMAGE_PNG_ALPHACLIFF > 0
945  if (pix_alpha < GDISP_NEED_IMAGE_PNG_ALPHACLIFF) {
946  PNG_oTransparent(&d->o);
947  continue;
948  }
949  #endif
950  #endif
951 
952  PNG_oColor(&d->o, pix_color);
953 
954  #undef pix_color
955  #undef pix_alpha
956  }
957  }
958  }
959 #endif
960 #if GDISP_NEED_IMAGE_PNG_PALETTE_8
961  static void PNG_OutPAL8(PNG_decode *d) {
962  unsigned i;
963  PNG_info *pinfo;
964  unsigned idx;
965 
966  pinfo = d->pinfo;
967  for(i = 0; i < d->f.scanbytes; i++) {
968  idx = (unsigned)d->f.line[i];
969 
970  if ((gU16)idx >= pinfo->palsize) {
971  PNG_oColor(&d->o, RGB2COLOR(0, 0, 0));
972  continue;
973  }
974  idx *= 4;
975 
976  #define pix_color RGB2COLOR(pinfo->palette[idx], pinfo->palette[idx+1], pinfo->palette[idx+2])
977  #define pix_alpha pinfo->palette[idx+3]
978 
979  #if GDISP_NEED_IMAGE_PNG_TRANSPARENCY
980  #if GDISP_NEED_IMAGE_PNG_BACKGROUND
981  if (pix_alpha != 255 && (pinfo->flags & PNG_FLG_BACKGROUND)) {
982  PNG_oColor(&d->o, gdispBlendColor(pix_color, pinfo->bg, pix_alpha));
983  continue;
984  }
985  #endif
986  #if GDISP_NEED_IMAGE_PNG_ALPHACLIFF > 0
987  if (pix_alpha < GDISP_NEED_IMAGE_PNG_ALPHACLIFF) {
988  PNG_oTransparent(&d->o);
989  continue;
990  }
991  #endif
992  #endif
993 
994  PNG_oColor(&d->o, pix_color);
995 
996  #undef pix_color
997  #undef pix_alpha
998  }
999  }
1000 #endif
1001 #if GDISP_NEED_IMAGE_PNG_GRAYALPHA_8
1002  static void PNG_OutGRAYA8(PNG_decode *d) {
1003  unsigned i;
1004  #if GDISP_NEED_IMAGE_PNG_BACKGROUND
1005  PNG_info *pinfo = d->pinfo;
1006  #endif
1007 
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]
1011 
1012  #if GDISP_NEED_IMAGE_PNG_BACKGROUND
1013  if (pix_alpha != 255 && (pinfo->flags & PNG_FLG_BACKGROUND)) {
1014  PNG_oColor(&d->o, gdispBlendColor(pix_color, pinfo->bg, pix_alpha));
1015  continue;
1016  }
1017  #endif
1018  #if GDISP_NEED_IMAGE_PNG_ALPHACLIFF > 0
1019  if (pix_alpha < GDISP_NEED_IMAGE_PNG_ALPHACLIFF) {
1020  PNG_oTransparent(&d->o);
1021  continue;
1022  }
1023  #endif
1024 
1025  PNG_oColor(&d->o, pix_color);
1026 
1027  #undef pix_color
1028  #undef pix_alpha
1029  }
1030  }
1031 #endif
1032 #if GDISP_NEED_IMAGE_PNG_GRAYALPHA_16
1033  static void PNG_OutGRAYA16(PNG_decode *d) {
1034  unsigned i;
1035  #if GDISP_NEED_IMAGE_PNG_BACKGROUND
1036  PNG_info *pinfo = d->pinfo;
1037  #endif
1038 
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]
1042 
1043  #if GDISP_NEED_IMAGE_PNG_BACKGROUND
1044  if (pix_alpha != 255 && (pinfo->flags & PNG_FLG_BACKGROUND)) {
1045  PNG_oColor(&d->o, gdispBlendColor(pix_color, pinfo->bg, pix_alpha));
1046  continue;
1047  }
1048  #endif
1049  #if GDISP_NEED_IMAGE_PNG_ALPHACLIFF > 0
1050  if (pix_alpha < GDISP_NEED_IMAGE_PNG_ALPHACLIFF) {
1051  PNG_oTransparent(&d->o);
1052  continue;
1053  }
1054  #endif
1055 
1056  PNG_oColor(&d->o, pix_color);
1057 
1058  #undef pix_color
1059  #undef pix_alpha
1060  }
1061  }
1062 #endif
1063 #if GDISP_NEED_IMAGE_PNG_RGBALPHA_8
1064  static void PNG_OutRGBA8(PNG_decode *d) {
1065  unsigned i;
1066  #if GDISP_NEED_IMAGE_PNG_BACKGROUND
1067  PNG_info *pinfo = d->pinfo;
1068  #endif
1069 
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]
1073 
1074  #if GDISP_NEED_IMAGE_PNG_BACKGROUND
1075  if (pix_alpha != 255 && (pinfo->flags & PNG_FLG_BACKGROUND)) {
1076  PNG_oColor(&d->o, gdispBlendColor(pix_color, pinfo->bg, pix_alpha));
1077  continue;
1078  }
1079  #endif
1080  #if GDISP_NEED_IMAGE_PNG_ALPHACLIFF > 0
1081  if (pix_alpha < GDISP_NEED_IMAGE_PNG_ALPHACLIFF) {
1082  PNG_oTransparent(&d->o);
1083  continue;
1084  }
1085  #endif
1086 
1087  PNG_oColor(&d->o, pix_color);
1088 
1089  #undef pix_color
1090  #undef pix_alpha
1091  }
1092  }
1093 #endif
1094 #if GDISP_NEED_IMAGE_PNG_RGBALPHA_16
1095  static void PNG_OutRGBA16(PNG_decode *d) {
1096  unsigned i;
1097  #if GDISP_NEED_IMAGE_PNG_BACKGROUND
1098  PNG_info *pinfo = d->pinfo;
1099  #endif
1100 
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]
1104 
1105  #if GDISP_NEED_IMAGE_PNG_BACKGROUND
1106  if (pix_alpha != 255 && (pinfo->flags & PNG_FLG_BACKGROUND)) {
1107  PNG_oColor(&d->o, gdispBlendColor(pix_color, pinfo->bg, pix_alpha));
1108  continue;
1109  }
1110  #endif
1111  #if GDISP_NEED_IMAGE_PNG_ALPHACLIFF > 0
1112  if (pix_alpha < GDISP_NEED_IMAGE_PNG_ALPHACLIFF) {
1113  PNG_oTransparent(&d->o);
1114  continue;
1115  }
1116  #endif
1117 
1118  PNG_oColor(&d->o, pix_color);
1119 
1120  #undef pix_color
1121  #undef pix_alpha
1122  }
1123  }
1124 #endif
1125 
1126 /*-----------------------------------------------------------------
1127  * Public PNG functions
1128  *---------------------------------------------------------------*/
1129 
1130 void gdispImageClose_PNG(gImage *img) {
1131  PNG_info *pinfo;
1132 
1133  pinfo = (PNG_info *)img->priv;
1134  if (pinfo) {
1135  if (pinfo->palette)
1136  gdispImageFree(img, (void *)pinfo->palette, pinfo->palsize*4);
1137  if (pinfo->cache)
1138  gdispImageFree(img, (void *)pinfo->cache, pinfo->cachesz);
1139  gdispImageFree(img, (void *)pinfo, sizeof(PNG_info));
1140  img->priv = 0;
1141  }
1142 }
1143 
1144 gdispImageError gdispImageOpen_PNG(gImage *img) {
1145  PNG_info *pinfo;
1146  gU32 pos;
1147  gU32 len;
1148  gU8 buf[13];
1149 
1150  /* Read the file identifier */
1151  if (gfileRead(img->f, buf, 8) != 8)
1152  return GDISP_IMAGE_ERR_BADFORMAT; // It can't be us
1153 
1154  // Check the PNG signature
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; // It can't be us
1157 
1158  /* We know we are a PNG format image */
1159  img->flags = 0;
1160  img->priv = 0;
1161  img->type = GDISP_IMAGE_TYPE_PNG;
1162 
1163  /* Allocate our private area */
1164  if (!(img->priv = gdispImageAlloc(img, sizeof(PNG_info))))
1165  return GDISP_IMAGE_ERR_NOMEMORY;
1166 
1167  /* Initialise the essential bits in the private area */
1168  pinfo = (PNG_info *)img->priv;
1169  pinfo->flags = 0;
1170  pinfo->cache = 0;
1171  pinfo->trans_r = 0;
1172  pinfo->trans_g = 0;
1173  pinfo->trans_b = 0;
1175  pinfo->palsize = 0;
1176  pinfo->palette = 0;
1177  #endif
1178 
1179  // Cycle the chunks to get other information
1180  for(pos = 8; ; pos += len+12, gfileSetPos(img->f, pos)) {
1181  // Get a chunk header
1182  if (gfileRead(img->f, buf, 8) != 8)
1183  goto exit_baddata;
1184 
1185  // Calculate the chunk length
1186  len = gdispImageGetAlignedBE32(buf, 0);
1187 
1188  // Process the interesting information chunks
1189  switch (gdispImageGetAlignedBE32(buf, 4)) {
1190  case 0x49484452: // "IHDR" - Header block
1191 
1192  // Check if the header is already done
1193  if ((pinfo->flags & PNG_FLG_HEADERDONE))
1194  goto exit_baddata;
1195 
1196  // Read the image parameters
1197  if (len < 13 || gfileRead(img->f, buf, 13) != 13)
1198  goto exit_baddata;
1199 
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;
1208  #endif
1209  }
1210 
1211  // Check width and height, filter, compression and interlacing
1212  if (gdispImageGetVar(gU16, buf, 0) != 0 || img->width <= 0 // width
1213  || gdispImageGetVar(gU16, buf, 4) != 0 || img->height <= 0 // height
1214  || gdispImageGetVar(gU8, buf, 10) != 0 // compression
1215  || gdispImageGetVar(gU8, buf, 11) != 0 // filter
1216  || gdispImageGetVar(gU8, buf, 12) > 1 // interlace
1217  )
1218  goto exit_unsupported;
1219 
1220  // Check mode, bitdepth and calculate bits per pixel
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
1226  case 1:
1227  case 2:
1228  case 4: pinfo->out = PNG_OutGRAY124; break;
1229  #endif
1230  #if GDISP_NEED_IMAGE_PNG_GRAYSCALE_8
1231  case 8: pinfo->out = PNG_OutGRAY8; break;
1232  #endif
1233  #if GDISP_NEED_IMAGE_PNG_GRAYSCALE_16
1234  case 16: pinfo->out = PNG_OutGRAY16; break;
1235  #endif
1236  default: goto exit_unsupported;
1237  }
1238  pinfo->bpp = pinfo->bitdepth;
1239  break;
1240  #endif
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;
1246  #endif
1247  #if GDISP_NEED_IMAGE_PNG_RGB_16
1248  case 16: pinfo->out = PNG_OutRGB16; break;
1249  #endif
1250  default: goto exit_unsupported;
1251  }
1252  pinfo->bpp = pinfo->bitdepth * 3;
1253  break;
1254  #endif
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
1259  case 1:
1260  case 2:
1261  case 4: pinfo->out = PNG_OutPAL124; break;
1262  #endif
1263  #if GDISP_NEED_IMAGE_PNG_PALETTE_8
1264  case 8: pinfo->out = PNG_OutPAL8; break;
1265  #endif
1266  default: goto exit_unsupported;
1267  }
1268  pinfo->bpp = pinfo->bitdepth;
1269  break;
1270  #endif
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;
1276  #endif
1277  #if GDISP_NEED_IMAGE_PNG_GRAYALPHA_16
1278  case 16: pinfo->out = PNG_OutGRAYA16; break;
1279  #endif
1280  default: goto exit_unsupported;
1281  }
1282  pinfo->bpp = pinfo->bitdepth * 2;
1283  break;
1284  #endif
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;
1290  #endif
1291  #if GDISP_NEED_IMAGE_PNG_RGBALPHA_16
1292  case 16: pinfo->out = PNG_OutRGBA16; break;
1293  #endif
1294  default: goto exit_unsupported;
1295  }
1296  pinfo->bpp = pinfo->bitdepth * 4;
1297  break;
1298  #endif
1299  default:
1300  goto exit_unsupported;
1301  }
1302 
1303  pinfo->flags |= PNG_FLG_HEADERDONE;
1304  break;
1305 
1306  case 0x49454E44: // "IEND" - All done
1307  goto exit_baddata; // Oops we didn't get any data.
1308 
1309  case 0x49444154: // "IDAT" - Image Data
1310 
1311  // Check if the header is already done
1312  if (!(pinfo->flags & PNG_FLG_HEADERDONE))
1313  goto exit_baddata;
1314 
1315  #if GDISP_NEED_IMAGE_PNG_PALETTE_124 || GDISP_NEED_IMAGE_PNG_PALETTE_8
1316  // Make sure a palette image actually has a palette
1317  if (pinfo->mode == PNG_COLORMODE_PALETTE && !pinfo->palette)
1318  goto exit_baddata;
1319  #endif
1320 
1321  // All good
1322  return GDISP_IMAGE_ERR_OK;
1323 
1324  #if GDISP_NEED_IMAGE_PNG_PALETTE_124 || GDISP_NEED_IMAGE_PNG_PALETTE_8
1325  case 0x504C5445: // "PLTE" - Palette
1326 
1327  // Check if the header is already done
1328  if (!(pinfo->flags & PNG_FLG_HEADERDONE))
1329  goto exit_baddata;
1330 
1331  // Skip a palette if we don't need it.
1332  if (pinfo->mode != PNG_COLORMODE_PALETTE)
1333  break;
1334 
1335  // Check the size and that we don't have one already
1336  if (len > 3 * 256 || pinfo->palette)
1337  goto exit_baddata;
1338 
1339  // Allocate the palette
1340  pinfo->palsize = len / 3;
1341  if (!(pinfo->palette = gfxAlloc(pinfo->palsize * 4)))
1342  goto exit_nonmem;
1343 
1344  // Read the palette
1345  {
1346  gU16 idx;
1347  gU8 *p;
1348 
1349  for(idx=pinfo->palsize, p=pinfo->palette; idx; p += 4, idx--) {
1350  if (gfileRead(img->f, p, 3) != 3)
1351  goto exit_baddata;
1352  p[3] = 255;
1353  }
1354  }
1355 
1356  break;
1357  #endif
1358 
1359  #if GDISP_NEED_IMAGE_PNG_TRANSPARENCY
1360  case 0x74524E53: // "tRNS" - Transparency
1361 
1362  // Check if the header is already done
1363  if (!(pinfo->flags & PNG_FLG_HEADERDONE))
1364  goto exit_baddata;
1365 
1366  // Transparency is handled differently depending on the mode
1367  switch(pinfo->mode) {
1368 
1369  #if GDISP_NEED_IMAGE_PNG_PALETTE_124 || GDISP_NEED_IMAGE_PNG_PALETTE_8
1370  case PNG_COLORMODE_PALETTE:
1371  if (len > pinfo->palsize)
1372  goto exit_baddata;
1373 
1374  // Adjust the palette
1375  {
1376  gU16 idx;
1377  gU8 *p;
1378 
1379  for(idx=len, p=pinfo->palette+3; idx; p += 4, idx--) {
1380  if (gfileRead(img->f, p, 1) != 1)
1381  goto exit_baddata;
1382  }
1383  }
1384  break;
1385  #endif
1386 
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:
1389  // Read the transparency color
1390  if (len != 2 || gfileRead(img->f, buf, 2) != 2)
1391  goto exit_baddata;
1392 
1393  pinfo->flags |= PNG_FLG_TRANSPARENT;
1394  pinfo->trans_r = gdispImageGetAlignedBE16(buf, 0);
1395  break;
1396  #endif
1397  #if GDISP_NEED_IMAGE_PNG_RGB_8 || GDISP_NEED_IMAGE_PNG_RGB_16
1398  case PNG_COLORMODE_RGB:
1399  // Read the transparency color
1400  if (len != 6 || gfileRead(img->f, buf, 6) != 6)
1401  goto exit_baddata;
1402 
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);
1407  break;
1408  #endif
1409  default:
1410  goto exit_unsupported;
1411  }
1412 
1413  break;
1414  #endif
1415 
1416  #if GDISP_NEED_IMAGE_PNG_BACKGROUND
1417  case 0x624B4744: // "bKGD" - Background
1418 
1419  // Check if the header is already done
1420  if (!(pinfo->flags & PNG_FLG_HEADERDONE))
1421  goto exit_baddata;
1422 
1423  pinfo->flags |= PNG_FLG_BACKGROUND;
1424 
1425  // Background data is handled differently depending on the mode
1426  switch(pinfo->mode) {
1427 
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)
1431  goto exit_baddata;
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]);
1435  break;
1436  #endif
1437 
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)
1442  goto exit_baddata;
1443  switch(pinfo->bitdepth) {
1444  #if GDISP_NEED_IMAGE_PNG_GRAYSCALE_124
1445  case 1:
1446  case 2:
1447  case 4:
1448  buf[1] <<= 8-pinfo->bitdepth;
1449  if (buf[1] >= 0x80)
1450  buf[1] += ((1U << (8-pinfo->bitdepth))-1);
1451  pinfo->bg = LUMA2COLOR(buf[1]);
1452  break;
1453  #endif
1454  #if GDISP_NEED_IMAGE_PNG_GRAYSCALE_8 || GDISP_NEED_IMAGE_PNG_GRAYALPHA_8
1455  case 8:
1456  pinfo->bg = LUMA2COLOR(buf[1]);
1457  break;
1458  #endif
1459  #if GDISP_NEED_IMAGE_PNG_GRAYSCALE_16 || GDISP_NEED_IMAGE_PNG_GRAYALPHA_16
1460  case 16:
1461  pinfo->bg = LUMA2COLOR(buf[0]);
1462  break;
1463  #endif
1464  }
1465  break;
1466  #endif
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)
1471  goto exit_baddata;
1472 
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]);
1476  } else
1477  #endif
1478  pinfo->bg = RGB2COLOR(buf[1], buf[3], buf[5]);
1479  break;
1480  #endif
1481  default:
1482  goto exit_unsupported;
1483  }
1484  break;
1485  #endif
1486 
1487  }
1488  }
1489 exit_baddata:
1490  gdispImageClose_PNG(img);
1491  return GDISP_IMAGE_ERR_BADDATA;
1492 exit_unsupported:
1493  gdispImageClose_PNG(img);
1494  return GDISP_IMAGE_ERR_UNSUPPORTED;
1495 exit_nonmem:
1496  gdispImageClose_PNG(img);
1497  return GDISP_IMAGE_ERR_NOMEMORY;
1498 }
1499 
1500 gdispImageError gdispGImageDraw_PNG(GDisplay *g, gImage *img, gCoord x, gCoord y, gCoord cx, gCoord cy, gCoord sx, gCoord sy) {
1501  PNG_info *pinfo;
1502  PNG_decode *d;
1503 
1504  // Allocate the space to decode with including space for 2 full scan lines for filtering.
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;
1508 
1509 
1510  // Initialise the decoder
1511  d->img = img;
1512  d->pinfo = pinfo;
1513  PNG_iInit(d);
1514  PNG_oInit(&d->o, g, x, y, cx, cy, sx, sy);
1515  PNG_zInit(&d->z);
1516 
1517  // Process the zlib inflate header
1518  if (!PNG_zGetHeader(d))
1519  goto exit_baddata;
1520 
1521  #if GDISP_NEED_IMAGE_PNG_INTERLACED
1522  if ((pinfo->flags & PNG_FLG_INTERLACE)) {
1523  // Interlaced decoding
1524  #error "PNG Decoder: Interlaced PNG's are not supported yet!"
1525  } else
1526  #endif
1527  {
1528  // Non-interlaced decoding
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))
1532  goto exit_baddata;
1533  if (PNG_oStartY(&d->o, y)) {
1534  pinfo->out(d);
1535  PNG_oFlush(&d->o);
1536  }
1537  }
1538  }
1539 
1540  // Clean up
1541  gdispImageFree(img, d, sizeof(PNG_decode) + (img->width * pinfo->bpp + 7) / 4);
1542  return GDISP_IMAGE_ERR_OK;
1543 
1544 exit_baddata:
1545  gdispImageFree(img, d, sizeof(PNG_decode) + (img->width * pinfo->bpp + 7) / 4);
1546  return GDISP_IMAGE_ERR_BADDATA;
1547 }
1548 
1549 gdispImageError gdispImageCache_PNG(gImage *img) {
1550  PNG_info *pinfo;
1551  unsigned chunknext;
1552  unsigned chunklen;
1553  gU8 *pcache;
1554  gU8 buf[8];
1555 
1556  // If we are already cached - just return OK
1557  pinfo = (PNG_info *)img->priv;
1558  if (pinfo->cache)
1559  return GDISP_IMAGE_ERR_OK;
1560 
1561  // Calculate the size of all the image data blocks in the image
1562  pinfo->cachesz = 0;
1563  chunknext = 8;
1564  while(1) {
1565  // Find a new chunk
1566  gfileSetPos(img->f, chunknext);
1567  if (gfileRead(img->f, buf, 8) != 8)
1568  return GDISP_IMAGE_ERR_BADDATA;
1569 
1570  // Calculate the chunk length and next chunk
1571  chunklen = gdispImageGetAlignedBE32(buf, 0);
1572  chunknext += chunklen + 12;
1573 
1574  // Process only image data chunks
1575  switch (gdispImageGetAlignedBE32(buf, 4)) {
1576  case 0x49444154: // "IDAT" - Image Data
1577  pinfo->cachesz += chunklen;
1578  break;
1579  case 0x49454E44: // "IEND" - All done
1580  if (!pinfo->cachesz)
1581  return GDISP_IMAGE_ERR_BADDATA;
1582  goto gotsize;
1583  }
1584  }
1585 
1586 gotsize:
1587  // Allocate the cache
1588  if (!(pcache = gdispImageAlloc(img, pinfo->cachesz)))
1589  return GDISP_IMAGE_ERR_NOMEMORY;
1590 
1591  pinfo->cache = pcache;
1592 
1593  // Read the image data into the cache
1594  chunknext = 8;
1595  while(1) {
1596  // Find a new chunk
1597  gfileSetPos(img->f, chunknext);
1598  if (gfileRead(img->f, buf, 8) != 8)
1599  goto baddata;
1600 
1601  // Calculate the chunk length and next chunk
1602  chunklen = gdispImageGetAlignedBE32(buf, 0);
1603  chunknext += chunklen + 12;
1604 
1605  // Process only image data chunks
1606  switch (gdispImageGetAlignedBE32(buf, 4)) {
1607  case 0x49444154: // "IDAT" - Image Data
1608  if (gfileRead(img->f, pcache, chunklen) != chunklen)
1609  goto baddata;
1610  pcache += chunklen;
1611  break;
1612  case 0x49454E44: // "IEND" - All done
1613  return GDISP_IMAGE_ERR_OK;
1614  }
1615  }
1616 
1617 baddata:
1618  // Oops - can't read the data. Throw away the cache.
1619  gdispImageFree(img, pinfo->cache, pinfo->cachesz);
1620  pinfo->cache = 0;
1621  return GDISP_IMAGE_ERR_BADDATA;
1622 }
1623 
1624 gDelay gdispImageNext_PNG(gImage *img) {
1625  (void) img;
1626 
1627  /* No more frames/pages */
1628  return gDelayForever;
1629 }
1630 
1631 #endif /* GFX_USE_GDISP && GDISP_NEED_IMAGE && GDISP_NEED_IMAGE_PNG */
GDISP image support routines header file.
#define LUMA2COLOR(l)
Convert a luminance (0 to 255) into a color value.
Definition: gdisp_colors.h:191
#define RGB2COLOR(r, g, b)
Convert red, green, blue (each 0 to 255) into a color value.
Definition: gdisp_colors.h:196
COLOR_TYPE gColor
The color type definition.
Definition: gdisp_colors.h:437
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.
Definition: gdisp.h:226
#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.
Definition: gdisp.h:39
#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.
Definition: gfile.h:34
void * gfxAlloc(gMemSize sz)
Allocate memory.
gU16 gdispImageError
An image error code.
Definition: gdisp_image.h:37
The structure for an image.
Definition: gdisp_image.h:59