Chameleon Applications

Chameleon Applications Svn Source Tree

Root/branches/iFabio/i386/boot2/picopng.c

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

Archive Download this file

Revision: 214