Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 1146