Move c/h files implementing/defining standard library stuff into a new libc directory...
[kugel-rb.git] / apps / plugins / imageviewer / png / png.c
blobc398af70c5fad87eb70a6e66d3c581fce7e2763a
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$id $
10 * Copyright (C) 2009 by Christophe Gouiran <bechris13250 -at- gmail -dot- com>
12 * Based on lodepng, a lightweight png decoder/encoder
13 * (c) 2005-2008 Lode Vandevenne
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
23 ****************************************************************************/
26 LodePNG version 20080927
28 Copyright (c) 2005-2008 Lode Vandevenne
30 This software is provided 'as-is', without any express or implied
31 warranty. In no event will the authors be held liable for any damages
32 arising from the use of this software.
34 Permission is granted to anyone to use this software for any purpose,
35 including commercial applications, and to alter it and redistribute it
36 freely, subject to the following restrictions:
38 1. The origin of this software must not be misrepresented; you must not
39 claim that you wrote the original software. If you use this software
40 in a product, an acknowledgment in the product documentation would be
41 appreciated but is not required.
43 2. Altered source versions must be plainly marked as such, and must not be
44 misrepresented as being the original software.
46 3. This notice may not be removed or altered from any source
47 distribution.
51 The manual and changelog can be found in the header file "lodepng.h"
52 You are free to name this file lodepng.cpp or lodepng.c depending on your usage.
55 #include "plugin.h"
56 #include "lcd.h"
57 #include <lib/pluginlib_bmp.h>
58 #include "zlib.h"
59 #include "png.h"
61 /* ////////////////////////////////////////////////////////////////////////// */
62 /* LodeFlate & LodeZlib Setting structs */
63 /* ////////////////////////////////////////////////////////////////////////// */
65 typedef struct LodePNG_InfoColor /*info about the color type of an image*/
67 /*header (IHDR)*/
68 unsigned colorType; /*color type*/
69 unsigned bitDepth; /*bits per sample*/
71 /*palette (PLTE)*/
72 unsigned char palette[256 * 4]; /*palette in RGBARGBA... order*/
73 size_t palettesize; /*palette size in number of colors (amount of bytes is 4 * palettesize)*/
75 /*transparent color key (tRNS)*/
76 unsigned key_defined; /*is a transparent color key given?*/
77 unsigned key_r; /*red component of color key*/
78 unsigned key_g; /*green component of color key*/
79 unsigned key_b; /*blue component of color key*/
80 } LodePNG_InfoColor;
82 typedef struct LodePNG_Time /*LodePNG's encoder does not generate the current time. To make it add a time chunk the correct time has to be provided*/
84 unsigned year; /*2 bytes*/
85 unsigned char month; /*1-12*/
86 unsigned char day; /*1-31*/
87 unsigned char hour; /*0-23*/
88 unsigned char minute; /*0-59*/
89 unsigned char second; /*0-60 (to allow for leap seconds)*/
90 } LodePNG_Time;
92 typedef struct LodePNG_InfoPng /*information about the PNG image, except pixels and sometimes except width and height*/
94 /*header (IHDR), palette (PLTE) and transparency (tRNS)*/
95 unsigned width; /*width of the image in pixels (ignored by encoder, but filled in by decoder)*/
96 unsigned height; /*height of the image in pixels (ignored by encoder, but filled in by decoder)*/
97 unsigned compressionMethod; /*compression method of the original file*/
98 unsigned filterMethod; /*filter method of the original file*/
99 unsigned interlaceMethod; /*interlace method of the original file*/
100 LodePNG_InfoColor color; /*color type and bits, palette, transparency*/
102 /*suggested background color (bKGD)*/
103 unsigned background_defined; /*is a suggested background color given?*/
104 unsigned background_r; /*red component of suggested background color*/
105 unsigned background_g; /*green component of suggested background color*/
106 unsigned background_b; /*blue component of suggested background color*/
108 /*time chunk (tIME)*/
109 unsigned char time_defined; /*if 0, no tIME chunk was or will be generated in the PNG image*/
110 LodePNG_Time time;
112 /*phys chunk (pHYs)*/
113 unsigned phys_defined; /*is pHYs chunk defined?*/
114 unsigned phys_x;
115 unsigned phys_y;
116 unsigned char phys_unit; /*may be 0 (unknown unit) or 1 (metre)*/
118 } LodePNG_InfoPng;
120 typedef struct LodePNG_InfoRaw /*contains user-chosen information about the raw image data, which is independent of the PNG image*/
122 LodePNG_InfoColor color;
123 } LodePNG_InfoRaw;
125 typedef struct LodePNG_DecodeSettings
127 unsigned color_convert; /*whether to convert the PNG to the color type you want. Default: yes*/
128 } LodePNG_DecodeSettings;
130 typedef struct LodePNG_Decoder
132 LodePNG_DecodeSettings settings;
133 LodePNG_InfoRaw infoRaw;
134 LodePNG_InfoPng infoPng; /*info of the PNG image obtained after decoding*/
135 long error;
136 char error_msg[128];
137 } LodePNG_Decoder;
139 #define VERSION_STRING "20080927"
141 /* decompressed image in the possible sizes (1,2,4,8), wasting the other */
142 static fb_data *disp[9];
143 /* up to here currently used by image(s) */
144 static fb_data *disp_buf;
146 /* my memory pool (from the mp3 buffer) */
147 static char print[32]; /* use a common snprintf() buffer */
149 unsigned char *memory, *memory_max; /* inffast.c needs memory_max */
150 static size_t memory_size;
152 static unsigned char *image; /* where we put the content of the file */
153 static size_t image_size;
155 static fb_data *converted_image; /* the (color) converted image */
156 static size_t converted_image_size;
158 static unsigned char *decoded_image; /* the decoded image */
159 static size_t decoded_image_size;
161 static LodePNG_Decoder _decoder;
164 The two functions below (LodePNG_decompress and LodePNG_compress) directly call the
165 LodeZlib_decompress and LodeZlib_compress functions. The only purpose of the functions
166 below, is to provide the ability to let LodePNG use a different Zlib encoder by only
167 changing the two functions below, instead of changing it inside the vareous places
168 in the other LodePNG functions.
170 *out must be NULL and *outsize must be 0 initially, and after the function is done,
171 *out must point to the decompressed data, *outsize must be the size of it, and must
172 be the size of the useful data in bytes, not the alloc size.
175 static unsigned LodePNG_decompress(unsigned char* out, size_t* outsize, const unsigned char* in, size_t insize, char *error_msg)
177 z_stream stream;
178 int err;
180 rb->strcpy(error_msg, "");
182 stream.next_in = (Bytef*)in;
183 stream.avail_in = (uInt)insize;
185 stream.next_out = out;
186 stream.avail_out = (uInt)*outsize;
188 stream.zalloc = (alloc_func)0;
189 stream.zfree = (free_func)0;
191 err = inflateInit(&stream);
192 if (err != Z_OK) return err;
194 err = inflate(&stream, Z_FINISH);
195 if (err != Z_STREAM_END) {
196 inflateEnd(&stream);
197 if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
198 return Z_DATA_ERROR;
199 return err;
201 *outsize = stream.total_out;
203 err = inflateEnd(&stream);
204 if (stream.msg != Z_NULL)
205 rb->strcpy(error_msg, stream.msg);
206 return err;
209 /* ////////////////////////////////////////////////////////////////////////// */
210 /* / Reading and writing single bits and bytes from/to stream for LodePNG / */
211 /* ////////////////////////////////////////////////////////////////////////// */
213 static unsigned char readBitFromReversedStream(size_t* bitpointer, const unsigned char* bitstream)
215 unsigned char result = (unsigned char)((bitstream[(*bitpointer) >> 3] >> (7 - ((*bitpointer) & 0x7))) & 1);
216 (*bitpointer)++;
217 return result;
220 static unsigned readBitsFromReversedStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits)
222 unsigned result = 0;
223 size_t i;
224 for (i = nbits - 1; i < nbits; i--) result += (unsigned)readBitFromReversedStream(bitpointer, bitstream) << i;
225 return result;
228 static void setBitOfReversedStream0(size_t* bitpointer, unsigned char* bitstream, unsigned char bit)
230 /*the current bit in bitstream must be 0 for this to work*/
231 if (bit) bitstream[(*bitpointer) >> 3] |= (bit << (7 - ((*bitpointer) & 0x7))); /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/
232 (*bitpointer)++;
235 static void setBitOfReversedStream(size_t* bitpointer, unsigned char* bitstream, unsigned char bit)
237 /*the current bit in bitstream may be 0 or 1 for this to work*/
238 if (bit == 0) bitstream[(*bitpointer) >> 3] &= (unsigned char)(~(1 << (7 - ((*bitpointer) & 0x7))));
239 else bitstream[(*bitpointer) >> 3] |= (1 << (7 - ((*bitpointer) & 0x7)));
240 (*bitpointer)++;
243 static unsigned LodePNG_read32bitInt(const unsigned char* buffer)
245 return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
248 /* ////////////////////////////////////////////////////////////////////////// */
249 /* / PNG chunks / */
250 /* ////////////////////////////////////////////////////////////////////////// */
252 unsigned LodePNG_chunk_length(const unsigned char* chunk) /*get the length of the data of the chunk. Total chunk length has 12 bytes more.*/
254 return LodePNG_read32bitInt(&chunk[0]);
257 void LodePNG_chunk_type(char type[5], const unsigned char* chunk) /*puts the 4-byte type in null terminated string*/
259 unsigned i;
260 for (i = 0; i < 4; i++) type[i] = chunk[4 + i];
261 type[4] = 0; /*null termination char*/
264 unsigned char LodePNG_chunk_type_equals(const unsigned char* chunk, const char* type) /*check if the type is the given type*/
266 if (type[4] != 0) return 0;
267 return (chunk[4] == type[0] && chunk[5] == type[1] && chunk[6] == type[2] && chunk[7] == type[3]);
270 /*properties of PNG chunks gotten from capitalization of chunk type name, as defined by the standard*/
271 unsigned char LodePNG_chunk_critical(const unsigned char* chunk) /*0: ancillary chunk, 1: it's one of the critical chunk types*/
273 return((chunk[4] & 32) == 0);
276 unsigned char LodePNG_chunk_private(const unsigned char* chunk) /*0: public, 1: private*/
278 return((chunk[6] & 32) != 0);
281 unsigned char LodePNG_chunk_safetocopy(const unsigned char* chunk) /*0: the chunk is unsafe to copy, 1: the chunk is safe to copy*/
283 return((chunk[7] & 32) != 0);
286 unsigned char* LodePNG_chunk_data(unsigned char* chunk) /*get pointer to the data of the chunk*/
288 return &chunk[8];
291 const unsigned char* LodePNG_chunk_data_const(const unsigned char* chunk) /*get pointer to the data of the chunk*/
293 return &chunk[8];
296 unsigned LodePNG_chunk_check_crc(const unsigned char* chunk) /*returns 0 if the crc is correct, error code if it's incorrect*/
298 unsigned length = LodePNG_chunk_length(chunk);
299 unsigned CRC = LodePNG_read32bitInt(&chunk[length + 8]);
300 unsigned checksum = crc32(0L, &chunk[4], length + 4); /*the CRC is taken of the data and the 4 chunk type letters, not the length*/
301 if (CRC != checksum) return 1;
302 else return 0;
305 unsigned char* LodePNG_chunk_next(unsigned char* chunk) /*don't use on IEND chunk, as there is no next chunk then*/
307 unsigned total_chunk_length = LodePNG_chunk_length(chunk) + 12;
308 return &chunk[total_chunk_length];
311 const unsigned char* LodePNG_chunk_next_const(const unsigned char* chunk) /*don't use on IEND chunk, as there is no next chunk then*/
313 unsigned total_chunk_length = LodePNG_chunk_length(chunk) + 12;
314 return &chunk[total_chunk_length];
317 /* ////////////////////////////////////////////////////////////////////////// */
318 /* / Color types and such / */
319 /* ////////////////////////////////////////////////////////////////////////// */
321 /*return type is a LodePNG error code*/
322 static unsigned checkColorValidity(unsigned colorType, unsigned bd) /*bd = bitDepth*/
324 switch (colorType)
326 case 0:
327 if (!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16)) return 37; break; /*grey*/
328 case 2:
329 if (!( bd == 8 || bd == 16)) return 37; break; /*RGB*/
330 case 3:
331 if (!(bd == 1 || bd == 2 || bd == 4 || bd == 8 )) return 37; break; /*palette*/
332 case 4:
333 if (!( bd == 8 || bd == 16)) return 37; break; /*grey + alpha*/
334 case 6:
335 if (!( bd == 8 || bd == 16)) return 37; break; /*RGBA*/
336 default:
337 return 31;
339 return 0; /*allowed color type / bits combination*/
342 static unsigned getNumColorChannels(unsigned colorType)
344 switch (colorType)
346 case 0:
347 return 1; /*grey*/
348 case 2:
349 return 3; /*RGB*/
350 case 3:
351 return 1; /*palette*/
352 case 4:
353 return 2; /*grey + alpha*/
354 case 6:
355 return 4; /*RGBA*/
357 return 0; /*unexisting color type*/
360 static unsigned getBpp(unsigned colorType, unsigned bitDepth)
362 return getNumColorChannels(colorType) * bitDepth; /*bits per pixel is amount of channels * bits per channel*/
365 /* ////////////////////////////////////////////////////////////////////////// */
367 void LodePNG_InfoColor_init(LodePNG_InfoColor* info)
369 info->key_defined = 0;
370 info->key_r = info->key_g = info->key_b = 0;
371 info->colorType = 6;
372 info->bitDepth = 8;
373 memset(info->palette, 0, 256 * 4 * sizeof(unsigned char));
374 info->palettesize = 0;
377 void LodePNG_InfoColor_cleanup(LodePNG_InfoColor* info)
379 info->palettesize = 0;
382 unsigned LodePNG_InfoColor_getBpp(const LodePNG_InfoColor* info) { return getBpp(info->colorType, info->bitDepth); } /*calculate bits per pixel out of colorType and bitDepth*/
383 unsigned LodePNG_InfoColor_isGreyscaleType(const LodePNG_InfoColor* info) { return info->colorType == 0 || info->colorType == 4; }
385 unsigned LodePNG_InfoColor_equal(const LodePNG_InfoColor* info1, const LodePNG_InfoColor* info2)
387 return info1->colorType == info2->colorType
388 && info1->bitDepth == info2->bitDepth; /*palette and color key not compared*/
391 void LodePNG_InfoPng_init(LodePNG_InfoPng* info)
393 info->width = info->height = 0;
394 LodePNG_InfoColor_init(&info->color);
395 info->interlaceMethod = 0;
396 info->compressionMethod = 0;
397 info->filterMethod = 0;
398 info->background_defined = 0;
399 info->background_r = info->background_g = info->background_b = 0;
401 info->time_defined = 0;
402 info->phys_defined = 0;
405 void LodePNG_InfoPng_cleanup(LodePNG_InfoPng* info)
407 LodePNG_InfoColor_cleanup(&info->color);
410 unsigned LodePNG_InfoColor_copy(LodePNG_InfoColor* dest, const LodePNG_InfoColor* source)
412 size_t i;
413 LodePNG_InfoColor_cleanup(dest);
414 *dest = *source;
415 for (i = 0; i < source->palettesize * 4; i++) dest->palette[i] = source->palette[i];
416 return 0;
419 unsigned LodePNG_InfoPng_copy(LodePNG_InfoPng* dest, const LodePNG_InfoPng* source)
421 unsigned error = 0;
422 LodePNG_InfoPng_cleanup(dest);
423 *dest = *source;
424 LodePNG_InfoColor_init(&dest->color);
425 error = LodePNG_InfoColor_copy(&dest->color, &source->color); if (error) return error;
426 return error;
429 void LodePNG_InfoPng_swap(LodePNG_InfoPng* a, LodePNG_InfoPng* b)
431 LodePNG_InfoPng temp = *a;
432 *a = *b;
433 *b = temp;
436 void LodePNG_InfoRaw_init(LodePNG_InfoRaw* info)
438 LodePNG_InfoColor_init(&info->color);
441 void LodePNG_InfoRaw_cleanup(LodePNG_InfoRaw* info)
443 LodePNG_InfoColor_cleanup(&info->color);
446 unsigned LodePNG_InfoRaw_copy(LodePNG_InfoRaw* dest, const LodePNG_InfoRaw* source)
448 unsigned error = 0;
449 LodePNG_InfoRaw_cleanup(dest);
450 *dest = *source;
451 LodePNG_InfoColor_init(&dest->color);
452 error = LodePNG_InfoColor_copy(&dest->color, &source->color); if (error) return error;
453 return error;
456 /* ////////////////////////////////////////////////////////////////////////// */
459 converts from any color type to 24-bit or 32-bit (later maybe more supported). return value = LodePNG error code
460 the out buffer must have (w * h * bpp + 7) / 8 bytes, where bpp is the bits per pixel of the output color type (LodePNG_InfoColor_getBpp)
461 for < 8 bpp images, there may _not_ be padding bits at the end of scanlines.
463 unsigned LodePNG_convert(fb_data* out, const unsigned char* in, LodePNG_InfoColor* infoOut, LodePNG_InfoColor* infoIn, unsigned w, unsigned h)
465 size_t i, j, bp = 0; /*bitpointer, used by less-than-8-bit color types*/
466 size_t x, y;
467 unsigned char c;
469 if (!running_slideshow)
471 rb->lcd_puts(0, 3, "color conversion in progress");
472 rb->lcd_update();
475 /*cases where in and out already have the same format*/
476 if (LodePNG_InfoColor_equal(infoIn, infoOut))
479 i = 0;
480 j = 0;
481 for (y = 0 ; y < h ; y++) {
482 for (x = 0 ; x < w ; x++) {
483 unsigned char r = in[i++];
484 unsigned char g = in[i++];
485 unsigned char b = in[i++];
486 out[j++] = LCD_RGBPACK(r,g,b);
489 return 0;
492 if ((infoOut->colorType == 2 || infoOut->colorType == 6) && infoOut->bitDepth == 8)
494 if (infoIn->bitDepth == 8)
496 switch (infoIn->colorType)
498 case 0: /*greyscale color*/
499 i = 0;
500 for (y = 0 ; y < h ; y++) {
501 for (x = 0 ; x < w ; x++) {
502 c=in[i];
503 //unsigned char r = in[i];
504 //unsigned char g = in[i];
505 //unsigned char b = in[i];
506 out[i++] = LCD_RGBPACK(c,c,c);
509 break;
510 case 2: /*RGB color*/
511 i = 0;
512 for (y = 0 ; y < h ; y++) {
513 for (x = 0 ; x < w ; x++) {
514 j = 3 * i;
515 unsigned char r = in[j];
516 unsigned char g = in[j + 1];
517 unsigned char b = in[j + 2];
518 out[i++] = LCD_RGBPACK(r,g,b);
521 break;
522 case 3: /*indexed color (palette)*/
523 i = 0;
524 for (y = 0 ; y < h ; y++) {
525 for (x = 0 ; x < w ; x++) {
526 if (in[i] >= infoIn->palettesize) return 46;
527 j = in[i] << 2;
528 unsigned char r = infoIn->palette[j];
529 unsigned char g = infoIn->palette[j + 1];
530 unsigned char b = infoIn->palette[j + 2];
531 out[i++] = LCD_RGBPACK(r,g,b);
534 break;
535 case 4: /*greyscale with alpha*/
536 i = 0;
537 for (y = 0 ; y < h ; y++) {
538 for (x = 0 ; x < w ; x++) {
539 c = in[i << 1];
540 //unsigned char r = in[i<<1];
541 //unsigned char g = in[i<<1];
542 //unsigned char b = in[i<<1];
543 out[i++] = LCD_RGBPACK(c,c,c);
546 break;
547 case 6: /*RGB with alpha*/
548 i = 0;
549 for (y = 0 ; y < h ; y++) {
550 for (x = 0 ; x < w ; x++) {
551 j = i << 2;
552 unsigned char r = in[j];
553 unsigned char g = in[j + 1];
554 unsigned char b = in[j + 2];
555 out[i++] = LCD_RGBPACK(r,g,b);
558 break;
559 default:
560 break;
563 else if (infoIn->bitDepth == 16)
565 switch (infoIn->colorType)
567 case 0: /*greyscale color*/
568 i = 0;
569 for (y = 0 ; y < h ; y++) {
570 for (x = 0 ; x < w ; x++) {
571 c = in[i << 1];
572 //unsigned char r = in[2 * i];
573 //unsigned char g = in[2 * i];
574 //unsigned char b = in[2 * i];
575 out[i++] = LCD_RGBPACK(c,c,c);
578 break;
579 case 2: /*RGB color*/
580 i = 0;
581 for (y = 0 ; y < h ; y++) {
582 for (x = 0 ; x < w ; x++) {
583 j = 6 * i;
584 unsigned char r = in[j];
585 unsigned char g = in[j + 2];
586 unsigned char b = in[j + 4];
587 out[i++] = LCD_RGBPACK(r,g,b);
590 break;
591 case 4: /*greyscale with alpha*/
592 i = 0;
593 for (y = 0 ; y < h ; y++) {
594 for (x = 0 ; x < w ; x++) {
595 c = in[i << 2];
596 //unsigned char r = in[4 * i];
597 //unsigned char g = in[4 * i];
598 //unsigned char b = in[4 * i];
599 out[i++] = LCD_RGBPACK(c,c,c);
602 break;
603 case 6: /*RGB with alpha*/
604 i = 0;
605 for (y = 0 ; y < h ; y++) {
606 for (x = 0 ; x < w ; x++) {
607 j = i << 3;
608 unsigned char r = in[j];
609 unsigned char g = in[j + 2];
610 unsigned char b = in[j + 4];
611 out[i++] = LCD_RGBPACK(r,g,b);
614 break;
615 default:
616 break;
619 else /*infoIn->bitDepth is less than 8 bit per channel*/
621 switch (infoIn->colorType)
623 case 0: /*greyscale color*/
624 i = 0;
625 for (y = 0 ; y < h ; y++) {
626 for (x = 0 ; x < w ; x++) {
627 unsigned value = readBitsFromReversedStream(&bp, in, infoIn->bitDepth);
628 value = (value * 255) / ((1 << infoIn->bitDepth) - 1); /*scale value from 0 to 255*/
629 unsigned char r = (unsigned char)value;
630 unsigned char g = (unsigned char)value;
631 unsigned char b = (unsigned char)value;
632 out[i++] = LCD_RGBPACK(r,g,b);
635 break;
636 case 3: /*indexed color (palette)*/
637 i = 0;
638 for (y = 0 ; y < h ; y++) {
639 for (x = 0 ; x < w ; x++) {
640 unsigned value = readBitsFromReversedStream(&bp, in, infoIn->bitDepth);
641 if (value >= infoIn->palettesize) return 47;
642 j = value << 2;
643 unsigned char r = infoIn->palette[j];
644 unsigned char g = infoIn->palette[j + 1];
645 unsigned char b = infoIn->palette[j + 2];
646 out[i++] = LCD_RGBPACK(r,g,b);
649 break;
650 default:
651 break;
655 else if (LodePNG_InfoColor_isGreyscaleType(infoOut) && infoOut->bitDepth == 8) /*conversion from greyscale to greyscale*/
657 if (!LodePNG_InfoColor_isGreyscaleType(infoIn)) return 62;
658 if (infoIn->bitDepth == 8)
660 switch (infoIn->colorType)
662 case 0: /*greyscale color*/
663 i = 0;
664 for (y = 0 ; y < h ; y++) {
665 for (x = 0 ; x < w ; x++) {
666 c = in[i];
667 //unsigned char r = in[i];
668 //unsigned char g = in[i];
669 //unsigned char b = in[i];
670 out[i++] = LCD_RGBPACK(c,c,c);
673 break;
674 case 4: /*greyscale with alpha*/
675 i = 0;
676 for (y = 0 ; y < h ; y++) {
677 for (x = 0 ; x < w ; x++) {
678 c = in[(i << 1) + 1];
679 //unsigned char r = in[2 * i + 1];
680 //unsigned char g = in[2 * i + 1];
681 //unsigned char b = in[2 * i + 1];
682 out[i++] = LCD_RGBPACK(c,c,c);
685 break;
686 default:
687 return 31;
690 else if (infoIn->bitDepth == 16)
692 switch (infoIn->colorType)
694 case 0: /*greyscale color*/
695 i = 0;
696 for (y = 0 ; y < h ; y++) {
697 for (x = 0 ; x < w ; x++) {
698 c = in[i << 1];
699 //unsigned char r = in[2 * i];
700 //unsigned char g = in[2 * i];
701 //unsigned char b = in[2 * i];
702 out[i++] = LCD_RGBPACK(c,c,c);
705 break;
706 case 4: /*greyscale with alpha*/
707 i = 0;
708 for (y = 0 ; y < h ; y++) {
709 for (x = 0 ; x < w ; x++) {
710 c = in[i << 2];
711 //unsigned char r = in[4 * i];
712 //unsigned char g = in[4 * i];
713 //unsigned char b = in[4 * i];
714 out[i++] = LCD_RGBPACK(c,c,c);
717 break;
718 default:
719 return 31;
722 else /*infoIn->bitDepth is less than 8 bit per channel*/
724 if (infoIn->colorType != 0) return 31; /*colorType 0 is the only greyscale type with < 8 bits per channel*/
725 i = 0;
726 for (y = 0 ; y < h ; y++) {
727 for (x = 0 ; x < w ; x++) {
728 unsigned value = readBitsFromReversedStream(&bp, in, infoIn->bitDepth);
729 value = (value * 255) / ((1 << infoIn->bitDepth) - 1); /*scale value from 0 to 255*/
730 unsigned char r = (unsigned char)value;
731 unsigned char g = (unsigned char)value;
732 unsigned char b = (unsigned char)value;
733 out[i++] = LCD_RGBPACK(r,g,b);
738 else return 59;
740 return 0;
743 /*Paeth predicter, used by PNG filter type 4*/
744 static int paethPredictor(int a, int b, int c)
746 int p = a + b - c;
747 int pa = p > a ? p - a : a - p;
748 int pb = p > b ? p - b : b - p;
749 int pc = p > c ? p - c : c - p;
751 if (pa <= pb && pa <= pc) return a;
752 else if (pb <= pc) return b;
753 else return c;
756 /*shared values used by multiple Adam7 related functions*/
758 static const unsigned ADAM7_IX[7] = { 0, 4, 0, 2, 0, 1, 0 }; /*x start values*/
759 static const unsigned ADAM7_IY[7] = { 0, 0, 4, 0, 2, 0, 1 }; /*y start values*/
760 static const unsigned ADAM7_DX[7] = { 8, 8, 4, 4, 2, 2, 1 }; /*x delta values*/
761 static const unsigned ADAM7_DY[7] = { 8, 8, 8, 4, 4, 2, 2 }; /*y delta values*/
763 static void Adam7_getpassvalues(unsigned passw[7], unsigned passh[7], size_t filter_passstart[8], size_t padded_passstart[8], size_t passstart[8], unsigned w, unsigned h, unsigned bpp)
765 /*the passstart values have 8 values: the 8th one actually indicates the byte after the end of the 7th (= last) pass*/
766 unsigned i;
768 /*calculate width and height in pixels of each pass*/
769 for (i = 0; i < 7; i++)
771 passw[i] = (w + ADAM7_DX[i] - ADAM7_IX[i] - 1) / ADAM7_DX[i];
772 passh[i] = (h + ADAM7_DY[i] - ADAM7_IY[i] - 1) / ADAM7_DY[i];
773 if (passw[i] == 0) passh[i] = 0;
774 if (passh[i] == 0) passw[i] = 0;
777 filter_passstart[0] = padded_passstart[0] = passstart[0] = 0;
778 for (i = 0; i < 7; i++)
780 filter_passstart[i + 1] = filter_passstart[i] + ((passw[i] && passh[i]) ? passh[i] * (1 + (passw[i] * bpp + 7) / 8) : 0); /*if passw[i] is 0, it's 0 bytes, not 1 (no filtertype-byte)*/
781 padded_passstart[i + 1] = padded_passstart[i] + passh[i] * ((passw[i] * bpp + 7) / 8); /*bits padded if needed to fill full byte at end of each scanline*/
782 passstart[i + 1] = passstart[i] + (passh[i] * passw[i] * bpp + 7) / 8; /*only padded at end of reduced image*/
786 /* ////////////////////////////////////////////////////////////////////////// */
787 /* / PNG Decoder / */
788 /* ////////////////////////////////////////////////////////////////////////// */
790 /*read the information from the header and store it in the LodePNG_Info. return value is error*/
791 void LodePNG_inspect(LodePNG_Decoder* decoder, const unsigned char* in, size_t inlength)
793 if (inlength == 0 || in == 0) { decoder->error = 48; return; } /*the given data is empty*/
794 if (inlength < 29) { decoder->error = 27; return; } /*error: the data length is smaller than the length of the header*/
796 /*when decoding a new PNG image, make sure all parameters created after previous decoding are reset*/
797 LodePNG_InfoPng_cleanup(&decoder->infoPng);
798 LodePNG_InfoPng_init(&decoder->infoPng);
799 decoder->error = 0;
801 if (in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71 || in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10) { decoder->error = 28; return; } /*error: the first 8 bytes are not the correct PNG signature*/
802 if (in[12] != 'I' || in[13] != 'H' || in[14] != 'D' || in[15] != 'R') { decoder->error = 29; return; } /*error: it doesn't start with a IHDR chunk!*/
804 /*read the values given in the header*/
805 decoder->infoPng.width = LodePNG_read32bitInt(&in[16]);
806 decoder->infoPng.height = LodePNG_read32bitInt(&in[20]);
807 decoder->infoPng.color.bitDepth = in[24];
808 decoder->infoPng.color.colorType = in[25];
809 decoder->infoPng.compressionMethod = in[26];
810 decoder->infoPng.filterMethod = in[27];
811 decoder->infoPng.interlaceMethod = in[28];
813 unsigned CRC = LodePNG_read32bitInt(&in[29]);
814 unsigned checksum = crc32(0L, &in[12], 17);
815 if (CRC != checksum) { decoder->error = 57; return; }
817 if (decoder->infoPng.compressionMethod != 0) { decoder->error = 32; return; } /*error: only compression method 0 is allowed in the specification*/
818 if (decoder->infoPng.filterMethod != 0) { decoder->error = 33; return; } /*error: only filter method 0 is allowed in the specification*/
819 if (decoder->infoPng.interlaceMethod > 1) { decoder->error = 34; return; } /*error: only interlace methods 0 and 1 exist in the specification*/
821 decoder->error = checkColorValidity(decoder->infoPng.color.colorType, decoder->infoPng.color.bitDepth);
824 static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scanline, const unsigned char* precon, size_t bytewidth, unsigned char filterType, size_t length)
827 For PNG filter method 0
828 unfilter a PNG image scanline by scanline. when the pixels are smaller than 1 byte, the filter works byte per byte (bytewidth = 1)
829 precon is the previous unfiltered scanline, recon the result, scanline the current one
830 the incoming scanlines do NOT include the filtertype byte, that one is given in the parameter filterType instead
831 recon and scanline MAY be the same memory address! precon must be disjoint.
834 size_t i;
835 switch (filterType)
837 case 0:
838 //for(i = 0; i < length; i++) recon[i] = scanline[i];
839 memcpy(recon, scanline, length * sizeof(unsigned char));
840 break;
841 case 1:
842 //for(i = 0; i < bytewidth; i++) recon[i] = scanline[i];
843 memcpy(recon, scanline, bytewidth * sizeof(unsigned char));
844 for (i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth];
845 break;
846 case 2:
847 if (precon) for (i = 0; i < length; i++) recon[i] = scanline[i] + precon[i];
848 else //for(i = 0; i < length; i++) recon[i] = scanline[i];
849 memcpy(recon, scanline, length * sizeof(unsigned char));
850 break;
851 case 3:
852 if (precon)
854 for (i = 0; i < bytewidth; i++) recon[i] = scanline[i] + precon[i] / 2;
855 for (i = bytewidth; i < length; i++) recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) / 2);
857 else
859 //for(i = 0; i < bytewidth; i++) recon[i] = scanline[i];
860 memcpy(recon, scanline, bytewidth * sizeof(unsigned char));
861 for (i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth] / 2;
863 break;
864 case 4:
865 if (precon)
867 for (i = 0; i < bytewidth; i++) recon[i] = (unsigned char)(scanline[i] + paethPredictor(0, precon[i], 0));
868 for (i = bytewidth; i < length; i++) recon[i] = (unsigned char)(scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth]));
870 else
872 //for(i = 0; i < bytewidth; i++) recon[i] = scanline[i];
873 memcpy(recon, scanline, bytewidth * sizeof(unsigned char));
874 for (i = bytewidth; i < length; i++) recon[i] = (unsigned char)(scanline[i] + paethPredictor(recon[i - bytewidth], 0, 0));
876 break;
877 default:
878 return 36; /*error: unexisting filter type given*/
880 return 0;
883 static unsigned unfilter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp)
886 For PNG filter method 0
887 this function unfilters a single image (e.g. without interlacing this is called once, with Adam7 it's called 7 times)
888 out must have enough bytes allocated already, in must have the scanlines + 1 filtertype byte per scanline
889 w and h are image dimensions or dimensions of reduced image, bpp is bits per pixel
890 in and out are allowed to be the same memory address!
893 unsigned y;
894 unsigned char* prevline = 0;
896 size_t bytewidth = (bpp + 7) / 8; /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/
897 size_t linebytes = (w * bpp + 7) / 8;
899 for (y = 0; y < h; y++)
901 size_t outindex = linebytes * y;
902 size_t inindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/
903 unsigned char filterType = in[inindex];
905 unsigned error = unfilterScanline(&out[outindex], &in[inindex + 1], prevline, bytewidth, filterType, linebytes);
906 if (error) return error;
908 prevline = &out[outindex];
911 return 0;
914 static void Adam7_deinterlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp)
916 /*Note: this function works on image buffers WITHOUT padding bits at end of scanlines with non-multiple-of-8 bit amounts, only between reduced images is padding
917 out must be big enough AND must be 0 everywhere if bpp < 8 in the current implementation (because that's likely a little bit faster)*/
918 unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8];
919 unsigned i;
921 Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp);
923 if (bpp >= 8)
925 for (i = 0; i < 7; i++)
927 unsigned x, y, b;
928 size_t bytewidth = bpp / 8;
929 for (y = 0; y < passh[i]; y++)
930 for (x = 0; x < passw[i]; x++)
932 size_t pixelinstart = passstart[i] + (y * passw[i] + x) * bytewidth;
933 size_t pixeloutstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth;
934 for (b = 0; b < bytewidth; b++)
936 out[pixeloutstart + b] = in[pixelinstart + b];
941 else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/
943 for (i = 0; i < 7; i++)
945 unsigned x, y, b;
946 unsigned ilinebits = bpp * passw[i];
947 unsigned olinebits = bpp * w;
948 size_t obp, ibp; /*bit pointers (for out and in buffer)*/
949 for (y = 0; y < passh[i]; y++)
950 for (x = 0; x < passw[i]; x++)
952 ibp = (8 * passstart[i]) + (y * ilinebits + x * bpp);
953 obp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp;
954 for (b = 0; b < bpp; b++)
956 unsigned char bit = readBitFromReversedStream(&ibp, in);
957 setBitOfReversedStream0(&obp, out, bit); /*note that this function assumes the out buffer is completely 0, use setBitOfReversedStream otherwise*/
964 static void removePaddingBits(unsigned char* out, const unsigned char* in, size_t olinebits, size_t ilinebits, unsigned h)
967 After filtering there are still padding bits if scanlines have non multiple of 8 bit amounts. They need to be removed (except at last scanline of (Adam7-reduced) image) before working with pure image buffers for the Adam7 code, the color convert code and the output to the user.
968 in and out are allowed to be the same buffer, in may also be higher but still overlapping; in must have >= ilinebits*h bits, out must have >= olinebits*h bits, olinebits must be <= ilinebits
969 also used to move bits after earlier such operations happened, e.g. in a sequence of reduced images from Adam7
970 only useful if (ilinebits - olinebits) is a value in the range 1..7
972 unsigned y;
973 size_t diff = ilinebits - olinebits;
974 size_t obp = 0, ibp = 0; /*bit pointers*/
975 for (y = 0; y < h; y++)
977 size_t x;
978 for (x = 0; x < olinebits; x++)
980 unsigned char bit = readBitFromReversedStream(&ibp, in);
981 setBitOfReversedStream(&obp, out, bit);
983 ibp += diff;
987 /*out must be buffer big enough to contain full image, and in must contain the full decompressed data from the IDAT chunks*/
988 static unsigned postProcessScanlines(unsigned char* out, unsigned char* in, const LodePNG_Decoder* decoder) /*return value is error*/
991 This function converts the filtered-padded-interlaced data into pure 2D image buffer with the PNG's colortype. Steps:
992 *) if no Adam7: 1) unfilter 2) remove padding bits (= posible extra bits per scanline if bpp < 8)
993 *) if adam7: 1) 7x unfilter 2) 7x remove padding bits 3) Adam7_deinterlace
994 NOTE: the in buffer will be overwritten with intermediate data!
996 unsigned bpp = LodePNG_InfoColor_getBpp(&decoder->infoPng.color);
997 unsigned w = decoder->infoPng.width;
998 unsigned h = decoder->infoPng.height;
999 unsigned error = 0;
1000 if (bpp == 0) return 31; /*error: invalid colortype*/
1002 if (decoder->infoPng.interlaceMethod == 0)
1004 if (bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8)
1006 error = unfilter(in, in, w, h, bpp);
1007 if (error) return error;
1008 removePaddingBits(out, in, w * bpp, ((w * bpp + 7) / 8) * 8, h);
1010 else error = unfilter(out, in, w, h, bpp); /*we can immediatly filter into the out buffer, no other steps needed*/
1012 else /*interlaceMethod is 1 (Adam7)*/
1014 unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8];
1015 unsigned i;
1017 Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp);
1019 for (i = 0; i < 7; i++)
1021 error = unfilter(&in[padded_passstart[i]], &in[filter_passstart[i]], passw[i], passh[i], bpp);
1022 if (error) return error;
1023 if (bpp < 8) /*TODO: possible efficiency improvement: if in this reduced image the bits fit nicely in 1 scanline, move bytes instead of bits or move not at all*/
1025 /*remove padding bits in scanlines; after this there still may be padding bits between the different reduced images: each reduced image still starts nicely at a byte*/
1026 removePaddingBits(&in[passstart[i]], &in[padded_passstart[i]], passw[i] * bpp, ((passw[i] * bpp + 7) / 8) * 8, passh[i]);
1030 Adam7_deinterlace(out, in, w, h, bpp);
1033 return error;
1036 /*read a PNG, the result will be in the same color type as the PNG (hence "generic")*/
1037 static void decodeGeneric(LodePNG_Decoder* decoder, unsigned char* in, size_t size, void (*pf_progress)(int current, int total))
1039 if (pf_progress != NULL)
1040 pf_progress(0, 100);
1041 unsigned char IEND = 0;
1042 const unsigned char* chunk;
1043 size_t i;
1044 unsigned char *idat = memory;
1045 size_t idat_size = 0;
1047 /*for unknown chunk order*/
1048 unsigned unknown = 0;
1049 unsigned critical_pos = 1; /*1 = after IHDR, 2 = after PLTE, 3 = after IDAT*/
1051 /*provide some proper output values if error will happen*/
1052 decoded_image_size = 0;
1054 if (size == 0 || in == 0) { decoder->error = 48; return; } /*the given data is empty*/
1056 LodePNG_inspect(decoder, in, size); /*reads header and resets other parameters in decoder->infoPng*/
1057 if (decoder->error) return;
1059 chunk = &in[33]; /*first byte of the first chunk after the header*/
1061 while (!IEND) /*loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. IDAT data is put at the start of the in buffer*/
1063 unsigned chunkLength;
1064 const unsigned char* data; /*the data in the chunk*/
1066 if ((size_t)((chunk - in) + 12) > size || chunk < in) { decoder->error = 30; break; } /*error: size of the in buffer too small to contain next chunk*/
1067 chunkLength = LodePNG_chunk_length(chunk); /*length of the data of the chunk, excluding the length bytes, chunk type and CRC bytes*/
1068 if (chunkLength > 2147483647) { decoder->error = 63; break; }
1069 if ((size_t)((chunk - in) + chunkLength + 12) > size || (chunk + chunkLength + 12) < in) { decoder->error = 35; break; } /*error: size of the in buffer too small to contain next chunk*/
1070 data = LodePNG_chunk_data_const(chunk);
1072 /*IDAT chunk, containing compressed image data*/
1073 if (LodePNG_chunk_type_equals(chunk, "IDAT"))
1075 size_t oldsize = idat_size;
1076 idat_size += chunkLength;
1077 if (idat + idat_size >= image) { decoder->error = OUT_OF_MEMORY; break; }
1078 memcpy(idat+oldsize, data, chunkLength * sizeof(unsigned char));
1079 critical_pos = 3;
1081 /*IEND chunk*/
1082 else if (LodePNG_chunk_type_equals(chunk, "IEND"))
1084 IEND = 1;
1086 /*palette chunk (PLTE)*/
1087 else if (LodePNG_chunk_type_equals(chunk, "PLTE"))
1089 unsigned pos = 0;
1090 decoder->infoPng.color.palettesize = chunkLength / 3;
1091 if (decoder->infoPng.color.palettesize > 256) { decoder->error = 38; break; } /*error: palette too big*/
1092 for (i = 0; i < decoder->infoPng.color.palettesize; i++)
1094 decoder->infoPng.color.palette[4 * i + 0] = data[pos++]; /*R*/
1095 decoder->infoPng.color.palette[4 * i + 1] = data[pos++]; /*G*/
1096 decoder->infoPng.color.palette[4 * i + 2] = data[pos++]; /*B*/
1097 decoder->infoPng.color.palette[4 * i + 3] = 255; /*alpha*/
1099 critical_pos = 2;
1101 /*palette transparency chunk (tRNS)*/
1102 else if (LodePNG_chunk_type_equals(chunk, "tRNS"))
1104 if (decoder->infoPng.color.colorType == 3)
1106 if (chunkLength > decoder->infoPng.color.palettesize) { decoder->error = 39; break; } /*error: more alpha values given than there are palette entries*/
1107 for (i = 0; i < chunkLength; i++) decoder->infoPng.color.palette[4 * i + 3] = data[i];
1109 else if (decoder->infoPng.color.colorType == 0)
1111 if (chunkLength != 2) { decoder->error = 40; break; } /*error: this chunk must be 2 bytes for greyscale image*/
1112 decoder->infoPng.color.key_defined = 1;
1113 decoder->infoPng.color.key_r = decoder->infoPng.color.key_g = decoder->infoPng.color.key_b = 256 * data[0] + data[1];
1115 else if (decoder->infoPng.color.colorType == 2)
1117 if (chunkLength != 6) { decoder->error = 41; break; } /*error: this chunk must be 6 bytes for RGB image*/
1118 decoder->infoPng.color.key_defined = 1;
1119 decoder->infoPng.color.key_r = 256 * data[0] + data[1];
1120 decoder->infoPng.color.key_g = 256 * data[2] + data[3];
1121 decoder->infoPng.color.key_b = 256 * data[4] + data[5];
1123 else { decoder->error = 42; break; } /*error: tRNS chunk not allowed for other color models*/
1125 /*background color chunk (bKGD)*/
1126 else if (LodePNG_chunk_type_equals(chunk, "bKGD"))
1128 if (decoder->infoPng.color.colorType == 3)
1130 if (chunkLength != 1) { decoder->error = 43; break; } /*error: this chunk must be 1 byte for indexed color image*/
1131 decoder->infoPng.background_defined = 1;
1132 decoder->infoPng.background_r = decoder->infoPng.color.palette[4 * data[0] + 0];
1133 decoder->infoPng.background_g = decoder->infoPng.color.palette[4 * data[0] + 1];
1134 decoder->infoPng.background_b = decoder->infoPng.color.palette[4 * data[0] + 2];
1137 else if (decoder->infoPng.color.colorType == 0 || decoder->infoPng.color.colorType == 4)
1139 if (chunkLength != 2) { decoder->error = 44; break; } /*error: this chunk must be 2 bytes for greyscale image*/
1140 decoder->infoPng.background_defined = 1;
1141 decoder->infoPng.background_r = decoder->infoPng.background_g = decoder->infoPng.background_b = 256 * data[0] + data[1];
1143 else if (decoder->infoPng.color.colorType == 2 || decoder->infoPng.color.colorType == 6)
1145 if (chunkLength != 6) { decoder->error = 45; break; } /*error: this chunk must be 6 bytes for greyscale image*/
1146 decoder->infoPng.background_defined = 1;
1147 decoder->infoPng.background_r = 256 * data[0] + data[1];
1148 decoder->infoPng.background_g = 256 * data[2] + data[3];
1149 decoder->infoPng.background_b = 256 * data[4] + data[5];
1152 else if (LodePNG_chunk_type_equals(chunk, "tIME"))
1154 if (chunkLength != 7) { decoder->error = 73; break; }
1155 decoder->infoPng.time_defined = 1;
1156 decoder->infoPng.time.year = 256 * data[0] + data[+ 1];
1157 decoder->infoPng.time.month = data[2];
1158 decoder->infoPng.time.day = data[3];
1159 decoder->infoPng.time.hour = data[4];
1160 decoder->infoPng.time.minute = data[5];
1161 decoder->infoPng.time.second = data[6];
1163 else if (LodePNG_chunk_type_equals(chunk, "pHYs"))
1165 if (chunkLength != 9) { decoder->error = 74; break; }
1166 decoder->infoPng.phys_defined = 1;
1167 decoder->infoPng.phys_x = 16777216 * data[0] + 65536 * data[1] + 256 * data[2] + data[3];
1168 decoder->infoPng.phys_y = 16777216 * data[4] + 65536 * data[5] + 256 * data[6] + data[7];
1169 decoder->infoPng.phys_unit = data[8];
1171 else /*it's not an implemented chunk type, so ignore it: skip over the data*/
1173 if (LodePNG_chunk_critical(chunk)) { decoder->error = 69; break; } /*error: unknown critical chunk (5th bit of first byte of chunk type is 0)*/
1174 unknown = 1;
1177 if (!unknown) /*check CRC if wanted, only on known chunk types*/
1179 long time = *rb->current_tick;
1180 if (LodePNG_chunk_check_crc(chunk)) { decoder->error = 57; break; }
1181 time = *rb->current_tick-time;
1184 if (!IEND) chunk = LodePNG_chunk_next_const(chunk);
1187 if (!decoder->error)
1189 unsigned char *scanlines = idat + idat_size;
1190 size_t scanlines_size = (size_t)memory_max - idat_size;
1191 long time = *rb->current_tick;
1192 decoder->error = LodePNG_decompress(scanlines, &scanlines_size, idat, idat_size, decoder->error_msg); /*decompress with the Zlib decompressor*/
1193 if (pf_progress) pf_progress(100, 100);
1194 time = *rb->current_tick-time;
1196 if (!decoder->error)
1198 decoded_image_size = (decoder->infoPng.height * decoder->infoPng.width * LodePNG_InfoColor_getBpp(&decoder->infoPng.color) + 7) / 8;
1199 if (decoded_image_size > memory_size) { decoder->error = OUT_OF_MEMORY; return; }
1200 decoded_image = memory_max - decoded_image_size;
1201 if (scanlines + scanlines_size >= decoded_image) { decoder->error = OUT_OF_MEMORY; return; }
1202 memset(decoded_image, 0, decoded_image_size * sizeof(unsigned char));
1203 if (!running_slideshow)
1205 rb->lcd_puts(0, 3, "unfiltering scanlines");
1206 rb->lcd_update();
1208 decoder->error = postProcessScanlines(decoded_image, scanlines, decoder);
1213 void LodePNG_decode(LodePNG_Decoder* decoder, unsigned char* in, size_t insize, void (*pf_progress)(int current, int total))
1215 decodeGeneric(decoder, in, insize, pf_progress);
1216 if (decoder->error) return;
1218 /*TODO: check if this works according to the statement in the documentation: "The converter can convert from greyscale input color type, to 8-bit greyscale or greyscale with alpha"*/
1219 if (!(decoder->infoRaw.color.colorType == 2 || decoder->infoRaw.color.colorType == 6) && !(decoder->infoRaw.color.bitDepth == 8)) { decoder->error = 56; return; }
1220 converted_image = (fb_data *)memory;
1221 converted_image_size = decoder->infoPng.width*decoder->infoPng.height;
1222 if ((unsigned char *)(converted_image + converted_image_size) >= decoded_image) { decoder->error = OUT_OF_MEMORY; }
1223 if (!decoder->error) decoder->error = LodePNG_convert(converted_image, decoded_image, &decoder->infoRaw.color, &decoder->infoPng.color, decoder->infoPng.width, decoder->infoPng.height);
1226 void LodePNG_DecodeSettings_init(LodePNG_DecodeSettings* settings)
1228 settings->color_convert = 1;
1231 void LodePNG_Decoder_init(LodePNG_Decoder* decoder)
1233 LodePNG_DecodeSettings_init(&decoder->settings);
1234 LodePNG_InfoRaw_init(&decoder->infoRaw);
1235 LodePNG_InfoPng_init(&decoder->infoPng);
1236 decoder->error = 1;
1239 void LodePNG_Decoder_cleanup(LodePNG_Decoder* decoder)
1241 LodePNG_InfoRaw_cleanup(&decoder->infoRaw);
1242 LodePNG_InfoPng_cleanup(&decoder->infoPng);
1245 #define PNG_ERROR_MIN 27
1246 #define PNG_ERROR_MAX 74
1247 static const unsigned char *png_error_messages[PNG_ERROR_MAX-PNG_ERROR_MIN+1] =
1249 "png file smaller than a png header", /*27*/
1250 "incorrect png signature", /*28*/
1251 "first chunk is not IHDR", /*29*/
1252 "chunk length too large", /*30*/
1253 "illegal PNG color type or bpp", /*31*/
1254 "illegal PNG compression method", /*32*/
1255 "illegal PNG filter method", /*33*/
1256 "illegal PNG interlace method", /*34*/
1257 "chunk length of a chunk is too large or the chunk too small", /*35*/
1258 "illegal PNG filter type encountered", /*36*/
1259 "illegal bit depth for this color type given", /*37*/
1260 "the palette is too big (more than 256 colors)", /*38*/
1261 "more palette alpha values given in tRNS, than there are colors in the palette", /*39*/
1262 "tRNS chunk has wrong size for greyscale image", /*40*/
1263 "tRNS chunk has wrong size for RGB image", /*41*/
1264 "tRNS chunk appeared while it was not allowed for this color type", /*42*/
1265 "bKGD chunk has wrong size for palette image", /*43*/
1266 "bKGD chunk has wrong size for greyscale image", /*44*/
1267 "bKGD chunk has wrong size for RGB image", /*45*/
1268 "value encountered in indexed image is larger than the palette size", /*46*/
1269 "value encountered in indexed image is larger than the palette size", /*47*/
1270 "input file is empty", /*48*/
1271 NULL, /*49*/
1272 NULL, /*50*/
1273 NULL, /*51*/
1274 NULL, /*52*/
1275 NULL, /*53*/
1276 NULL, /*54*/
1277 NULL, /*55*/
1278 NULL, /*56*/
1279 "invalid CRC", /*57*/
1280 NULL, /*58*/
1281 "conversion to unexisting or unsupported color type or bit depth", /*59*/
1282 NULL, /*60*/
1283 NULL, /*61*/
1284 NULL, /*62*/
1285 "png chunk too long", /*63*/
1286 NULL, /*64*/
1287 NULL, /*65*/
1288 NULL, /*66*/
1289 NULL, /*67*/
1290 NULL, /*68*/
1291 "unknown critical chunk", /*69*/
1292 NULL, /*70*/
1293 NULL, /*71*/
1294 NULL, /*72*/
1295 "invalid tIME chunk size", /*73*/
1296 "invalid pHYs chunk size", /*74*/
1299 bool img_ext(const char *ext)
1301 if (!ext)
1302 return false;
1303 if (!rb->strcasecmp(ext,".png"))
1304 return true;
1305 else
1306 return false;
1309 void draw_image_rect(struct image_info *info,
1310 int x, int y, int width, int height)
1312 fb_data **pdisp = (fb_data**)info->data;
1313 rb->lcd_bitmap_part(*pdisp, info->x + x, info->y + y, info->width,
1314 x + MAX(0, (LCD_WIDTH-info->width)/2),
1315 y + MAX(0, (LCD_HEIGHT-info->height)/2),
1316 width, height);
1319 int img_mem(int ds)
1321 LodePNG_Decoder *decoder = &_decoder;
1322 return (decoder->infoPng.width/ds) * (decoder->infoPng.height/ds) * FB_DATA_SZ;
1325 int load_image(char *filename, struct image_info *info,
1326 unsigned char *buf, ssize_t *buf_size)
1328 int fd;
1329 long time = 0; /* measured ticks */
1330 int w, h; /* used to center output */
1331 LodePNG_Decoder *decoder = &_decoder;
1333 memset(&disp, 0, sizeof(disp));
1334 LodePNG_Decoder_init(decoder);
1336 /* align buffer */
1337 memory = (unsigned char *)((intptr_t)(buf + 3) & ~3);
1338 memory_max = (unsigned char *)((intptr_t)(memory + *buf_size) & ~3);
1339 memory_size = memory_max - memory;
1341 fd = rb->open(filename, O_RDONLY);
1342 if (fd < 0)
1344 rb->splashf(HZ, "err opening %s: %d", filename, fd);
1345 return PLUGIN_ERROR;
1347 image_size = rb->filesize(fd);
1349 DEBUGF("reading file '%s'\n", filename);
1351 if (!running_slideshow) {
1352 rb->lcd_puts(0, 0, rb->strrchr(filename,'/')+1);
1353 rb->lcd_update();
1356 if (image_size > memory_size) {
1357 decoder->error = FILE_TOO_LARGE;
1358 rb->close(fd);
1360 } else {
1361 if (!running_slideshow) {
1362 rb->snprintf(print, sizeof(print), "loading %zu bytes", image_size);
1363 rb->lcd_puts(0, 1, print);
1364 rb->lcd_update();
1367 image = memory_max - image_size;
1368 rb->read(fd, image, image_size);
1369 rb->close(fd);
1371 if (!running_slideshow) {
1372 rb->lcd_puts(0, 2, "decoding image");
1373 rb->lcd_update();
1375 #ifdef DISK_SPINDOWN
1376 else if (immediate_ata_off) {
1377 /* running slideshow and time is long enough: power down disk */
1378 rb->storage_sleep();
1380 #endif
1382 decoder->settings.color_convert = 1;
1383 decoder->infoRaw.color.colorType = 2;
1384 decoder->infoRaw.color.bitDepth = 8;
1386 LodePNG_inspect(decoder, image, image_size);
1388 if (!decoder->error) {
1390 if (!running_slideshow) {
1391 rb->snprintf(print, sizeof(print), "image %dx%d",
1392 decoder->infoPng.width, decoder->infoPng.height);
1393 rb->lcd_puts(0, 2, print);
1394 rb->lcd_update();
1396 rb->snprintf(print, sizeof(print), "decoding %d*%d",
1397 decoder->infoPng.width, decoder->infoPng.height);
1398 rb->lcd_puts(0, 3, print);
1399 rb->lcd_update();
1402 /* the actual decoding */
1403 time = *rb->current_tick;
1404 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
1405 rb->cpu_boost(true);
1406 LodePNG_decode(decoder, image, image_size, cb_progress);
1407 rb->cpu_boost(false);
1408 #else
1409 LodePNG_decode(decoder, image, image_size, cb_progress);
1410 #endif /*HAVE_ADJUSTABLE_CPU_FREQ*/
1411 time = *rb->current_tick - time;
1415 if (!running_slideshow && !decoder->error)
1417 rb->snprintf(print, sizeof(print), " %ld.%02ld sec ", time/HZ, time%HZ);
1418 rb->lcd_getstringsize(print, &w, &h); /* centered in progress bar */
1419 rb->lcd_putsxy((LCD_WIDTH - w)/2, LCD_HEIGHT - h, print);
1420 rb->lcd_update();
1423 if (decoder->error) {
1424 #ifdef USE_PLUG_BUF
1425 if (plug_buf && (decoder->error == FILE_TOO_LARGE
1426 || decoder->error == OUT_OF_MEMORY || decoder->error == Z_MEM_ERROR))
1427 return PLUGIN_OUTOFMEM;
1428 #endif
1430 if (decoder->error >= PNG_ERROR_MIN && decoder->error <= PNG_ERROR_MAX
1431 && png_error_messages[decoder->error-PNG_ERROR_MIN] != NULL)
1433 rb->splash(HZ, png_error_messages[decoder->error-PNG_ERROR_MIN]);
1435 else
1437 switch (decoder->error) {
1438 case PLUGIN_ABORT:
1439 break;
1440 case OUT_OF_MEMORY:
1441 case Z_MEM_ERROR:
1442 rb->splash(HZ, "Out of Memory");break;
1443 case FILE_TOO_LARGE:
1444 rb->splash(HZ, "File too large");break;
1445 case Z_DATA_ERROR:
1446 rb->splash(HZ, decoder->error_msg);break;
1447 default:
1448 rb->splashf(HZ, "other error : %ld", decoder->error);break;
1452 if (decoder->error == PLUGIN_ABORT)
1453 return PLUGIN_ABORT;
1454 else
1455 return PLUGIN_ERROR;
1458 disp_buf = converted_image + converted_image_size;
1459 info->x_size = decoder->infoPng.width;
1460 info->y_size = decoder->infoPng.height;
1461 *buf_size = memory_max - (unsigned char*)disp_buf;
1462 return PLUGIN_OK;
1465 int get_image(struct image_info *info, int ds)
1467 fb_data **p_disp = &disp[ds]; /* short cut */
1468 LodePNG_Decoder *decoder = &_decoder;
1470 info->width = decoder->infoPng.width / ds;
1471 info->height = decoder->infoPng.height / ds;
1472 info->data = p_disp;
1474 if (*p_disp != NULL)
1476 /* we still have it */
1477 return PLUGIN_OK;
1480 /* assign image buffer */
1481 if (ds > 1) {
1482 if (!running_slideshow)
1484 rb->snprintf(print, sizeof(print), "resizing %d*%d",
1485 info->width, info->height);
1486 rb->lcd_puts(0, 3, print);
1487 rb->lcd_update();
1489 struct bitmap bmp_src, bmp_dst;
1491 int size = info->width * info->height;
1493 if ((unsigned char *)(disp_buf + size) >= memory_max) {
1494 /* have to discard the current */
1495 int i;
1496 for (i=1; i<=8; i++)
1497 disp[i] = NULL; /* invalidate all bitmaps */
1498 /* start again from the beginning of the buffer */
1499 disp_buf = converted_image + converted_image_size;
1502 *p_disp = disp_buf;
1503 disp_buf += size;
1505 bmp_src.width = decoder->infoPng.width;
1506 bmp_src.height = decoder->infoPng.height;
1507 bmp_src.data = (unsigned char *)converted_image;
1509 bmp_dst.width = info->width;
1510 bmp_dst.height = info->height;
1511 bmp_dst.data = (unsigned char *)*p_disp;
1512 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
1513 rb->cpu_boost(true);
1514 smooth_resize_bitmap(&bmp_src, &bmp_dst);
1515 rb->cpu_boost(false);
1516 #else
1517 smooth_resize_bitmap(&bmp_src, &bmp_dst);
1518 #endif /*HAVE_ADJUSTABLE_CPU_FREQ*/
1519 } else {
1520 *p_disp = converted_image;
1523 return PLUGIN_OK;