Chameleon

Chameleon Svn Source Tree

Root/branches/slice/old749m/i386/modules/GUI/picopng.c

1// picoPNG version 20080503 (cleaned up and ported to c by kaitek)
2// Copyright (c) 2005-2008 Lode Vandevenne
3//
4// This software is provided 'as-is', without any express or implied
5// warranty. In no event will the authors be held liable for any damages
6// arising from the use of this software.
7//
8// Permission is granted to anyone to use this software for any purpose,
9// including commercial applications, and to alter it and redistribute it
10// freely, subject to the following restrictions:
11//
12// 1. The origin of this software must not be misrepresented; you must not
13// claim that you wrote the original software. If you use this software
14// in a product, an acknowledgment in the product documentation would be
15// appreciated but is not required.
16// 2. Altered source versions must be plainly marked as such, and must not be
17// misrepresented as being the original software.
18// 3. This notice may not be removed or altered from any source distribution.
19
20#include "libsa.h"
21#include "picopng.h"
22
23/* sys.c */
24int open_bvdev(const char *bvd, const char *path, int flags);
25int read(int fdesc, char * buf, int count);
26int close(int fdesc);
27int file_size(int fdesc);
28/*************************************************************************************************/
29
30typedef struct png_alloc_node {
31struct png_alloc_node *prev, *next;
32void *addr;
33size_t size;
34} png_alloc_node_t;
35
36png_alloc_node_t *png_alloc_head = NULL;
37png_alloc_node_t *png_alloc_tail = NULL;
38
39png_alloc_node_t *png_alloc_find_node(void *addr)
40{
41png_alloc_node_t *node;
42for (node = png_alloc_head; node; node = node->next)
43if (node->addr == addr)
44break;
45return node;
46}
47
48void png_alloc_add_node(void *addr, size_t size)
49{
50png_alloc_node_t *node;
51if (png_alloc_find_node(addr))
52return;
53node = malloc(sizeof (png_alloc_node_t));
54node->addr = addr;
55node->size = size;
56node->prev = png_alloc_tail;
57node->next = NULL;
58png_alloc_tail = node;
59if (node->prev)
60node->prev->next = node;
61if (!png_alloc_head)
62png_alloc_head = node;
63}
64
65void png_alloc_remove_node(png_alloc_node_t *node)
66{
67if (node->prev)
68node->prev->next = node->next;
69if (node->next)
70node->next->prev = node->prev;
71if (node == png_alloc_head)
72png_alloc_head = node->next;
73if (node == png_alloc_tail)
74png_alloc_tail = node->prev;
75node->prev = node->next = node->addr = NULL;
76free(node);
77}
78
79void *png_alloc_malloc(size_t size)
80{
81void *addr = malloc(size);
82png_alloc_add_node(addr, size);
83return addr;
84}
85
86void *png_alloc_realloc(void *addr, size_t size)
87{
88void *new_addr;
89if (!addr)
90return png_alloc_malloc(size);
91new_addr = realloc(addr, size);
92if (new_addr != addr) {
93png_alloc_node_t *old_node;
94old_node = png_alloc_find_node(addr);
95png_alloc_remove_node(old_node);
96png_alloc_add_node(new_addr, size);
97}
98return new_addr;
99}
100
101void png_alloc_free(void *addr)
102{
103png_alloc_node_t *node = png_alloc_find_node(addr);
104if (!node)
105return;
106png_alloc_remove_node(node);
107free(addr);
108}
109
110void png_alloc_free_all()
111{
112while (png_alloc_tail) {
113void *addr = png_alloc_tail->addr;
114png_alloc_remove_node(png_alloc_tail);
115free(addr);
116}
117}
118
119/*************************************************************************************************/
120
121__unused void vector32_cleanup(vector32_t *p)
122{
123p->size = p->allocsize = 0;
124if (p->data)
125png_alloc_free(p->data);
126p->data = NULL;
127}
128
129uint32_t vector32_resize(vector32_t *p, size_t size)
130{// returns 1 if success, 0 if failure ==> nothing done
131if (size * sizeof (uint32_t) > p->allocsize) {
132size_t newsize = size * sizeof (uint32_t) * 2;
133void *data = png_alloc_realloc(p->data, newsize);
134if (data) {
135p->allocsize = newsize;
136p->data = (uint32_t *) data;
137p->size = size;
138} else
139return 0;
140} else
141p->size = size;
142return 1;
143}
144
145uint32_t vector32_resizev(vector32_t *p, size_t size, uint32_t value)
146{// resize and give all new elements the value
147size_t oldsize = p->size, i;
148if (!vector32_resize(p, size))
149return 0;
150for (i = oldsize; i < size; i++)
151p->data[i] = value;
152return 1;
153}
154
155void vector32_init(vector32_t *p)
156{
157p->data = NULL;
158p->size = p->allocsize = 0;
159}
160
161vector32_t *vector32_new(size_t size, uint32_t value)
162{
163vector32_t *p = png_alloc_malloc(sizeof (vector32_t));
164vector32_init(p);
165if (size && !vector32_resizev(p, size, value))
166return NULL;
167return p;
168}
169
170/*************************************************************************************************/
171
172__unused void vector8_cleanup(vector8_t *p)
173{
174p->size = p->allocsize = 0;
175if (p->data)
176png_alloc_free(p->data);
177p->data = NULL;
178}
179
180uint32_t vector8_resize(vector8_t *p, size_t size)
181{// returns 1 if success, 0 if failure ==> nothing done
182// xxx: the use of sizeof uint32_t here seems like a bug (this descends from the lodepng vector
183// compatibility functions which do the same). without this there is corruption in certain cases,
184// so this was probably done to cover up allocation bug(s) in the original picopng code!
185if (size * sizeof (uint32_t) > p->allocsize) {
186size_t newsize = size * sizeof (uint32_t) * 2;
187void *data = png_alloc_realloc(p->data, newsize);
188if (data) {
189p->allocsize = newsize;
190p->data = (uint8_t *) data;
191p->size = size;
192} else
193return 0; // error: not enough memory
194} else
195p->size = size;
196return 1;
197}
198
199uint32_t vector8_resizev(vector8_t *p, size_t size, uint8_t value)
200{// resize and give all new elements the value
201size_t oldsize = p->size, i;
202if (!vector8_resize(p, size))
203return 0;
204for (i = oldsize; i < size; i++)
205p->data[i] = value;
206return 1;
207}
208
209void vector8_init(vector8_t *p)
210{
211p->data = NULL;
212p->size = p->allocsize = 0;
213}
214
215vector8_t *vector8_new(size_t size, uint8_t value)
216{
217vector8_t *p = png_alloc_malloc(sizeof (vector8_t));
218vector8_init(p);
219if (size && !vector8_resizev(p, size, value))
220return NULL;
221return p;
222}
223
224vector8_t *vector8_copy(vector8_t *p)
225{
226vector8_t *q = vector8_new(p->size, 0);
227uint32_t n;
228for (n = 0; n < q->size; n++)
229q->data[n] = p->data[n];
230return q;
231}
232
233/*************************************************************************************************/
234
235const uint32_t LENBASE[29] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51,
23659, 67, 83, 99, 115, 131, 163, 195, 227, 258 };
237const uint32_t LENEXTRA[29] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4,
2384, 5, 5, 5, 5, 0 };
239const uint32_t DISTBASE[30] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385,
240513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 };
241const uint32_t DISTEXTRA[30] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,
24210, 10, 11, 11, 12, 12, 13, 13 };
243// code length code lengths
244const uint32_t CLCL[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
245
246/*************************************************************************************************/
247
248typedef struct {
249// 2D representation of a huffman tree: The one dimension is "0" or "1", the other contains all
250// nodes and leaves of the tree.
251vector32_t *tree2d;
252} HuffmanTree;
253
254HuffmanTree *HuffmanTree_new()
255{
256HuffmanTree *tree = png_alloc_malloc(sizeof (HuffmanTree));
257tree->tree2d = NULL;
258return tree;
259}
260
261int HuffmanTree_makeFromLengths(HuffmanTree *tree, const vector32_t *bitlen, uint32_t maxbitlen)
262{// make tree given the lengths
263uint32_t bits, n, i;
264uint32_t numcodes = (uint32_t) bitlen->size, treepos = 0, nodefilled = 0;
265vector32_t *tree1d, *blcount, *nextcode;
266tree1d = vector32_new(numcodes, 0);
267blcount = vector32_new(maxbitlen + 1, 0);
268nextcode = vector32_new(maxbitlen + 1, 0);
269for (bits = 0; bits < numcodes; bits++)
270blcount->data[bitlen->data[bits]]++; // count number of instances of each code length
271for (bits = 1; bits <= maxbitlen; bits++)
272nextcode->data[bits] = (nextcode->data[bits - 1] + blcount->data[bits - 1]) << 1;
273for (n = 0; n < numcodes; n++)
274if (bitlen->data[n] != 0)
275tree1d->data[n] = nextcode->data[bitlen->data[n]]++; // generate all the codes
276// 0x7fff here means the tree2d isn't filled there yet
277vector32_t *tree2d = vector32_new(numcodes * 2, 0x7fff);
278tree->tree2d = tree2d;
279for (n = 0; n < numcodes; n++) // the codes
280for (i = 0; i < bitlen->data[n]; i++) { // the bits for this code
281uint32_t bit = (tree1d->data[n] >> (bitlen->data[n] - i - 1)) & 1;
282if (treepos > numcodes - 2)
283return 55;
284if (tree2d->data[2 * treepos + bit] == 0x7fff) { // not yet filled in
285if (i + 1 == bitlen->data[n]) { // last bit
286tree2d->data[2 * treepos + bit] = n;
287treepos = 0;
288} else { // addresses are encoded as values > numcodes
289tree2d->data[2 * treepos + bit] = ++nodefilled + numcodes;
290treepos = nodefilled;
291}
292} else // subtract numcodes from address to get address value
293treepos = tree2d->data[2 * treepos + bit] - numcodes;
294}
295return 0;
296}
297
298int HuffmanTree_decode(const HuffmanTree *tree, bool *decoded, uint32_t *result, size_t *treepos,
299uint32_t bit)
300{// Decodes a symbol from the tree
301const vector32_t *tree2d = tree->tree2d;
302uint32_t numcodes = (uint32_t) tree2d->size / 2;
303if (*treepos >= numcodes)
304return 11; // error: you appeared outside the codetree
305*result = tree2d->data[2 * (*treepos) + bit];
306*decoded = (*result < numcodes);
307*treepos = *decoded ? 0 : *result - numcodes;
308return 0;
309}
310
311/*************************************************************************************************/
312
313int Inflator_error;
314
315uint32_t Zlib_readBitFromStream(size_t *bitp, const uint8_t *bits)
316{
317uint32_t result = (bits[*bitp >> 3] >> (*bitp & 0x7)) & 1;
318(*bitp)++;
319return result;
320}
321
322uint32_t Zlib_readBitsFromStream(size_t *bitp, const uint8_t *bits, size_t nbits)
323{
324uint32_t i, result = 0;
325for (i = 0; i < nbits; i++)
326result += (Zlib_readBitFromStream(bitp, bits)) << i;
327return result;
328}
329
330void Inflator_generateFixedTrees(HuffmanTree *tree, HuffmanTree *treeD)
331{// get the tree of a deflated block with fixed tree
332size_t i;
333vector32_t *bitlen, *bitlenD;
334bitlen = vector32_new(288, 8);
335bitlenD = vector32_new(32, 5);
336for (i = 144; i <= 255; i++)
337bitlen->data[i] = 9;
338for (i = 256; i <= 279; i++)
339bitlen->data[i] = 7;
340HuffmanTree_makeFromLengths(tree, bitlen, 15);
341HuffmanTree_makeFromLengths(treeD, bitlenD, 15);
342}
343
344uint32_t Inflator_huffmanDecodeSymbol(const uint8_t *in, size_t *bp, const HuffmanTree *codetree,
345size_t inlength)
346{// decode a single symbol from given list of bits with given code tree. returns the symbol
347bool decoded = false;
348uint32_t ct = 0;
349size_t treepos = 0;
350for (;;) {
351if ((*bp & 0x07) == 0 && (*bp >> 3) > inlength) {
352Inflator_error = 10; // error: end reached without endcode
353return 0;
354}
355Inflator_error = HuffmanTree_decode(codetree, &decoded, &ct, &treepos,
356Zlib_readBitFromStream(bp, in));
357if (Inflator_error)
358return 0; // stop, an error happened
359if (decoded)
360return ct;
361}
362}
363
364void Inflator_getTreeInflateDynamic(HuffmanTree *tree, HuffmanTree *treeD, const uint8_t *in,
365size_t *bp, size_t inlength)
366{// get the tree of a deflated block with dynamic tree, the tree itself is also Huffman
367// compressed with a known tree
368size_t i, n;
369HuffmanTree *codelengthcodetree = HuffmanTree_new(); // the code tree for code length codes
370vector32_t *bitlen, *bitlenD;
371bitlen = vector32_new(288, 0);
372bitlenD = vector32_new(32, 0);
373if (*bp >> 3 >= inlength - 2) {
374Inflator_error = 49; // the bit pointer is or will go past the memory
375return;
376}
377size_t HLIT = Zlib_readBitsFromStream(bp, in, 5) + 257;// number of literal/length codes + 257
378size_t HDIST = Zlib_readBitsFromStream(bp, in, 5) + 1;// number of dist codes + 1
379size_t HCLEN = Zlib_readBitsFromStream(bp, in, 4) + 4;// number of code length codes + 4
380vector32_t *codelengthcode; // lengths of tree to decode the lengths of the dynamic tree
381codelengthcode = vector32_new(19, 0);
382for (i = 0; i < 19; i++)
383codelengthcode->data[CLCL[i]] = (i < HCLEN) ? Zlib_readBitsFromStream(bp, in, 3) : 0;
384Inflator_error = HuffmanTree_makeFromLengths(codelengthcodetree, codelengthcode, 7);
385if (Inflator_error)
386return;
387size_t replength;
388for (i = 0; i < HLIT + HDIST; ) {
389uint32_t code = Inflator_huffmanDecodeSymbol(in, bp, codelengthcodetree, inlength);
390if (Inflator_error)
391return;
392if (code <= 15) { // a length code
393if (i < HLIT)
394bitlen->data[i++] = code;
395else
396bitlenD->data[i++ - HLIT] = code;
397} else if (code == 16) { // repeat previous
398if (*bp >> 3 >= inlength) {
399Inflator_error = 50; // error, bit pointer jumps past memory
400return;
401}
402replength = 3 + Zlib_readBitsFromStream(bp, in, 2);
403uint32_t value; // set value to the previous code
404if ((i - 1) < HLIT)
405value = bitlen->data[i - 1];
406else
407value = bitlenD->data[i - HLIT - 1];
408for (n = 0; n < replength; n++) { // repeat this value in the next lengths
409if (i >= HLIT + HDIST) {
410Inflator_error = 13; // error: i is larger than the amount of codes
411return;
412}
413if (i < HLIT)
414bitlen->data[i++] = value;
415else
416bitlenD->data[i++ - HLIT] = value;
417}
418} else if (code == 17) { // repeat "0" 3-10 times
419if (*bp >> 3 >= inlength) {
420Inflator_error = 50; // error, bit pointer jumps past memory
421return;
422}
423replength = 3 + Zlib_readBitsFromStream(bp, in, 3);
424for (n = 0; n < replength; n++) { // repeat this value in the next lengths
425if (i >= HLIT + HDIST) {
426Inflator_error = 14; // error: i is larger than the amount of codes
427return;
428}
429if (i < HLIT)
430bitlen->data[i++] = 0;
431else
432bitlenD->data[i++ - HLIT] = 0;
433}
434} else if (code == 18) { // repeat "0" 11-138 times
435if (*bp >> 3 >= inlength) {
436Inflator_error = 50; // error, bit pointer jumps past memory
437return;
438}
439replength = 11 + Zlib_readBitsFromStream(bp, in, 7);
440for (n = 0; n < replength; n++) { // repeat this value in the next lengths
441if (i >= HLIT + HDIST) {
442Inflator_error = 15; // error: i is larger than the amount of codes
443return;
444}
445if (i < HLIT)
446bitlen->data[i++] = 0;
447else
448bitlenD->data[i++ - HLIT] = 0;
449}
450} else {
451Inflator_error = 16; // error: an nonexitent code appeared. This can never happen.
452return;
453}
454}
455if (bitlen->data[256] == 0) {
456Inflator_error = 64; // the length of the end code 256 must be larger than 0
457return;
458}
459// now we've finally got HLIT and HDIST, so generate the code trees, and the function is done
460Inflator_error = HuffmanTree_makeFromLengths(tree, bitlen, 15);
461if (Inflator_error)
462return;
463Inflator_error = HuffmanTree_makeFromLengths(treeD, bitlenD, 15);
464if (Inflator_error)
465return;
466}
467
468void Inflator_inflateHuffmanBlock(vector8_t *out, const uint8_t *in, size_t *bp, size_t *pos,
469size_t inlength, uint32_t btype)
470{
471HuffmanTree *codetree, *codetreeD; // the code tree for Huffman codes, dist codes
472codetree = HuffmanTree_new();
473codetreeD = HuffmanTree_new();
474if (btype == 1)
475Inflator_generateFixedTrees(codetree, codetreeD);
476else if (btype == 2) {
477Inflator_getTreeInflateDynamic(codetree, codetreeD, in, bp, inlength);
478if (Inflator_error)
479return;
480}
481for (;;) {
482uint32_t code = Inflator_huffmanDecodeSymbol(in, bp, codetree, inlength);
483if (Inflator_error)
484return;
485if (code == 256) // end code
486return;
487else if (code <= 255) { // literal symbol
488if (*pos >= out->size)
489vector8_resize(out, (*pos + 1) * 2); // reserve more room
490out->data[(*pos)++] = (uint8_t) code;
491} else if (code >= 257 && code <= 285) { // length code
492size_t length = LENBASE[code - 257], numextrabits = LENEXTRA[code - 257];
493if ((*bp >> 3) >= inlength) {
494Inflator_error = 51; // error, bit pointer will jump past memory
495return;
496}
497length += Zlib_readBitsFromStream(bp, in, numextrabits);
498uint32_t codeD = Inflator_huffmanDecodeSymbol(in, bp, codetreeD, inlength);
499if (Inflator_error)
500return;
501if (codeD > 29) {
502Inflator_error = 18; // error: invalid dist code (30-31 are never used)
503return;
504}
505uint32_t dist = DISTBASE[codeD], numextrabitsD = DISTEXTRA[codeD];
506if ((*bp >> 3) >= inlength) {
507Inflator_error = 51; // error, bit pointer will jump past memory
508return;
509}
510dist += Zlib_readBitsFromStream(bp, in, numextrabitsD);
511size_t start = *pos, back = start - dist; // backwards
512if (*pos + length >= out->size)
513vector8_resize(out, (*pos + length) * 2); // reserve more room
514size_t i;
515for (i = 0; i < length; i++) {
516out->data[(*pos)++] = out->data[back++];
517if (back >= start)
518back = start - dist;
519}
520}
521}
522}
523
524void Inflator_inflateNoCompression(vector8_t *out, const uint8_t *in, size_t *bp, size_t *pos,
525size_t inlength)
526{
527while ((*bp & 0x7) != 0)
528(*bp)++; // go to first boundary of byte
529size_t p = *bp / 8;
530if (p >= inlength - 4) {
531Inflator_error = 52; // error, bit pointer will jump past memory
532return;
533}
534uint32_t LEN = in[p] + 256 * in[p + 1], NLEN = in[p + 2] + 256 * in[p + 3];
535p += 4;
536if (LEN + NLEN != 65535) {
537Inflator_error = 21; // error: NLEN is not one's complement of LEN
538return;
539}
540if (*pos + LEN >= out->size)
541vector8_resize(out, *pos + LEN);
542if (p + LEN > inlength) {
543Inflator_error = 23; // error: reading outside of in buffer
544return;
545}
546uint32_t n;
547for (n = 0; n < LEN; n++)
548out->data[(*pos)++] = in[p++]; // read LEN bytes of literal data
549*bp = p * 8;
550}
551
552void Inflator_inflate(vector8_t *out, const vector8_t *in, size_t inpos)
553{
554size_t bp = 0, pos = 0; // bit pointer and byte pointer
555Inflator_error = 0;
556uint32_t BFINAL = 0;
557while (!BFINAL && !Inflator_error) {
558if (bp >> 3 >= in->size) {
559Inflator_error = 52; // error, bit pointer will jump past memory
560return;
561}
562BFINAL = Zlib_readBitFromStream(&bp, &in->data[inpos]);
563uint32_t BTYPE = Zlib_readBitFromStream(&bp, &in->data[inpos]);
564BTYPE += 2 * Zlib_readBitFromStream(&bp, &in->data[inpos]);
565if (BTYPE == 3) {
566Inflator_error = 20; // error: invalid BTYPE
567return;
568}
569else if (BTYPE == 0)
570Inflator_inflateNoCompression(out, &in->data[inpos], &bp, &pos, in->size);
571else
572Inflator_inflateHuffmanBlock(out, &in->data[inpos], &bp, &pos, in->size, BTYPE);
573}
574if (!Inflator_error)
575vector8_resize(out, pos); // Only now we know the true size of out, resize it to that
576}
577
578/*************************************************************************************************/
579
580int Zlib_decompress(vector8_t *out, const vector8_t *in) // returns error value
581{
582if (in->size < 2)
583return 53; // error, size of zlib data too small
584if ((in->data[0] * 256 + in->data[1]) % 31 != 0)
585// error: 256 * in->data[0] + in->data[1] must be a multiple of 31, the FCHECK value is
586// supposed to be made that way
587return 24;
588uint32_t CM = in->data[0] & 15, CINFO = (in->data[0] >> 4) & 15, FDICT = (in->data[1] >> 5) & 1;
589if (CM != 8 || CINFO > 7)
590// error: only compression method 8: inflate with sliding window of 32k is supported by
591// the PNG spec
592return 25;
593if (FDICT != 0)
594// error: the specification of PNG says about the zlib stream: "The additional flags shall
595// not specify a preset dictionary."
596return 26;
597Inflator_inflate(out, in, 2);
598return Inflator_error; // note: adler32 checksum was skipped and ignored
599}
600
601/*************************************************************************************************/
602
603#define PNG_SIGNATURE0x0a1a0a0d474e5089ull
604
605#define CHUNK_IHDR0x52444849
606#define CHUNK_IDAT0x54414449
607#define CHUNK_IEND0x444e4549
608#define CHUNK_PLTE0x45544c50
609#define CHUNK_tRNS0x534e5274
610
611int PNG_error;
612
613uint32_t PNG_readBitFromReversedStream(size_t *bitp, const uint8_t *bits)
614{
615uint32_t result = (bits[*bitp >> 3] >> (7 - (*bitp & 0x7))) & 1;
616(*bitp)++;
617return result;
618}
619
620uint32_t PNG_readBitsFromReversedStream(size_t *bitp, const uint8_t *bits, uint32_t nbits)
621{
622uint32_t i, result = 0;
623for (i = nbits - 1; i < nbits; i--)
624result += ((PNG_readBitFromReversedStream(bitp, bits)) << i);
625return result;
626}
627
628void PNG_setBitOfReversedStream(size_t *bitp, uint8_t *bits, uint32_t bit)
629{
630bits[*bitp >> 3] |= (bit << (7 - (*bitp & 0x7)));
631(*bitp)++;
632}
633
634uint32_t PNG_read32bitInt(const uint8_t *buffer)
635{
636return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
637}
638
639int PNG_checkColorValidity(uint32_t colorType, uint32_t bd) // return type is a LodePNG error code
640{
641if ((colorType == 2 || colorType == 4 || colorType == 6)) {
642if (!(bd == 8 || bd == 16))
643return 37;
644else
645return 0;
646} else if (colorType == 0) {
647if (!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16))
648return 37;
649else
650return 0;
651} else if (colorType == 3) {
652if (!(bd == 1 || bd == 2 || bd == 4 || bd == 8))
653return 37;
654else
655return 0;
656} else
657return 31; // nonexistent color type
658}
659
660uint32_t PNG_getBpp(const PNG_info_t *info)
661{
662uint32_t bitDepth, colorType;
663bitDepth = info->bitDepth;
664colorType = info->colorType;
665if (colorType == 2)
666return (3 * bitDepth);
667else if (colorType >= 4)
668return (colorType - 2) * bitDepth;
669else
670return bitDepth;
671}
672
673void PNG_readPngHeader(PNG_info_t *info, const uint8_t *in, size_t inlength)
674{// read the information from the header and store it in the Info
675if (inlength < 29) {
676PNG_error = 27; // error: the data length is smaller than the length of the header
677return;
678}
679if (*(uint64_t *) in != PNG_SIGNATURE) {
680PNG_error = 28; // no PNG signature
681return;
682}
683if (*(uint32_t *) &in[12] != CHUNK_IHDR) {
684PNG_error = 29; // error: it doesn't start with a IHDR chunk!
685return;
686}
687info->width = PNG_read32bitInt(&in[16]);
688info->height = PNG_read32bitInt(&in[20]);
689info->bitDepth = in[24];
690info->colorType = in[25];
691info->compressionMethod = in[26];
692if (in[26] != 0) {
693PNG_error = 32; // error: only compression method 0 is allowed in the specification
694return;
695}
696info->filterMethod = in[27];
697if (in[27] != 0) {
698PNG_error = 33; // error: only filter method 0 is allowed in the specification
699return;
700}
701info->interlaceMethod = in[28];
702if (in[28] > 1) {
703PNG_error = 34; // error: only interlace methods 0 and 1 exist in the specification
704return;
705}
706PNG_error = PNG_checkColorValidity(info->colorType, info->bitDepth);
707}
708
709int PNG_paethPredictor(int a, int b, int c) // Paeth predicter, used by PNG filter type 4
710{
711int p, pa, pb, pc;
712p = a + b - c;
713pa = p > a ? (p - a) : (a - p);
714pb = p > b ? (p - b) : (b - p);
715pc = p > c ? (p - c) : (c - p);
716return (pa <= pb && pa <= pc) ? a : (pb <= pc ? b : c);
717}
718
719void PNG_unFilterScanline(uint8_t *recon, const uint8_t *scanline, const uint8_t *precon,
720size_t bytewidth, uint32_t filterType, size_t length)
721{
722size_t i;
723switch (filterType) {
724case 0:
725for (i = 0; i < length; i++)
726recon[i] = scanline[i];
727break;
728case 1:
729for (i = 0; i < bytewidth; i++)
730recon[i] = scanline[i];
731for (i = bytewidth; i < length; i++)
732recon[i] = scanline[i] + recon[i - bytewidth];
733break;
734case 2:
735if (precon)
736for (i = 0; i < length; i++)
737recon[i] = scanline[i] + precon[i];
738else
739for (i = 0; i < length; i++)
740recon[i] = scanline[i];
741break;
742case 3:
743if (precon) {
744for (i = 0; i < bytewidth; i++)
745recon[i] = scanline[i] + precon[i] / 2;
746for (i = bytewidth; i < length; i++)
747recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) / 2);
748} else {
749for (i = 0; i < bytewidth; i++)
750recon[i] = scanline[i];
751for (i = bytewidth; i < length; i++)
752recon[i] = scanline[i] + recon[i - bytewidth] / 2;
753}
754break;
755case 4:
756if (precon) {
757for (i = 0; i < bytewidth; i++)
758recon[i] = (uint8_t) (scanline[i] + PNG_paethPredictor(0, precon[i], 0));
759for (i = bytewidth; i < length; i++)
760recon[i] = (uint8_t) (scanline[i] + PNG_paethPredictor(recon[i - bytewidth],
761precon[i], precon[i - bytewidth]));
762} else {
763for (i = 0; i < bytewidth; i++)
764recon[i] = scanline[i];
765for (i = bytewidth; i < length; i++)
766recon[i] = (uint8_t) (scanline[i] + PNG_paethPredictor(recon[i - bytewidth], 0, 0));
767}
768break;
769default:
770PNG_error = 36; // error: nonexistent filter type given
771return;
772}
773}
774
775void PNG_adam7Pass(uint8_t *out, uint8_t *linen, uint8_t *lineo, const uint8_t *in, uint32_t w,
776size_t passleft, size_t passtop, size_t spacex, size_t spacey, size_t passw, size_t passh,
777uint32_t bpp)
778{// filter and reposition the pixels into the output when the image is Adam7 interlaced. This
779// function can only do it after the full image is already decoded. The out buffer must have
780// the correct allocated memory size already.
781if (passw == 0)
782return;
783size_t bytewidth = (bpp + 7) / 8, linelength = 1 + ((bpp * passw + 7) / 8);
784uint32_t y;
785for (y = 0; y < passh; y++) {
786size_t i, b;
787uint8_t filterType = in[y * linelength], *prevline = (y == 0) ? 0 : lineo;
788PNG_unFilterScanline(linen, &in[y * linelength + 1], prevline, bytewidth, filterType,
789(w * bpp + 7) / 8);
790if (PNG_error)
791return;
792if (bpp >= 8)
793for (i = 0; i < passw; i++)
794for (b = 0; b < bytewidth; b++) // b = current byte of this pixel
795out[bytewidth * w * (passtop + spacey * y) + bytewidth *
796(passleft + spacex * i) + b] = linen[bytewidth * i + b];
797else
798for (i = 0; i < passw; i++) {
799size_t obp, bp;
800obp = bpp * w * (passtop + spacey * y) + bpp * (passleft + spacex * i);
801bp = i * bpp;
802for (b = 0; b < bpp; b++)
803PNG_setBitOfReversedStream(&obp, out, PNG_readBitFromReversedStream(&bp, linen));
804}
805uint8_t *temp = linen;
806linen = lineo;
807lineo = temp; // swap the two buffer pointers "line old" and "line new"
808}
809}
810
811int PNG_convert(const PNG_info_t *info, vector8_t *out, const uint8_t *in)
812{// converts from any color type to 32-bit. return value = LodePNG error code
813size_t i, c;
814uint32_t bitDepth, colorType;
815bitDepth = info->bitDepth;
816colorType = info->colorType;
817size_t numpixels = info->width * info->height, bp = 0;
818vector8_resize(out, numpixels * 4);
819uint8_t *out_data = out->size ? out->data : 0;
820if (bitDepth == 8 && colorType == 0) // greyscale
821for (i = 0; i < numpixels; i++) {
822out_data[4 * i + 0] = out_data[4 * i + 1] = out_data[4 * i + 2] = in[i];
823out_data[4 * i + 3] = (info->key_defined && (in[i] == info->key_r)) ? 0 : 255;
824}
825else if (bitDepth == 8 && colorType == 2) // RGB color
826for (i = 0; i < numpixels; i++) {
827for (c = 0; c < 3; c++)
828out_data[4 * i + c] = in[3 * i + c];
829out_data[4 * i + 3] = (info->key_defined && (in[3 * i + 0] == info->key_r) &&
830(in[3 * i + 1] == info->key_g) && (in[3 * i + 2] == info->key_b)) ? 0 : 255;
831}
832else if (bitDepth == 8 && colorType == 3) // indexed color (palette)
833for (i = 0; i < numpixels; i++) {
834if (4U * in[i] >= info->palette->size)
835return 46;
836for (c = 0; c < 4; c++) // get rgb colors from the palette
837out_data[4 * i + c] = info->palette->data[4 * in[i] + c];
838}
839else if (bitDepth == 8 && colorType == 4) // greyscale with alpha
840for (i = 0; i < numpixels; i++) {
841out_data[4 * i + 0] = out_data[4 * i + 1] = out_data[4 * i + 2] = in[2 * i + 0];
842out_data[4 * i + 3] = in[2 * i + 1];
843}
844else if (bitDepth == 8 && colorType == 6)
845for (i = 0; i < numpixels; i++)
846for (c = 0; c < 4; c++)
847out_data[4 * i + c] = in[4 * i + c]; // RGB with alpha
848else if (bitDepth == 16 && colorType == 0) // greyscale
849for (i = 0; i < numpixels; i++) {
850out_data[4 * i + 0] = out_data[4 * i + 1] = out_data[4 * i + 2] = in[2 * i];
851out_data[4 * i + 3] = (info->key_defined && (256U * in[i] + in[i + 1] == info->key_r))
852? 0 : 255;
853}
854else if (bitDepth == 16 && colorType == 2) // RGB color
855for (i = 0; i < numpixels; i++) {
856for (c = 0; c < 3; c++)
857out_data[4 * i + c] = in[6 * i + 2 * c];
858out_data[4 * i + 3] = (info->key_defined &&
859(256U * in[6 * i + 0] + in[6 * i + 1] == info->key_r) &&
860(256U * in[6 * i + 2] + in[6 * i + 3] == info->key_g) &&
861(256U * in[6 * i + 4] + in[6 * i + 5] == info->key_b)) ? 0 : 255;
862}
863else if (bitDepth == 16 && colorType == 4) // greyscale with alpha
864for (i = 0; i < numpixels; i++) {
865out_data[4 * i + 0] = out_data[4 * i + 1] = out_data[4 * i + 2] = in[4 * i]; // msb
866out_data[4 * i + 3] = in[4 * i + 2];
867}
868else if (bitDepth == 16 && colorType == 6)
869for (i = 0; i < numpixels; i++)
870for (c = 0; c < 4; c++)
871out_data[4 * i + c] = in[8 * i + 2 * c]; // RGB with alpha
872else if (bitDepth < 8 && colorType == 0) // greyscale
873for (i = 0; i < numpixels; i++) {
874uint32_t value = (PNG_readBitsFromReversedStream(&bp, in, bitDepth) * 255) /
875((1 << bitDepth) - 1); // scale value from 0 to 255
876out_data[4 * i + 0] = out_data[4 * i + 1] = out_data[4 * i + 2] = (uint8_t) value;
877out_data[4 * i + 3] = (info->key_defined && value &&
878(((1U << bitDepth) - 1U) == info->key_r) && ((1U << bitDepth) - 1U)) ? 0 : 255;
879}
880else if (bitDepth < 8 && colorType == 3) // palette
881for (i = 0; i < numpixels; i++) {
882uint32_t value = PNG_readBitsFromReversedStream(&bp, in, bitDepth);
883if (4 * value >= info->palette->size)
884return 47;
885for (c = 0; c < 4; c++) // get rgb colors from the palette
886out_data[4 * i + c] = info->palette->data[4 * value + c];
887}
888return 0;
889}
890
891PNG_info_t *PNG_info_new()
892{
893PNG_info_t *info = png_alloc_malloc(sizeof (PNG_info_t));
894uint32_t i;
895for (i = 0; i < sizeof (PNG_info_t); i++)
896((uint8_t *) info)[i] = 0;
897info->palette = vector8_new(0, 0);
898info->image = vector8_new(0, 0);
899return info;
900}
901
902PNG_info_t *PNG_decode(const uint8_t *in, uint32_t size)
903{
904PNG_info_t *info;
905PNG_error = 0;
906if (size == 0 || in == 0) {
907PNG_error = 48; // the given data is empty
908return NULL;
909}
910info = PNG_info_new();
911PNG_readPngHeader(info, in, size);
912if (PNG_error)
913return NULL;
914size_t pos = 33; // first byte of the first chunk after the header
915vector8_t *idat = NULL; // the data from idat chunks
916bool IEND = false, known_type = true;
917info->key_defined = false;
918// loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. IDAT data is
919// put at the start of the in buffer
920while (!IEND) {
921size_t i, j;
922if (pos + 8 >= size) {
923PNG_error = 30; // error: size of the in buffer too small to contain next chunk
924return NULL;
925}
926size_t chunkLength = PNG_read32bitInt(&in[pos]);
927pos += 4;
928if (chunkLength > 0x7fffffff) {
929PNG_error = 63;
930return NULL;
931}
932if (pos + chunkLength >= size) {
933PNG_error = 35; // error: size of the in buffer too small to contain next chunk
934return NULL;
935}
936uint32_t chunkType = *(uint32_t *) &in[pos];
937if (chunkType == CHUNK_IDAT) { // IDAT: compressed image data chunk
938size_t offset = 0;
939if (idat) {
940offset = idat->size;
941vector8_resize(idat, offset + chunkLength);
942} else
943idat = vector8_new(chunkLength, 0);
944for (i = 0; i < chunkLength; i++)
945idat->data[offset + i] = in[pos + 4 + i];
946pos += (4 + chunkLength);
947} else if (chunkType == CHUNK_IEND) { // IEND
948pos += 4;
949IEND = true;
950} else if (chunkType == CHUNK_PLTE) { // PLTE: palette chunk
951pos += 4; // go after the 4 letters
952vector8_resize(info->palette, 4 * (chunkLength / 3));
953if (info->palette->size > (4 * 256)) {
954PNG_error = 38; // error: palette too big
955return NULL;
956}
957for (i = 0; i < info->palette->size; i += 4) {
958for (j = 0; j < 3; j++)
959info->palette->data[i + j] = in[pos++]; // RGB
960info->palette->data[i + 3] = 255; // alpha
961}
962} else if (chunkType == CHUNK_tRNS) { // tRNS: palette transparency chunk
963pos += 4; // go after the 4 letters
964if (info->colorType == 3) {
965if (4 * chunkLength > info->palette->size) {
966PNG_error = 39; // error: more alpha values given than there are palette entries
967return NULL;
968}
969for (i = 0; i < chunkLength; i++)
970info->palette->data[4 * i + 3] = in[pos++];
971} else if (info->colorType == 0) {
972if (chunkLength != 2) {
973PNG_error = 40; // error: this chunk must be 2 bytes for greyscale image
974return NULL;
975}
976info->key_defined = true;
977info->key_r = info->key_g = info->key_b = 256 * in[pos] + in[pos + 1];
978pos += 2;
979} else if (info->colorType == 2) {
980if (chunkLength != 6) {
981PNG_error = 41; // error: this chunk must be 6 bytes for RGB image
982return NULL;
983}
984info->key_defined = true;
985info->key_r = 256 * in[pos] + in[pos + 1];
986pos += 2;
987info->key_g = 256 * in[pos] + in[pos + 1];
988pos += 2;
989info->key_b = 256 * in[pos] + in[pos + 1];
990pos += 2;
991} else {
992PNG_error = 42; // error: tRNS chunk not allowed for other color models
993return NULL;
994}
995} else { // it's not an implemented chunk type, so ignore it: skip over the data
996if (!(in[pos + 0] & 32)) {
997// error: unknown critical chunk (5th bit of first byte of chunk type is 0)
998PNG_error = 69;
999return NULL;
1000}
1001pos += (chunkLength + 4); // skip 4 letters and uninterpreted data of unimplemented chunk
1002known_type = false;
1003}
1004pos += 4; // step over CRC (which is ignored)
1005}
1006uint32_t bpp = PNG_getBpp(info);
1007vector8_t *scanlines; // now the out buffer will be filled
1008scanlines = vector8_new(((info->width * (info->height * bpp + 7)) / 8) + info->height, 0);
1009PNG_error = Zlib_decompress(scanlines, idat);
1010if (PNG_error)
1011return NULL; // stop if the zlib decompressor returned an error
1012size_t bytewidth = (bpp + 7) / 8, outlength = (info->height * info->width * bpp + 7) / 8;
1013vector8_resize(info->image, outlength); // time to fill the out buffer
1014uint8_t *out_data = outlength ? info->image->data : 0;
1015if (info->interlaceMethod == 0) { // no interlace, just filter
1016size_t y, obp, bp;
1017size_t linestart, linelength;
1018linestart = 0;
1019// length in bytes of a scanline, excluding the filtertype byte
1020linelength = (info->width * bpp + 7) / 8;
1021if (bpp >= 8) // byte per byte
1022for (y = 0; y < info->height; y++) {
1023uint32_t filterType = scanlines->data[linestart];
1024const uint8_t *prevline;
1025prevline = (y == 0) ? 0 : &out_data[(y - 1) * info->width * bytewidth];
1026PNG_unFilterScanline(&out_data[linestart - y], &scanlines->data[linestart + 1],
1027prevline, bytewidth, filterType, linelength);
1028if (PNG_error)
1029return NULL;
1030linestart += (1 + linelength); // go to start of next scanline
1031} else { // less than 8 bits per pixel, so fill it up bit per bit
1032vector8_t *templine; // only used if bpp < 8
1033templine = vector8_new((info->width * bpp + 7) >> 3, 0);
1034for (y = 0, obp = 0; y < info->height; y++) {
1035uint32_t filterType = scanlines->data[linestart];
1036const uint8_t *prevline;
1037prevline = (y == 0) ? 0 : &out_data[(y - 1) * info->width * bytewidth];
1038PNG_unFilterScanline(templine->data, &scanlines->data[linestart + 1], prevline,
1039bytewidth, filterType, linelength);
1040if (PNG_error)
1041return NULL;
1042for (bp = 0; bp < info->width * bpp;)
1043PNG_setBitOfReversedStream(&obp, out_data, PNG_readBitFromReversedStream(&bp,
1044templine->data));
1045linestart += (1 + linelength); // go to start of next scanline
1046}
1047}
1048} else { // interlaceMethod is 1 (Adam7)
1049int i;
1050size_t passw[7] = {
1051(info->width + 7) / 8, (info->width + 3) / 8, (info->width + 3) / 4,
1052(info->width + 1) / 4, (info->width + 1) / 2, (info->width + 0) / 2,
1053(info->width + 0) / 1
1054};
1055size_t passh[7] = {
1056(info->height + 7) / 8, (info->height + 7) / 8, (info->height + 3) / 8,
1057(info->height + 3) / 4, (info->height + 1) / 4, (info->height + 1) / 2,
1058(info->height + 0) / 2
1059};
1060size_t passstart[7] = { 0 };
1061size_t pattern[28] = { 0, 4, 0, 2, 0, 1, 0, 0, 0, 4, 0, 2, 0, 1, 8, 8, 4, 4, 2, 2, 1, 8, 8,
10628, 4, 4, 2, 2 }; // values for the adam7 passes
1063for (i = 0; i < 6; i++)
1064passstart[i + 1] = passstart[i] + passh[i] * ((passw[i] ? 1 : 0) + (passw[i] * bpp + 7) / 8);
1065vector8_t *scanlineo, *scanlinen; // "old" and "new" scanline
1066scanlineo = vector8_new((info->width * bpp + 7) / 8, 0);
1067scanlinen = vector8_new((info->width * bpp + 7) / 8, 0);
1068for (i = 0; i < 7; i++)
1069PNG_adam7Pass(out_data, scanlinen->data, scanlineo->data, &scanlines->data[passstart[i]],
1070info->width, pattern[i], pattern[i + 7], pattern[i + 14], pattern[i + 21],
1071passw[i], passh[i], bpp);
1072}
1073if (info->colorType != 6 || info->bitDepth != 8) { // conversion needed
1074vector8_t *copy = vector8_copy(info->image); // xxx: is this copy necessary?
1075PNG_error = PNG_convert(info, info->image, copy->data);
1076}
1077return info;
1078}
1079
1080/*************************************************************************************************/
1081
1082#ifdef TEST
1083
1084#include <stdio.h>
1085#include <sys/stat.h>
1086
1087int main(int argc, char **argv)
1088{
1089char *fname = (argc > 1) ? argv[1] : "test.png";
1090PNG_info_t *info;
1091struct stat statbuf;
1092uint32_t insize, outsize;
1093FILE *infp, *outfp;
1094uint8_t *inbuf;
1095uint32_t n;
1096
1097if (stat(fname, &statbuf) != 0) {
1098perror("stat");
1099return 1;
1100} else if (!statbuf.st_size) {
1101printf("file empty\n");
1102return 1;
1103}
1104insize = (uint32_t) statbuf.st_size;
1105inbuf = malloc(insize);
1106infp = fopen(fname, "rb");
1107if (!infp) {
1108perror("fopen");
1109return 1;
1110} else if (fread(inbuf, 1, insize, infp) != insize) {
1111perror("fread");
1112return 1;
1113}
1114fclose(infp);
1115
1116printf("input file: %s (size: %d)\n", fname, insize);
1117
1118info = PNG_decode(inbuf, insize);
1119free(inbuf);
1120printf("PNG_error: %d\n", PNG_error);
1121if (PNG_error != 0)
1122return 1;
1123
1124printf("width: %d, height: %d\nfirst 16 bytes: ", info->width, info->height);
1125for (n = 0; n < 16; n++)
1126printf("%02x ", info->image->data[n]);
1127printf("\n");
1128
1129outsize = info->width * info->height * 4;
1130printf("image size: %d\n", outsize);
1131if (outsize != info->image->size) {
1132printf("error: image size doesn't match dimensions\n");
1133return 1;
1134}
1135outfp = fopen("out.bin", "wb");
1136if (!outfp) {
1137perror("fopen");
1138return 1;
1139} else if (fwrite(info->image->data, 1, outsize, outfp) != outsize) {
1140perror("fwrite");
1141return 1;
1142}
1143fclose(outfp);
1144
1145#ifdef ALLOC_DEBUG
1146png_alloc_node_t *node;
1147for (node = png_alloc_head, n = 1; node; node = node->next, n++)
1148printf("node %d (%p) addr = %p, size = %ld\n", n, node, node->addr, node->size);
1149#endif
1150png_alloc_free_all(); // also frees info and image data from PNG_decode
1151
1152return 0;
1153}
1154
1155#endif
1156
1157
1158int loadPngImage(const char *filename, uint16_t *width, uint16_t *height,
1159 uint8_t **imageData)
1160{
1161 uint8_t *pngData = NULL;
1162 int pngFile = 0, pngSize;
1163 PNG_info_t *info;
1164 int error = 0;
1165
1166 pngFile = open_bvdev("bt(0,0)", filename, 0);
1167 if (pngFile == -1) {
1168 error = -1;
1169 goto failed;
1170 }
1171 pngSize = file_size(pngFile);
1172 if (!pngSize) {
1173 error = -1;
1174 goto failed;
1175 }
1176 pngData = malloc(pngSize);
1177 if (read(pngFile, (char *) pngData, pngSize) != pngSize) {
1178 error = -1;
1179 goto failed;
1180 }
1181
1182 PNG_error = -1;
1183 info = PNG_decode(pngData, pngSize);
1184 if (PNG_error != 0) {
1185 error = PNG_error;
1186 goto failed;
1187 } else if ((info->width > 0xffff) || (info->height > 0xffff)) {
1188 error = -1;
1189 goto failed;
1190 } else if ((info->width * info->height * 4) != info->image->size) {
1191 error = -1;
1192 goto failed;
1193 }
1194uint8_t *result = malloc(info->width*4*info->height);
1195 *width = info->width;
1196 *height = info->height;
1197memcpy(result, info->image->data, info->width*4*info->height);
1198*imageData = result;
1199
1200failed:
1201png_alloc_free_all();
1202 if (pngData)
1203 free(pngData);
1204 if (pngFile != -1)
1205 close(pngFile);
1206
1207 return error;
1208}
1209
1210int loadEmbeddedPngImage(uint8_t *pngData, int pngSize, uint16_t *width, uint16_t *height, uint8_t **imageData) {
1211 PNG_info_t *info;
1212 int error = 0;
1213
1214 PNG_error = -1;
1215 info = PNG_decode(pngData, pngSize);
1216if (PNG_error != 0) {
1217 error = PNG_error;
1218 goto failed;
1219 } else if ((info->width > 0xffff) || (info->height > 0xffff)) {
1220 error = -1;
1221 goto failed;
1222 } else if ((info->width * info->height * 4) != info->image->size) {
1223 error = -1;
1224 goto failed;
1225 }
1226uint8_t *result = malloc(info->width*4*info->height);
1227*width = info->width;
1228 *height = info->height;
1229memcpy(result, info->image->data, info->width*4*info->height);
1230*imageData = result;
1231
1232failed:
1233png_alloc_free_all();
1234
1235 return error;
1236}
1237
1238

Archive Download this file

Revision: 1174