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

Archive Download this file

Revision: 2066