Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 1119