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

Archive Download this file

Revision: 1913