summaryrefslogtreecommitdiff
path: root/apps/plugins/imageviewer/png/png_decoder.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/imageviewer/png/png_decoder.c')
-rw-r--r--apps/plugins/imageviewer/png/png_decoder.c2195
1 files changed, 2195 insertions, 0 deletions
diff --git a/apps/plugins/imageviewer/png/png_decoder.c b/apps/plugins/imageviewer/png/png_decoder.c
new file mode 100644
index 0000000000..b09d2e2ece
--- /dev/null
+++ b/apps/plugins/imageviewer/png/png_decoder.c
@@ -0,0 +1,2195 @@
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 * Copyright (c) 2010 Marcin Bukat
16 * - pixel format conversion & transparency handling
17 * - adaptation of tinf (tiny inflate library)
18 * - code refactoring & cleanups
19 *
20 * This program is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU General Public License
22 * as published by the Free Software Foundation; either version 2
23 * of the License, or (at your option) any later version.
24 *
25 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
26 * KIND, either express or implied.
27 *
28 ****************************************************************************/
29
30/*
31LodePNG version 20080927
32
33Copyright (c) 2005-2008 Lode Vandevenne
34
35This software is provided 'as-is', without any express or implied
36warranty. In no event will the authors be held liable for any damages
37arising from the use of this software.
38
39Permission is granted to anyone to use this software for any purpose,
40including commercial applications, and to alter it and redistribute it
41freely, subject to the following restrictions:
42
43 1. The origin of this software must not be misrepresented; you must not
44 claim that you wrote the original software. If you use this software
45 in a product, an acknowledgment in the product documentation would be
46 appreciated but is not required.
47
48 2. Altered source versions must be plainly marked as such, and must not be
49 misrepresented as being the original software.
50
51 3. This notice may not be removed or altered from any source
52 distribution.
53*/
54
55/*
56The manual and changelog can be found in the header file "lodepng.h"
57You are free to name this file lodepng.cpp or lodepng.c depending on your usage.
58*/
59
60/* supported chunk types:
61 * critical:
62 * IHDR
63 * PLTE
64 * IDAT
65 * IEND
66 *
67 * ancillary:
68 * tRNS
69 * bKGD
70 */
71
72#include "plugin.h"
73#include "lcd.h"
74#include <lib/pluginlib_bmp.h>
75#include "tinf.h"
76#include "bmp.h"
77#include "png_decoder.h"
78#if LCD_DEPTH < 8
79#include <lib/grey.h>
80#endif
81
82#ifndef resize_bitmap
83#if defined(HAVE_LCD_COLOR)
84#define resize_bitmap smooth_resize_bitmap
85#else
86#define resize_bitmap grey_resize_bitmap
87#endif
88#endif
89
90static const char *png_error_messages[PNG_ERROR_MAX-PNG_ERROR_MIN+1] =
91{
92 "png file smaller than a png header", /*27*/
93 "incorrect png signature", /*28*/
94 "first chunk is not IHDR", /*29*/
95 "chunk length too large", /*30*/
96 "illegal PNG color type or bpp", /*31*/
97 "illegal PNG compression method", /*32*/
98 "illegal PNG filter method", /*33*/
99 "illegal PNG interlace method", /*34*/
100 "chunk length of a chunk is too large or the chunk too small", /*35*/
101 "illegal PNG filter type encountered", /*36*/
102 "illegal bit depth for this color type given", /*37*/
103 "the palette is too big (more than 256 colors)", /*38*/
104 "more palette alpha values given in tRNS, than there are colors in the palette", /*39*/
105 "tRNS chunk has wrong size for greyscale image", /*40*/
106 "tRNS chunk has wrong size for RGB image", /*41*/
107 "tRNS chunk appeared while it was not allowed for this color type", /*42*/
108 "bKGD chunk has wrong size for palette image", /*43*/
109 "bKGD chunk has wrong size for greyscale image", /*44*/
110 "bKGD chunk has wrong size for RGB image", /*45*/
111 "value encountered in indexed image is larger than the palette size", /*46*/
112 "value encountered in indexed image is larger than the palette size", /*47*/
113 "input file is empty", /*48*/
114 NULL, /*49*/
115 NULL, /*50*/
116 NULL, /*51*/
117 NULL, /*52*/
118 NULL, /*53*/
119 NULL, /*54*/
120 NULL, /*55*/
121 NULL, /*56*/
122 "invalid CRC", /*57*/
123 NULL, /*58*/
124 "conversion to unexisting or unsupported color type or bit depth", /*59*/
125 NULL, /*60*/
126 NULL, /*61*/
127 NULL, /*62*/
128 "png chunk too long", /*63*/
129 NULL, /*64*/
130 NULL, /*65*/
131 NULL, /*66*/
132 NULL, /*67*/
133 NULL, /*68*/
134 "unknown critical chunk", /*69*/
135 NULL, /*70*/
136 NULL, /*71*/
137 NULL, /*72*/
138 "invalid tIME chunk size", /*73*/
139 "invalid pHYs chunk size", /*74*/
140};
141
142/*
143The two functions below (LodePNG_decompress and LodePNG_compress) directly call the
144LodeZlib_decompress and LodeZlib_compress functions. The only purpose of the functions
145below, is to provide the ability to let LodePNG use a different Zlib encoder by only
146changing the two functions below, instead of changing it inside the vareous places
147in the other LodePNG functions.
148
149*out must be NULL and *outsize must be 0 initially, and after the function is done,
150*out must point to the decompressed data, *outsize must be the size of it, and must
151be the size of the useful data in bytes, not the alloc size.
152*/
153
154static unsigned LodePNG_decompress(unsigned char* out,
155 size_t* outsize,
156 const unsigned char* in,
157 size_t insize)
158{
159 int err;
160 err = tinf_zlib_uncompress((void *)out,
161 (unsigned int*)outsize,
162 (const void*)in,
163 (unsigned int)insize);
164 return err;
165}
166
167/* ////////////////////////////////////////////////////////////////////////// */
168/* / Reading and writing single bits and bytes from/to stream for LodePNG / */
169/* ////////////////////////////////////////////////////////////////////////// */
170
171static unsigned char readBitFromReversedStream(size_t* bitpointer,
172 const unsigned char* bitstream)
173{
174 unsigned char result = (unsigned char)((bitstream[(*bitpointer) >> 3] >>
175 (7 - ((*bitpointer) & 0x7))) & 1);
176 (*bitpointer)++;
177 return result;
178}
179
180static unsigned readBitsFromReversedStream(size_t* bitpointer,
181 const unsigned char* bitstream,
182 size_t nbits)
183{
184 unsigned result = 0;
185 size_t i;
186 for (i = nbits - 1; i < nbits; i--)
187 result += (unsigned)readBitFromReversedStream(bitpointer, bitstream)<<i;
188
189 return result;
190}
191
192static void setBitOfReversedStream0(size_t* bitpointer,
193 unsigned char* bitstream,
194 unsigned char bit)
195{
196 /* the current bit in bitstream must be 0 for this to work
197 * earlier bit of huffman code is in a lesser significant bit
198 * of an earlier byte
199 */
200 if (bit)
201 bitstream[(*bitpointer) >> 3] |= (bit << (7 - ((*bitpointer) & 0x7)));
202
203 (*bitpointer)++;
204}
205
206static void setBitOfReversedStream(size_t* bitpointer,
207 unsigned char* bitstream,
208 unsigned char bit)
209{
210 /* the current bit in bitstream may be 0 or 1 for this to work */
211 if (bit == 0)
212 bitstream[(*bitpointer) >> 3] &=
213 (unsigned char)(~(1 << (7 - ((*bitpointer) & 0x7))));
214 else
215 bitstream[(*bitpointer) >> 3] |= (1 << (7 - ((*bitpointer) & 0x7)));
216
217 (*bitpointer)++;
218}
219
220/* ////////////////////////////////////////////////////////////////////////// */
221/* / PNG chunks / */
222/* ////////////////////////////////////////////////////////////////////////// */
223
224/* get the length of the data of the chunk.
225 * Total chunk length has 12 bytes more.
226 */
227static unsigned LodePNG_chunk_length(const uint8_t* chunk)
228{
229 return chunk[0]<<24|chunk[1]<<16|chunk[2]<<8|chunk[3];
230}
231
232/* check if the type is the given type */
233static bool LodePNG_chunk_type_equals(const uint8_t* chunk, uint32_t type)
234{
235 /* chunk type field: A 4-byte chunk type code. For convenience in
236 * description and in examining PNG files, type codes are restricted
237 * to consist of uppercase and lowercase ASCII letters
238 * (A-Z and a-z, or 65-90 and 97-122 decimal). However, encoders and
239 * decoders must treat the codes as fixed binary values, not character
240 * strings."
241 */
242 return ((uint32_t)(chunk[4]<<24|chunk[5]<<16|chunk[6]<<8|chunk[7]) == (uint32_t)type);
243}
244
245/* properties of PNG chunks gotten from capitalization of chunk type name,
246 * as defined by the standard
247 * 0: ancillary chunk
248 * 1: critical chunk type
249 */
250static inline bool LodePNG_chunk_critical(const uint8_t* chunk)
251{
252 return((chunk[4] & 32) == 0);
253}
254
255/* 0: public, 1: private */
256static inline bool LodePNG_chunk_private(const uint8_t* chunk)
257{
258 return((chunk[6] & 32) != 0);
259}
260
261/* get pointer to the data of the chunk */
262static inline const uint8_t* LodePNG_chunk_data(const uint8_t* chunk)
263{
264 return &chunk[8];
265}
266
267/* returns 0 if the crc is correct, error code if it's incorrect */
268static bool LodePNG_chunk_check_crc(const uint8_t* chunk)
269{
270 uint32_t length = LodePNG_chunk_length(chunk);
271 uint32_t crc = chunk[length + 8]<<24|chunk[length + 8 + 1]<<16|
272 chunk[length + 8 + 2]<<8|chunk[length + 8 + 3];
273
274 /* the CRC is taken of the data and the 4 chunk type letters,
275 * not the length
276 */
277 uint32_t checksum = tinf_crc32(chunk + 4, length + 4);
278 return (crc == checksum);
279}
280
281/* don't use on IEND chunk, as there is no next chunk then */
282static const uint8_t* LodePNG_chunk_next(const uint8_t* chunk)
283{
284 uint32_t total_chunk_length = LodePNG_chunk_length(chunk) + 12;
285 return &chunk[total_chunk_length];
286}
287
288/* ////////////////////////////////////////////////////////////////////////// */
289/* / Color types and such / */
290/* ////////////////////////////////////////////////////////////////////////// */
291
292/* return type is a LodePNG error code
293 * bd - bit depth
294 */
295static uint8_t checkColorValidity(uint8_t colorType, uint8_t bd)
296{
297 switch (colorType)
298 {
299 case PNG_COLORTYPE_GREY:
300 if (!(bd == 1 || bd == 2 ||
301 bd == 4 || bd == 8 ||
302 bd == 16))
303 return 37;
304 break; /*grey*/
305
306 case PNG_COLORTYPE_RGB:
307 if (!(bd == 8 || bd == 16))
308 return 37;
309 break; /*RGB*/
310
311 case PNG_COLORTYPE_PALETTE:
312 if (!(bd == 1 || bd == 2 ||
313 bd == 4 || bd == 8 ))
314 return 37;
315 break; /*palette*/
316
317 case PNG_COLORTYPE_GREYA:
318 if (!( bd == 8 || bd == 16 ))
319 return 37;
320 break; /*grey + alpha*/
321
322 case PNG_COLORTYPE_RGBA:
323 if (!( bd == 8 || bd == 16 ))
324 return 37;
325 break; /*RGBA*/
326
327 default:
328 return 31;
329 }
330 return 0; /*allowed color type / bits combination*/
331}
332
333static uint8_t getNumColorChannels(uint8_t colorType)
334{
335 switch (colorType)
336 {
337 case PNG_COLORTYPE_GREY:
338 return 1; /*grey*/
339 case PNG_COLORTYPE_RGB:
340 return 3; /*RGB*/
341 case PNG_COLORTYPE_PALETTE:
342 return 1; /*palette*/
343 case PNG_COLORTYPE_GREYA:
344 return 2; /*grey + alpha*/
345 case PNG_COLORTYPE_RGBA:
346 return 4; /*RGBA*/
347 }
348 return 0; /*unexisting color type*/
349}
350
351static uint8_t getBpp(uint8_t colorType, uint8_t bitDepth)
352{
353 /* bits per pixel is amount of channels * bits per channel */
354 return getNumColorChannels(colorType) * bitDepth;
355}
356
357static void LodePNG_InfoColor_init(LodePNG_InfoColor* info)
358{
359 info->key_defined = 0;
360 info->key_r = info->key_g = info->key_b = 0;
361 info->colorType = PNG_COLORTYPE_RGBA;
362 info->bitDepth = 8;
363 memset(info->palette, 0, 256 * 4 * sizeof(unsigned char));
364 info->palettesize = 0;
365}
366
367static void LodePNG_InfoColor_cleanup(LodePNG_InfoColor* info)
368{
369 info->palettesize = 0;
370}
371
372static void LodePNG_InfoPng_init(LodePNG_InfoPng* info)
373{
374 info->width = info->height = 0;
375 LodePNG_InfoColor_init(&info->color);
376 info->interlaceMethod = 0;
377 info->compressionMethod = 0;
378 info->filterMethod = 0;
379#ifdef HAVE_LCD_COLOR
380 info->background_r = info->background_g = info->background_b = 0;
381#else
382 info->background_r = info->background_g = info->background_b = 255;
383#endif
384}
385
386void LodePNG_InfoPng_cleanup(LodePNG_InfoPng* info)
387{
388 LodePNG_InfoColor_cleanup(&info->color);
389}
390
391/*
392 * Convert from every colortype to rockbox native pixel format (color targets) or
393 * greylib pixel format (grey targets)
394 */
395static void LodePNG_convert(LodePNG_Decoder *decoder)
396{
397
398 LodePNG_InfoPng *infoIn = &decoder->infoPng;
399 const uint8_t *in = decoder->decoded_img;
400 uint8_t *out = decoder->buf;
401 uint16_t w = infoIn->width;
402 uint16_t h = infoIn->height;
403 size_t i, j, bp = 0; /*bitpointer, used by less-than-8-bit color types*/
404 size_t x, y;
405 uint16_t value, alpha, alpha_complement;
406
407 /* line buffer for pixel format transformation */
408#ifdef HAVE_LCD_COLOR
409 struct uint8_rgb *line_buf = (struct uint8_rgb *)(out + w * h * FB_DATA_SZ);
410#else
411 uint8_t *line_buf = (unsigned char *)(out + w * h * FB_DATA_SZ);
412#endif
413
414 struct bitmap bm = {
415 .width = w,
416 .height = h,
417 .data = (unsigned char*)out,
418 };
419
420 struct scaler_context ctx = {
421 .bm = &bm,
422 .dither = 0,
423 };
424
425#if LCD_DEPTH < 8
426 const struct custom_format *cformat = &format_grey;
427#else
428 const struct custom_format *cformat = &format_native;
429#endif
430
431void (*output_row_8)(uint32_t, void*, struct scaler_context*) = cformat->output_row_8;
432
433#ifdef HAVE_LCD_COLOR
434struct uint8_rgb *pixel;
435#else
436unsigned char *pixel;
437#endif
438
439#ifdef HAVE_LCD_COLOR
440 if (infoIn->color.bitDepth == 8)
441 {
442 switch (infoIn->color.colorType)
443 {
444 case PNG_COLORTYPE_GREY: /*greyscale color*/
445 i = 0;
446 for (y = 0 ; y < h ; y++) {
447 /* reset line buf */
448 pixel = line_buf;
449
450 for (x = 0; x < w ; x++) {
451 value = in[i++];
452 if (infoIn->color.key_defined)
453 if ( (uint8_t)value == (uint8_t)infoIn->color.key_r )
454 value = infoIn->background_r; /* full transparent */
455
456 pixel->red = (uint8_t)value;
457 pixel->green = (uint8_t)value;
458 pixel->blue = (uint8_t)value;
459 pixel++;
460 }
461 output_row_8(y,(void *)line_buf,&ctx);
462 }
463 break;
464 case PNG_COLORTYPE_RGB: /*RGB color*/
465 i = 0;
466 for (y = 0 ; y < h ; y++) {
467 pixel = line_buf;
468 for (x = 0 ; x < w ; x++) {
469 j = 3*i++;
470
471 /* tRNs & bKGD */
472 if (infoIn->color.key_defined &&
473 in[j] == (uint8_t)infoIn->color.key_r &&
474 in[j + 1] == (uint8_t)infoIn->color.key_g &&
475 in[j + 2] == (uint8_t)infoIn->color.key_b)
476 {
477 pixel->red = (uint8_t)infoIn->background_r;
478 pixel->green = (uint8_t)infoIn->background_g;
479 pixel->blue = (uint8_t)infoIn->background_b;
480 }
481 else
482 {
483 pixel->red = in[j];
484 pixel->green = in[j + 1];
485 pixel->blue = in[j + 2];
486 }
487 pixel++;
488 }
489 output_row_8(y,(void *)line_buf,&ctx);
490 }
491 break;
492 case PNG_COLORTYPE_PALETTE: /*indexed color (palette)*/
493 i = 0;
494 for (y = 0 ; y < h ; y++) {
495 /* reset line buf */
496 pixel = line_buf;
497 for (x = 0 ; x < w ; x++) {
498 if (in[i] >= infoIn->color.palettesize)
499 {
500 decoder->error = 46;
501 return;
502 }
503
504 j = in[i++]<<2;
505 alpha = infoIn->color.palette[j + 3];
506 alpha_complement = (256 - alpha);
507
508 /* tRNS and bKGD */
509 pixel->red = (infoIn->color.palette[j] * alpha +
510 alpha_complement*infoIn->background_r)>>8;
511 pixel->green = (infoIn->color.palette[j + 1] * alpha +
512 alpha_complement*infoIn->background_g)>>8;
513 pixel->blue = (infoIn->color.palette[j + 2] * alpha +
514 alpha_complement*infoIn->background_b)>>8;
515 pixel++;
516 }
517 output_row_8(y,(void *)(line_buf),&ctx);
518 }
519 break;
520 case PNG_COLORTYPE_GREYA: /*greyscale with alpha*/
521 i = 0;
522 for (y = 0 ; y < h ; y++) {
523 pixel = line_buf;
524 for (x = 0 ; x < w ; x++) {
525 alpha = in[(i << 1) + 1];
526 alpha_complement = (256 - alpha)*infoIn->background_r;
527 value = (alpha * in[i++ << 1] + alpha_complement)>>8;
528 pixel->red = (uint8_t)(value);
529 pixel->green = (uint8_t)value;
530 pixel->blue = (uint8_t)value;
531 pixel++;
532 }
533 output_row_8(y,(void *)line_buf,&ctx);
534 }
535 break;
536 case PNG_COLORTYPE_RGBA: /*RGB with alpha*/
537 i = 0;
538 for (y = 0 ; y < h ; y++) {
539 pixel = line_buf;
540 for (x = 0 ; x < w ; x++) {
541 j = i++ << 2;
542 alpha = in[j + 3];
543 alpha_complement = (256 - alpha);
544 pixel->red = (in[j] * alpha +
545 alpha_complement*infoIn->background_r)>>8;
546 pixel->green = (in[j + 1] * alpha +
547 alpha_complement*infoIn->background_g)>>8;
548 pixel->blue = (in[j + 2] * alpha +
549 alpha_complement*infoIn->background_b)>>8;
550 pixel++;
551 }
552 output_row_8(y,(void *)line_buf,&ctx);
553 }
554 break;
555 default:
556 break;
557 }
558 }
559 else if (infoIn->color.bitDepth == 16)
560 {
561 switch (infoIn->color.colorType)
562 {
563 case PNG_COLORTYPE_GREY: /*greyscale color*/
564 i = 0;
565 for (y = 0 ; y < h ; y++) {
566 pixel = line_buf;
567 for (x = 0 ; x < w ; x++) {
568 value = (in[i<<1]<<8)|in[(i << 1) + 1];
569 i++;
570
571 /* tRNS and bKGD */
572 if (infoIn->color.key_defined &&
573 value == infoIn->color.key_r)
574 value = infoIn->background_r<<8;
575
576 pixel->red =
577 pixel->green =
578 pixel->blue = (uint8_t)(value>>8);
579 pixel++;
580 }
581 output_row_8(y,(void *)line_buf,&ctx);
582 }
583 break;
584 case PNG_COLORTYPE_RGB: /*RGB color*/
585 i = 0;
586 for (y = 0 ; y < h ; y++) {
587 pixel = line_buf;
588 for (x = 0 ; x < w ; x++) {
589 j = 6 * i++;
590
591 /* tRNS and bKGD */
592 if (infoIn->color.key_defined &&
593 ((uint16_t)(in[j]<<8|in[j + 1]) ==
594 infoIn->color.key_r) &&
595 ((uint16_t)(in[j + 2]<<8|in[j + 3]) ==
596 infoIn->color.key_g) &&
597 ((uint16_t)(in[j + 4]<<8|in[j + 5]) ==
598 infoIn->color.key_b))
599 {
600 pixel->red = (uint8_t)infoIn->background_r;
601 pixel->green = (uint8_t)infoIn->background_g;
602 pixel->blue = (uint8_t)infoIn->background_b;
603 }
604 else
605 {
606 pixel->red = in[j];
607 pixel->green = in[j + 2];
608 pixel->blue = in[j + 4];
609 }
610 pixel++;
611 }
612 output_row_8(y,(void *)line_buf,&ctx);
613 }
614 break;
615 case PNG_COLORTYPE_GREYA: /*greyscale with alpha*/
616 i = 0;
617 for (y = 0 ; y < h ; y++) {
618 pixel = line_buf;
619 for (x = 0 ; x < w ; x++) {
620 alpha = in[(i << 2) + 2];
621 alpha_complement = (256-alpha)*infoIn->background_r;
622 value = (in[i++ << 2] * alpha + alpha_complement)>>8;
623 pixel->red = (uint8_t)value;
624 pixel->green = (uint8_t)value;
625 pixel->blue = (uint8_t)value;
626 pixel++;
627 }
628 output_row_8(y,(void *)line_buf,&ctx);
629 }
630 break;
631 case PNG_COLORTYPE_RGBA: /*RGB with alpha*/
632 i = 0;
633 for (y = 0 ; y < h ; y++) {
634 pixel = line_buf;
635 for (x = 0 ; x < w ; x++) {
636 j = i++ << 3;
637 alpha = in[j + 6];
638 alpha_complement = (256-alpha);
639 pixel->red = (in[j] * alpha +
640 alpha_complement*infoIn->background_r)>>8;
641 pixel->green = (in[j + 2] * alpha +
642 alpha_complement*infoIn->background_g)>>8;
643 pixel->blue = (in[j + 4] * alpha +
644 alpha_complement*infoIn->background_b)>>8;
645 pixel++;
646 }
647 output_row_8(y,(void *)line_buf,&ctx);
648 }
649 break;
650 default:
651 break;
652 }
653 }
654 else /*infoIn->bitDepth is less than 8 bit per channel*/
655 {
656 switch (infoIn->color.colorType)
657 {
658 case PNG_COLORTYPE_GREY: /*greyscale color*/
659 i = 0;
660 for (y = 0 ; y < h ; y++) {
661 pixel = line_buf;
662 for (x = 0 ; x < w ; x++) {
663 value = readBitsFromReversedStream(&bp, in, infoIn->color.bitDepth);
664
665 /* tRNS and bKGD */
666 if (infoIn->color.key_defined)
667 if ( value == infoIn->color.key_r )
668 value = infoIn->background_r; /* full transparent */
669
670 /* scale value from 0 to 255 */
671 value = (value * 255) / ((1 << infoIn->color.bitDepth) - 1);
672
673 pixel->red = (uint8_t)value;
674 pixel->green = (uint8_t)value;
675 pixel->blue = (uint8_t)value;
676 pixel++;
677 }
678 output_row_8(y,(void *)line_buf,&ctx);
679 }
680 break;
681 case PNG_COLORTYPE_PALETTE: /*indexed color (palette)*/
682 i = 0;
683 for (y = 0 ; y < h ; y++) {
684 pixel = line_buf;
685 for (x = 0 ; x < w ; x++) {
686 value = readBitsFromReversedStream(&bp, in, infoIn->color.bitDepth);
687 if (value >= infoIn->color.palettesize)
688 {
689 decoder->error = 47;
690 return;
691 }
692
693 j = value << 2;
694
695 /* tRNS and bKGD */
696 alpha = infoIn->color.palette[j + 3];
697 alpha_complement = (256 - alpha);
698 pixel->red = (alpha * infoIn->color.palette[j] +
699 alpha_complement*infoIn->background_r)>>8;
700 pixel->green = (alpha * infoIn->color.palette[j + 1] +
701 alpha_complement*infoIn->background_g)>>8;
702 pixel->blue = (alpha * infoIn->color.palette[j + 2] +
703 alpha_complement*infoIn->background_b)>>8;
704 pixel++;
705 }
706 output_row_8(y,(void *)line_buf,&ctx);
707 }
708 break;
709 default:
710 break;
711 }
712 }
713#else /* greyscale targets */
714struct uint8_rgb px_rgb; /* for rgb(a) -> greyscale conversion */
715uint8_t background_grey; /* for rgb background -> greyscale background */
716
717 if (infoIn->color.bitDepth == 8)
718 {
719 switch (infoIn->color.colorType)
720 {
721 case PNG_COLORTYPE_GREY: /*greyscale color*/
722 i = 0;
723 for (y = 0 ; y < h ; y++) {
724 pixel = line_buf;
725 for (x = 0 ; x < w ; x++ ) {
726 value = in[i++];
727
728 /* transparent color defined in tRNS chunk */
729 if (infoIn->color.key_defined)
730 if ( (uint8_t)value == (uint8_t)infoIn->color.key_r )
731 value = infoIn->background_r;
732
733 *pixel++ = (uint8_t)value;
734 }
735 output_row_8(y,(void *)line_buf,&ctx);
736 }
737 break;
738 case PNG_COLORTYPE_RGB: /*RGB color*/
739 /* convert background rgb color to greyscale */
740 px_rgb.red = infoIn->background_r;
741 px_rgb.green = infoIn->background_g;
742 px_rgb.blue = infoIn->background_b;
743 background_grey = brightness(px_rgb);
744
745 i = 0;
746 for (y = 0 ; y < h ; y++) {
747 pixel = line_buf;
748 for (x = 0 ; x < w ; x++) {
749 j = 3*i++;
750
751 /* tRNs & bKGD */
752 if (infoIn->color.key_defined &&
753 in[j] == (uint8_t)infoIn->color.key_r &&
754 in[j + 1] == (uint8_t)infoIn->color.key_g &&
755 in[j + 2] == (uint8_t)infoIn->color.key_b)
756 {
757 *pixel = background_grey;
758 }
759 else
760 {
761 /* rgb -> greyscale */
762 px_rgb.red = in[j];
763 px_rgb.green = in[j + 1];
764 px_rgb.blue = in[j + 2];
765 *pixel = brightness(px_rgb);
766 }
767 pixel++;
768
769 }
770 output_row_8(y,(void *)line_buf,&ctx);
771 }
772 break;
773 case PNG_COLORTYPE_PALETTE: /*indexed color (palette)*/
774 i = 0;
775 /* calculate grey value of rgb background */
776 px_rgb.red = infoIn->background_r;
777 px_rgb.green = infoIn->background_g;
778 px_rgb.blue = infoIn->background_b;
779 background_grey = brightness(px_rgb);
780
781 for (y = 0 ; y < h ; y++) {
782 /* reset line buf */
783 pixel = line_buf;
784 for (x = 0 ; x < w ; x++) {
785 if (in[i] >= infoIn->color.palettesize)
786 {
787 decoder->error = 46;
788 return;
789 }
790
791 j = in[i++] << 2;
792 alpha = infoIn->color.palette[j + 3];
793 alpha_complement = (256 - alpha);
794
795 /* tRNS and bKGD */
796 px_rgb.red = (alpha * infoIn->color.palette[j] +
797 alpha_complement*background_grey)>>8;
798 px_rgb.green = (alpha * infoIn->color.palette[j + 1] +
799 alpha_complement*background_grey)>>8;
800 px_rgb.blue = (alpha * infoIn->color.palette[j + 2] +
801 alpha_complement*background_grey)>>8;
802
803 *pixel++ = brightness(px_rgb);
804 }
805 output_row_8(y,(void *)(line_buf),&ctx);
806 }
807 break;
808 case PNG_COLORTYPE_GREYA: /*greyscale with alpha*/
809 i = 0;
810 for (y = 0 ; y < h ; y++) {
811 pixel = line_buf;
812 for (x = 0 ; x < w ; x++) {
813 alpha = in[(i << 1) + 1];
814 alpha_complement = ((256 - alpha)*infoIn->background_r);
815 *pixel++ = (alpha * in[i++ << 1] + alpha_complement)>>8;
816 }
817 output_row_8(y,(void *)line_buf,&ctx);
818 }
819 break;
820 case PNG_COLORTYPE_RGBA: /*RGB with alpha*/
821 px_rgb.red = infoIn->background_r;
822 px_rgb.green = infoIn->background_g;
823 px_rgb.blue = infoIn->background_b;
824 background_grey = brightness(px_rgb);
825
826 i = 0;
827 for (y = 0 ; y < h ; y++) {
828 pixel = line_buf;
829 for (x = 0 ; x < w ; x++) {
830 j = i++ << 2;
831 alpha = in[j + 3];
832 alpha_complement = ((256 - alpha)*background_grey);
833
834 px_rgb.red = in[j];
835 px_rgb.green = in[j + 1];
836 px_rgb.blue = in[j + 2];
837 *pixel++ = (alpha * brightness(px_rgb) +
838 alpha_complement)>>8;
839 }
840 output_row_8(y,(void *)line_buf,&ctx);
841 }
842 break;
843 default:
844 break;
845 }
846 }
847 else if (infoIn->color.bitDepth == 16)
848 {
849 switch (infoIn->color.colorType)
850 {
851 case PNG_COLORTYPE_GREY: /*greyscale color*/
852 i = 0;
853 for (y = 0 ; y < h ; y++) {
854 pixel = line_buf;
855 for (x = 0 ; x < w ; x++) {
856 /* specification states that we have to compare
857 * colors for simple transparency in 16bits
858 * even if we scale down to 8bits later
859 */
860 value = in[i<<1]<<8|in[(i << 1) + 1];
861 i++;
862
863 /* tRNS and bKGD */
864 if (infoIn->color.key_defined &&
865 value == infoIn->color.key_r)
866 value = infoIn->background_r<<8;
867
868 /* we take upper 8bits */
869 *pixel++ = (uint8_t)(value>>8);
870 }
871
872 output_row_8(y,(void *)line_buf,&ctx);
873 }
874 break;
875 case PNG_COLORTYPE_RGB: /*RGB color*/
876 i = 0;
877 px_rgb.red = infoIn->background_r;
878 px_rgb.green = infoIn->background_g;
879 px_rgb.blue = infoIn->background_b;
880 background_grey = brightness(px_rgb);
881
882 for (y = 0 ; y < h ; y++) {
883 pixel = line_buf;
884 for (x = 0 ; x < w ; x++) {
885 j = 6 * i++;
886
887 /* tRNS and bKGD */
888 if (infoIn->color.key_defined &&
889 (uint16_t)(in[j]<<8|in[j + 1]) ==
890 infoIn->color.key_r &&
891 (uint16_t)(in[j + 2]<<8|in[j + 3]) ==
892 infoIn->color.key_g &&
893 (uint16_t)(in[j + 4]<<8|in[j + 5]) ==
894 infoIn->color.key_b)
895 {
896 *pixel = background_grey;
897 }
898 else
899 {
900 /* we take only upper byte of 16bit value */
901 px_rgb.red = in[j];
902 px_rgb.green = in[j + 2];
903 px_rgb.blue = in[j + 4];
904 *pixel = brightness(px_rgb);
905 }
906 pixel++;
907 }
908 output_row_8(y,(void *)line_buf,&ctx);
909 }
910 break;
911 case PNG_COLORTYPE_GREYA: /*greyscale with alpha*/
912 i = 0;
913 for (y = 0 ; y < h ; y++) {
914 pixel = line_buf;
915 for (x = 0 ; x < w ; x++) {
916 alpha = in[(i << 2) + 2];
917 alpha_complement = (256 - alpha)*infoIn->background_r;
918 *pixel++ = (alpha * in[i++ << 2] + alpha_complement)>>8;
919 }
920 output_row_8(y,(void *)line_buf,&ctx);
921 }
922 break;
923 case PNG_COLORTYPE_RGBA: /*RGB with alpha*/
924 px_rgb.red = infoIn->background_r;
925 px_rgb.green = infoIn->background_g;
926 px_rgb.blue = infoIn->background_b;
927 background_grey = brightness(px_rgb);
928
929 i = 0;
930 for (y = 0 ; y < h ; y++) {
931 pixel = line_buf;
932 for (x = 0 ; x < w ; x++) {
933 j = i++ << 3;
934 alpha = in[j + 6];
935 alpha_complement = (256 - alpha)*background_grey;
936 px_rgb.red = in[j];
937 px_rgb.green = in[j + 2];
938 px_rgb.blue = in[j + 4];
939 *pixel++ = (alpha * brightness(px_rgb) + alpha_complement)>>8;
940 }
941 output_row_8(y,(void *)line_buf,&ctx);
942 }
943 break;
944 default:
945 break;
946 }
947 }
948 else /*infoIn->bitDepth is less than 8 bit per channel*/
949 {
950 switch (infoIn->color.colorType)
951 {
952 case PNG_COLORTYPE_GREY: /*greyscale color*/
953 i = 0;
954 for (y = 0 ; y < h ; y++) {
955 pixel = line_buf;
956 for (x = 0 ; x < w ; x++) {
957 value = readBitsFromReversedStream(&bp, in, infoIn->color.bitDepth);
958
959 /* tRNS and bKGD */
960 if (infoIn->color.key_defined)
961 if ( value == infoIn->color.key_r )
962 value = infoIn->background_r; /* full transparent */
963
964 /*scale value from 0 to 255*/
965 value = (value * 255) / ((1 << infoIn->color.bitDepth) - 1);
966
967 *pixel++ = (unsigned char)value;
968 }
969 output_row_8(y,(void *)line_buf,&ctx);
970 }
971 break;
972 case PNG_COLORTYPE_PALETTE: /*indexed color (palette)*/
973 i = 0;
974 px_rgb.red = infoIn->background_r;
975 px_rgb.green = infoIn->background_g;
976 px_rgb.blue = infoIn->background_b;
977 uint8_t background_grey = brightness(px_rgb);
978
979 for (y = 0 ; y < h ; y++) {
980 pixel = line_buf;
981 for (x = 0 ; x < w ; x++) {
982 value = readBitsFromReversedStream(&bp, in, infoIn->color.bitDepth);
983 if (value >= infoIn->color.palettesize)
984 {
985 decoder->error = 47;
986 return;
987 }
988
989 j = value << 2;
990
991 /* tRNS and bKGD */
992 alpha = infoIn->color.palette[j + 3];
993 alpha_complement = (256 - alpha) * background_grey;
994
995 px_rgb.red = (alpha * infoIn->color.palette[j] +
996 alpha_complement)>>8;
997 px_rgb.green = (alpha * infoIn->color.palette[j + 1] +
998 alpha_complement)>>8;
999 px_rgb.blue = (alpha * infoIn->color.palette[j + 2] +
1000 alpha_complement)>>8;
1001 *pixel++ = brightness(px_rgb);
1002 }
1003 output_row_8(y,(void *)line_buf,&ctx);
1004 }
1005 break;
1006 default:
1007 break;
1008 }
1009 }
1010#endif
1011}
1012
1013/*Paeth predicter, used by PNG filter type 4*/
1014static int paethPredictor(int a, int b, int c)
1015{
1016 int p = a + b - c;
1017 int pa = p > a ? p - a : a - p;
1018 int pb = p > b ? p - b : b - p;
1019 int pc = p > c ? p - c : c - p;
1020
1021 if (pa <= pb && pa <= pc) return a;
1022 else if (pb <= pc) return b;
1023 else return c;
1024}
1025
1026/*shared values used by multiple Adam7 related functions*/
1027
1028static const uint8_t ADAM7_IX[7] = { 0, 4, 0, 2, 0, 1, 0 }; /*x start values*/
1029static const uint8_t ADAM7_IY[7] = { 0, 0, 4, 0, 2, 0, 1 }; /*y start values*/
1030static const uint8_t ADAM7_DX[7] = { 8, 8, 4, 4, 2, 2, 1 }; /*x delta values*/
1031static const uint8_t ADAM7_DY[7] = { 8, 8, 8, 4, 4, 2, 2 }; /*y delta values*/
1032
1033static void Adam7_getpassvalues(uint16_t passw[7],
1034 uint16_t passh[7],
1035 size_t filter_passstart[8],
1036 size_t padded_passstart[8],
1037 size_t passstart[8],
1038 uint16_t w,
1039 uint16_t h,
1040 uint8_t bpp)
1041{
1042 /* the passstart values have 8 values:
1043 * the 8th one actually indicates the byte after the end
1044 * of the 7th (= last) pass
1045 */
1046 uint8_t i;
1047
1048 /*calculate width and height in pixels of each pass*/
1049 for (i = 0; i < 7; i++)
1050 {
1051 passw[i] = (w + ADAM7_DX[i] - ADAM7_IX[i] - 1) / ADAM7_DX[i];
1052 passh[i] = (h + ADAM7_DY[i] - ADAM7_IY[i] - 1) / ADAM7_DY[i];
1053 if (passw[i] == 0) passh[i] = 0;
1054 if (passh[i] == 0) passw[i] = 0;
1055 }
1056
1057 filter_passstart[0] = padded_passstart[0] = passstart[0] = 0;
1058 for (i = 0; i < 7; i++)
1059 {
1060 /* if passw[i] is 0, it's 0 bytes, not 1 (no filtertype-byte) */
1061 filter_passstart[i + 1] = filter_passstart[i] + ((passw[i] && passh[i])?
1062 passh[i] * (1 + (passw[i] * bpp + 7) / 8):0);
1063
1064 /* bits padded if needed to fill full byte at end of each scanline */
1065 padded_passstart[i + 1] = padded_passstart[i] +
1066 passh[i] * ((passw[i] * bpp + 7) / 8);
1067
1068 /* only padded at end of reduced image */
1069 passstart[i + 1] = passstart[i] + (passh[i] * passw[i] * bpp + 7) / 8;
1070 }
1071}
1072
1073/* ////////////////////////////////////////////////////////////////////////// */
1074/* / PNG Decoder / */
1075/* ////////////////////////////////////////////////////////////////////////// */
1076
1077
1078
1079static uint8_t unfilterScanline(uint8_t* recon,
1080 const uint8_t* scanline,
1081 const uint8_t* precon,
1082 size_t bytewidth,
1083 uint8_t filterType,
1084 size_t length)
1085{
1086 /* For PNG filter method 0
1087 * unfilter a PNG image scanline by scanline. when the pixels are smaller
1088 * than 1 byte, the filter works byte per byte (bytewidth = 1)
1089 *
1090 * precon is the previous unfiltered scanline, recon the result,
1091 * scanline the current one
1092 *
1093 * the incoming scanlines do NOT include the filtertype byte, that one is
1094 * given in the parameter filterType instead
1095 *
1096 * recon and scanline MAY be the same memory address! precon must be
1097 * disjoint.
1098 */
1099
1100/* storage space for cached portion of scanline */
1101unsigned char cache[512+16];
1102
1103/* ptr to second element of the cache */
1104unsigned char *cache_1 = cache + bytewidth;
1105unsigned char *p_cache = cache + 256 + 8; /* half way */
1106unsigned char *p_cache_1 = p_cache + bytewidth;
1107
1108 size_t i;
1109 switch (filterType)
1110 {
1111 case PNG_FILTERTYPE_NONE:
1112 /* for(i = 0; i < length; i++) recon[i] = scanline[i]; */
1113 memcpy(recon, scanline, length * sizeof(uint8_t));
1114 break;
1115 case PNG_FILTERTYPE_SUB:
1116 /*
1117 for(i = 0; i < bytewidth; i++) recon[i] = scanline[i];
1118 for (i = bytewidth; i < length; i++)
1119 recon[i] = scanline[i] + recon[i - bytewidth];
1120 */
1121
1122 /* first pixel */
1123 memcpy(cache, scanline, bytewidth * sizeof(unsigned char));
1124 scanline += bytewidth;
1125
1126 while ((length - bytewidth) >> 9) /* length >> 9 */
1127 {
1128 /* cache part of scanline */
1129 memcpy(cache_1, scanline, 512);
1130
1131 /* filtering */
1132 for (i=bytewidth; i < 512 + bytewidth; i++)
1133 cache[i] += cache[i - bytewidth];
1134
1135 /* copy part of filtered scanline */
1136 memcpy(recon, cache, 512);
1137
1138 /* adjust pointers */
1139 recon += 512;
1140 scanline += 512;
1141 length -= 512;
1142
1143 /* copy last pixel back to the begining of the cache */
1144 memcpy(cache, cache + 512, bytewidth * sizeof(unsigned char));
1145 }
1146
1147 /* less than our cache size */
1148 if (length)
1149 {
1150 /* cache last part of the scanline */
1151 memcpy(cache_1, scanline, length - bytewidth);
1152
1153 /* filtering */
1154 for (i=bytewidth; i < length; i++)
1155 cache[i] += cache[i - bytewidth];
1156
1157 /* copy remaining part of the filtered scanline */
1158 memcpy(recon, cache, length * sizeof(unsigned char));
1159 }
1160 break;
1161 case PNG_FILTERTYPE_UP:
1162 /*
1163 if (precon) for (i = 0; i < length; i++)
1164 recon[i] = scanline[i] + precon[i];
1165 */
1166 if (precon)
1167 {
1168 while (length >> 8)
1169 {
1170 memcpy(cache, scanline, 256);
1171 memcpy(p_cache, precon, 256);
1172
1173 for (i=0; i < 256; i++)
1174 cache[i] += p_cache[i];
1175
1176 memcpy(recon, cache, 256);
1177
1178 scanline += 256;
1179 recon += 256;
1180 precon += 256;
1181 length -= 256;
1182 }
1183
1184 if (length)
1185 {
1186 memcpy(cache, scanline, length);
1187 memcpy(p_cache, precon, length);
1188
1189 for (i=0; i < length; i++)
1190 cache[i] += p_cache[i];
1191
1192 memcpy(recon, cache, length);
1193 }
1194 }
1195 else
1196 /* for(i = 0; i < length; i++) recon[i] = scanline[i]; */
1197 memcpy(recon, scanline, length * sizeof(uint8_t));
1198 break;
1199 case PNG_FILTERTYPE_AVERAGE:
1200 if (precon)
1201 {
1202 /*
1203 for (i = 0; i < bytewidth; i++)
1204 recon[i] = scanline[i] + precon[i] / 2;
1205 for (i = bytewidth; i < length; i++)
1206 recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) / 2);
1207 */
1208 memcpy(cache, scanline, bytewidth * sizeof(unsigned char));
1209 memcpy(p_cache, precon, bytewidth * sizeof(unsigned char));
1210
1211 for (i = 0; i < bytewidth; i++)
1212 cache[i] += p_cache[i]>>1;
1213
1214 scanline += bytewidth;
1215 precon += bytewidth;
1216
1217 while ((length - bytewidth)>> 8) /* length/256 */
1218 {
1219 memcpy(cache_1, scanline, 256);
1220 memcpy(p_cache_1, precon, 256);
1221
1222 for (i=bytewidth; i < 256 + bytewidth; i++)
1223 cache[i] += (cache[i - bytewidth] + p_cache[i])>>1;
1224
1225 memcpy(recon, cache, 256);
1226
1227 recon += 256;
1228 scanline += 256;
1229 precon += 256;
1230 length -= 256;
1231
1232 memcpy(cache, cache + 256, bytewidth * sizeof(unsigned char));
1233 memcpy(p_cache, p_cache + 256, bytewidth * sizeof(unsigned char));
1234 }
1235
1236 /* less than our cache size */
1237 if (length)
1238 {
1239 /* cache last part of the scanline */
1240 memcpy(cache_1, scanline, length - bytewidth);
1241 memcpy(p_cache_1, precon, length - bytewidth);
1242
1243 /* filtering */
1244 for (i=bytewidth; i < length; i++)
1245 cache[i] += (cache[i - bytewidth] + p_cache[i])>>1;
1246
1247 /* copy remaining part of the filtered scanline */
1248 memcpy(recon, cache, length * sizeof(unsigned char));
1249 }
1250 }
1251 else
1252 {
1253 /*
1254 for(i = 0; i < bytewidth; i++) recon[i] = scanline[i];
1255 for (i = bytewidth; i < length; i++)
1256 recon[i] = scanline[i] + recon[i - bytewidth] / 2;
1257 */
1258
1259 /* first pixel */
1260 memcpy(cache, scanline, bytewidth * sizeof(unsigned char));
1261 scanline += bytewidth;
1262
1263 while ((length - bytewidth) >> 9) /* length/512 */
1264 {
1265 /* cache part of scanline */
1266 memcpy(cache_1, scanline, 512);
1267
1268 /* filtering */
1269 for (i=bytewidth; i < 512 + bytewidth; i++)
1270 cache[i] += (cache[i - bytewidth])>>1;
1271
1272 /* copy part of filtered scanline */
1273 memcpy(recon, cache, 512);
1274
1275 /* adjust pointers */
1276 recon += 512;
1277 scanline += 512;
1278 length -= 512;
1279
1280 /* copy last pixel back to the begining of the cache */
1281 memcpy(cache, cache + 512, bytewidth * sizeof(unsigned char));
1282 }
1283
1284 /* less than our cache size */
1285 if (length)
1286 {
1287 /* cache last part of the scanline */
1288 memcpy(cache_1, scanline, length - bytewidth);
1289
1290 /* filtering */
1291 for (i=bytewidth; i < length; i++)
1292 cache[i] += (cache[i - bytewidth])>>1;
1293
1294 /* copy remaining part of the filtered scanline */
1295 memcpy(recon, cache, length * sizeof(unsigned char));
1296 }
1297 }
1298 break;
1299 case PNG_FILTERTYPE_PAETH:
1300 if (precon)
1301 {
1302 /*
1303 for (i = 0; i < bytewidth; i++)
1304 recon[i] = (uint8_t)(scanline[i] +
1305 paethPredictor(0, precon[i], 0));
1306 for (i = bytewidth; i < length; i++)
1307 recon[i] = (uint8_t)(scanline[i] +
1308 paethPredictor(recon[i - bytewidth],
1309 precon[i],
1310 precon[i - bytewidth]));
1311 */
1312
1313 memcpy(cache, scanline, bytewidth * sizeof(unsigned char));
1314 memcpy(p_cache, precon, bytewidth * sizeof(unsigned char));
1315
1316 for (i = 0; i < bytewidth; i++)
1317 cache[i] += paethPredictor(0, p_cache[i], 0);
1318
1319 scanline += bytewidth;
1320 precon += bytewidth;
1321
1322 while ((length - bytewidth)>> 8) /* length/256 */
1323 {
1324 memcpy(cache_1, scanline, 256);
1325 memcpy(p_cache_1, precon, 256);
1326
1327 for (i=bytewidth; i < 256 + bytewidth; i++)
1328 cache[i] += paethPredictor(cache[i - bytewidth],
1329 p_cache[i],
1330 p_cache[i - bytewidth]);
1331
1332 memcpy(recon, cache, 256);
1333
1334 recon += 256;
1335 scanline += 256;
1336 precon += 256;
1337 length -= 256;
1338
1339 memcpy(cache, cache + 256, bytewidth * sizeof(unsigned char));
1340 memcpy(p_cache, p_cache + 256, bytewidth * sizeof(unsigned char));
1341 }
1342
1343 /* less than our cache size */
1344 if (length)
1345 {
1346 /* cache last part of the scanline */
1347 memcpy(cache_1, scanline, length - bytewidth);
1348 memcpy(p_cache_1, precon, length - bytewidth);
1349
1350 /* filtering */
1351 for (i=bytewidth; i < length; i++)
1352 cache[i] += paethPredictor(cache[i - bytewidth],
1353 p_cache[i],
1354 p_cache[i - bytewidth]);
1355
1356 /* copy remaining part of the filtered scanline */
1357 memcpy(recon, cache, length * sizeof(unsigned char));
1358 }
1359 }
1360 else
1361 {
1362 /*
1363 for(i = 0; i < bytewidth; i++) recon[i] = scanline[i];
1364 for (i = bytewidth; i < length; i++)
1365 recon[i] = (uint8_t)(scanline[i] +
1366 paethPredictor(recon[i - bytewidth],
1367 0, 0));
1368 */
1369
1370 memcpy(cache, scanline, bytewidth * sizeof(unsigned char));
1371 scanline += bytewidth;
1372
1373 while ((length - bytewidth) >> 9) /* length/512 */
1374 {
1375 /* cache part of scanline */
1376 memcpy(cache_1, scanline, 512);
1377
1378 /* filtering */
1379 for (i=bytewidth; i < 512 + bytewidth; i++)
1380 cache[i] += paethPredictor(cache[i - bytewidth], 0, 0);
1381
1382 /* copy part of filtered scanline */
1383 memcpy(recon, cache, 512);
1384
1385 /* adjust pointers */
1386 recon += 512;
1387 scanline += 512;
1388 length -= 512;
1389
1390 /* copy last pixel back to the begining of the cache */
1391 memcpy(cache, cache + 512, bytewidth * sizeof(unsigned char));
1392 }
1393
1394 /* less than our cache size */
1395 if (length)
1396 {
1397 /* cache last part of the scanline */
1398 memcpy(cache_1, scanline, length - bytewidth);
1399
1400 /* filtering */
1401 for (i=bytewidth; i < length; i++)
1402 cache[i] += paethPredictor(cache[i - bytewidth], 0, 0);
1403
1404 /* copy remaining part of the filtered scanline */
1405 memcpy(recon, cache, length * sizeof(unsigned char));
1406 }
1407 }
1408 break;
1409 default:
1410 return 36; /*error: unexisting filter type given*/
1411 }
1412 return 0;
1413}
1414
1415static uint8_t unfilter(uint8_t* out,
1416 const uint8_t* in,
1417 uint16_t w,
1418 uint16_t h,
1419 uint8_t bpp)
1420{
1421 /* For PNG filter method 0
1422 * this function unfilters a single image (e.g. without interlacing this is
1423 * called once, with Adam7 it's called 7 times)
1424 *
1425 * out must have enough bytes allocated already, in must have the
1426 * scanlines + 1 filtertype byte per scanline
1427 *
1428 * w and h are image dimensions or dimensions of reduced image,
1429 * bpp is bits per pixel
1430 *
1431 * in and out are allowed to be the same memory address!
1432 */
1433
1434 uint16_t y;
1435 uint8_t* prevline = 0;
1436
1437 /* bytewidth is used for filtering, is 1 when bpp < 8,
1438 * number of bytes per pixel otherwise
1439 */
1440 size_t bytewidth = (bpp + 7) / 8;
1441 size_t linebytes = (w * bpp + 7) / 8;
1442
1443 for (y = 0; y < h; y++)
1444 {
1445 size_t outindex = linebytes * y;
1446
1447 /* the extra filterbyte added to each row */
1448 size_t inindex = (1 + linebytes) * y;
1449 uint8_t filterType = in[inindex];
1450
1451 uint8_t error = unfilterScanline(&out[outindex], &in[inindex + 1],
1452 prevline, bytewidth, filterType,
1453 linebytes);
1454 if (error)
1455 return error;
1456
1457 prevline = &out[outindex];
1458 }
1459
1460 return 0;
1461}
1462
1463static void Adam7_deinterlace(uint8_t* out,
1464 const uint8_t* in,
1465 uint16_t w,
1466 uint16_t h,
1467 uint8_t bpp)
1468{
1469 /* Note: this function works on image buffers WITHOUT padding bits at end
1470 * of scanlines with non-multiple-of-8 bit amounts, only between reduced
1471 * images is padding
1472 * out must be big enough AND must be 0 everywhere if bpp < 8
1473 * in the current implementation (because that's likely a little bit faster)
1474 */
1475 uint16_t passw[7], passh[7];
1476 size_t filter_passstart[8], padded_passstart[8], passstart[8];
1477 uint8_t i;
1478
1479 Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart,
1480 passstart, w, h, bpp);
1481
1482 if (bpp >= 8)
1483 {
1484 for (i = 0; i < 7; i++)
1485 {
1486 uint16_t x, y, b;
1487 size_t bytewidth = bpp >> 3;
1488 for (y = 0; y < passh[i]; y++)
1489 for (x = 0; x < passw[i]; x++)
1490 {
1491 size_t pixelinstart = passstart[i] +
1492 (y * passw[i] + x) * bytewidth;
1493 size_t pixeloutstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w +
1494 ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth;
1495 for (b = 0; b < bytewidth; b++)
1496 {
1497 out[pixeloutstart + b] = in[pixelinstart + b];
1498 }
1499 }
1500 }
1501 }
1502 else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/
1503 {
1504 for (i = 0; i < 7; i++)
1505 {
1506 uint16_t x, y, b;
1507 uint32_t ilinebits = bpp * passw[i];
1508 uint32_t olinebits = bpp * w;
1509 size_t obp, ibp; /*bit pointers (for out and in buffer)*/
1510 for (y = 0; y < passh[i]; y++)
1511 for (x = 0; x < passw[i]; x++)
1512 {
1513 ibp = (8 * passstart[i]) + (y * ilinebits + x * bpp);
1514 obp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits +
1515 (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp;
1516 for (b = 0; b < bpp; b++)
1517 {
1518 uint8_t bit = readBitFromReversedStream(&ibp, in);
1519 /* note that this function assumes the out buffer
1520 * is completely 0, use setBitOfReversedStream
1521 * otherwise*/
1522 setBitOfReversedStream0(&obp, out, bit);
1523 }
1524 }
1525 }
1526 }
1527}
1528
1529static void removePaddingBits(uint8_t* out,
1530 const uint8_t* in,
1531 size_t olinebits,
1532 size_t ilinebits,
1533 uint16_t h)
1534{
1535 /* After filtering there are still padding bits if scanlines have
1536 * non multiple of 8 bit amounts. They need to be removed
1537 * (except at last scanline of (Adam7-reduced) image) before working
1538 * with pure image buffers for the Adam7 code, the color convert code
1539 * and the output to the user.
1540 *
1541 * in and out are allowed to be the same buffer, in may also be higher
1542 * but still overlapping; in must have >= ilinebits*h bits,
1543 * out must have >= olinebits*h bits, olinebits must be <= ilinebits
1544 * also used to move bits after earlier such operations happened, e.g.
1545 * in a sequence of reduced images from Adam7
1546 * only useful if (ilinebits - olinebits) is a value in the range 1..7
1547 */
1548 uint16_t y;
1549 size_t diff = ilinebits - olinebits;
1550 size_t obp = 0, ibp = 0; /*bit pointers*/
1551 for (y = 0; y < h; y++)
1552 {
1553 size_t x;
1554 for (x = 0; x < olinebits; x++)
1555 {
1556 uint8_t bit = readBitFromReversedStream(&ibp, in);
1557 setBitOfReversedStream(&obp, out, bit);
1558 }
1559 ibp += diff;
1560 }
1561}
1562
1563/* out must be buffer big enough to contain full image,
1564 * and in must contain the full decompressed data from the IDAT chunks
1565 */
1566static uint8_t postProcessScanlines(uint8_t* out,
1567 uint8_t* in,
1568 const LodePNG_Decoder* decoder)
1569{
1570 /*return value is error*/
1571
1572 /* This function converts the filtered-padded-interlaced data into pure 2D
1573 * image buffer with the PNG's colortype.
1574 * Steps:
1575 * I) if no Adam7:
1576 * 1) unfilter
1577 * 2) remove padding bits (= posible extra bits per scanline if bpp < 8)
1578 * II) if adam7:
1579 * 1) 7x unfilter
1580 * 2) 7x remove padding bits
1581 * 3) Adam7_deinterlace
1582 *
1583 * NOTE: the in buffer will be overwritten with intermediate data!
1584 */
1585 uint8_t bpp = getBpp(decoder->infoPng.color.colorType,
1586 decoder->infoPng.color.bitDepth);
1587 uint16_t w = decoder->infoPng.width;
1588 uint16_t h = decoder->infoPng.height;
1589 uint8_t error = 0;
1590
1591 if (bpp == 0)
1592 return 31; /*error: invalid colortype*/
1593
1594 if (decoder->infoPng.interlaceMethod == 0)
1595 {
1596 if (bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8)
1597 {
1598 error = unfilter(in, in, w, h, bpp);
1599 if (error) return error;
1600 removePaddingBits(out, in, w * bpp, ((w * bpp + 7) / 8) * 8, h);
1601 }
1602 else
1603 /* we can immediatly filter into the out buffer,
1604 * no other steps needed
1605 */
1606 error = unfilter(out, in, w, h, bpp);
1607 }
1608 else /*interlaceMethod is 1 (Adam7)*/
1609 {
1610 uint16_t passw[7], passh[7];
1611 size_t filter_passstart[8], padded_passstart[8], passstart[8];
1612 uint8_t i;
1613
1614 Adam7_getpassvalues(passw,
1615 passh,
1616 filter_passstart,
1617 padded_passstart,
1618 passstart,
1619 w,
1620 h,
1621 bpp);
1622
1623 for (i = 0; i < 7; i++)
1624 {
1625 error = unfilter(&in[padded_passstart[i]],
1626 &in[filter_passstart[i]],
1627 passw[i],
1628 passh[i],
1629 bpp);
1630 if (error)
1631 return error;
1632 if (bpp < 8)
1633 /* TODO: possible efficiency improvement: if in this reduced
1634 * image the bits fit nicely in 1 scanline, move bytes instead
1635 * of bits or move not at all
1636 */
1637 {
1638 /* remove padding bits in scanlines; after this there still
1639 * may be padding bits between the different reduced images:
1640 * each reduced image still starts nicely at a byte
1641 */
1642 removePaddingBits(&in[passstart[i]],
1643 &in[padded_passstart[i]],
1644 passw[i] * bpp,
1645 ((passw[i] * bpp + 7) / 8) * 8,
1646 passh[i]);
1647 }
1648 }
1649
1650 Adam7_deinterlace(out, in, w, h, bpp);
1651 }
1652
1653 return error;
1654}
1655
1656/* read a PNG, the result will be in the same color type as the PNG
1657 * (hence "generic")
1658 */
1659static void decodeGeneric(LodePNG_Decoder* decoder)
1660{
1661 uint8_t *in = decoder->file;
1662
1663 uint8_t IEND = 0;
1664 const uint8_t* chunk;
1665 size_t i;
1666
1667 size_t chunkLength; /* chunk length */
1668 const uint8_t* data; /*the data in the chunk*/
1669
1670 uint8_t *idat = decoder->buf; /* allocated buffer */
1671
1672 size_t idat_size = 0;
1673
1674 signed long free_mem = decoder->buf_size;
1675
1676 /* for unknown chunk order */
1677 bool unknown = false;
1678 uint8_t critical_pos = 1; /*1 = after IHDR, 2 = after PLTE, 3 = after IDAT*/
1679
1680 if (decoder->file_size == 0 || in == NULL)
1681 {
1682 /* the given data is empty */
1683 decoder->error = 48;
1684 return;
1685 }
1686
1687 chunk = in + 33; /*first byte of the first chunk after the header*/
1688
1689 /* loop through the chunks, ignoring unknown chunks and stopping at IEND
1690 * chunk. IDAT data is put at the start of the in buffer
1691 */
1692 while (!IEND) {
1693
1694 /* minimal size of chunk is 12 bytes */
1695 if ((size_t)((chunk - in) + 12) > decoder->file_size || chunk < in)
1696 {
1697 /* error: size of the in buffer too small to contain next chunk */
1698 decoder->error = 30;
1699 break;
1700 }
1701
1702 /* length of the data of the chunk, excluding the length bytes,
1703 * chunk type and CRC bytes
1704 *
1705 * data field of the chunk is restricted to 2^31-1 bytes in size
1706 */
1707 chunkLength = LodePNG_chunk_length(chunk);
1708
1709 if (chunkLength > 2147483647)
1710 {
1711 decoder->error = 63;
1712 break;
1713 }
1714
1715 /* check if chunk fits in buffer */
1716 if ((size_t)((chunk - in) + chunkLength + 12) > decoder->file_size ||
1717 (chunk + chunkLength + 12) < in)
1718 {
1719 /* error: size of the in buffer too small to contain next chunk */
1720 decoder->error = 35;
1721 break;
1722 }
1723 data = LodePNG_chunk_data(chunk);
1724
1725 /* IDAT chunk, containing compressed image data
1726 * there may be more than 1 IDAT chunk, complete
1727 * compressed stream is concatenation of consecutive
1728 * chunks data
1729 */
1730 if (LodePNG_chunk_type_equals(chunk, PNG_CHUNK_IDAT))
1731 {
1732 free_mem -= chunkLength;
1733
1734 if (free_mem < 0)
1735 {
1736 decoder->error = OUT_OF_MEMORY;
1737 break;
1738 }
1739 /* copy compressed data */
1740 memcpy(idat+idat_size, data, chunkLength * sizeof(uint8_t));
1741 idat_size += chunkLength;
1742 critical_pos = 3;
1743 }
1744 /*IEND chunk*/
1745 else if (LodePNG_chunk_type_equals(chunk, PNG_CHUNK_IEND))
1746 {
1747 IEND = 1;
1748 }
1749 /*palette chunk (PLTE)*/
1750 else if (LodePNG_chunk_type_equals(chunk, PNG_CHUNK_PLTE))
1751 {
1752 uint32_t pos = 0;
1753 decoder->infoPng.color.palettesize = chunkLength / 3;
1754 if (decoder->infoPng.color.palettesize > 256)
1755 {
1756 /*error: palette too big*/
1757 decoder->error = 38;
1758 break;
1759 }
1760
1761 for (i = 0; i < decoder->infoPng.color.palettesize; i++)
1762 {
1763 decoder->infoPng.color.palette[(i<<2)] = data[pos++]; /*R*/
1764 decoder->infoPng.color.palette[(i<<2) | 1] = data[pos++]; /*G*/
1765 decoder->infoPng.color.palette[(i<<2) | 2] = data[pos++]; /*B*/
1766 decoder->infoPng.color.palette[(i<<2) | 3] = 255; /*alpha*/
1767 }
1768 critical_pos = 2;
1769 }
1770 /*palette transparency chunk (tRNS)*/
1771 else if (LodePNG_chunk_type_equals(chunk, PNG_CHUNK_tRNS))
1772 {
1773 if (decoder->infoPng.color.colorType == PNG_COLORTYPE_PALETTE)
1774 {
1775 if (chunkLength > decoder->infoPng.color.palettesize)
1776 {
1777 /* error: more alpha values given than there are palette
1778 * entries
1779 */
1780 decoder->error = 39;
1781 break;
1782 }
1783 for (i = 0; i < chunkLength; i++)
1784 /* copy alpha informations for palette colors */
1785 decoder->infoPng.color.palette[(i<<2) | 3] = data[i];
1786 }
1787 else if (decoder->infoPng.color.colorType == PNG_COLORTYPE_GREY)
1788 {
1789 if (chunkLength != 2)
1790 {
1791 /* error: this chunk must be 2 bytes for greyscale image */
1792 decoder->error = 40;
1793 break;
1794 }
1795 /* transparent color definition */
1796 decoder->infoPng.color.key_defined = 1;
1797 decoder->infoPng.color.key_r =
1798 decoder->infoPng.color.key_g =
1799 decoder->infoPng.color.key_b = data[0]<<8|data[1];
1800 }
1801 else if (decoder->infoPng.color.colorType == PNG_COLORTYPE_RGB)
1802 {
1803 if (chunkLength != 6)
1804 {
1805 /* error: this chunk must be 6 bytes for RGB image */
1806 decoder->error = 41;
1807 break;
1808 }
1809 /* transparent color definition */
1810 decoder->infoPng.color.key_defined = 1;
1811 decoder->infoPng.color.key_r = data[0]<<8|data[1];
1812 decoder->infoPng.color.key_g = data[2]<<8|data[3];
1813 decoder->infoPng.color.key_b = data[4]<<8|data[5];
1814 }
1815 else
1816 {
1817 /* error: tRNS chunk not allowed for other color models */
1818 decoder->error = 42;
1819 break;
1820 }
1821 }
1822 /*background color chunk (bKGD)*/
1823 else if (LodePNG_chunk_type_equals(chunk, PNG_CHUNK_bKGD))
1824 {
1825 if (decoder->infoPng.color.colorType == PNG_COLORTYPE_PALETTE)
1826 {
1827 if (chunkLength != 1)
1828 {
1829 /* error: this chunk must be 1 byte for indexed color image */
1830 decoder->error = 43;
1831 break;
1832 }
1833 decoder->infoPng.background_r =
1834 decoder->infoPng.color.palette[(data[0]<<2)];
1835
1836 decoder->infoPng.background_g =
1837 decoder->infoPng.color.palette[(data[0]<<2) | 1];
1838
1839 decoder->infoPng.background_b =
1840 decoder->infoPng.color.palette[(data[0]<<2) | 2];
1841
1842 }
1843 else if (decoder->infoPng.color.colorType == PNG_COLORTYPE_GREY ||
1844 decoder->infoPng.color.colorType == PNG_COLORTYPE_GREYA)
1845 {
1846 if (chunkLength != 2)
1847 {
1848 /* error: this chunk must be 2 bytes for greyscale image */
1849 decoder->error = 44;
1850 break;
1851 }
1852 decoder->infoPng.background_r =
1853 decoder->infoPng.background_g =
1854 decoder->infoPng.background_b = data[0];
1855 }
1856 else if (decoder->infoPng.color.colorType == PNG_COLORTYPE_RGB ||
1857 decoder->infoPng.color.colorType == PNG_COLORTYPE_RGBA)
1858 {
1859 if (chunkLength != 6)
1860 {
1861 /* error: this chunk must be 6 bytes for greyscale image */
1862 decoder->error = 45;
1863 break;
1864 }
1865 decoder->infoPng.background_r = data[0];
1866 decoder->infoPng.background_g = data[2];
1867 decoder->infoPng.background_b = data[4];
1868 }
1869 }
1870 else
1871 {
1872 /* it's not an implemented chunk type,
1873 * so ignore it (unless it is critical)
1874 * skip over the data
1875 */
1876 if (LodePNG_chunk_critical(chunk))
1877 {
1878 /* error: unknown critical chunk
1879 * (5th bit of first byte of chunk type is 0)
1880 */
1881 decoder->error = 69;
1882 break;
1883 }
1884 unknown = true;
1885 }
1886
1887 if (!unknown) /*check CRC if wanted, only on known chunk types*/
1888 {
1889 if (!LodePNG_chunk_check_crc(chunk))
1890 {
1891 decoder->error = 57;
1892 break;
1893 }
1894 }
1895
1896 if (!IEND)
1897 chunk = LodePNG_chunk_next(chunk);
1898 }
1899
1900 if (!decoder->error)
1901 {
1902 /* ptr to buffer just after concatenated IDATs */
1903 uint8_t *scanlines = idat + idat_size;
1904 size_t scanline_size = free_mem;
1905
1906 /* decompress with the Zlib decompressor
1907 * decompressor updates scanlines_size to actual size
1908 * of decompressed data
1909 */
1910 decoder->error = LodePNG_decompress(scanlines,
1911 &scanline_size,
1912 idat,
1913 idat_size);
1914
1915 free_mem -= scanline_size;
1916 /* possible memory saving (at cost of memcpy)
1917 * memcpy(decoder->buf - scanlines_size,
1918 * scanlines,
1919 * scanlines_size * sizeof(uint8_t));
1920 * this will free compressed IDATs and
1921 * will trash raw PNG file (it is trashed anyway
1922 */
1923 if (!decoder->error)
1924 {
1925 /* size of decoded image in bytes rounded up */
1926 size_t decoded_img_size = (decoder->infoPng.height *
1927 decoder->infoPng.width *
1928 getBpp(decoder->infoPng.color.colorType,
1929 decoder->infoPng.color.bitDepth) +
1930 7) / 8;
1931
1932 /* at this time buffer contains:
1933 * compressed IDATs
1934 * decompressed IDATs
1935 * png raw file at the end of the buffer (not needed any more )
1936 */
1937 free_mem -= decoded_img_size;
1938
1939 if (free_mem < 0)
1940 {
1941 decoder->error = OUT_OF_MEMORY;
1942 return;
1943 }
1944
1945 /* ptr to decoded png image
1946 * this will overwrite raw png file loaded into memory
1947 * decoded image is put in the end of allocated buffer
1948 */
1949 decoder->decoded_img = decoder->buf +
1950 decoder->buf_size -
1951 decoded_img_size;
1952
1953 /* clear memory as filters assume 0'ed memory */
1954 memset(decoder->decoded_img,0,decoded_img_size*sizeof(uint8_t));
1955
1956 decoder->error = postProcessScanlines(decoder->decoded_img,
1957 scanlines,
1958 decoder);
1959 }
1960 }
1961}
1962
1963/* Public functions */
1964
1965/* read the information from the header and store it in the decoder
1966 * context struct
1967 * value is error
1968 */
1969void LodePNG_inspect(LodePNG_Decoder* decoder, uint8_t *in, size_t inlength)
1970{
1971 uint32_t header_crc, checksum;
1972 if (inlength == 0 || in == NULL)
1973 {
1974 /* the given data is empty */
1975 decoder->error = 48;
1976 return;
1977 }
1978
1979 if (inlength < 29)
1980 {
1981 /*error: the data length is smaller than the length of the header*/
1982 decoder->error = 27;
1983 return;
1984 }
1985
1986 /* when decoding a new PNG image, make sure all parameters created after
1987 * previous decoding are reset
1988 */
1989 LodePNG_InfoPng_cleanup(&decoder->infoPng);
1990 LodePNG_InfoPng_init(&decoder->infoPng);
1991 decoder->error = 0;
1992
1993 decoder->file = in;
1994 decoder->file_size = inlength;
1995
1996 if (in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71 ||
1997 in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10)
1998 {
1999 /* error: the first 8 bytes are not the correct PNG signature */
2000 decoder->error = 28;
2001 return;
2002 }
2003
2004 if (in[12] != 'I' || in[13] != 'H' || in[14] != 'D' || in[15] != 'R')
2005 {
2006 /* error: it doesn't start with a IHDR chunk! */
2007 decoder->error = 29;
2008 return;
2009 }
2010
2011 /* read the values given in the header */
2012 decoder->infoPng.width = in[16]<<24|in[17]<<16|in[18]<<8|in[19];
2013 decoder->infoPng.height = in[20]<<24|in[21]<<16|in[22]<<8|in[23];
2014 decoder->infoPng.color.bitDepth = in[24];
2015 decoder->infoPng.color.colorType = in[25];
2016 decoder->infoPng.compressionMethod = in[26];
2017 decoder->infoPng.filterMethod = in[27];
2018 decoder->infoPng.interlaceMethod = in[28];
2019
2020 /* get the value from the chunk's crc field */
2021 header_crc = in[29]<<24|in[30]<<16|in[31]<<8|in[32];
2022
2023 /* calculate crc of the header chunk */
2024 checksum = tinf_crc32(in + 12, 17);
2025
2026 if (header_crc != checksum)
2027 {
2028 decoder->error = 57;
2029 return;
2030 }
2031
2032 if (decoder->infoPng.compressionMethod != 0)
2033 {
2034 /* error: only compression method 0 is allowed in the specification */
2035 decoder->error = 32;
2036 return;
2037 }
2038
2039 if (decoder->infoPng.filterMethod != 0)
2040 {
2041 /* error: only filter method 0 is allowed in the specification */
2042 decoder->error = 33;
2043 return;
2044 }
2045
2046 if (decoder->infoPng.interlaceMethod > 1)
2047 {
2048 /* error: only interlace methods 0 and 1 exist in the specification */
2049 decoder->error = 34;
2050 return;
2051 }
2052
2053 /* check validity of colortype and bitdepth combination */
2054 decoder->error = checkColorValidity(decoder->infoPng.color.colorType,
2055 decoder->infoPng.color.bitDepth);
2056}
2057
2058void LodePNG_decode(LodePNG_Decoder* decoder,
2059 uint8_t* in,
2060 size_t insize,
2061 void (*pf_progress)(int current, int total))
2062{
2063 size_t line_buf_size;
2064 /* parse header */
2065 LodePNG_inspect(decoder, in, insize);
2066
2067
2068 /* Check memory available against worst case where
2069 * we have to have decoded PNG image
2070 * and converted to the native pixel format image
2071 * in buffer at the same time (do we realy need that much?)
2072 */
2073
2074 size_t decoded_img_size = (decoder->infoPng.height *
2075 decoder->infoPng.width *
2076 getBpp(decoder->infoPng.color.colorType,
2077 decoder->infoPng.color.bitDepth) +
2078 7) / 8;
2079
2080 /* one line more as temp buffer for conversion */
2081#ifdef HAVE_LCD_COLOR
2082 decoder->native_img_size = decoder->infoPng.width *
2083 (decoder->infoPng.height)*FB_DATA_SZ;
2084 line_buf_size = decoder->infoPng.width * sizeof(struct uint8_rgb);
2085#else
2086 decoder->native_img_size = decoder->infoPng.width *
2087 decoder->infoPng.height;
2088 line_buf_size = decoder->infoPng.width;
2089#endif
2090
2091 if (decoded_img_size + decoder->native_img_size + line_buf_size
2092 > decoder->buf_size)
2093 {
2094 decoder->error = OUT_OF_MEMORY;
2095 return;
2096 }
2097
2098 if (pf_progress != NULL)
2099 pf_progress(0, 100);
2100
2101 long time = *rb->current_tick;
2102 /* put decoded png data (pure 2D array of pixels in format
2103 * defined by PNG header at the end of the allocated buffer
2104 */
2105 decodeGeneric(decoder);
2106 if (decoder->error) return;
2107
2108 if (pf_progress != NULL)
2109 pf_progress(50, 100);
2110
2111 /* convert decoded png data into native rockbox
2112 * pixel format (native LCD data for color
2113 * or greylib pixel format for greyscale)
2114 *
2115 * converted image will be put at the begining
2116 * of the allocated buffer
2117 */
2118 LodePNG_convert(decoder);
2119
2120 /* correct aspect ratio */
2121#if (LCD_PIXEL_ASPECT_HEIGHT != 1 || LCD_PIXEL_ASPECT_WIDTH != 1)
2122 struct bitmap img_src, img_dst; /* scaler vars */
2123 struct dim dim_src, dim_dst; /* recalc_dimensions vars */
2124 unsigned int c_native_img_size; /* size of the image after correction */
2125
2126 dim_src.width = decoder->infoPng.width;
2127 dim_src.height = decoder->infoPng.height;
2128
2129 dim_dst.width = decoder->infoPng.width;
2130 dim_dst.height = decoder->infoPng.height;
2131
2132 /* defined in apps/recorder/resize.c */
2133 if (!recalc_dimension(&dim_dst, &dim_src))
2134 {
2135 /* calculate 'corrected' image size */
2136#ifdef HAVE_LCD_COLOR
2137 c_native_img_size = dim_dst.width *
2138 (dim_dst.height)*FB_DATA_SZ;
2139#else
2140 c_native_img_size = dim_dst.width *
2141 dim_dst.height;
2142#endif
2143 /* check memory constraints
2144 * do the correction only if there is enough
2145 * free memory
2146 */
2147 if ( decoder->native_img_size + c_native_img_size <=
2148 decoder->buf_size )
2149 {
2150 img_src.width = dim_src.width;
2151 img_src.height = dim_src.height;
2152 img_src.data = (unsigned char *)decoder->buf;
2153
2154 img_dst.width = dim_dst.width;
2155 img_dst.height = dim_dst.height;
2156 img_dst.data = (unsigned char *)decoder->buf +
2157 decoder->native_img_size;
2158
2159 /* scale the bitmap to correct physical
2160 * pixel dimentions
2161 */
2162 resize_bitmap(&img_src, &img_dst);
2163
2164 /* update decoder struct */
2165 decoder->infoPng.width = img_dst.width;
2166 decoder->infoPng.height = img_dst.height;
2167 decoder->native_img_size = c_native_img_size;
2168
2169 /* copy back corrected image to the begining of the buffer */
2170 memcpy(img_src.data, img_dst.data, decoder->native_img_size);
2171 }
2172 }
2173
2174#endif /* (LCD_PIXEL_ASPECT_HEIGHT != 1 || LCD_PIXEL_ASPECT_WIDTH != 1) */
2175time = *rb->current_tick - time;
2176if (pf_progress) pf_progress(100, 100);
2177}
2178
2179void LodePNG_Decoder_init(LodePNG_Decoder* decoder,
2180 uint8_t *buf,
2181 size_t buf_size)
2182{
2183 LodePNG_InfoPng_init(&decoder->infoPng);
2184 decoder->error = 0;
2185 decoder->buf = buf;
2186 decoder->buf_size = buf_size;
2187 decoder->decoded_img = NULL;
2188 decoder->file = NULL;
2189 decoder->file_size = 0;
2190}
2191
2192const char* LodePNG_perror(LodePNG_Decoder *decoder)
2193{
2194 return png_error_messages[decoder->error-PNG_ERROR_MIN];
2195}