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

Archive Download this file

Revision: 2182