summaryrefslogtreecommitdiff
path: root/apps/plugins/imageviewer/png/png.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/imageviewer/png/png.c')
-rw-r--r--apps/plugins/imageviewer/png/png.c1526
1 files changed, 1526 insertions, 0 deletions
diff --git a/apps/plugins/imageviewer/png/png.c b/apps/plugins/imageviewer/png/png.c
new file mode 100644
index 0000000000..5cf6f4d471
--- /dev/null
+++ b/apps/plugins/imageviewer/png/png.c
@@ -0,0 +1,1526 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$id $
9 *
10 * Copyright (C) 2009 by Christophe Gouiran <bechris13250 -at- gmail -dot- com>
11 *
12 * Based on lodepng, a lightweight png decoder/encoder
13 * (c) 2005-2008 Lode Vandevenne
14 *
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.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24
25/*
26LodePNG version 20080927
27
28Copyright (c) 2005-2008 Lode Vandevenne
29
30This software is provided 'as-is', without any express or implied
31warranty. In no event will the authors be held liable for any damages
32arising from the use of this software.
33
34Permission is granted to anyone to use this software for any purpose,
35including commercial applications, and to alter it and redistribute it
36freely, subject to the following restrictions:
37
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.
42
43 2. Altered source versions must be plainly marked as such, and must not be
44 misrepresented as being the original software.
45
46 3. This notice may not be removed or altered from any source
47 distribution.
48*/
49
50/*
51The manual and changelog can be found in the header file "lodepng.h"
52You are free to name this file lodepng.cpp or lodepng.c depending on your usage.
53*/
54
55#include "plugin.h"
56#include "lcd.h"
57#include <lib/pluginlib_bmp.h>
58#include "zlib.h"
59#include "png.h"
60
61/* ////////////////////////////////////////////////////////////////////////// */
62/* LodeFlate & LodeZlib Setting structs */
63/* ////////////////////////////////////////////////////////////////////////// */
64
65typedef struct LodePNG_InfoColor /*info about the color type of an image*/
66{
67 /*header (IHDR)*/
68 unsigned colorType; /*color type*/
69 unsigned bitDepth; /*bits per sample*/
70
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)*/
74
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;
81
82typedef 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*/
83{
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;
91
92typedef struct LodePNG_InfoPng /*information about the PNG image, except pixels and sometimes except width and height*/
93{
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*/
101
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*/
107
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;
111
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)*/
117
118} LodePNG_InfoPng;
119
120typedef struct LodePNG_InfoRaw /*contains user-chosen information about the raw image data, which is independent of the PNG image*/
121{
122 LodePNG_InfoColor color;
123} LodePNG_InfoRaw;
124
125typedef struct LodePNG_DecodeSettings
126{
127 unsigned color_convert; /*whether to convert the PNG to the color type you want. Default: yes*/
128} LodePNG_DecodeSettings;
129
130typedef struct LodePNG_Decoder
131{
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;
138
139#define VERSION_STRING "20080927"
140
141/* decompressed image in the possible sizes (1,2,4,8), wasting the other */
142static fb_data *disp[9];
143/* up to here currently used by image(s) */
144static fb_data *disp_buf;
145
146/* my memory pool (from the mp3 buffer) */
147static char print[128]; /* use a common snprintf() buffer */
148
149unsigned char *memory, *memory_max;
150static size_t memory_size;
151
152static unsigned char *image; /* where we put the content of the file */
153static size_t image_size;
154
155static fb_data *converted_image; /* the (color) converted image */
156static size_t converted_image_size;
157
158static unsigned char *decoded_image; /* the decoded image */
159static size_t decoded_image_size;
160
161static LodePNG_Decoder _decoder;
162
163/*
164The two functions below (LodePNG_decompress and LodePNG_compress) directly call the
165LodeZlib_decompress and LodeZlib_compress functions. The only purpose of the functions
166below, is to provide the ability to let LodePNG use a different Zlib encoder by only
167changing the two functions below, instead of changing it inside the vareous places
168in the other LodePNG functions.
169
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
172be the size of the useful data in bytes, not the alloc size.
173*/
174
175static unsigned LodePNG_decompress(unsigned char* out, size_t* outsize, const unsigned char* in, size_t insize, char *error_msg)
176{
177 z_stream stream;
178 int err;
179
180 rb->strcpy(error_msg, "");
181
182 stream.next_in = (Bytef*)in;
183 stream.avail_in = (uInt)insize;
184
185 stream.next_out = out;
186 stream.avail_out = (uInt)*outsize;
187
188 stream.zalloc = (alloc_func)0;
189 stream.zfree = (free_func)0;
190
191 err = inflateInit(&stream);
192 if (err != Z_OK) return err;
193
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;
200 }
201 *outsize = stream.total_out;
202
203 err = inflateEnd(&stream);
204 if (stream.msg != Z_NULL)
205 rb->strcpy(error_msg, stream.msg);
206 return err;
207
208}
209
210/* ////////////////////////////////////////////////////////////////////////// */
211/* / Reading and writing single bits and bytes from/to stream for LodePNG / */
212/* ////////////////////////////////////////////////////////////////////////// */
213
214static unsigned char readBitFromReversedStream(size_t* bitpointer, const unsigned char* bitstream)
215{
216 unsigned char result = (unsigned char)((bitstream[(*bitpointer) >> 3] >> (7 - ((*bitpointer) & 0x7))) & 1);
217 (*bitpointer)++;
218 return result;
219}
220
221static unsigned readBitsFromReversedStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits)
222{
223 unsigned result = 0;
224 size_t i;
225 for (i = nbits - 1; i < nbits; i--) result += (unsigned)readBitFromReversedStream(bitpointer, bitstream) << i;
226 return result;
227}
228
229static void setBitOfReversedStream0(size_t* bitpointer, unsigned char* bitstream, unsigned char bit)
230{
231 /*the current bit in bitstream must be 0 for this to work*/
232 if (bit) bitstream[(*bitpointer) >> 3] |= (bit << (7 - ((*bitpointer) & 0x7))); /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/
233 (*bitpointer)++;
234}
235
236static void setBitOfReversedStream(size_t* bitpointer, unsigned char* bitstream, unsigned char bit)
237{
238 /*the current bit in bitstream may be 0 or 1 for this to work*/
239 if (bit == 0) bitstream[(*bitpointer) >> 3] &= (unsigned char)(~(1 << (7 - ((*bitpointer) & 0x7))));
240 else bitstream[(*bitpointer) >> 3] |= (1 << (7 - ((*bitpointer) & 0x7)));
241 (*bitpointer)++;
242}
243
244static unsigned LodePNG_read32bitInt(const unsigned char* buffer)
245{
246 return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
247}
248
249/* ////////////////////////////////////////////////////////////////////////// */
250/* / PNG chunks / */
251/* ////////////////////////////////////////////////////////////////////////// */
252
253unsigned LodePNG_chunk_length(const unsigned char* chunk) /*get the length of the data of the chunk. Total chunk length has 12 bytes more.*/
254{
255 return LodePNG_read32bitInt(&chunk[0]);
256}
257
258void LodePNG_chunk_type(char type[5], const unsigned char* chunk) /*puts the 4-byte type in null terminated string*/
259{
260 unsigned i;
261 for (i = 0; i < 4; i++) type[i] = chunk[4 + i];
262 type[4] = 0; /*null termination char*/
263}
264
265unsigned char LodePNG_chunk_type_equals(const unsigned char* chunk, const char* type) /*check if the type is the given type*/
266{
267 if (type[4] != 0) return 0;
268 return (chunk[4] == type[0] && chunk[5] == type[1] && chunk[6] == type[2] && chunk[7] == type[3]);
269}
270
271/*properties of PNG chunks gotten from capitalization of chunk type name, as defined by the standard*/
272unsigned char LodePNG_chunk_critical(const unsigned char* chunk) /*0: ancillary chunk, 1: it's one of the critical chunk types*/
273{
274 return((chunk[4] & 32) == 0);
275}
276
277unsigned char LodePNG_chunk_private(const unsigned char* chunk) /*0: public, 1: private*/
278{
279 return((chunk[6] & 32) != 0);
280}
281
282unsigned char LodePNG_chunk_safetocopy(const unsigned char* chunk) /*0: the chunk is unsafe to copy, 1: the chunk is safe to copy*/
283{
284 return((chunk[7] & 32) != 0);
285}
286
287unsigned char* LodePNG_chunk_data(unsigned char* chunk) /*get pointer to the data of the chunk*/
288{
289 return &chunk[8];
290}
291
292const unsigned char* LodePNG_chunk_data_const(const unsigned char* chunk) /*get pointer to the data of the chunk*/
293{
294 return &chunk[8];
295}
296
297unsigned LodePNG_chunk_check_crc(const unsigned char* chunk) /*returns 0 if the crc is correct, error code if it's incorrect*/
298{
299 unsigned length = LodePNG_chunk_length(chunk);
300 unsigned CRC = LodePNG_read32bitInt(&chunk[length + 8]);
301 unsigned checksum = crc32(0L, &chunk[4], length + 4); /*the CRC is taken of the data and the 4 chunk type letters, not the length*/
302 if (CRC != checksum) return 1;
303 else return 0;
304}
305
306unsigned char* LodePNG_chunk_next(unsigned char* chunk) /*don't use on IEND chunk, as there is no next chunk then*/
307{
308 unsigned total_chunk_length = LodePNG_chunk_length(chunk) + 12;
309 return &chunk[total_chunk_length];
310}
311
312const unsigned char* LodePNG_chunk_next_const(const unsigned char* chunk) /*don't use on IEND chunk, as there is no next chunk then*/
313{
314 unsigned total_chunk_length = LodePNG_chunk_length(chunk) + 12;
315 return &chunk[total_chunk_length];
316}
317
318/* ////////////////////////////////////////////////////////////////////////// */
319/* / Color types and such / */
320/* ////////////////////////////////////////////////////////////////////////// */
321
322/*return type is a LodePNG error code*/
323static unsigned checkColorValidity(unsigned colorType, unsigned bd) /*bd = bitDepth*/
324{
325 switch (colorType)
326 {
327 case 0:
328 if (!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16)) return 37; break; /*grey*/
329 case 2:
330 if (!( bd == 8 || bd == 16)) return 37; break; /*RGB*/
331 case 3:
332 if (!(bd == 1 || bd == 2 || bd == 4 || bd == 8 )) return 37; break; /*palette*/
333 case 4:
334 if (!( bd == 8 || bd == 16)) return 37; break; /*grey + alpha*/
335 case 6:
336 if (!( bd == 8 || bd == 16)) return 37; break; /*RGBA*/
337 default:
338 return 31;
339 }
340 return 0; /*allowed color type / bits combination*/
341}
342
343static unsigned getNumColorChannels(unsigned colorType)
344{
345 switch (colorType)
346 {
347 case 0:
348 return 1; /*grey*/
349 case 2:
350 return 3; /*RGB*/
351 case 3:
352 return 1; /*palette*/
353 case 4:
354 return 2; /*grey + alpha*/
355 case 6:
356 return 4; /*RGBA*/
357 }
358 return 0; /*unexisting color type*/
359}
360
361static unsigned getBpp(unsigned colorType, unsigned bitDepth)
362{
363 return getNumColorChannels(colorType) * bitDepth; /*bits per pixel is amount of channels * bits per channel*/
364}
365
366/* ////////////////////////////////////////////////////////////////////////// */
367
368void LodePNG_InfoColor_init(LodePNG_InfoColor* info)
369{
370 info->key_defined = 0;
371 info->key_r = info->key_g = info->key_b = 0;
372 info->colorType = 6;
373 info->bitDepth = 8;
374 memset(info->palette, 0, 256 * 4 * sizeof(unsigned char));
375 info->palettesize = 0;
376}
377
378void LodePNG_InfoColor_cleanup(LodePNG_InfoColor* info)
379{
380 info->palettesize = 0;
381}
382
383unsigned LodePNG_InfoColor_getBpp(const LodePNG_InfoColor* info) { return getBpp(info->colorType, info->bitDepth); } /*calculate bits per pixel out of colorType and bitDepth*/
384unsigned LodePNG_InfoColor_isGreyscaleType(const LodePNG_InfoColor* info) { return info->colorType == 0 || info->colorType == 4; }
385
386unsigned LodePNG_InfoColor_equal(const LodePNG_InfoColor* info1, const LodePNG_InfoColor* info2)
387{
388 return info1->colorType == info2->colorType
389 && info1->bitDepth == info2->bitDepth; /*palette and color key not compared*/
390}
391
392void LodePNG_InfoPng_init(LodePNG_InfoPng* info)
393{
394 info->width = info->height = 0;
395 LodePNG_InfoColor_init(&info->color);
396 info->interlaceMethod = 0;
397 info->compressionMethod = 0;
398 info->filterMethod = 0;
399 info->background_defined = 0;
400 info->background_r = info->background_g = info->background_b = 0;
401
402 info->time_defined = 0;
403 info->phys_defined = 0;
404}
405
406void LodePNG_InfoPng_cleanup(LodePNG_InfoPng* info)
407{
408 LodePNG_InfoColor_cleanup(&info->color);
409}
410
411unsigned LodePNG_InfoColor_copy(LodePNG_InfoColor* dest, const LodePNG_InfoColor* source)
412{
413 size_t i;
414 LodePNG_InfoColor_cleanup(dest);
415 *dest = *source;
416 for (i = 0; i < source->palettesize * 4; i++) dest->palette[i] = source->palette[i];
417 return 0;
418}
419
420unsigned LodePNG_InfoPng_copy(LodePNG_InfoPng* dest, const LodePNG_InfoPng* source)
421{
422 unsigned error = 0;
423 LodePNG_InfoPng_cleanup(dest);
424 *dest = *source;
425 LodePNG_InfoColor_init(&dest->color);
426 error = LodePNG_InfoColor_copy(&dest->color, &source->color); if (error) return error;
427 return error;
428}
429
430void LodePNG_InfoPng_swap(LodePNG_InfoPng* a, LodePNG_InfoPng* b)
431{
432 LodePNG_InfoPng temp = *a;
433 *a = *b;
434 *b = temp;
435}
436
437void LodePNG_InfoRaw_init(LodePNG_InfoRaw* info)
438{
439 LodePNG_InfoColor_init(&info->color);
440}
441
442void LodePNG_InfoRaw_cleanup(LodePNG_InfoRaw* info)
443{
444 LodePNG_InfoColor_cleanup(&info->color);
445}
446
447unsigned LodePNG_InfoRaw_copy(LodePNG_InfoRaw* dest, const LodePNG_InfoRaw* source)
448{
449 unsigned error = 0;
450 LodePNG_InfoRaw_cleanup(dest);
451 *dest = *source;
452 LodePNG_InfoColor_init(&dest->color);
453 error = LodePNG_InfoColor_copy(&dest->color, &source->color); if (error) return error;
454 return error;
455}
456
457/* ////////////////////////////////////////////////////////////////////////// */
458
459/*
460converts from any color type to 24-bit or 32-bit (later maybe more supported). return value = LodePNG error code
461the 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)
462for < 8 bpp images, there may _not_ be padding bits at the end of scanlines.
463*/
464unsigned LodePNG_convert(fb_data* out, const unsigned char* in, LodePNG_InfoColor* infoOut, LodePNG_InfoColor* infoIn, unsigned w, unsigned h)
465{
466 size_t i, j, bp = 0; /*bitpointer, used by less-than-8-bit color types*/
467 size_t x, y;
468 unsigned char c;
469
470 if (!running_slideshow)
471 {
472 rb->snprintf(print, sizeof(print), "color conversion in progress");
473 rb->lcd_puts(0, 3, print);
474 rb->lcd_update();
475 }
476
477 /*cases where in and out already have the same format*/
478 if (LodePNG_InfoColor_equal(infoIn, infoOut))
479 {
480
481 i = 0;
482 j = 0;
483 for (y = 0 ; y < h ; y++) {
484 for (x = 0 ; x < w ; x++) {
485 unsigned char r = in[i++];
486 unsigned char g = in[i++];
487 unsigned char b = in[i++];
488 out[j++] = LCD_RGBPACK(r,g,b);
489 }
490 }
491 return 0;
492 }
493
494 if ((infoOut->colorType == 2 || infoOut->colorType == 6) && infoOut->bitDepth == 8)
495 {
496 if (infoIn->bitDepth == 8)
497 {
498 switch (infoIn->colorType)
499 {
500 case 0: /*greyscale color*/
501 i = 0;
502 for (y = 0 ; y < h ; y++) {
503 for (x = 0 ; x < w ; x++) {
504 c=in[i];
505 //unsigned char r = in[i];
506 //unsigned char g = in[i];
507 //unsigned char b = in[i];
508 out[i++] = LCD_RGBPACK(c,c,c);
509 }
510 }
511 break;
512 case 2: /*RGB color*/
513 i = 0;
514 for (y = 0 ; y < h ; y++) {
515 for (x = 0 ; x < w ; x++) {
516 j = 3 * i;
517 unsigned char r = in[j];
518 unsigned char g = in[j + 1];
519 unsigned char b = in[j + 2];
520 out[i++] = LCD_RGBPACK(r,g,b);
521 }
522 }
523 break;
524 case 3: /*indexed color (palette)*/
525 i = 0;
526 for (y = 0 ; y < h ; y++) {
527 for (x = 0 ; x < w ; x++) {
528 if (in[i] >= infoIn->palettesize) return 46;
529 j = in[i] << 2;
530 unsigned char r = infoIn->palette[j];
531 unsigned char g = infoIn->palette[j + 1];
532 unsigned char b = infoIn->palette[j + 2];
533 out[i++] = LCD_RGBPACK(r,g,b);
534 }
535 }
536 break;
537 case 4: /*greyscale with alpha*/
538 i = 0;
539 for (y = 0 ; y < h ; y++) {
540 for (x = 0 ; x < w ; x++) {
541 c = in[i << 1];
542 //unsigned char r = in[i<<1];
543 //unsigned char g = in[i<<1];
544 //unsigned char b = in[i<<1];
545 out[i++] = LCD_RGBPACK(c,c,c);
546 }
547 }
548 break;
549 case 6: /*RGB with alpha*/
550 i = 0;
551 for (y = 0 ; y < h ; y++) {
552 for (x = 0 ; x < w ; x++) {
553 j = i << 2;
554 unsigned char r = in[j];
555 unsigned char g = in[j + 1];
556 unsigned char b = in[j + 2];
557 out[i++] = LCD_RGBPACK(r,g,b);
558 }
559 }
560 break;
561 default:
562 break;
563 }
564 }
565 else if (infoIn->bitDepth == 16)
566 {
567 switch (infoIn->colorType)
568 {
569 case 0: /*greyscale color*/
570 i = 0;
571 for (y = 0 ; y < h ; y++) {
572 for (x = 0 ; x < w ; x++) {
573 c = in[i << 1];
574 //unsigned char r = in[2 * i];
575 //unsigned char g = in[2 * i];
576 //unsigned char b = in[2 * i];
577 out[i++] = LCD_RGBPACK(c,c,c);
578 }
579 }
580 break;
581 case 2: /*RGB color*/
582 i = 0;
583 for (y = 0 ; y < h ; y++) {
584 for (x = 0 ; x < w ; x++) {
585 j = 6 * i;
586 unsigned char r = in[j];
587 unsigned char g = in[j + 2];
588 unsigned char b = in[j + 4];
589 out[i++] = LCD_RGBPACK(r,g,b);
590 }
591 }
592 break;
593 case 4: /*greyscale with alpha*/
594 i = 0;
595 for (y = 0 ; y < h ; y++) {
596 for (x = 0 ; x < w ; x++) {
597 c = in[i << 2];
598 //unsigned char r = in[4 * i];
599 //unsigned char g = in[4 * i];
600 //unsigned char b = in[4 * i];
601 out[i++] = LCD_RGBPACK(c,c,c);
602 }
603 }
604 break;
605 case 6: /*RGB with alpha*/
606 i = 0;
607 for (y = 0 ; y < h ; y++) {
608 for (x = 0 ; x < w ; x++) {
609 j = i << 3;
610 unsigned char r = in[j];
611 unsigned char g = in[j + 2];
612 unsigned char b = in[j + 4];
613 out[i++] = LCD_RGBPACK(r,g,b);
614 }
615 }
616 break;
617 default:
618 break;
619 }
620 }
621 else /*infoIn->bitDepth is less than 8 bit per channel*/
622 {
623 switch (infoIn->colorType)
624 {
625 case 0: /*greyscale color*/
626 i = 0;
627 for (y = 0 ; y < h ; y++) {
628 for (x = 0 ; x < w ; x++) {
629 unsigned value = readBitsFromReversedStream(&bp, in, infoIn->bitDepth);
630 value = (value * 255) / ((1 << infoIn->bitDepth) - 1); /*scale value from 0 to 255*/
631 unsigned char r = (unsigned char)value;
632 unsigned char g = (unsigned char)value;
633 unsigned char b = (unsigned char)value;
634 out[i++] = LCD_RGBPACK(r,g,b);
635 }
636 }
637 break;
638 case 3: /*indexed color (palette)*/
639 i = 0;
640 for (y = 0 ; y < h ; y++) {
641 for (x = 0 ; x < w ; x++) {
642 unsigned value = readBitsFromReversedStream(&bp, in, infoIn->bitDepth);
643 if (value >= infoIn->palettesize) return 47;
644 j = value << 2;
645 unsigned char r = infoIn->palette[j];
646 unsigned char g = infoIn->palette[j + 1];
647 unsigned char b = infoIn->palette[j + 2];
648 out[i++] = LCD_RGBPACK(r,g,b);
649 }
650 }
651 break;
652 default:
653 break;
654 }
655 }
656 }
657 else if (LodePNG_InfoColor_isGreyscaleType(infoOut) && infoOut->bitDepth == 8) /*conversion from greyscale to greyscale*/
658 {
659 if (!LodePNG_InfoColor_isGreyscaleType(infoIn)) return 62;
660 if (infoIn->bitDepth == 8)
661 {
662 switch (infoIn->colorType)
663 {
664 case 0: /*greyscale color*/
665 i = 0;
666 for (y = 0 ; y < h ; y++) {
667 for (x = 0 ; x < w ; x++) {
668 c = in[i];
669 //unsigned char r = in[i];
670 //unsigned char g = in[i];
671 //unsigned char b = in[i];
672 out[i++] = LCD_RGBPACK(c,c,c);
673 }
674 }
675 break;
676 case 4: /*greyscale with alpha*/
677 i = 0;
678 for (y = 0 ; y < h ; y++) {
679 for (x = 0 ; x < w ; x++) {
680 c = in[(i << 1) + 1];
681 //unsigned char r = in[2 * i + 1];
682 //unsigned char g = in[2 * i + 1];
683 //unsigned char b = in[2 * i + 1];
684 out[i++] = LCD_RGBPACK(c,c,c);
685 }
686 }
687 break;
688 default:
689 return 31;
690 }
691 }
692 else if (infoIn->bitDepth == 16)
693 {
694 switch (infoIn->colorType)
695 {
696 case 0: /*greyscale color*/
697 i = 0;
698 for (y = 0 ; y < h ; y++) {
699 for (x = 0 ; x < w ; x++) {
700 c = in[i << 1];
701 //unsigned char r = in[2 * i];
702 //unsigned char g = in[2 * i];
703 //unsigned char b = in[2 * i];
704 out[i++] = LCD_RGBPACK(c,c,c);
705 }
706 }
707 break;
708 case 4: /*greyscale with alpha*/
709 i = 0;
710 for (y = 0 ; y < h ; y++) {
711 for (x = 0 ; x < w ; x++) {
712 c = in[i << 2];
713 //unsigned char r = in[4 * i];
714 //unsigned char g = in[4 * i];
715 //unsigned char b = in[4 * i];
716 out[i++] = LCD_RGBPACK(c,c,c);
717 }
718 }
719 break;
720 default:
721 return 31;
722 }
723 }
724 else /*infoIn->bitDepth is less than 8 bit per channel*/
725 {
726 if (infoIn->colorType != 0) return 31; /*colorType 0 is the only greyscale type with < 8 bits per channel*/
727 i = 0;
728 for (y = 0 ; y < h ; y++) {
729 for (x = 0 ; x < w ; x++) {
730 unsigned value = readBitsFromReversedStream(&bp, in, infoIn->bitDepth);
731 value = (value * 255) / ((1 << infoIn->bitDepth) - 1); /*scale value from 0 to 255*/
732 unsigned char r = (unsigned char)value;
733 unsigned char g = (unsigned char)value;
734 unsigned char b = (unsigned char)value;
735 out[i++] = LCD_RGBPACK(r,g,b);
736 }
737 }
738 }
739 }
740 else return 59;
741
742 return 0;
743}
744
745/*Paeth predicter, used by PNG filter type 4*/
746static int paethPredictor(int a, int b, int c)
747{
748 int p = a + b - c;
749 int pa = p > a ? p - a : a - p;
750 int pb = p > b ? p - b : b - p;
751 int pc = p > c ? p - c : c - p;
752
753 if (pa <= pb && pa <= pc) return a;
754 else if (pb <= pc) return b;
755 else return c;
756}
757
758/*shared values used by multiple Adam7 related functions*/
759
760static const unsigned ADAM7_IX[7] = { 0, 4, 0, 2, 0, 1, 0 }; /*x start values*/
761static const unsigned ADAM7_IY[7] = { 0, 0, 4, 0, 2, 0, 1 }; /*y start values*/
762static const unsigned ADAM7_DX[7] = { 8, 8, 4, 4, 2, 2, 1 }; /*x delta values*/
763static const unsigned ADAM7_DY[7] = { 8, 8, 8, 4, 4, 2, 2 }; /*y delta values*/
764
765static 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)
766{
767 /*the passstart values have 8 values: the 8th one actually indicates the byte after the end of the 7th (= last) pass*/
768 unsigned i;
769
770 /*calculate width and height in pixels of each pass*/
771 for (i = 0; i < 7; i++)
772 {
773 passw[i] = (w + ADAM7_DX[i] - ADAM7_IX[i] - 1) / ADAM7_DX[i];
774 passh[i] = (h + ADAM7_DY[i] - ADAM7_IY[i] - 1) / ADAM7_DY[i];
775 if (passw[i] == 0) passh[i] = 0;
776 if (passh[i] == 0) passw[i] = 0;
777 }
778
779 filter_passstart[0] = padded_passstart[0] = passstart[0] = 0;
780 for (i = 0; i < 7; i++)
781 {
782 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)*/
783 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*/
784 passstart[i + 1] = passstart[i] + (passh[i] * passw[i] * bpp + 7) / 8; /*only padded at end of reduced image*/
785 }
786}
787
788/* ////////////////////////////////////////////////////////////////////////// */
789/* / PNG Decoder / */
790/* ////////////////////////////////////////////////////////////////////////// */
791
792/*read the information from the header and store it in the LodePNG_Info. return value is error*/
793void LodePNG_inspect(LodePNG_Decoder* decoder, const unsigned char* in, size_t inlength)
794{
795 if (inlength == 0 || in == 0) { decoder->error = 48; return; } /*the given data is empty*/
796 if (inlength < 29) { decoder->error = 27; return; } /*error: the data length is smaller than the length of the header*/
797
798 /*when decoding a new PNG image, make sure all parameters created after previous decoding are reset*/
799 LodePNG_InfoPng_cleanup(&decoder->infoPng);
800 LodePNG_InfoPng_init(&decoder->infoPng);
801 decoder->error = 0;
802
803 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*/
804 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!*/
805
806 /*read the values given in the header*/
807 decoder->infoPng.width = LodePNG_read32bitInt(&in[16]);
808 decoder->infoPng.height = LodePNG_read32bitInt(&in[20]);
809 decoder->infoPng.color.bitDepth = in[24];
810 decoder->infoPng.color.colorType = in[25];
811 decoder->infoPng.compressionMethod = in[26];
812 decoder->infoPng.filterMethod = in[27];
813 decoder->infoPng.interlaceMethod = in[28];
814
815 unsigned CRC = LodePNG_read32bitInt(&in[29]);
816 unsigned checksum = crc32(0L, &in[12], 17);
817 if (CRC != checksum) { decoder->error = 57; return; }
818
819 if (decoder->infoPng.compressionMethod != 0) { decoder->error = 32; return; } /*error: only compression method 0 is allowed in the specification*/
820 if (decoder->infoPng.filterMethod != 0) { decoder->error = 33; return; } /*error: only filter method 0 is allowed in the specification*/
821 if (decoder->infoPng.interlaceMethod > 1) { decoder->error = 34; return; } /*error: only interlace methods 0 and 1 exist in the specification*/
822
823 decoder->error = checkColorValidity(decoder->infoPng.color.colorType, decoder->infoPng.color.bitDepth);
824}
825
826static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scanline, const unsigned char* precon, size_t bytewidth, unsigned char filterType, size_t length)
827{
828 /*
829 For PNG filter method 0
830 unfilter a PNG image scanline by scanline. when the pixels are smaller than 1 byte, the filter works byte per byte (bytewidth = 1)
831 precon is the previous unfiltered scanline, recon the result, scanline the current one
832 the incoming scanlines do NOT include the filtertype byte, that one is given in the parameter filterType instead
833 recon and scanline MAY be the same memory address! precon must be disjoint.
834 */
835
836 size_t i;
837 switch (filterType)
838 {
839 case 0:
840 //for(i = 0; i < length; i++) recon[i] = scanline[i];
841 memcpy(recon, scanline, length * sizeof(unsigned char));
842 break;
843 case 1:
844 //for(i = 0; i < bytewidth; i++) recon[i] = scanline[i];
845 memcpy(recon, scanline, bytewidth * sizeof(unsigned char));
846 for (i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth];
847 break;
848 case 2:
849 if (precon) for (i = 0; i < length; i++) recon[i] = scanline[i] + precon[i];
850 else //for(i = 0; i < length; i++) recon[i] = scanline[i];
851 memcpy(recon, scanline, length * sizeof(unsigned char));
852 break;
853 case 3:
854 if (precon)
855 {
856 for (i = 0; i < bytewidth; i++) recon[i] = scanline[i] + precon[i] / 2;
857 for (i = bytewidth; i < length; i++) recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) / 2);
858 }
859 else
860 {
861 //for(i = 0; i < bytewidth; i++) recon[i] = scanline[i];
862 memcpy(recon, scanline, bytewidth * sizeof(unsigned char));
863 for (i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth] / 2;
864 }
865 break;
866 case 4:
867 if (precon)
868 {
869 for (i = 0; i < bytewidth; i++) recon[i] = (unsigned char)(scanline[i] + paethPredictor(0, precon[i], 0));
870 for (i = bytewidth; i < length; i++) recon[i] = (unsigned char)(scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth]));
871 }
872 else
873 {
874 //for(i = 0; i < bytewidth; i++) recon[i] = scanline[i];
875 memcpy(recon, scanline, bytewidth * sizeof(unsigned char));
876 for (i = bytewidth; i < length; i++) recon[i] = (unsigned char)(scanline[i] + paethPredictor(recon[i - bytewidth], 0, 0));
877 }
878 break;
879 default:
880 return 36; /*error: unexisting filter type given*/
881 }
882 return 0;
883}
884
885static unsigned unfilter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp)
886{
887 /*
888 For PNG filter method 0
889 this function unfilters a single image (e.g. without interlacing this is called once, with Adam7 it's called 7 times)
890 out must have enough bytes allocated already, in must have the scanlines + 1 filtertype byte per scanline
891 w and h are image dimensions or dimensions of reduced image, bpp is bits per pixel
892 in and out are allowed to be the same memory address!
893 */
894
895 unsigned y;
896 unsigned char* prevline = 0;
897
898 size_t bytewidth = (bpp + 7) / 8; /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/
899 size_t linebytes = (w * bpp + 7) / 8;
900
901 for (y = 0; y < h; y++)
902 {
903 size_t outindex = linebytes * y;
904 size_t inindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/
905 unsigned char filterType = in[inindex];
906
907 unsigned error = unfilterScanline(&out[outindex], &in[inindex + 1], prevline, bytewidth, filterType, linebytes);
908 if (error) return error;
909
910 prevline = &out[outindex];
911 }
912
913 return 0;
914}
915
916static void Adam7_deinterlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp)
917{
918 /*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
919 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)*/
920 unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8];
921 unsigned i;
922
923 Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp);
924
925 if (bpp >= 8)
926 {
927 for (i = 0; i < 7; i++)
928 {
929 unsigned x, y, b;
930 size_t bytewidth = bpp / 8;
931 for (y = 0; y < passh[i]; y++)
932 for (x = 0; x < passw[i]; x++)
933 {
934 size_t pixelinstart = passstart[i] + (y * passw[i] + x) * bytewidth;
935 size_t pixeloutstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth;
936 for (b = 0; b < bytewidth; b++)
937 {
938 out[pixeloutstart + b] = in[pixelinstart + b];
939 }
940 }
941 }
942 }
943 else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/
944 {
945 for (i = 0; i < 7; i++)
946 {
947 unsigned x, y, b;
948 unsigned ilinebits = bpp * passw[i];
949 unsigned olinebits = bpp * w;
950 size_t obp, ibp; /*bit pointers (for out and in buffer)*/
951 for (y = 0; y < passh[i]; y++)
952 for (x = 0; x < passw[i]; x++)
953 {
954 ibp = (8 * passstart[i]) + (y * ilinebits + x * bpp);
955 obp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp;
956 for (b = 0; b < bpp; b++)
957 {
958 unsigned char bit = readBitFromReversedStream(&ibp, in);
959 setBitOfReversedStream0(&obp, out, bit); /*note that this function assumes the out buffer is completely 0, use setBitOfReversedStream otherwise*/
960 }
961 }
962 }
963 }
964}
965
966static void removePaddingBits(unsigned char* out, const unsigned char* in, size_t olinebits, size_t ilinebits, unsigned h)
967{
968 /*
969 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.
970 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
971 also used to move bits after earlier such operations happened, e.g. in a sequence of reduced images from Adam7
972 only useful if (ilinebits - olinebits) is a value in the range 1..7
973 */
974 unsigned y;
975 size_t diff = ilinebits - olinebits;
976 size_t obp = 0, ibp = 0; /*bit pointers*/
977 for (y = 0; y < h; y++)
978 {
979 size_t x;
980 for (x = 0; x < olinebits; x++)
981 {
982 unsigned char bit = readBitFromReversedStream(&ibp, in);
983 setBitOfReversedStream(&obp, out, bit);
984 }
985 ibp += diff;
986 }
987}
988
989/*out must be buffer big enough to contain full image, and in must contain the full decompressed data from the IDAT chunks*/
990static unsigned postProcessScanlines(unsigned char* out, unsigned char* in, const LodePNG_Decoder* decoder) /*return value is error*/
991{
992 /*
993 This function converts the filtered-padded-interlaced data into pure 2D image buffer with the PNG's colortype. Steps:
994 *) if no Adam7: 1) unfilter 2) remove padding bits (= posible extra bits per scanline if bpp < 8)
995 *) if adam7: 1) 7x unfilter 2) 7x remove padding bits 3) Adam7_deinterlace
996 NOTE: the in buffer will be overwritten with intermediate data!
997 */
998 unsigned bpp = LodePNG_InfoColor_getBpp(&decoder->infoPng.color);
999 unsigned w = decoder->infoPng.width;
1000 unsigned h = decoder->infoPng.height;
1001 unsigned error = 0;
1002 if (bpp == 0) return 31; /*error: invalid colortype*/
1003
1004 if (decoder->infoPng.interlaceMethod == 0)
1005 {
1006 if (bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8)
1007 {
1008 error = unfilter(in, in, w, h, bpp);
1009 if (error) return error;
1010 removePaddingBits(out, in, w * bpp, ((w * bpp + 7) / 8) * 8, h);
1011 }
1012 else error = unfilter(out, in, w, h, bpp); /*we can immediatly filter into the out buffer, no other steps needed*/
1013 }
1014 else /*interlaceMethod is 1 (Adam7)*/
1015 {
1016 unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8];
1017 unsigned i;
1018
1019 Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp);
1020
1021 for (i = 0; i < 7; i++)
1022 {
1023 error = unfilter(&in[padded_passstart[i]], &in[filter_passstart[i]], passw[i], passh[i], bpp);
1024 if (error) return error;
1025 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*/
1026 {
1027 /*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*/
1028 removePaddingBits(&in[passstart[i]], &in[padded_passstart[i]], passw[i] * bpp, ((passw[i] * bpp + 7) / 8) * 8, passh[i]);
1029 }
1030 }
1031
1032 Adam7_deinterlace(out, in, w, h, bpp);
1033 }
1034
1035 return error;
1036}
1037
1038/*read a PNG, the result will be in the same color type as the PNG (hence "generic")*/
1039static void decodeGeneric(LodePNG_Decoder* decoder, unsigned char* in, size_t size, void (*pf_progress)(int current, int total))
1040{
1041 if (pf_progress != NULL)
1042 pf_progress(0, 100);
1043 unsigned char IEND = 0;
1044 const unsigned char* chunk;
1045 size_t i;
1046 unsigned char *idat = memory;
1047 size_t idat_size = 0;
1048
1049 /*for unknown chunk order*/
1050 unsigned unknown = 0;
1051 unsigned critical_pos = 1; /*1 = after IHDR, 2 = after PLTE, 3 = after IDAT*/
1052
1053 /*provide some proper output values if error will happen*/
1054 decoded_image_size = 0;
1055
1056if (size == 0 || in == 0) { decoder->error = 48; return; } /*the given data is empty*/
1057
1058 LodePNG_inspect(decoder, in, size); /*reads header and resets other parameters in decoder->infoPng*/
1059 if (decoder->error) return;
1060
1061 chunk = &in[33]; /*first byte of the first chunk after the header*/
1062
1063 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*/
1064 {
1065 unsigned chunkLength;
1066 const unsigned char* data; /*the data in the chunk*/
1067
1068 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*/
1069 chunkLength = LodePNG_chunk_length(chunk); /*length of the data of the chunk, excluding the length bytes, chunk type and CRC bytes*/
1070 if (chunkLength > 2147483647) { decoder->error = 63; break; }
1071 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*/
1072 data = LodePNG_chunk_data_const(chunk);
1073
1074 /*IDAT chunk, containing compressed image data*/
1075 if (LodePNG_chunk_type_equals(chunk, "IDAT"))
1076 {
1077 size_t oldsize = idat_size;
1078 idat_size += chunkLength;
1079 if (idat + idat_size >= image) { decoder->error = OUT_OF_MEMORY; break; }
1080 memcpy(idat+oldsize, data, chunkLength * sizeof(unsigned char));
1081 critical_pos = 3;
1082 }
1083 /*IEND chunk*/
1084 else if (LodePNG_chunk_type_equals(chunk, "IEND"))
1085 {
1086 IEND = 1;
1087 }
1088 /*palette chunk (PLTE)*/
1089 else if (LodePNG_chunk_type_equals(chunk, "PLTE"))
1090 {
1091 unsigned pos = 0;
1092 decoder->infoPng.color.palettesize = chunkLength / 3;
1093 if (decoder->infoPng.color.palettesize > 256) { decoder->error = 38; break; } /*error: palette too big*/
1094 for (i = 0; i < decoder->infoPng.color.palettesize; i++)
1095 {
1096 decoder->infoPng.color.palette[4 * i + 0] = data[pos++]; /*R*/
1097 decoder->infoPng.color.palette[4 * i + 1] = data[pos++]; /*G*/
1098 decoder->infoPng.color.palette[4 * i + 2] = data[pos++]; /*B*/
1099 decoder->infoPng.color.palette[4 * i + 3] = 255; /*alpha*/
1100 }
1101 critical_pos = 2;
1102 }
1103 /*palette transparency chunk (tRNS)*/
1104 else if (LodePNG_chunk_type_equals(chunk, "tRNS"))
1105 {
1106 if (decoder->infoPng.color.colorType == 3)
1107 {
1108 if (chunkLength > decoder->infoPng.color.palettesize) { decoder->error = 39; break; } /*error: more alpha values given than there are palette entries*/
1109 for (i = 0; i < chunkLength; i++) decoder->infoPng.color.palette[4 * i + 3] = data[i];
1110 }
1111 else if (decoder->infoPng.color.colorType == 0)
1112 {
1113 if (chunkLength != 2) { decoder->error = 40; break; } /*error: this chunk must be 2 bytes for greyscale image*/
1114 decoder->infoPng.color.key_defined = 1;
1115 decoder->infoPng.color.key_r = decoder->infoPng.color.key_g = decoder->infoPng.color.key_b = 256 * data[0] + data[1];
1116 }
1117 else if (decoder->infoPng.color.colorType == 2)
1118 {
1119 if (chunkLength != 6) { decoder->error = 41; break; } /*error: this chunk must be 6 bytes for RGB image*/
1120 decoder->infoPng.color.key_defined = 1;
1121 decoder->infoPng.color.key_r = 256 * data[0] + data[1];
1122 decoder->infoPng.color.key_g = 256 * data[2] + data[3];
1123 decoder->infoPng.color.key_b = 256 * data[4] + data[5];
1124 }
1125 else { decoder->error = 42; break; } /*error: tRNS chunk not allowed for other color models*/
1126 }
1127 /*background color chunk (bKGD)*/
1128 else if (LodePNG_chunk_type_equals(chunk, "bKGD"))
1129 {
1130 if (decoder->infoPng.color.colorType == 3)
1131 {
1132 if (chunkLength != 1) { decoder->error = 43; break; } /*error: this chunk must be 1 byte for indexed color image*/
1133 decoder->infoPng.background_defined = 1;
1134 decoder->infoPng.background_r = decoder->infoPng.background_g = decoder->infoPng.background_g = data[0];
1135 }
1136 else if (decoder->infoPng.color.colorType == 0 || decoder->infoPng.color.colorType == 4)
1137 {
1138 if (chunkLength != 2) { decoder->error = 44; break; } /*error: this chunk must be 2 bytes for greyscale image*/
1139 decoder->infoPng.background_defined = 1;
1140 decoder->infoPng.background_r = decoder->infoPng.background_g = decoder->infoPng.background_b = 256 * data[0] + data[1];
1141 }
1142 else if (decoder->infoPng.color.colorType == 2 || decoder->infoPng.color.colorType == 6)
1143 {
1144 if (chunkLength != 6) { decoder->error = 45; break; } /*error: this chunk must be 6 bytes for greyscale image*/
1145 decoder->infoPng.background_defined = 1;
1146 decoder->infoPng.background_r = 256 * data[0] + data[1];
1147 decoder->infoPng.background_g = 256 * data[2] + data[3];
1148 decoder->infoPng.background_b = 256 * data[4] + data[5];
1149 }
1150 }
1151 else if (LodePNG_chunk_type_equals(chunk, "tIME"))
1152 {
1153 if (chunkLength != 7) { decoder->error = 73; break; }
1154 decoder->infoPng.time_defined = 1;
1155 decoder->infoPng.time.year = 256 * data[0] + data[+ 1];
1156 decoder->infoPng.time.month = data[2];
1157 decoder->infoPng.time.day = data[3];
1158 decoder->infoPng.time.hour = data[4];
1159 decoder->infoPng.time.minute = data[5];
1160 decoder->infoPng.time.second = data[6];
1161 }
1162 else if (LodePNG_chunk_type_equals(chunk, "pHYs"))
1163 {
1164 if (chunkLength != 9) { decoder->error = 74; break; }
1165 decoder->infoPng.phys_defined = 1;
1166 decoder->infoPng.phys_x = 16777216 * data[0] + 65536 * data[1] + 256 * data[2] + data[3];
1167 decoder->infoPng.phys_y = 16777216 * data[4] + 65536 * data[5] + 256 * data[6] + data[7];
1168 decoder->infoPng.phys_unit = data[8];
1169 }
1170 else /*it's not an implemented chunk type, so ignore it: skip over the data*/
1171 {
1172 if (LodePNG_chunk_critical(chunk)) { decoder->error = 69; break; } /*error: unknown critical chunk (5th bit of first byte of chunk type is 0)*/
1173 unknown = 1;
1174 }
1175
1176 if (!unknown) /*check CRC if wanted, only on known chunk types*/
1177 {
1178 long time = *rb->current_tick;
1179 if (LodePNG_chunk_check_crc(chunk)) { decoder->error = 57; break; }
1180 time = *rb->current_tick-time;
1181 }
1182
1183 if (!IEND) chunk = LodePNG_chunk_next_const(chunk);
1184 }
1185
1186 if (!decoder->error)
1187 {
1188 unsigned char *scanlines = idat + idat_size;
1189 size_t scanlines_size = (size_t)memory_max - idat_size;
1190 long time = *rb->current_tick;
1191 decoder->error = LodePNG_decompress(scanlines, &scanlines_size, idat, idat_size, decoder->error_msg); /*decompress with the Zlib decompressor*/
1192 if (pf_progress) pf_progress(100, 100);
1193 time = *rb->current_tick-time;
1194
1195 if (!decoder->error)
1196 {
1197 decoded_image_size = (decoder->infoPng.height * decoder->infoPng.width * LodePNG_InfoColor_getBpp(&decoder->infoPng.color) + 7) / 8;
1198 if (decoded_image_size > memory_size) { decoder->error = OUT_OF_MEMORY; return; }
1199 decoded_image = memory_max - decoded_image_size;
1200 if (scanlines + scanlines_size >= decoded_image) { decoder->error = OUT_OF_MEMORY; return; }
1201 memset(decoded_image, 0, decoded_image_size * sizeof(unsigned char));
1202 if (!running_slideshow)
1203 {
1204 rb->snprintf(print, sizeof(print), "unfiltering scanlines");
1205 rb->lcd_puts(0, 3, print);
1206 rb->lcd_update();
1207 }
1208 decoder->error = postProcessScanlines(decoded_image, scanlines, decoder);
1209 }
1210 }
1211}
1212
1213void LodePNG_decode(LodePNG_Decoder* decoder, unsigned char* in, size_t insize, void (*pf_progress)(int current, int total))
1214{
1215 decodeGeneric(decoder, in, insize, pf_progress);
1216 if (decoder->error) return;
1217
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"*/
1219if (!(decoder->infoRaw.color.colorType == 2 || decoder->infoRaw.color.colorType == 6) && !(decoder->infoRaw.color.bitDepth == 8)) { decoder->error = 56; return; }
1220 converted_image = (fb_data *)((intptr_t)(memory + 3) & ~3);
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);
1224}
1225
1226void LodePNG_DecodeSettings_init(LodePNG_DecodeSettings* settings)
1227{
1228 settings->color_convert = 1;
1229}
1230
1231void LodePNG_Decoder_init(LodePNG_Decoder* decoder)
1232{
1233 LodePNG_DecodeSettings_init(&decoder->settings);
1234 LodePNG_InfoRaw_init(&decoder->infoRaw);
1235 LodePNG_InfoPng_init(&decoder->infoPng);
1236 decoder->error = 1;
1237}
1238
1239void LodePNG_Decoder_cleanup(LodePNG_Decoder* decoder)
1240{
1241 LodePNG_InfoRaw_cleanup(&decoder->infoRaw);
1242 LodePNG_InfoPng_cleanup(&decoder->infoPng);
1243}
1244
1245#define PNG_ERROR_MIN 27
1246#define PNG_ERROR_MAX 74
1247static const unsigned char *png_error_messages[PNG_ERROR_MAX-PNG_ERROR_MIN+1] =
1248{
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*/
1297};
1298
1299bool img_ext(const char *ext)
1300{
1301 if (!ext)
1302 return false;
1303 if (!rb->strcasecmp(ext,".png"))
1304 return true;
1305 else
1306 return false;
1307}
1308
1309void draw_image_rect(struct image_info *info,
1310 int x, int y, int width, int height)
1311{
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);
1317}
1318
1319int img_mem(int ds)
1320{
1321 LodePNG_Decoder *decoder = &_decoder;
1322 return (decoder->infoPng.width/ds) * (decoder->infoPng.height/ds) * FB_DATA_SZ;
1323}
1324
1325int load_image(char *filename, struct image_info *info,
1326 unsigned char *buf, ssize_t *buf_size)
1327{
1328 int fd;
1329 long time = 0; /* measured ticks */
1330 int w, h; /* used to center output */
1331 LodePNG_Decoder *decoder = &_decoder;
1332
1333 memset(&disp, 0, sizeof(disp));
1334 LodePNG_Decoder_init(decoder);
1335
1336 memory = buf;
1337 memory_size = *buf_size;
1338 memory_max = memory + memory_size;
1339
1340 fd = rb->open(filename, O_RDONLY);
1341 if (fd < 0)
1342 {
1343 rb->splashf(HZ, "err opening %s:%d", filename, fd);
1344 return PLUGIN_ERROR;
1345 }
1346 image_size = rb->filesize(fd);
1347
1348 DEBUGF("reading file '%s'\n", filename);
1349
1350 if (!running_slideshow) {
1351 rb->snprintf(print, sizeof(print), "%s:", rb->strrchr(filename,'/')+1);
1352 rb->lcd_puts(0, 0, print);
1353 rb->lcd_update();
1354 }
1355
1356 if (image_size > memory_size) {
1357 decoder->error = FILE_TOO_LARGE;
1358 rb->close(fd);
1359
1360 } else {
1361 if (!running_slideshow) {
1362 rb->snprintf(print, sizeof(print), "loading %lu bytes", image_size);
1363 rb->lcd_puts(0, 1, print);
1364 rb->lcd_update();
1365 }
1366
1367 image = memory_max - image_size;
1368 rb->read(fd, image, image_size);
1369 rb->close(fd);
1370
1371 if (!running_slideshow) {
1372 rb->snprintf(print, sizeof(print), "decoding image");
1373 rb->lcd_puts(0, 2, print);
1374 rb->lcd_update();
1375 }
1376#ifdef DISK_SPINDOWN
1377 else if (immediate_ata_off) {
1378 /* running slideshow and time is long enough: power down disk */
1379 rb->storage_sleep();
1380 }
1381#endif
1382
1383 decoder->settings.color_convert = 1;
1384 decoder->infoRaw.color.colorType = 2;
1385 decoder->infoRaw.color.bitDepth = 8;
1386
1387 LodePNG_inspect(decoder, image, image_size);
1388
1389 if (!decoder->error) {
1390
1391 if (!running_slideshow) {
1392 rb->snprintf(print, sizeof(print), "image %dx%d",
1393 decoder->infoPng.width, decoder->infoPng.height);
1394 rb->lcd_puts(0, 2, print);
1395 rb->lcd_update();
1396
1397 rb->snprintf(print, sizeof(print), "decoding %d*%d",
1398 decoder->infoPng.width, decoder->infoPng.height);
1399 rb->lcd_puts(0, 3, print);
1400 rb->lcd_update();
1401 }
1402
1403 /* the actual decoding */
1404 time = *rb->current_tick;
1405#ifdef HAVE_ADJUSTABLE_CPU_FREQ
1406 rb->cpu_boost(true);
1407 LodePNG_decode(decoder, image, image_size, cb_progress);
1408 rb->cpu_boost(false);
1409#else
1410 LodePNG_decode(decoder, image, image_size, cb_progress);
1411#endif /*HAVE_ADJUSTABLE_CPU_FREQ*/
1412 }
1413 }
1414
1415 time = *rb->current_tick - time;
1416
1417 if (!running_slideshow && !decoder->error)
1418 {
1419 rb->snprintf(print, sizeof(print), " %ld.%02ld sec ", time/HZ, time%HZ);
1420 rb->lcd_getstringsize(print, &w, &h); /* centered in progress bar */
1421 rb->lcd_putsxy((LCD_WIDTH - w)/2, LCD_HEIGHT - h, print);
1422 rb->lcd_update();
1423 }
1424
1425 if (decoder->error) {
1426#if PLUGIN_BUFFER_SIZE >= MIN_MEM
1427 if (plug_buf && (decoder->error == FILE_TOO_LARGE
1428 || decoder->error == OUT_OF_MEMORY || decoder->error == Z_MEM_ERROR))
1429 return PLUGIN_OUTOFMEM;
1430#endif
1431
1432 if (decoder->error >= PNG_ERROR_MIN && decoder->error <= PNG_ERROR_MAX
1433 && png_error_messages[decoder->error-PNG_ERROR_MIN] != NULL)
1434 {
1435 rb->splash(HZ, png_error_messages[decoder->error-PNG_ERROR_MIN]);
1436 }
1437 else
1438 {
1439 switch (decoder->error) {
1440 case PLUGIN_ABORT:
1441 break;
1442 case OUT_OF_MEMORY:
1443 case Z_MEM_ERROR:
1444 rb->splash(HZ, "Out of Memory");break;
1445 case FILE_TOO_LARGE:
1446 rb->splash(HZ, "File too large");break;
1447 case Z_DATA_ERROR:
1448 rb->splash(HZ, decoder->error_msg);break;
1449 default:
1450 rb->splashf(HZ, "other error : %ld", decoder->error);break;
1451 }
1452 }
1453
1454 if (decoder->error == PLUGIN_ABORT)
1455 return PLUGIN_ABORT;
1456 else
1457 return PLUGIN_ERROR;
1458 }
1459
1460 disp_buf = (fb_data *)((intptr_t)(converted_image + converted_image_size + 3) & ~3);
1461 info->x_size = decoder->infoPng.width;
1462 info->y_size = decoder->infoPng.height;
1463 *buf_size = memory_max - (unsigned char*)disp_buf;
1464 return PLUGIN_OK;
1465}
1466
1467int get_image(struct image_info *info, int ds)
1468{
1469 fb_data **p_disp = &disp[ds]; /* short cut */
1470 LodePNG_Decoder *decoder = &_decoder;
1471
1472 info->width = decoder->infoPng.width / ds;
1473 info->height = decoder->infoPng.height / ds;
1474 info->data = p_disp;
1475
1476 if (*p_disp != NULL)
1477 {
1478 /* we still have it */
1479 return PLUGIN_OK;
1480 }
1481
1482 /* assign image buffer */
1483 if (ds > 1) {
1484 if (!running_slideshow)
1485 {
1486 rb->snprintf(print, sizeof(print), "resizing %d*%d",
1487 info->width, info->height);
1488 rb->lcd_puts(0, 3, print);
1489 rb->lcd_update();
1490 }
1491 struct bitmap bmp_src, bmp_dst;
1492
1493 int size = info->width * info->height;
1494
1495 if ((unsigned char *)(disp_buf + size) >= memory_max) {
1496 /* have to discard the current */
1497 int i;
1498 for (i=1; i<=8; i++)
1499 disp[i] = NULL; /* invalidate all bitmaps */
1500 /* start again from the beginning of the buffer */
1501 disp_buf = (fb_data *)((intptr_t)(converted_image + converted_image_size + 3) & ~3);
1502 }
1503
1504 *p_disp = disp_buf;
1505 disp_buf = (fb_data *)((intptr_t)(disp_buf + size + 3) & ~3);
1506
1507 bmp_src.width = decoder->infoPng.width;
1508 bmp_src.height = decoder->infoPng.height;
1509 bmp_src.data = (unsigned char *)converted_image;
1510
1511 bmp_dst.width = info->width;
1512 bmp_dst.height = info->height;
1513 bmp_dst.data = (unsigned char *)*p_disp;
1514#ifdef HAVE_ADJUSTABLE_CPU_FREQ
1515 rb->cpu_boost(true);
1516 smooth_resize_bitmap(&bmp_src, &bmp_dst);
1517 rb->cpu_boost(false);
1518#else
1519 smooth_resize_bitmap(&bmp_src, &bmp_dst);
1520#endif /*HAVE_ADJUSTABLE_CPU_FREQ*/
1521 } else {
1522 *p_disp = converted_image;
1523 }
1524
1525 return PLUGIN_OK;
1526}