Chameleon

Chameleon Svn Source Tree

Root/branches/cparm/i386/modules/GUI/picopng.c

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

Archive Download this file

Revision: 1899