diff options
Diffstat (limited to 'apps/plugins/imageviewer/png/png_decoder.c')
-rw-r--r-- | apps/plugins/imageviewer/png/png_decoder.c | 2195 |
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 | /* | ||
31 | LodePNG version 20080927 | ||
32 | |||
33 | Copyright (c) 2005-2008 Lode Vandevenne | ||
34 | |||
35 | This software is provided 'as-is', without any express or implied | ||
36 | warranty. In no event will the authors be held liable for any damages | ||
37 | arising from the use of this software. | ||
38 | |||
39 | Permission is granted to anyone to use this software for any purpose, | ||
40 | including commercial applications, and to alter it and redistribute it | ||
41 | freely, 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 | /* | ||
56 | The manual and changelog can be found in the header file "lodepng.h" | ||
57 | You 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 | |||
90 | static 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 | /* | ||
143 | The two functions below (LodePNG_decompress and LodePNG_compress) directly call the | ||
144 | LodeZlib_decompress and LodeZlib_compress functions. The only purpose of the functions | ||
145 | below, is to provide the ability to let LodePNG use a different Zlib encoder by only | ||
146 | changing the two functions below, instead of changing it inside the vareous places | ||
147 | in 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 | ||
151 | be the size of the useful data in bytes, not the alloc size. | ||
152 | */ | ||
153 | |||
154 | static 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 | |||
171 | static 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 | |||
180 | static 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 | |||
192 | static 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 | |||
206 | static 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 | */ | ||
227 | static 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 */ | ||
233 | static 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 | */ | ||
250 | static inline bool LodePNG_chunk_critical(const uint8_t* chunk) | ||
251 | { | ||
252 | return((chunk[4] & 32) == 0); | ||
253 | } | ||
254 | |||
255 | /* 0: public, 1: private */ | ||
256 | static 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 */ | ||
262 | static 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 */ | ||
268 | static 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 */ | ||
282 | static 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 | */ | ||
295 | static 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 | |||
333 | static 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 | |||
351 | static 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 | |||
357 | static 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 | |||
367 | static void LodePNG_InfoColor_cleanup(LodePNG_InfoColor* info) | ||
368 | { | ||
369 | info->palettesize = 0; | ||
370 | } | ||
371 | |||
372 | static 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 | |||
386 | void 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 | */ | ||
395 | static 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 | |||
431 | void (*output_row_8)(uint32_t, void*, struct scaler_context*) = cformat->output_row_8; | ||
432 | |||
433 | #ifdef HAVE_LCD_COLOR | ||
434 | struct uint8_rgb *pixel; | ||
435 | #else | ||
436 | unsigned 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 */ | ||
714 | struct uint8_rgb px_rgb; /* for rgb(a) -> greyscale conversion */ | ||
715 | uint8_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*/ | ||
1014 | static 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 | |||
1028 | static const uint8_t ADAM7_IX[7] = { 0, 4, 0, 2, 0, 1, 0 }; /*x start values*/ | ||
1029 | static const uint8_t ADAM7_IY[7] = { 0, 0, 4, 0, 2, 0, 1 }; /*y start values*/ | ||
1030 | static const uint8_t ADAM7_DX[7] = { 8, 8, 4, 4, 2, 2, 1 }; /*x delta values*/ | ||
1031 | static const uint8_t ADAM7_DY[7] = { 8, 8, 8, 4, 4, 2, 2 }; /*y delta values*/ | ||
1032 | |||
1033 | static 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 | |||
1079 | static 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 */ | ||
1101 | unsigned char cache[512+16]; | ||
1102 | |||
1103 | /* ptr to second element of the cache */ | ||
1104 | unsigned char *cache_1 = cache + bytewidth; | ||
1105 | unsigned char *p_cache = cache + 256 + 8; /* half way */ | ||
1106 | unsigned 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 | |||
1415 | static 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 | |||
1463 | static 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 | |||
1529 | static 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 | */ | ||
1566 | static 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 | */ | ||
1659 | static 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 | */ | ||
1969 | void 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 | |||
2058 | void 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) */ | ||
2175 | time = *rb->current_tick - time; | ||
2176 | if (pf_progress) pf_progress(100, 100); | ||
2177 | } | ||
2178 | |||
2179 | void 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 | |||
2192 | const char* LodePNG_perror(LodePNG_Decoder *decoder) | ||
2193 | { | ||
2194 | return png_error_messages[decoder->error-PNG_ERROR_MIN]; | ||
2195 | } | ||