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

Archive Download this file

Revision: 2057