Graphical demo for the LPC4088 Experiment Base Board with one of the Display Expansion Kits. This program decodes decodes and shows two png images.

Dependencies:   EALib mbed

Committer:
embeddedartists
Date:
Fri Oct 03 13:30:09 2014 +0000
Revision:
0:b567d56a59d7
First version

Who changed what in which revision?

UserRevisionLine numberNew contents of line
embeddedartists 0:b567d56a59d7 1 /*
embeddedartists 0:b567d56a59d7 2 LodePNG version 20131222
embeddedartists 0:b567d56a59d7 3
embeddedartists 0:b567d56a59d7 4 Copyright (c) 2005-2013 Lode Vandevenne
embeddedartists 0:b567d56a59d7 5
embeddedartists 0:b567d56a59d7 6 This software is provided 'as-is', without any express or implied
embeddedartists 0:b567d56a59d7 7 warranty. In no event will the authors be held liable for any damages
embeddedartists 0:b567d56a59d7 8 arising from the use of this software.
embeddedartists 0:b567d56a59d7 9
embeddedartists 0:b567d56a59d7 10 Permission is granted to anyone to use this software for any purpose,
embeddedartists 0:b567d56a59d7 11 including commercial applications, and to alter it and redistribute it
embeddedartists 0:b567d56a59d7 12 freely, subject to the following restrictions:
embeddedartists 0:b567d56a59d7 13
embeddedartists 0:b567d56a59d7 14 1. The origin of this software must not be misrepresented; you must not
embeddedartists 0:b567d56a59d7 15 claim that you wrote the original software. If you use this software
embeddedartists 0:b567d56a59d7 16 in a product, an acknowledgment in the product documentation would be
embeddedartists 0:b567d56a59d7 17 appreciated but is not required.
embeddedartists 0:b567d56a59d7 18
embeddedartists 0:b567d56a59d7 19 2. Altered source versions must be plainly marked as such, and must not be
embeddedartists 0:b567d56a59d7 20 misrepresented as being the original software.
embeddedartists 0:b567d56a59d7 21
embeddedartists 0:b567d56a59d7 22 3. This notice may not be removed or altered from any source
embeddedartists 0:b567d56a59d7 23 distribution.
embeddedartists 0:b567d56a59d7 24 */
embeddedartists 0:b567d56a59d7 25
embeddedartists 0:b567d56a59d7 26 /*
embeddedartists 0:b567d56a59d7 27 The manual and changelog are in the header file "lodepng.h"
embeddedartists 0:b567d56a59d7 28 Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for C.
embeddedartists 0:b567d56a59d7 29 */
embeddedartists 0:b567d56a59d7 30
embeddedartists 0:b567d56a59d7 31 #include "lodepng.h"
embeddedartists 0:b567d56a59d7 32
embeddedartists 0:b567d56a59d7 33 #include <stdio.h>
embeddedartists 0:b567d56a59d7 34 #include <stdlib.h>
embeddedartists 0:b567d56a59d7 35
embeddedartists 0:b567d56a59d7 36 #ifdef LODEPNG_COMPILE_CPP
embeddedartists 0:b567d56a59d7 37 #include <fstream>
embeddedartists 0:b567d56a59d7 38 #endif /*LODEPNG_COMPILE_CPP*/
embeddedartists 0:b567d56a59d7 39
embeddedartists 0:b567d56a59d7 40 #define VERSION_STRING "20131222"
embeddedartists 0:b567d56a59d7 41
embeddedartists 0:b567d56a59d7 42 /*
embeddedartists 0:b567d56a59d7 43 This source file is built up in the following large parts. The code sections
embeddedartists 0:b567d56a59d7 44 with the "LODEPNG_COMPILE_" #defines divide this up further in an intermixed way.
embeddedartists 0:b567d56a59d7 45 -Tools for C and common code for PNG and Zlib
embeddedartists 0:b567d56a59d7 46 -C Code for Zlib (huffman, deflate, ...)
embeddedartists 0:b567d56a59d7 47 -C Code for PNG (file format chunks, adam7, PNG filters, color conversions, ...)
embeddedartists 0:b567d56a59d7 48 -The C++ wrapper around all of the above
embeddedartists 0:b567d56a59d7 49 */
embeddedartists 0:b567d56a59d7 50
embeddedartists 0:b567d56a59d7 51 /*The malloc, realloc and free functions defined here with "lodepng_" in front
embeddedartists 0:b567d56a59d7 52 of the name, so that you can easily change them to others related to your
embeddedartists 0:b567d56a59d7 53 platform if needed. Everything else in the code calls these. Pass
embeddedartists 0:b567d56a59d7 54 -DLODEPNG_NO_COMPILE_ALLOCATORS to the compiler, or comment out
embeddedartists 0:b567d56a59d7 55 #define LODEPNG_COMPILE_ALLOCATORS in the header, to disable the ones here and
embeddedartists 0:b567d56a59d7 56 define them in your own project's source files without needing to change
embeddedartists 0:b567d56a59d7 57 lodepng source code. Don't forget to remove "static" if you copypaste them
embeddedartists 0:b567d56a59d7 58 from here.*/
embeddedartists 0:b567d56a59d7 59
embeddedartists 0:b567d56a59d7 60 #ifdef LODEPNG_COMPILE_ALLOCATORS
embeddedartists 0:b567d56a59d7 61 static void* lodepng_malloc(size_t size)
embeddedartists 0:b567d56a59d7 62 {
embeddedartists 0:b567d56a59d7 63 return malloc(size);
embeddedartists 0:b567d56a59d7 64 }
embeddedartists 0:b567d56a59d7 65
embeddedartists 0:b567d56a59d7 66 static void* lodepng_realloc(void* ptr, size_t new_size)
embeddedartists 0:b567d56a59d7 67 {
embeddedartists 0:b567d56a59d7 68 return realloc(ptr, new_size);
embeddedartists 0:b567d56a59d7 69 }
embeddedartists 0:b567d56a59d7 70
embeddedartists 0:b567d56a59d7 71 static void lodepng_free(void* ptr)
embeddedartists 0:b567d56a59d7 72 {
embeddedartists 0:b567d56a59d7 73 free(ptr);
embeddedartists 0:b567d56a59d7 74 }
embeddedartists 0:b567d56a59d7 75 #else /*LODEPNG_COMPILE_ALLOCATORS*/
embeddedartists 0:b567d56a59d7 76 void* lodepng_malloc(size_t size);
embeddedartists 0:b567d56a59d7 77 void* lodepng_realloc(void* ptr, size_t new_size);
embeddedartists 0:b567d56a59d7 78 void lodepng_free(void* ptr);
embeddedartists 0:b567d56a59d7 79 #endif /*LODEPNG_COMPILE_ALLOCATORS*/
embeddedartists 0:b567d56a59d7 80
embeddedartists 0:b567d56a59d7 81 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 82 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 83 /* // Tools for C, and common code for PNG and Zlib. // */
embeddedartists 0:b567d56a59d7 84 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 85 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 86
embeddedartists 0:b567d56a59d7 87 /*
embeddedartists 0:b567d56a59d7 88 Often in case of an error a value is assigned to a variable and then it breaks
embeddedartists 0:b567d56a59d7 89 out of a loop (to go to the cleanup phase of a function). This macro does that.
embeddedartists 0:b567d56a59d7 90 It makes the error handling code shorter and more readable.
embeddedartists 0:b567d56a59d7 91
embeddedartists 0:b567d56a59d7 92 Example: if(!uivector_resizev(&frequencies_ll, 286, 0)) ERROR_BREAK(83);
embeddedartists 0:b567d56a59d7 93 */
embeddedartists 0:b567d56a59d7 94 #define CERROR_BREAK(errorvar, code)\
embeddedartists 0:b567d56a59d7 95 {\
embeddedartists 0:b567d56a59d7 96 errorvar = code;\
embeddedartists 0:b567d56a59d7 97 break;\
embeddedartists 0:b567d56a59d7 98 }
embeddedartists 0:b567d56a59d7 99
embeddedartists 0:b567d56a59d7 100 /*version of CERROR_BREAK that assumes the common case where the error variable is named "error"*/
embeddedartists 0:b567d56a59d7 101 #define ERROR_BREAK(code) CERROR_BREAK(error, code)
embeddedartists 0:b567d56a59d7 102
embeddedartists 0:b567d56a59d7 103 /*Set error var to the error code, and return it.*/
embeddedartists 0:b567d56a59d7 104 #define CERROR_RETURN_ERROR(errorvar, code)\
embeddedartists 0:b567d56a59d7 105 {\
embeddedartists 0:b567d56a59d7 106 errorvar = code;\
embeddedartists 0:b567d56a59d7 107 return code;\
embeddedartists 0:b567d56a59d7 108 }
embeddedartists 0:b567d56a59d7 109
embeddedartists 0:b567d56a59d7 110 /*Try the code, if it returns error, also return the error.*/
embeddedartists 0:b567d56a59d7 111 #define CERROR_TRY_RETURN(call)\
embeddedartists 0:b567d56a59d7 112 {\
embeddedartists 0:b567d56a59d7 113 unsigned error = call;\
embeddedartists 0:b567d56a59d7 114 if(error) return error;\
embeddedartists 0:b567d56a59d7 115 }
embeddedartists 0:b567d56a59d7 116
embeddedartists 0:b567d56a59d7 117 /*
embeddedartists 0:b567d56a59d7 118 About uivector, ucvector and string:
embeddedartists 0:b567d56a59d7 119 -All of them wrap dynamic arrays or text strings in a similar way.
embeddedartists 0:b567d56a59d7 120 -LodePNG was originally written in C++. The vectors replace the std::vectors that were used in the C++ version.
embeddedartists 0:b567d56a59d7 121 -The string tools are made to avoid problems with compilers that declare things like strncat as deprecated.
embeddedartists 0:b567d56a59d7 122 -They're not used in the interface, only internally in this file as static functions.
embeddedartists 0:b567d56a59d7 123 -As with many other structs in this file, the init and cleanup functions serve as ctor and dtor.
embeddedartists 0:b567d56a59d7 124 */
embeddedartists 0:b567d56a59d7 125
embeddedartists 0:b567d56a59d7 126 #ifdef LODEPNG_COMPILE_ZLIB
embeddedartists 0:b567d56a59d7 127 /*dynamic vector of unsigned ints*/
embeddedartists 0:b567d56a59d7 128 typedef struct uivector
embeddedartists 0:b567d56a59d7 129 {
embeddedartists 0:b567d56a59d7 130 unsigned* data;
embeddedartists 0:b567d56a59d7 131 size_t size; /*size in number of unsigned longs*/
embeddedartists 0:b567d56a59d7 132 size_t allocsize; /*allocated size in bytes*/
embeddedartists 0:b567d56a59d7 133 } uivector;
embeddedartists 0:b567d56a59d7 134
embeddedartists 0:b567d56a59d7 135 static void uivector_cleanup(void* p)
embeddedartists 0:b567d56a59d7 136 {
embeddedartists 0:b567d56a59d7 137 ((uivector*)p)->size = ((uivector*)p)->allocsize = 0;
embeddedartists 0:b567d56a59d7 138 lodepng_free(((uivector*)p)->data);
embeddedartists 0:b567d56a59d7 139 ((uivector*)p)->data = NULL;
embeddedartists 0:b567d56a59d7 140 }
embeddedartists 0:b567d56a59d7 141
embeddedartists 0:b567d56a59d7 142 /*returns 1 if success, 0 if failure ==> nothing done*/
embeddedartists 0:b567d56a59d7 143 static unsigned uivector_resize(uivector* p, size_t size)
embeddedartists 0:b567d56a59d7 144 {
embeddedartists 0:b567d56a59d7 145 if(size * sizeof(unsigned) > p->allocsize)
embeddedartists 0:b567d56a59d7 146 {
embeddedartists 0:b567d56a59d7 147 size_t newsize = size * sizeof(unsigned) * 2;
embeddedartists 0:b567d56a59d7 148 void* data = lodepng_realloc(p->data, newsize);
embeddedartists 0:b567d56a59d7 149 if(data)
embeddedartists 0:b567d56a59d7 150 {
embeddedartists 0:b567d56a59d7 151 p->allocsize = newsize;
embeddedartists 0:b567d56a59d7 152 p->data = (unsigned*)data;
embeddedartists 0:b567d56a59d7 153 p->size = size;
embeddedartists 0:b567d56a59d7 154 }
embeddedartists 0:b567d56a59d7 155 else return 0;
embeddedartists 0:b567d56a59d7 156 }
embeddedartists 0:b567d56a59d7 157 else p->size = size;
embeddedartists 0:b567d56a59d7 158 return 1;
embeddedartists 0:b567d56a59d7 159 }
embeddedartists 0:b567d56a59d7 160
embeddedartists 0:b567d56a59d7 161 /*resize and give all new elements the value*/
embeddedartists 0:b567d56a59d7 162 static unsigned uivector_resizev(uivector* p, size_t size, unsigned value)
embeddedartists 0:b567d56a59d7 163 {
embeddedartists 0:b567d56a59d7 164 size_t oldsize = p->size, i;
embeddedartists 0:b567d56a59d7 165 if(!uivector_resize(p, size)) return 0;
embeddedartists 0:b567d56a59d7 166 for(i = oldsize; i < size; i++) p->data[i] = value;
embeddedartists 0:b567d56a59d7 167 return 1;
embeddedartists 0:b567d56a59d7 168 }
embeddedartists 0:b567d56a59d7 169
embeddedartists 0:b567d56a59d7 170 static void uivector_init(uivector* p)
embeddedartists 0:b567d56a59d7 171 {
embeddedartists 0:b567d56a59d7 172 p->data = NULL;
embeddedartists 0:b567d56a59d7 173 p->size = p->allocsize = 0;
embeddedartists 0:b567d56a59d7 174 }
embeddedartists 0:b567d56a59d7 175
embeddedartists 0:b567d56a59d7 176 #ifdef LODEPNG_COMPILE_ENCODER
embeddedartists 0:b567d56a59d7 177 /*returns 1 if success, 0 if failure ==> nothing done*/
embeddedartists 0:b567d56a59d7 178 static unsigned uivector_push_back(uivector* p, unsigned c)
embeddedartists 0:b567d56a59d7 179 {
embeddedartists 0:b567d56a59d7 180 if(!uivector_resize(p, p->size + 1)) return 0;
embeddedartists 0:b567d56a59d7 181 p->data[p->size - 1] = c;
embeddedartists 0:b567d56a59d7 182 return 1;
embeddedartists 0:b567d56a59d7 183 }
embeddedartists 0:b567d56a59d7 184
embeddedartists 0:b567d56a59d7 185 /*copy q to p, returns 1 if success, 0 if failure ==> nothing done*/
embeddedartists 0:b567d56a59d7 186 static unsigned uivector_copy(uivector* p, const uivector* q)
embeddedartists 0:b567d56a59d7 187 {
embeddedartists 0:b567d56a59d7 188 size_t i;
embeddedartists 0:b567d56a59d7 189 if(!uivector_resize(p, q->size)) return 0;
embeddedartists 0:b567d56a59d7 190 for(i = 0; i < q->size; i++) p->data[i] = q->data[i];
embeddedartists 0:b567d56a59d7 191 return 1;
embeddedartists 0:b567d56a59d7 192 }
embeddedartists 0:b567d56a59d7 193 #endif /*LODEPNG_COMPILE_ENCODER*/
embeddedartists 0:b567d56a59d7 194 #endif /*LODEPNG_COMPILE_ZLIB*/
embeddedartists 0:b567d56a59d7 195
embeddedartists 0:b567d56a59d7 196 /* /////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 197
embeddedartists 0:b567d56a59d7 198 /*dynamic vector of unsigned chars*/
embeddedartists 0:b567d56a59d7 199 typedef struct ucvector
embeddedartists 0:b567d56a59d7 200 {
embeddedartists 0:b567d56a59d7 201 unsigned char* data;
embeddedartists 0:b567d56a59d7 202 size_t size; /*used size*/
embeddedartists 0:b567d56a59d7 203 size_t allocsize; /*allocated size*/
embeddedartists 0:b567d56a59d7 204 } ucvector;
embeddedartists 0:b567d56a59d7 205
embeddedartists 0:b567d56a59d7 206 /*returns 1 if success, 0 if failure ==> nothing done*/
embeddedartists 0:b567d56a59d7 207 static unsigned ucvector_resize(ucvector* p, size_t size)
embeddedartists 0:b567d56a59d7 208 {
embeddedartists 0:b567d56a59d7 209 if(size * sizeof(unsigned char) > p->allocsize)
embeddedartists 0:b567d56a59d7 210 {
embeddedartists 0:b567d56a59d7 211 size_t newsize = size * sizeof(unsigned char) * 2;
embeddedartists 0:b567d56a59d7 212 void* data = lodepng_realloc(p->data, newsize);
embeddedartists 0:b567d56a59d7 213 if(data)
embeddedartists 0:b567d56a59d7 214 {
embeddedartists 0:b567d56a59d7 215 p->allocsize = newsize;
embeddedartists 0:b567d56a59d7 216 p->data = (unsigned char*)data;
embeddedartists 0:b567d56a59d7 217 p->size = size;
embeddedartists 0:b567d56a59d7 218 }
embeddedartists 0:b567d56a59d7 219 else return 0; /*error: not enough memory*/
embeddedartists 0:b567d56a59d7 220 }
embeddedartists 0:b567d56a59d7 221 else p->size = size;
embeddedartists 0:b567d56a59d7 222 return 1;
embeddedartists 0:b567d56a59d7 223 }
embeddedartists 0:b567d56a59d7 224
embeddedartists 0:b567d56a59d7 225 #ifdef LODEPNG_COMPILE_PNG
embeddedartists 0:b567d56a59d7 226
embeddedartists 0:b567d56a59d7 227 static void ucvector_cleanup(void* p)
embeddedartists 0:b567d56a59d7 228 {
embeddedartists 0:b567d56a59d7 229 ((ucvector*)p)->size = ((ucvector*)p)->allocsize = 0;
embeddedartists 0:b567d56a59d7 230 lodepng_free(((ucvector*)p)->data);
embeddedartists 0:b567d56a59d7 231 ((ucvector*)p)->data = NULL;
embeddedartists 0:b567d56a59d7 232 }
embeddedartists 0:b567d56a59d7 233
embeddedartists 0:b567d56a59d7 234 static void ucvector_init(ucvector* p)
embeddedartists 0:b567d56a59d7 235 {
embeddedartists 0:b567d56a59d7 236 p->data = NULL;
embeddedartists 0:b567d56a59d7 237 p->size = p->allocsize = 0;
embeddedartists 0:b567d56a59d7 238 }
embeddedartists 0:b567d56a59d7 239
embeddedartists 0:b567d56a59d7 240 #ifdef LODEPNG_COMPILE_DECODER
embeddedartists 0:b567d56a59d7 241 /*resize and give all new elements the value*/
embeddedartists 0:b567d56a59d7 242 static unsigned ucvector_resizev(ucvector* p, size_t size, unsigned char value)
embeddedartists 0:b567d56a59d7 243 {
embeddedartists 0:b567d56a59d7 244 size_t oldsize = p->size, i;
embeddedartists 0:b567d56a59d7 245 if(!ucvector_resize(p, size)) return 0;
embeddedartists 0:b567d56a59d7 246 for(i = oldsize; i < size; i++) p->data[i] = value;
embeddedartists 0:b567d56a59d7 247 return 1;
embeddedartists 0:b567d56a59d7 248 }
embeddedartists 0:b567d56a59d7 249 #endif /*LODEPNG_COMPILE_DECODER*/
embeddedartists 0:b567d56a59d7 250 #endif /*LODEPNG_COMPILE_PNG*/
embeddedartists 0:b567d56a59d7 251
embeddedartists 0:b567d56a59d7 252 #ifdef LODEPNG_COMPILE_ZLIB
embeddedartists 0:b567d56a59d7 253 /*you can both convert from vector to buffer&size and vica versa. If you use
embeddedartists 0:b567d56a59d7 254 init_buffer to take over a buffer and size, it is not needed to use cleanup*/
embeddedartists 0:b567d56a59d7 255 static void ucvector_init_buffer(ucvector* p, unsigned char* buffer, size_t size)
embeddedartists 0:b567d56a59d7 256 {
embeddedartists 0:b567d56a59d7 257 p->data = buffer;
embeddedartists 0:b567d56a59d7 258 p->allocsize = p->size = size;
embeddedartists 0:b567d56a59d7 259 }
embeddedartists 0:b567d56a59d7 260 #endif /*LODEPNG_COMPILE_ZLIB*/
embeddedartists 0:b567d56a59d7 261
embeddedartists 0:b567d56a59d7 262 #if (defined(LODEPNG_COMPILE_PNG) && defined(LODEPNG_COMPILE_ANCILLARY_CHUNKS)) || defined(LODEPNG_COMPILE_ENCODER)
embeddedartists 0:b567d56a59d7 263 /*returns 1 if success, 0 if failure ==> nothing done*/
embeddedartists 0:b567d56a59d7 264 static unsigned ucvector_push_back(ucvector* p, unsigned char c)
embeddedartists 0:b567d56a59d7 265 {
embeddedartists 0:b567d56a59d7 266 if(!ucvector_resize(p, p->size + 1)) return 0;
embeddedartists 0:b567d56a59d7 267 p->data[p->size - 1] = c;
embeddedartists 0:b567d56a59d7 268 return 1;
embeddedartists 0:b567d56a59d7 269 }
embeddedartists 0:b567d56a59d7 270 #endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)*/
embeddedartists 0:b567d56a59d7 271
embeddedartists 0:b567d56a59d7 272
embeddedartists 0:b567d56a59d7 273 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 274
embeddedartists 0:b567d56a59d7 275 #ifdef LODEPNG_COMPILE_PNG
embeddedartists 0:b567d56a59d7 276 #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
embeddedartists 0:b567d56a59d7 277 /*returns 1 if success, 0 if failure ==> nothing done*/
embeddedartists 0:b567d56a59d7 278 static unsigned string_resize(char** out, size_t size)
embeddedartists 0:b567d56a59d7 279 {
embeddedartists 0:b567d56a59d7 280 char* data = (char*)lodepng_realloc(*out, size + 1);
embeddedartists 0:b567d56a59d7 281 if(data)
embeddedartists 0:b567d56a59d7 282 {
embeddedartists 0:b567d56a59d7 283 data[size] = 0; /*null termination char*/
embeddedartists 0:b567d56a59d7 284 *out = data;
embeddedartists 0:b567d56a59d7 285 }
embeddedartists 0:b567d56a59d7 286 return data != 0;
embeddedartists 0:b567d56a59d7 287 }
embeddedartists 0:b567d56a59d7 288
embeddedartists 0:b567d56a59d7 289 /*init a {char*, size_t} pair for use as string*/
embeddedartists 0:b567d56a59d7 290 static void string_init(char** out)
embeddedartists 0:b567d56a59d7 291 {
embeddedartists 0:b567d56a59d7 292 *out = NULL;
embeddedartists 0:b567d56a59d7 293 string_resize(out, 0);
embeddedartists 0:b567d56a59d7 294 }
embeddedartists 0:b567d56a59d7 295
embeddedartists 0:b567d56a59d7 296 /*free the above pair again*/
embeddedartists 0:b567d56a59d7 297 static void string_cleanup(char** out)
embeddedartists 0:b567d56a59d7 298 {
embeddedartists 0:b567d56a59d7 299 lodepng_free(*out);
embeddedartists 0:b567d56a59d7 300 *out = NULL;
embeddedartists 0:b567d56a59d7 301 }
embeddedartists 0:b567d56a59d7 302
embeddedartists 0:b567d56a59d7 303 static void string_set(char** out, const char* in)
embeddedartists 0:b567d56a59d7 304 {
embeddedartists 0:b567d56a59d7 305 size_t insize = strlen(in), i = 0;
embeddedartists 0:b567d56a59d7 306 if(string_resize(out, insize))
embeddedartists 0:b567d56a59d7 307 {
embeddedartists 0:b567d56a59d7 308 for(i = 0; i < insize; i++)
embeddedartists 0:b567d56a59d7 309 {
embeddedartists 0:b567d56a59d7 310 (*out)[i] = in[i];
embeddedartists 0:b567d56a59d7 311 }
embeddedartists 0:b567d56a59d7 312 }
embeddedartists 0:b567d56a59d7 313 }
embeddedartists 0:b567d56a59d7 314 #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
embeddedartists 0:b567d56a59d7 315 #endif /*LODEPNG_COMPILE_PNG*/
embeddedartists 0:b567d56a59d7 316
embeddedartists 0:b567d56a59d7 317 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 318
embeddedartists 0:b567d56a59d7 319 unsigned lodepng_read32bitInt(const unsigned char* buffer)
embeddedartists 0:b567d56a59d7 320 {
embeddedartists 0:b567d56a59d7 321 return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
embeddedartists 0:b567d56a59d7 322 }
embeddedartists 0:b567d56a59d7 323
embeddedartists 0:b567d56a59d7 324 #if defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)
embeddedartists 0:b567d56a59d7 325 /*buffer must have at least 4 allocated bytes available*/
embeddedartists 0:b567d56a59d7 326 static void lodepng_set32bitInt(unsigned char* buffer, unsigned value)
embeddedartists 0:b567d56a59d7 327 {
embeddedartists 0:b567d56a59d7 328 buffer[0] = (unsigned char)((value >> 24) & 0xff);
embeddedartists 0:b567d56a59d7 329 buffer[1] = (unsigned char)((value >> 16) & 0xff);
embeddedartists 0:b567d56a59d7 330 buffer[2] = (unsigned char)((value >> 8) & 0xff);
embeddedartists 0:b567d56a59d7 331 buffer[3] = (unsigned char)((value ) & 0xff);
embeddedartists 0:b567d56a59d7 332 }
embeddedartists 0:b567d56a59d7 333 #endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)*/
embeddedartists 0:b567d56a59d7 334
embeddedartists 0:b567d56a59d7 335 #ifdef LODEPNG_COMPILE_ENCODER
embeddedartists 0:b567d56a59d7 336 static void lodepng_add32bitInt(ucvector* buffer, unsigned value)
embeddedartists 0:b567d56a59d7 337 {
embeddedartists 0:b567d56a59d7 338 ucvector_resize(buffer, buffer->size + 4); /*todo: give error if resize failed*/
embeddedartists 0:b567d56a59d7 339 lodepng_set32bitInt(&buffer->data[buffer->size - 4], value);
embeddedartists 0:b567d56a59d7 340 }
embeddedartists 0:b567d56a59d7 341 #endif /*LODEPNG_COMPILE_ENCODER*/
embeddedartists 0:b567d56a59d7 342
embeddedartists 0:b567d56a59d7 343 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 344 /* / File IO / */
embeddedartists 0:b567d56a59d7 345 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 346
embeddedartists 0:b567d56a59d7 347 #ifdef LODEPNG_COMPILE_DISK
embeddedartists 0:b567d56a59d7 348
embeddedartists 0:b567d56a59d7 349 unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename)
embeddedartists 0:b567d56a59d7 350 {
embeddedartists 0:b567d56a59d7 351 FILE* file;
embeddedartists 0:b567d56a59d7 352 long size;
embeddedartists 0:b567d56a59d7 353
embeddedartists 0:b567d56a59d7 354 /*provide some proper output values if error will happen*/
embeddedartists 0:b567d56a59d7 355 *out = 0;
embeddedartists 0:b567d56a59d7 356 *outsize = 0;
embeddedartists 0:b567d56a59d7 357
embeddedartists 0:b567d56a59d7 358 file = fopen(filename, "rb");
embeddedartists 0:b567d56a59d7 359 if(!file) return 78;
embeddedartists 0:b567d56a59d7 360
embeddedartists 0:b567d56a59d7 361 /*get filesize:*/
embeddedartists 0:b567d56a59d7 362 fseek(file , 0 , SEEK_END);
embeddedartists 0:b567d56a59d7 363 size = ftell(file);
embeddedartists 0:b567d56a59d7 364 rewind(file);
embeddedartists 0:b567d56a59d7 365
embeddedartists 0:b567d56a59d7 366 /*read contents of the file into the vector*/
embeddedartists 0:b567d56a59d7 367 *outsize = 0;
embeddedartists 0:b567d56a59d7 368 *out = (unsigned char*)lodepng_malloc((size_t)size);
embeddedartists 0:b567d56a59d7 369 if(size && (*out)) (*outsize) = fread(*out, 1, (size_t)size, file);
embeddedartists 0:b567d56a59d7 370
embeddedartists 0:b567d56a59d7 371 fclose(file);
embeddedartists 0:b567d56a59d7 372 if(!(*out) && size) return 83; /*the above malloc failed*/
embeddedartists 0:b567d56a59d7 373 return 0;
embeddedartists 0:b567d56a59d7 374 }
embeddedartists 0:b567d56a59d7 375
embeddedartists 0:b567d56a59d7 376 /*write given buffer to the file, overwriting the file, it doesn't append to it.*/
embeddedartists 0:b567d56a59d7 377 unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename)
embeddedartists 0:b567d56a59d7 378 {
embeddedartists 0:b567d56a59d7 379 FILE* file;
embeddedartists 0:b567d56a59d7 380 file = fopen(filename, "wb" );
embeddedartists 0:b567d56a59d7 381 if(!file) return 79;
embeddedartists 0:b567d56a59d7 382 fwrite((char*)buffer , 1 , buffersize, file);
embeddedartists 0:b567d56a59d7 383 fclose(file);
embeddedartists 0:b567d56a59d7 384 return 0;
embeddedartists 0:b567d56a59d7 385 }
embeddedartists 0:b567d56a59d7 386
embeddedartists 0:b567d56a59d7 387 #endif /*LODEPNG_COMPILE_DISK*/
embeddedartists 0:b567d56a59d7 388
embeddedartists 0:b567d56a59d7 389 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 390 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 391 /* // End of common code and tools. Begin of Zlib related code. // */
embeddedartists 0:b567d56a59d7 392 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 393 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 394
embeddedartists 0:b567d56a59d7 395 #ifdef LODEPNG_COMPILE_ZLIB
embeddedartists 0:b567d56a59d7 396 #ifdef LODEPNG_COMPILE_ENCODER
embeddedartists 0:b567d56a59d7 397 /*TODO: this ignores potential out of memory errors*/
embeddedartists 0:b567d56a59d7 398 #define addBitToStream(/*size_t**/ bitpointer, /*ucvector**/ bitstream, /*unsigned char*/ bit)\
embeddedartists 0:b567d56a59d7 399 {\
embeddedartists 0:b567d56a59d7 400 /*add a new byte at the end*/\
embeddedartists 0:b567d56a59d7 401 if(((*bitpointer) & 7) == 0) ucvector_push_back(bitstream, (unsigned char)0);\
embeddedartists 0:b567d56a59d7 402 /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/\
embeddedartists 0:b567d56a59d7 403 (bitstream->data[bitstream->size - 1]) |= (bit << ((*bitpointer) & 0x7));\
embeddedartists 0:b567d56a59d7 404 (*bitpointer)++;\
embeddedartists 0:b567d56a59d7 405 }
embeddedartists 0:b567d56a59d7 406
embeddedartists 0:b567d56a59d7 407 static void addBitsToStream(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits)
embeddedartists 0:b567d56a59d7 408 {
embeddedartists 0:b567d56a59d7 409 size_t i;
embeddedartists 0:b567d56a59d7 410 for(i = 0; i < nbits; i++) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> i) & 1));
embeddedartists 0:b567d56a59d7 411 }
embeddedartists 0:b567d56a59d7 412
embeddedartists 0:b567d56a59d7 413 static void addBitsToStreamReversed(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits)
embeddedartists 0:b567d56a59d7 414 {
embeddedartists 0:b567d56a59d7 415 size_t i;
embeddedartists 0:b567d56a59d7 416 for(i = 0; i < nbits; i++) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> (nbits - 1 - i)) & 1));
embeddedartists 0:b567d56a59d7 417 }
embeddedartists 0:b567d56a59d7 418 #endif /*LODEPNG_COMPILE_ENCODER*/
embeddedartists 0:b567d56a59d7 419
embeddedartists 0:b567d56a59d7 420 #ifdef LODEPNG_COMPILE_DECODER
embeddedartists 0:b567d56a59d7 421
embeddedartists 0:b567d56a59d7 422 #define READBIT(bitpointer, bitstream) ((bitstream[bitpointer >> 3] >> (bitpointer & 0x7)) & (unsigned char)1)
embeddedartists 0:b567d56a59d7 423
embeddedartists 0:b567d56a59d7 424 static unsigned char readBitFromStream(size_t* bitpointer, const unsigned char* bitstream)
embeddedartists 0:b567d56a59d7 425 {
embeddedartists 0:b567d56a59d7 426 unsigned char result = (unsigned char)(READBIT(*bitpointer, bitstream));
embeddedartists 0:b567d56a59d7 427 (*bitpointer)++;
embeddedartists 0:b567d56a59d7 428 return result;
embeddedartists 0:b567d56a59d7 429 }
embeddedartists 0:b567d56a59d7 430
embeddedartists 0:b567d56a59d7 431 static unsigned readBitsFromStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits)
embeddedartists 0:b567d56a59d7 432 {
embeddedartists 0:b567d56a59d7 433 unsigned result = 0, i;
embeddedartists 0:b567d56a59d7 434 for(i = 0; i < nbits; i++)
embeddedartists 0:b567d56a59d7 435 {
embeddedartists 0:b567d56a59d7 436 result += ((unsigned)READBIT(*bitpointer, bitstream)) << i;
embeddedartists 0:b567d56a59d7 437 (*bitpointer)++;
embeddedartists 0:b567d56a59d7 438 }
embeddedartists 0:b567d56a59d7 439 return result;
embeddedartists 0:b567d56a59d7 440 }
embeddedartists 0:b567d56a59d7 441 #endif /*LODEPNG_COMPILE_DECODER*/
embeddedartists 0:b567d56a59d7 442
embeddedartists 0:b567d56a59d7 443 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 444 /* / Deflate - Huffman / */
embeddedartists 0:b567d56a59d7 445 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 446
embeddedartists 0:b567d56a59d7 447 #define FIRST_LENGTH_CODE_INDEX 257
embeddedartists 0:b567d56a59d7 448 #define LAST_LENGTH_CODE_INDEX 285
embeddedartists 0:b567d56a59d7 449 /*256 literals, the end code, some length codes, and 2 unused codes*/
embeddedartists 0:b567d56a59d7 450 #define NUM_DEFLATE_CODE_SYMBOLS 288
embeddedartists 0:b567d56a59d7 451 /*the distance codes have their own symbols, 30 used, 2 unused*/
embeddedartists 0:b567d56a59d7 452 #define NUM_DISTANCE_SYMBOLS 32
embeddedartists 0:b567d56a59d7 453 /*the code length codes. 0-15: code lengths, 16: copy previous 3-6 times, 17: 3-10 zeros, 18: 11-138 zeros*/
embeddedartists 0:b567d56a59d7 454 #define NUM_CODE_LENGTH_CODES 19
embeddedartists 0:b567d56a59d7 455
embeddedartists 0:b567d56a59d7 456 /*the base lengths represented by codes 257-285*/
embeddedartists 0:b567d56a59d7 457 static const unsigned LENGTHBASE[29]
embeddedartists 0:b567d56a59d7 458 = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59,
embeddedartists 0:b567d56a59d7 459 67, 83, 99, 115, 131, 163, 195, 227, 258};
embeddedartists 0:b567d56a59d7 460
embeddedartists 0:b567d56a59d7 461 /*the extra bits used by codes 257-285 (added to base length)*/
embeddedartists 0:b567d56a59d7 462 static const unsigned LENGTHEXTRA[29]
embeddedartists 0:b567d56a59d7 463 = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
embeddedartists 0:b567d56a59d7 464 4, 4, 4, 4, 5, 5, 5, 5, 0};
embeddedartists 0:b567d56a59d7 465
embeddedartists 0:b567d56a59d7 466 /*the base backwards distances (the bits of distance codes appear after length codes and use their own huffman tree)*/
embeddedartists 0:b567d56a59d7 467 static const unsigned DISTANCEBASE[30]
embeddedartists 0:b567d56a59d7 468 = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513,
embeddedartists 0:b567d56a59d7 469 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577};
embeddedartists 0:b567d56a59d7 470
embeddedartists 0:b567d56a59d7 471 /*the extra bits of backwards distances (added to base)*/
embeddedartists 0:b567d56a59d7 472 static const unsigned DISTANCEEXTRA[30]
embeddedartists 0:b567d56a59d7 473 = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8,
embeddedartists 0:b567d56a59d7 474 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13};
embeddedartists 0:b567d56a59d7 475
embeddedartists 0:b567d56a59d7 476 /*the order in which "code length alphabet code lengths" are stored, out of this
embeddedartists 0:b567d56a59d7 477 the huffman tree of the dynamic huffman tree lengths is generated*/
embeddedartists 0:b567d56a59d7 478 static const unsigned CLCL_ORDER[NUM_CODE_LENGTH_CODES]
embeddedartists 0:b567d56a59d7 479 = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
embeddedartists 0:b567d56a59d7 480
embeddedartists 0:b567d56a59d7 481 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 482
embeddedartists 0:b567d56a59d7 483 /*
embeddedartists 0:b567d56a59d7 484 Huffman tree struct, containing multiple representations of the tree
embeddedartists 0:b567d56a59d7 485 */
embeddedartists 0:b567d56a59d7 486 typedef struct HuffmanTree
embeddedartists 0:b567d56a59d7 487 {
embeddedartists 0:b567d56a59d7 488 unsigned* tree2d;
embeddedartists 0:b567d56a59d7 489 unsigned* tree1d;
embeddedartists 0:b567d56a59d7 490 unsigned* lengths; /*the lengths of the codes of the 1d-tree*/
embeddedartists 0:b567d56a59d7 491 unsigned maxbitlen; /*maximum number of bits a single code can get*/
embeddedartists 0:b567d56a59d7 492 unsigned numcodes; /*number of symbols in the alphabet = number of codes*/
embeddedartists 0:b567d56a59d7 493 } HuffmanTree;
embeddedartists 0:b567d56a59d7 494
embeddedartists 0:b567d56a59d7 495 /*function used for debug purposes to draw the tree in ascii art with C++*/
embeddedartists 0:b567d56a59d7 496 /*
embeddedartists 0:b567d56a59d7 497 static void HuffmanTree_draw(HuffmanTree* tree)
embeddedartists 0:b567d56a59d7 498 {
embeddedartists 0:b567d56a59d7 499 std::cout << "tree. length: " << tree->numcodes << " maxbitlen: " << tree->maxbitlen << std::endl;
embeddedartists 0:b567d56a59d7 500 for(size_t i = 0; i < tree->tree1d.size; i++)
embeddedartists 0:b567d56a59d7 501 {
embeddedartists 0:b567d56a59d7 502 if(tree->lengths.data[i])
embeddedartists 0:b567d56a59d7 503 std::cout << i << " " << tree->tree1d.data[i] << " " << tree->lengths.data[i] << std::endl;
embeddedartists 0:b567d56a59d7 504 }
embeddedartists 0:b567d56a59d7 505 std::cout << std::endl;
embeddedartists 0:b567d56a59d7 506 }*/
embeddedartists 0:b567d56a59d7 507
embeddedartists 0:b567d56a59d7 508 static void HuffmanTree_init(HuffmanTree* tree)
embeddedartists 0:b567d56a59d7 509 {
embeddedartists 0:b567d56a59d7 510 tree->tree2d = 0;
embeddedartists 0:b567d56a59d7 511 tree->tree1d = 0;
embeddedartists 0:b567d56a59d7 512 tree->lengths = 0;
embeddedartists 0:b567d56a59d7 513 }
embeddedartists 0:b567d56a59d7 514
embeddedartists 0:b567d56a59d7 515 static void HuffmanTree_cleanup(HuffmanTree* tree)
embeddedartists 0:b567d56a59d7 516 {
embeddedartists 0:b567d56a59d7 517 lodepng_free(tree->tree2d);
embeddedartists 0:b567d56a59d7 518 lodepng_free(tree->tree1d);
embeddedartists 0:b567d56a59d7 519 lodepng_free(tree->lengths);
embeddedartists 0:b567d56a59d7 520 }
embeddedartists 0:b567d56a59d7 521
embeddedartists 0:b567d56a59d7 522 /*the tree representation used by the decoder. return value is error*/
embeddedartists 0:b567d56a59d7 523 static unsigned HuffmanTree_make2DTree(HuffmanTree* tree)
embeddedartists 0:b567d56a59d7 524 {
embeddedartists 0:b567d56a59d7 525 unsigned nodefilled = 0; /*up to which node it is filled*/
embeddedartists 0:b567d56a59d7 526 unsigned treepos = 0; /*position in the tree (1 of the numcodes columns)*/
embeddedartists 0:b567d56a59d7 527 unsigned n, i;
embeddedartists 0:b567d56a59d7 528
embeddedartists 0:b567d56a59d7 529 tree->tree2d = (unsigned*)lodepng_malloc(tree->numcodes * 2 * sizeof(unsigned));
embeddedartists 0:b567d56a59d7 530 if(!tree->tree2d) return 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 531
embeddedartists 0:b567d56a59d7 532 /*
embeddedartists 0:b567d56a59d7 533 convert tree1d[] to tree2d[][]. In the 2D array, a value of 32767 means
embeddedartists 0:b567d56a59d7 534 uninited, a value >= numcodes is an address to another bit, a value < numcodes
embeddedartists 0:b567d56a59d7 535 is a code. The 2 rows are the 2 possible bit values (0 or 1), there are as
embeddedartists 0:b567d56a59d7 536 many columns as codes - 1.
embeddedartists 0:b567d56a59d7 537 A good huffmann tree has N * 2 - 1 nodes, of which N - 1 are internal nodes.
embeddedartists 0:b567d56a59d7 538 Here, the internal nodes are stored (what their 0 and 1 option point to).
embeddedartists 0:b567d56a59d7 539 There is only memory for such good tree currently, if there are more nodes
embeddedartists 0:b567d56a59d7 540 (due to too long length codes), error 55 will happen
embeddedartists 0:b567d56a59d7 541 */
embeddedartists 0:b567d56a59d7 542 for(n = 0; n < tree->numcodes * 2; n++)
embeddedartists 0:b567d56a59d7 543 {
embeddedartists 0:b567d56a59d7 544 tree->tree2d[n] = 32767; /*32767 here means the tree2d isn't filled there yet*/
embeddedartists 0:b567d56a59d7 545 }
embeddedartists 0:b567d56a59d7 546
embeddedartists 0:b567d56a59d7 547 for(n = 0; n < tree->numcodes; n++) /*the codes*/
embeddedartists 0:b567d56a59d7 548 {
embeddedartists 0:b567d56a59d7 549 for(i = 0; i < tree->lengths[n]; i++) /*the bits for this code*/
embeddedartists 0:b567d56a59d7 550 {
embeddedartists 0:b567d56a59d7 551 unsigned char bit = (unsigned char)((tree->tree1d[n] >> (tree->lengths[n] - i - 1)) & 1);
embeddedartists 0:b567d56a59d7 552 if(treepos > tree->numcodes - 2) return 55; /*oversubscribed, see comment in lodepng_error_text*/
embeddedartists 0:b567d56a59d7 553 if(tree->tree2d[2 * treepos + bit] == 32767) /*not yet filled in*/
embeddedartists 0:b567d56a59d7 554 {
embeddedartists 0:b567d56a59d7 555 if(i + 1 == tree->lengths[n]) /*last bit*/
embeddedartists 0:b567d56a59d7 556 {
embeddedartists 0:b567d56a59d7 557 tree->tree2d[2 * treepos + bit] = n; /*put the current code in it*/
embeddedartists 0:b567d56a59d7 558 treepos = 0;
embeddedartists 0:b567d56a59d7 559 }
embeddedartists 0:b567d56a59d7 560 else
embeddedartists 0:b567d56a59d7 561 {
embeddedartists 0:b567d56a59d7 562 /*put address of the next step in here, first that address has to be found of course
embeddedartists 0:b567d56a59d7 563 (it's just nodefilled + 1)...*/
embeddedartists 0:b567d56a59d7 564 nodefilled++;
embeddedartists 0:b567d56a59d7 565 /*addresses encoded with numcodes added to it*/
embeddedartists 0:b567d56a59d7 566 tree->tree2d[2 * treepos + bit] = nodefilled + tree->numcodes;
embeddedartists 0:b567d56a59d7 567 treepos = nodefilled;
embeddedartists 0:b567d56a59d7 568 }
embeddedartists 0:b567d56a59d7 569 }
embeddedartists 0:b567d56a59d7 570 else treepos = tree->tree2d[2 * treepos + bit] - tree->numcodes;
embeddedartists 0:b567d56a59d7 571 }
embeddedartists 0:b567d56a59d7 572 }
embeddedartists 0:b567d56a59d7 573
embeddedartists 0:b567d56a59d7 574 for(n = 0; n < tree->numcodes * 2; n++)
embeddedartists 0:b567d56a59d7 575 {
embeddedartists 0:b567d56a59d7 576 if(tree->tree2d[n] == 32767) tree->tree2d[n] = 0; /*remove possible remaining 32767's*/
embeddedartists 0:b567d56a59d7 577 }
embeddedartists 0:b567d56a59d7 578
embeddedartists 0:b567d56a59d7 579 return 0;
embeddedartists 0:b567d56a59d7 580 }
embeddedartists 0:b567d56a59d7 581
embeddedartists 0:b567d56a59d7 582 /*
embeddedartists 0:b567d56a59d7 583 Second step for the ...makeFromLengths and ...makeFromFrequencies functions.
embeddedartists 0:b567d56a59d7 584 numcodes, lengths and maxbitlen must already be filled in correctly. return
embeddedartists 0:b567d56a59d7 585 value is error.
embeddedartists 0:b567d56a59d7 586 */
embeddedartists 0:b567d56a59d7 587 static unsigned HuffmanTree_makeFromLengths2(HuffmanTree* tree)
embeddedartists 0:b567d56a59d7 588 {
embeddedartists 0:b567d56a59d7 589 uivector blcount;
embeddedartists 0:b567d56a59d7 590 uivector nextcode;
embeddedartists 0:b567d56a59d7 591 unsigned bits, n, error = 0;
embeddedartists 0:b567d56a59d7 592
embeddedartists 0:b567d56a59d7 593 uivector_init(&blcount);
embeddedartists 0:b567d56a59d7 594 uivector_init(&nextcode);
embeddedartists 0:b567d56a59d7 595
embeddedartists 0:b567d56a59d7 596 tree->tree1d = (unsigned*)lodepng_malloc(tree->numcodes * sizeof(unsigned));
embeddedartists 0:b567d56a59d7 597 if(!tree->tree1d) error = 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 598
embeddedartists 0:b567d56a59d7 599 if(!uivector_resizev(&blcount, tree->maxbitlen + 1, 0)
embeddedartists 0:b567d56a59d7 600 || !uivector_resizev(&nextcode, tree->maxbitlen + 1, 0))
embeddedartists 0:b567d56a59d7 601 error = 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 602
embeddedartists 0:b567d56a59d7 603 if(!error)
embeddedartists 0:b567d56a59d7 604 {
embeddedartists 0:b567d56a59d7 605 /*step 1: count number of instances of each code length*/
embeddedartists 0:b567d56a59d7 606 for(bits = 0; bits < tree->numcodes; bits++) blcount.data[tree->lengths[bits]]++;
embeddedartists 0:b567d56a59d7 607 /*step 2: generate the nextcode values*/
embeddedartists 0:b567d56a59d7 608 for(bits = 1; bits <= tree->maxbitlen; bits++)
embeddedartists 0:b567d56a59d7 609 {
embeddedartists 0:b567d56a59d7 610 nextcode.data[bits] = (nextcode.data[bits - 1] + blcount.data[bits - 1]) << 1;
embeddedartists 0:b567d56a59d7 611 }
embeddedartists 0:b567d56a59d7 612 /*step 3: generate all the codes*/
embeddedartists 0:b567d56a59d7 613 for(n = 0; n < tree->numcodes; n++)
embeddedartists 0:b567d56a59d7 614 {
embeddedartists 0:b567d56a59d7 615 if(tree->lengths[n] != 0) tree->tree1d[n] = nextcode.data[tree->lengths[n]]++;
embeddedartists 0:b567d56a59d7 616 }
embeddedartists 0:b567d56a59d7 617 }
embeddedartists 0:b567d56a59d7 618
embeddedartists 0:b567d56a59d7 619 uivector_cleanup(&blcount);
embeddedartists 0:b567d56a59d7 620 uivector_cleanup(&nextcode);
embeddedartists 0:b567d56a59d7 621
embeddedartists 0:b567d56a59d7 622 if(!error) return HuffmanTree_make2DTree(tree);
embeddedartists 0:b567d56a59d7 623 else return error;
embeddedartists 0:b567d56a59d7 624 }
embeddedartists 0:b567d56a59d7 625
embeddedartists 0:b567d56a59d7 626 /*
embeddedartists 0:b567d56a59d7 627 given the code lengths (as stored in the PNG file), generate the tree as defined
embeddedartists 0:b567d56a59d7 628 by Deflate. maxbitlen is the maximum bits that a code in the tree can have.
embeddedartists 0:b567d56a59d7 629 return value is error.
embeddedartists 0:b567d56a59d7 630 */
embeddedartists 0:b567d56a59d7 631 static unsigned HuffmanTree_makeFromLengths(HuffmanTree* tree, const unsigned* bitlen,
embeddedartists 0:b567d56a59d7 632 size_t numcodes, unsigned maxbitlen)
embeddedartists 0:b567d56a59d7 633 {
embeddedartists 0:b567d56a59d7 634 unsigned i;
embeddedartists 0:b567d56a59d7 635 tree->lengths = (unsigned*)lodepng_malloc(numcodes * sizeof(unsigned));
embeddedartists 0:b567d56a59d7 636 if(!tree->lengths) return 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 637 for(i = 0; i < numcodes; i++) tree->lengths[i] = bitlen[i];
embeddedartists 0:b567d56a59d7 638 tree->numcodes = (unsigned)numcodes; /*number of symbols*/
embeddedartists 0:b567d56a59d7 639 tree->maxbitlen = maxbitlen;
embeddedartists 0:b567d56a59d7 640 return HuffmanTree_makeFromLengths2(tree);
embeddedartists 0:b567d56a59d7 641 }
embeddedartists 0:b567d56a59d7 642
embeddedartists 0:b567d56a59d7 643 #ifdef LODEPNG_COMPILE_ENCODER
embeddedartists 0:b567d56a59d7 644
embeddedartists 0:b567d56a59d7 645 /*
embeddedartists 0:b567d56a59d7 646 A coin, this is the terminology used for the package-merge algorithm and the
embeddedartists 0:b567d56a59d7 647 coin collector's problem. This is used to generate the huffman tree.
embeddedartists 0:b567d56a59d7 648 A coin can be multiple coins (when they're merged)
embeddedartists 0:b567d56a59d7 649 */
embeddedartists 0:b567d56a59d7 650 typedef struct Coin
embeddedartists 0:b567d56a59d7 651 {
embeddedartists 0:b567d56a59d7 652 uivector symbols;
embeddedartists 0:b567d56a59d7 653 float weight; /*the sum of all weights in this coin*/
embeddedartists 0:b567d56a59d7 654 } Coin;
embeddedartists 0:b567d56a59d7 655
embeddedartists 0:b567d56a59d7 656 static void coin_init(Coin* c)
embeddedartists 0:b567d56a59d7 657 {
embeddedartists 0:b567d56a59d7 658 uivector_init(&c->symbols);
embeddedartists 0:b567d56a59d7 659 }
embeddedartists 0:b567d56a59d7 660
embeddedartists 0:b567d56a59d7 661 /*argument c is void* so that this dtor can be given as function pointer to the vector resize function*/
embeddedartists 0:b567d56a59d7 662 static void coin_cleanup(void* c)
embeddedartists 0:b567d56a59d7 663 {
embeddedartists 0:b567d56a59d7 664 uivector_cleanup(&((Coin*)c)->symbols);
embeddedartists 0:b567d56a59d7 665 }
embeddedartists 0:b567d56a59d7 666
embeddedartists 0:b567d56a59d7 667 static void coin_copy(Coin* c1, const Coin* c2)
embeddedartists 0:b567d56a59d7 668 {
embeddedartists 0:b567d56a59d7 669 c1->weight = c2->weight;
embeddedartists 0:b567d56a59d7 670 uivector_copy(&c1->symbols, &c2->symbols);
embeddedartists 0:b567d56a59d7 671 }
embeddedartists 0:b567d56a59d7 672
embeddedartists 0:b567d56a59d7 673 static void add_coins(Coin* c1, const Coin* c2)
embeddedartists 0:b567d56a59d7 674 {
embeddedartists 0:b567d56a59d7 675 size_t i;
embeddedartists 0:b567d56a59d7 676 for(i = 0; i < c2->symbols.size; i++) uivector_push_back(&c1->symbols, c2->symbols.data[i]);
embeddedartists 0:b567d56a59d7 677 c1->weight += c2->weight;
embeddedartists 0:b567d56a59d7 678 }
embeddedartists 0:b567d56a59d7 679
embeddedartists 0:b567d56a59d7 680 static void init_coins(Coin* coins, size_t num)
embeddedartists 0:b567d56a59d7 681 {
embeddedartists 0:b567d56a59d7 682 size_t i;
embeddedartists 0:b567d56a59d7 683 for(i = 0; i < num; i++) coin_init(&coins[i]);
embeddedartists 0:b567d56a59d7 684 }
embeddedartists 0:b567d56a59d7 685
embeddedartists 0:b567d56a59d7 686 static void cleanup_coins(Coin* coins, size_t num)
embeddedartists 0:b567d56a59d7 687 {
embeddedartists 0:b567d56a59d7 688 size_t i;
embeddedartists 0:b567d56a59d7 689 for(i = 0; i < num; i++) coin_cleanup(&coins[i]);
embeddedartists 0:b567d56a59d7 690 }
embeddedartists 0:b567d56a59d7 691
embeddedartists 0:b567d56a59d7 692 static int coin_compare(const void* a, const void* b) {
embeddedartists 0:b567d56a59d7 693 float wa = ((const Coin*)a)->weight;
embeddedartists 0:b567d56a59d7 694 float wb = ((const Coin*)b)->weight;
embeddedartists 0:b567d56a59d7 695 return wa > wb ? 1 : wa < wb ? -1 : 0;
embeddedartists 0:b567d56a59d7 696 }
embeddedartists 0:b567d56a59d7 697
embeddedartists 0:b567d56a59d7 698 static unsigned append_symbol_coins(Coin* coins, const unsigned* frequencies, unsigned numcodes, size_t sum)
embeddedartists 0:b567d56a59d7 699 {
embeddedartists 0:b567d56a59d7 700 unsigned i;
embeddedartists 0:b567d56a59d7 701 unsigned j = 0; /*index of present symbols*/
embeddedartists 0:b567d56a59d7 702 for(i = 0; i < numcodes; i++)
embeddedartists 0:b567d56a59d7 703 {
embeddedartists 0:b567d56a59d7 704 if(frequencies[i] != 0) /*only include symbols that are present*/
embeddedartists 0:b567d56a59d7 705 {
embeddedartists 0:b567d56a59d7 706 coins[j].weight = frequencies[i] / (float)sum;
embeddedartists 0:b567d56a59d7 707 uivector_push_back(&coins[j].symbols, i);
embeddedartists 0:b567d56a59d7 708 j++;
embeddedartists 0:b567d56a59d7 709 }
embeddedartists 0:b567d56a59d7 710 }
embeddedartists 0:b567d56a59d7 711 return 0;
embeddedartists 0:b567d56a59d7 712 }
embeddedartists 0:b567d56a59d7 713
embeddedartists 0:b567d56a59d7 714 unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies,
embeddedartists 0:b567d56a59d7 715 size_t numcodes, unsigned maxbitlen)
embeddedartists 0:b567d56a59d7 716 {
embeddedartists 0:b567d56a59d7 717 unsigned i, j;
embeddedartists 0:b567d56a59d7 718 size_t sum = 0, numpresent = 0;
embeddedartists 0:b567d56a59d7 719 unsigned error = 0;
embeddedartists 0:b567d56a59d7 720 Coin* coins; /*the coins of the currently calculated row*/
embeddedartists 0:b567d56a59d7 721 Coin* prev_row; /*the previous row of coins*/
embeddedartists 0:b567d56a59d7 722 unsigned numcoins;
embeddedartists 0:b567d56a59d7 723 unsigned coinmem;
embeddedartists 0:b567d56a59d7 724
embeddedartists 0:b567d56a59d7 725 if(numcodes == 0) return 80; /*error: a tree of 0 symbols is not supposed to be made*/
embeddedartists 0:b567d56a59d7 726
embeddedartists 0:b567d56a59d7 727 for(i = 0; i < numcodes; i++)
embeddedartists 0:b567d56a59d7 728 {
embeddedartists 0:b567d56a59d7 729 if(frequencies[i] > 0)
embeddedartists 0:b567d56a59d7 730 {
embeddedartists 0:b567d56a59d7 731 numpresent++;
embeddedartists 0:b567d56a59d7 732 sum += frequencies[i];
embeddedartists 0:b567d56a59d7 733 }
embeddedartists 0:b567d56a59d7 734 }
embeddedartists 0:b567d56a59d7 735
embeddedartists 0:b567d56a59d7 736 for(i = 0; i < numcodes; i++) lengths[i] = 0;
embeddedartists 0:b567d56a59d7 737
embeddedartists 0:b567d56a59d7 738 /*ensure at least two present symbols. There should be at least one symbol
embeddedartists 0:b567d56a59d7 739 according to RFC 1951 section 3.2.7. To decoders incorrectly require two. To
embeddedartists 0:b567d56a59d7 740 make these work as well ensure there are at least two symbols. The
embeddedartists 0:b567d56a59d7 741 Package-Merge code below also doesn't work correctly if there's only one
embeddedartists 0:b567d56a59d7 742 symbol, it'd give it the theoritical 0 bits but in practice zlib wants 1 bit*/
embeddedartists 0:b567d56a59d7 743 if(numpresent == 0)
embeddedartists 0:b567d56a59d7 744 {
embeddedartists 0:b567d56a59d7 745 lengths[0] = lengths[1] = 1; /*note that for RFC 1951 section 3.2.7, only lengths[0] = 1 is needed*/
embeddedartists 0:b567d56a59d7 746 }
embeddedartists 0:b567d56a59d7 747 else if(numpresent == 1)
embeddedartists 0:b567d56a59d7 748 {
embeddedartists 0:b567d56a59d7 749 for(i = 0; i < numcodes; i++)
embeddedartists 0:b567d56a59d7 750 {
embeddedartists 0:b567d56a59d7 751 if(frequencies[i])
embeddedartists 0:b567d56a59d7 752 {
embeddedartists 0:b567d56a59d7 753 lengths[i] = 1;
embeddedartists 0:b567d56a59d7 754 lengths[i == 0 ? 1 : 0] = 1;
embeddedartists 0:b567d56a59d7 755 break;
embeddedartists 0:b567d56a59d7 756 }
embeddedartists 0:b567d56a59d7 757 }
embeddedartists 0:b567d56a59d7 758 }
embeddedartists 0:b567d56a59d7 759 else
embeddedartists 0:b567d56a59d7 760 {
embeddedartists 0:b567d56a59d7 761 /*Package-Merge algorithm represented by coin collector's problem
embeddedartists 0:b567d56a59d7 762 For every symbol, maxbitlen coins will be created*/
embeddedartists 0:b567d56a59d7 763
embeddedartists 0:b567d56a59d7 764 coinmem = numpresent * 2; /*max amount of coins needed with the current algo*/
embeddedartists 0:b567d56a59d7 765 coins = (Coin*)lodepng_malloc(sizeof(Coin) * coinmem);
embeddedartists 0:b567d56a59d7 766 prev_row = (Coin*)lodepng_malloc(sizeof(Coin) * coinmem);
embeddedartists 0:b567d56a59d7 767 if(!coins || !prev_row)
embeddedartists 0:b567d56a59d7 768 {
embeddedartists 0:b567d56a59d7 769 lodepng_free(coins);
embeddedartists 0:b567d56a59d7 770 lodepng_free(prev_row);
embeddedartists 0:b567d56a59d7 771 return 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 772 }
embeddedartists 0:b567d56a59d7 773 init_coins(coins, coinmem);
embeddedartists 0:b567d56a59d7 774 init_coins(prev_row, coinmem);
embeddedartists 0:b567d56a59d7 775
embeddedartists 0:b567d56a59d7 776 /*first row, lowest denominator*/
embeddedartists 0:b567d56a59d7 777 error = append_symbol_coins(coins, frequencies, numcodes, sum);
embeddedartists 0:b567d56a59d7 778 numcoins = numpresent;
embeddedartists 0:b567d56a59d7 779 qsort(coins, numcoins, sizeof(Coin), coin_compare);
embeddedartists 0:b567d56a59d7 780 if(!error)
embeddedartists 0:b567d56a59d7 781 {
embeddedartists 0:b567d56a59d7 782 unsigned numprev = 0;
embeddedartists 0:b567d56a59d7 783 for(j = 1; j <= maxbitlen && !error; j++) /*each of the remaining rows*/
embeddedartists 0:b567d56a59d7 784 {
embeddedartists 0:b567d56a59d7 785 unsigned tempnum;
embeddedartists 0:b567d56a59d7 786 Coin* tempcoins;
embeddedartists 0:b567d56a59d7 787 /*swap prev_row and coins, and their amounts*/
embeddedartists 0:b567d56a59d7 788 tempcoins = prev_row; prev_row = coins; coins = tempcoins;
embeddedartists 0:b567d56a59d7 789 tempnum = numprev; numprev = numcoins; numcoins = tempnum;
embeddedartists 0:b567d56a59d7 790
embeddedartists 0:b567d56a59d7 791 cleanup_coins(coins, numcoins);
embeddedartists 0:b567d56a59d7 792 init_coins(coins, numcoins);
embeddedartists 0:b567d56a59d7 793
embeddedartists 0:b567d56a59d7 794 numcoins = 0;
embeddedartists 0:b567d56a59d7 795
embeddedartists 0:b567d56a59d7 796 /*fill in the merged coins of the previous row*/
embeddedartists 0:b567d56a59d7 797 for(i = 0; i + 1 < numprev; i += 2)
embeddedartists 0:b567d56a59d7 798 {
embeddedartists 0:b567d56a59d7 799 /*merge prev_row[i] and prev_row[i + 1] into new coin*/
embeddedartists 0:b567d56a59d7 800 Coin* coin = &coins[numcoins++];
embeddedartists 0:b567d56a59d7 801 coin_copy(coin, &prev_row[i]);
embeddedartists 0:b567d56a59d7 802 add_coins(coin, &prev_row[i + 1]);
embeddedartists 0:b567d56a59d7 803 }
embeddedartists 0:b567d56a59d7 804 /*fill in all the original symbols again*/
embeddedartists 0:b567d56a59d7 805 if(j < maxbitlen)
embeddedartists 0:b567d56a59d7 806 {
embeddedartists 0:b567d56a59d7 807 error = append_symbol_coins(coins + numcoins, frequencies, numcodes, sum);
embeddedartists 0:b567d56a59d7 808 numcoins += numpresent;
embeddedartists 0:b567d56a59d7 809 }
embeddedartists 0:b567d56a59d7 810 qsort(coins, numcoins, sizeof(Coin), coin_compare);
embeddedartists 0:b567d56a59d7 811 }
embeddedartists 0:b567d56a59d7 812 }
embeddedartists 0:b567d56a59d7 813
embeddedartists 0:b567d56a59d7 814 if(!error)
embeddedartists 0:b567d56a59d7 815 {
embeddedartists 0:b567d56a59d7 816 /*calculate the lenghts of each symbol, as the amount of times a coin of each symbol is used*/
embeddedartists 0:b567d56a59d7 817 for(i = 0; i < numpresent - 1; i++)
embeddedartists 0:b567d56a59d7 818 {
embeddedartists 0:b567d56a59d7 819 Coin* coin = &coins[i];
embeddedartists 0:b567d56a59d7 820 for(j = 0; j < coin->symbols.size; j++) lengths[coin->symbols.data[j]]++;
embeddedartists 0:b567d56a59d7 821 }
embeddedartists 0:b567d56a59d7 822 }
embeddedartists 0:b567d56a59d7 823
embeddedartists 0:b567d56a59d7 824 cleanup_coins(coins, coinmem);
embeddedartists 0:b567d56a59d7 825 lodepng_free(coins);
embeddedartists 0:b567d56a59d7 826 cleanup_coins(prev_row, coinmem);
embeddedartists 0:b567d56a59d7 827 lodepng_free(prev_row);
embeddedartists 0:b567d56a59d7 828 }
embeddedartists 0:b567d56a59d7 829
embeddedartists 0:b567d56a59d7 830 return error;
embeddedartists 0:b567d56a59d7 831 }
embeddedartists 0:b567d56a59d7 832
embeddedartists 0:b567d56a59d7 833 /*Create the Huffman tree given the symbol frequencies*/
embeddedartists 0:b567d56a59d7 834 static unsigned HuffmanTree_makeFromFrequencies(HuffmanTree* tree, const unsigned* frequencies,
embeddedartists 0:b567d56a59d7 835 size_t mincodes, size_t numcodes, unsigned maxbitlen)
embeddedartists 0:b567d56a59d7 836 {
embeddedartists 0:b567d56a59d7 837 unsigned error = 0;
embeddedartists 0:b567d56a59d7 838 while(!frequencies[numcodes - 1] && numcodes > mincodes) numcodes--; /*trim zeroes*/
embeddedartists 0:b567d56a59d7 839 tree->maxbitlen = maxbitlen;
embeddedartists 0:b567d56a59d7 840 tree->numcodes = (unsigned)numcodes; /*number of symbols*/
embeddedartists 0:b567d56a59d7 841 tree->lengths = (unsigned*)lodepng_realloc(tree->lengths, numcodes * sizeof(unsigned));
embeddedartists 0:b567d56a59d7 842 if(!tree->lengths) return 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 843 /*initialize all lengths to 0*/
embeddedartists 0:b567d56a59d7 844 memset(tree->lengths, 0, numcodes * sizeof(unsigned));
embeddedartists 0:b567d56a59d7 845
embeddedartists 0:b567d56a59d7 846 error = lodepng_huffman_code_lengths(tree->lengths, frequencies, numcodes, maxbitlen);
embeddedartists 0:b567d56a59d7 847 if(!error) error = HuffmanTree_makeFromLengths2(tree);
embeddedartists 0:b567d56a59d7 848 return error;
embeddedartists 0:b567d56a59d7 849 }
embeddedartists 0:b567d56a59d7 850
embeddedartists 0:b567d56a59d7 851 static unsigned HuffmanTree_getCode(const HuffmanTree* tree, unsigned index)
embeddedartists 0:b567d56a59d7 852 {
embeddedartists 0:b567d56a59d7 853 return tree->tree1d[index];
embeddedartists 0:b567d56a59d7 854 }
embeddedartists 0:b567d56a59d7 855
embeddedartists 0:b567d56a59d7 856 static unsigned HuffmanTree_getLength(const HuffmanTree* tree, unsigned index)
embeddedartists 0:b567d56a59d7 857 {
embeddedartists 0:b567d56a59d7 858 return tree->lengths[index];
embeddedartists 0:b567d56a59d7 859 }
embeddedartists 0:b567d56a59d7 860 #endif /*LODEPNG_COMPILE_ENCODER*/
embeddedartists 0:b567d56a59d7 861
embeddedartists 0:b567d56a59d7 862 /*get the literal and length code tree of a deflated block with fixed tree, as per the deflate specification*/
embeddedartists 0:b567d56a59d7 863 static unsigned generateFixedLitLenTree(HuffmanTree* tree)
embeddedartists 0:b567d56a59d7 864 {
embeddedartists 0:b567d56a59d7 865 unsigned i, error = 0;
embeddedartists 0:b567d56a59d7 866 unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned));
embeddedartists 0:b567d56a59d7 867 if(!bitlen) return 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 868
embeddedartists 0:b567d56a59d7 869 /*288 possible codes: 0-255=literals, 256=endcode, 257-285=lengthcodes, 286-287=unused*/
embeddedartists 0:b567d56a59d7 870 for(i = 0; i <= 143; i++) bitlen[i] = 8;
embeddedartists 0:b567d56a59d7 871 for(i = 144; i <= 255; i++) bitlen[i] = 9;
embeddedartists 0:b567d56a59d7 872 for(i = 256; i <= 279; i++) bitlen[i] = 7;
embeddedartists 0:b567d56a59d7 873 for(i = 280; i <= 287; i++) bitlen[i] = 8;
embeddedartists 0:b567d56a59d7 874
embeddedartists 0:b567d56a59d7 875 error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DEFLATE_CODE_SYMBOLS, 15);
embeddedartists 0:b567d56a59d7 876
embeddedartists 0:b567d56a59d7 877 lodepng_free(bitlen);
embeddedartists 0:b567d56a59d7 878 return error;
embeddedartists 0:b567d56a59d7 879 }
embeddedartists 0:b567d56a59d7 880
embeddedartists 0:b567d56a59d7 881 /*get the distance code tree of a deflated block with fixed tree, as specified in the deflate specification*/
embeddedartists 0:b567d56a59d7 882 static unsigned generateFixedDistanceTree(HuffmanTree* tree)
embeddedartists 0:b567d56a59d7 883 {
embeddedartists 0:b567d56a59d7 884 unsigned i, error = 0;
embeddedartists 0:b567d56a59d7 885 unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned));
embeddedartists 0:b567d56a59d7 886 if(!bitlen) return 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 887
embeddedartists 0:b567d56a59d7 888 /*there are 32 distance codes, but 30-31 are unused*/
embeddedartists 0:b567d56a59d7 889 for(i = 0; i < NUM_DISTANCE_SYMBOLS; i++) bitlen[i] = 5;
embeddedartists 0:b567d56a59d7 890 error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DISTANCE_SYMBOLS, 15);
embeddedartists 0:b567d56a59d7 891
embeddedartists 0:b567d56a59d7 892 lodepng_free(bitlen);
embeddedartists 0:b567d56a59d7 893 return error;
embeddedartists 0:b567d56a59d7 894 }
embeddedartists 0:b567d56a59d7 895
embeddedartists 0:b567d56a59d7 896 #ifdef LODEPNG_COMPILE_DECODER
embeddedartists 0:b567d56a59d7 897
embeddedartists 0:b567d56a59d7 898 /*
embeddedartists 0:b567d56a59d7 899 returns the code, or (unsigned)(-1) if error happened
embeddedartists 0:b567d56a59d7 900 inbitlength is the length of the complete buffer, in bits (so its byte length times 8)
embeddedartists 0:b567d56a59d7 901 */
embeddedartists 0:b567d56a59d7 902 static unsigned huffmanDecodeSymbol(const unsigned char* in, size_t* bp,
embeddedartists 0:b567d56a59d7 903 const HuffmanTree* codetree, size_t inbitlength)
embeddedartists 0:b567d56a59d7 904 {
embeddedartists 0:b567d56a59d7 905 unsigned treepos = 0, ct;
embeddedartists 0:b567d56a59d7 906 for(;;)
embeddedartists 0:b567d56a59d7 907 {
embeddedartists 0:b567d56a59d7 908 if(*bp >= inbitlength) return (unsigned)(-1); /*error: end of input memory reached without endcode*/
embeddedartists 0:b567d56a59d7 909 /*
embeddedartists 0:b567d56a59d7 910 decode the symbol from the tree. The "readBitFromStream" code is inlined in
embeddedartists 0:b567d56a59d7 911 the expression below because this is the biggest bottleneck while decoding
embeddedartists 0:b567d56a59d7 912 */
embeddedartists 0:b567d56a59d7 913 ct = codetree->tree2d[(treepos << 1) + READBIT(*bp, in)];
embeddedartists 0:b567d56a59d7 914 (*bp)++;
embeddedartists 0:b567d56a59d7 915 if(ct < codetree->numcodes) return ct; /*the symbol is decoded, return it*/
embeddedartists 0:b567d56a59d7 916 else treepos = ct - codetree->numcodes; /*symbol not yet decoded, instead move tree position*/
embeddedartists 0:b567d56a59d7 917
embeddedartists 0:b567d56a59d7 918 if(treepos >= codetree->numcodes) return (unsigned)(-1); /*error: it appeared outside the codetree*/
embeddedartists 0:b567d56a59d7 919 }
embeddedartists 0:b567d56a59d7 920 }
embeddedartists 0:b567d56a59d7 921 #endif /*LODEPNG_COMPILE_DECODER*/
embeddedartists 0:b567d56a59d7 922
embeddedartists 0:b567d56a59d7 923 #ifdef LODEPNG_COMPILE_DECODER
embeddedartists 0:b567d56a59d7 924
embeddedartists 0:b567d56a59d7 925 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 926 /* / Inflator (Decompressor) / */
embeddedartists 0:b567d56a59d7 927 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 928
embeddedartists 0:b567d56a59d7 929 /*get the tree of a deflated block with fixed tree, as specified in the deflate specification*/
embeddedartists 0:b567d56a59d7 930 static void getTreeInflateFixed(HuffmanTree* tree_ll, HuffmanTree* tree_d)
embeddedartists 0:b567d56a59d7 931 {
embeddedartists 0:b567d56a59d7 932 /*TODO: check for out of memory errors*/
embeddedartists 0:b567d56a59d7 933 generateFixedLitLenTree(tree_ll);
embeddedartists 0:b567d56a59d7 934 generateFixedDistanceTree(tree_d);
embeddedartists 0:b567d56a59d7 935 }
embeddedartists 0:b567d56a59d7 936
embeddedartists 0:b567d56a59d7 937 /*get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree*/
embeddedartists 0:b567d56a59d7 938 static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d,
embeddedartists 0:b567d56a59d7 939 const unsigned char* in, size_t* bp, size_t inlength)
embeddedartists 0:b567d56a59d7 940 {
embeddedartists 0:b567d56a59d7 941 /*make sure that length values that aren't filled in will be 0, or a wrong tree will be generated*/
embeddedartists 0:b567d56a59d7 942 unsigned error = 0;
embeddedartists 0:b567d56a59d7 943 unsigned n, HLIT, HDIST, HCLEN, i;
embeddedartists 0:b567d56a59d7 944 size_t inbitlength = inlength * 8;
embeddedartists 0:b567d56a59d7 945
embeddedartists 0:b567d56a59d7 946 /*see comments in deflateDynamic for explanation of the context and these variables, it is analogous*/
embeddedartists 0:b567d56a59d7 947 unsigned* bitlen_ll = 0; /*lit,len code lengths*/
embeddedartists 0:b567d56a59d7 948 unsigned* bitlen_d = 0; /*dist code lengths*/
embeddedartists 0:b567d56a59d7 949 /*code length code lengths ("clcl"), the bit lengths of the huffman tree used to compress bitlen_ll and bitlen_d*/
embeddedartists 0:b567d56a59d7 950 unsigned* bitlen_cl = 0;
embeddedartists 0:b567d56a59d7 951 HuffmanTree tree_cl; /*the code tree for code length codes (the huffman tree for compressed huffman trees)*/
embeddedartists 0:b567d56a59d7 952
embeddedartists 0:b567d56a59d7 953 if((*bp) >> 3 >= inlength - 2) return 49; /*error: the bit pointer is or will go past the memory*/
embeddedartists 0:b567d56a59d7 954
embeddedartists 0:b567d56a59d7 955 /*number of literal/length codes + 257. Unlike the spec, the value 257 is added to it here already*/
embeddedartists 0:b567d56a59d7 956 HLIT = readBitsFromStream(bp, in, 5) + 257;
embeddedartists 0:b567d56a59d7 957 /*number of distance codes. Unlike the spec, the value 1 is added to it here already*/
embeddedartists 0:b567d56a59d7 958 HDIST = readBitsFromStream(bp, in, 5) + 1;
embeddedartists 0:b567d56a59d7 959 /*number of code length codes. Unlike the spec, the value 4 is added to it here already*/
embeddedartists 0:b567d56a59d7 960 HCLEN = readBitsFromStream(bp, in, 4) + 4;
embeddedartists 0:b567d56a59d7 961
embeddedartists 0:b567d56a59d7 962 HuffmanTree_init(&tree_cl);
embeddedartists 0:b567d56a59d7 963
embeddedartists 0:b567d56a59d7 964 while(!error)
embeddedartists 0:b567d56a59d7 965 {
embeddedartists 0:b567d56a59d7 966 /*read the code length codes out of 3 * (amount of code length codes) bits*/
embeddedartists 0:b567d56a59d7 967
embeddedartists 0:b567d56a59d7 968 bitlen_cl = (unsigned*)lodepng_malloc(NUM_CODE_LENGTH_CODES * sizeof(unsigned));
embeddedartists 0:b567d56a59d7 969 if(!bitlen_cl) ERROR_BREAK(83 /*alloc fail*/);
embeddedartists 0:b567d56a59d7 970
embeddedartists 0:b567d56a59d7 971 for(i = 0; i < NUM_CODE_LENGTH_CODES; i++)
embeddedartists 0:b567d56a59d7 972 {
embeddedartists 0:b567d56a59d7 973 if(i < HCLEN) bitlen_cl[CLCL_ORDER[i]] = readBitsFromStream(bp, in, 3);
embeddedartists 0:b567d56a59d7 974 else bitlen_cl[CLCL_ORDER[i]] = 0; /*if not, it must stay 0*/
embeddedartists 0:b567d56a59d7 975 }
embeddedartists 0:b567d56a59d7 976
embeddedartists 0:b567d56a59d7 977 error = HuffmanTree_makeFromLengths(&tree_cl, bitlen_cl, NUM_CODE_LENGTH_CODES, 7);
embeddedartists 0:b567d56a59d7 978 if(error) break;
embeddedartists 0:b567d56a59d7 979
embeddedartists 0:b567d56a59d7 980 /*now we can use this tree to read the lengths for the tree that this function will return*/
embeddedartists 0:b567d56a59d7 981 bitlen_ll = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned));
embeddedartists 0:b567d56a59d7 982 bitlen_d = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned));
embeddedartists 0:b567d56a59d7 983 if(!bitlen_ll || !bitlen_d) ERROR_BREAK(83 /*alloc fail*/);
embeddedartists 0:b567d56a59d7 984 for(i = 0; i < NUM_DEFLATE_CODE_SYMBOLS; i++) bitlen_ll[i] = 0;
embeddedartists 0:b567d56a59d7 985 for(i = 0; i < NUM_DISTANCE_SYMBOLS; i++) bitlen_d[i] = 0;
embeddedartists 0:b567d56a59d7 986
embeddedartists 0:b567d56a59d7 987 /*i is the current symbol we're reading in the part that contains the code lengths of lit/len and dist codes*/
embeddedartists 0:b567d56a59d7 988 i = 0;
embeddedartists 0:b567d56a59d7 989 while(i < HLIT + HDIST)
embeddedartists 0:b567d56a59d7 990 {
embeddedartists 0:b567d56a59d7 991 unsigned code = huffmanDecodeSymbol(in, bp, &tree_cl, inbitlength);
embeddedartists 0:b567d56a59d7 992 if(code <= 15) /*a length code*/
embeddedartists 0:b567d56a59d7 993 {
embeddedartists 0:b567d56a59d7 994 if(i < HLIT) bitlen_ll[i] = code;
embeddedartists 0:b567d56a59d7 995 else bitlen_d[i - HLIT] = code;
embeddedartists 0:b567d56a59d7 996 i++;
embeddedartists 0:b567d56a59d7 997 }
embeddedartists 0:b567d56a59d7 998 else if(code == 16) /*repeat previous*/
embeddedartists 0:b567d56a59d7 999 {
embeddedartists 0:b567d56a59d7 1000 unsigned replength = 3; /*read in the 2 bits that indicate repeat length (3-6)*/
embeddedartists 0:b567d56a59d7 1001 unsigned value; /*set value to the previous code*/
embeddedartists 0:b567d56a59d7 1002
embeddedartists 0:b567d56a59d7 1003 if(*bp >= inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/
embeddedartists 0:b567d56a59d7 1004 if (i == 0) ERROR_BREAK(54); /*can't repeat previous if i is 0*/
embeddedartists 0:b567d56a59d7 1005
embeddedartists 0:b567d56a59d7 1006 replength += readBitsFromStream(bp, in, 2);
embeddedartists 0:b567d56a59d7 1007
embeddedartists 0:b567d56a59d7 1008 if(i < HLIT + 1) value = bitlen_ll[i - 1];
embeddedartists 0:b567d56a59d7 1009 else value = bitlen_d[i - HLIT - 1];
embeddedartists 0:b567d56a59d7 1010 /*repeat this value in the next lengths*/
embeddedartists 0:b567d56a59d7 1011 for(n = 0; n < replength; n++)
embeddedartists 0:b567d56a59d7 1012 {
embeddedartists 0:b567d56a59d7 1013 if(i >= HLIT + HDIST) ERROR_BREAK(13); /*error: i is larger than the amount of codes*/
embeddedartists 0:b567d56a59d7 1014 if(i < HLIT) bitlen_ll[i] = value;
embeddedartists 0:b567d56a59d7 1015 else bitlen_d[i - HLIT] = value;
embeddedartists 0:b567d56a59d7 1016 i++;
embeddedartists 0:b567d56a59d7 1017 }
embeddedartists 0:b567d56a59d7 1018 }
embeddedartists 0:b567d56a59d7 1019 else if(code == 17) /*repeat "0" 3-10 times*/
embeddedartists 0:b567d56a59d7 1020 {
embeddedartists 0:b567d56a59d7 1021 unsigned replength = 3; /*read in the bits that indicate repeat length*/
embeddedartists 0:b567d56a59d7 1022 if(*bp >= inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/
embeddedartists 0:b567d56a59d7 1023
embeddedartists 0:b567d56a59d7 1024 replength += readBitsFromStream(bp, in, 3);
embeddedartists 0:b567d56a59d7 1025
embeddedartists 0:b567d56a59d7 1026 /*repeat this value in the next lengths*/
embeddedartists 0:b567d56a59d7 1027 for(n = 0; n < replength; n++)
embeddedartists 0:b567d56a59d7 1028 {
embeddedartists 0:b567d56a59d7 1029 if(i >= HLIT + HDIST) ERROR_BREAK(14); /*error: i is larger than the amount of codes*/
embeddedartists 0:b567d56a59d7 1030
embeddedartists 0:b567d56a59d7 1031 if(i < HLIT) bitlen_ll[i] = 0;
embeddedartists 0:b567d56a59d7 1032 else bitlen_d[i - HLIT] = 0;
embeddedartists 0:b567d56a59d7 1033 i++;
embeddedartists 0:b567d56a59d7 1034 }
embeddedartists 0:b567d56a59d7 1035 }
embeddedartists 0:b567d56a59d7 1036 else if(code == 18) /*repeat "0" 11-138 times*/
embeddedartists 0:b567d56a59d7 1037 {
embeddedartists 0:b567d56a59d7 1038 unsigned replength = 11; /*read in the bits that indicate repeat length*/
embeddedartists 0:b567d56a59d7 1039 if(*bp >= inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/
embeddedartists 0:b567d56a59d7 1040
embeddedartists 0:b567d56a59d7 1041 replength += readBitsFromStream(bp, in, 7);
embeddedartists 0:b567d56a59d7 1042
embeddedartists 0:b567d56a59d7 1043 /*repeat this value in the next lengths*/
embeddedartists 0:b567d56a59d7 1044 for(n = 0; n < replength; n++)
embeddedartists 0:b567d56a59d7 1045 {
embeddedartists 0:b567d56a59d7 1046 if(i >= HLIT + HDIST) ERROR_BREAK(15); /*error: i is larger than the amount of codes*/
embeddedartists 0:b567d56a59d7 1047
embeddedartists 0:b567d56a59d7 1048 if(i < HLIT) bitlen_ll[i] = 0;
embeddedartists 0:b567d56a59d7 1049 else bitlen_d[i - HLIT] = 0;
embeddedartists 0:b567d56a59d7 1050 i++;
embeddedartists 0:b567d56a59d7 1051 }
embeddedartists 0:b567d56a59d7 1052 }
embeddedartists 0:b567d56a59d7 1053 else /*if(code == (unsigned)(-1))*/ /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/
embeddedartists 0:b567d56a59d7 1054 {
embeddedartists 0:b567d56a59d7 1055 if(code == (unsigned)(-1))
embeddedartists 0:b567d56a59d7 1056 {
embeddedartists 0:b567d56a59d7 1057 /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol
embeddedartists 0:b567d56a59d7 1058 (10=no endcode, 11=wrong jump outside of tree)*/
embeddedartists 0:b567d56a59d7 1059 error = (*bp) > inbitlength ? 10 : 11;
embeddedartists 0:b567d56a59d7 1060 }
embeddedartists 0:b567d56a59d7 1061 else error = 16; /*unexisting code, this can never happen*/
embeddedartists 0:b567d56a59d7 1062 break;
embeddedartists 0:b567d56a59d7 1063 }
embeddedartists 0:b567d56a59d7 1064 }
embeddedartists 0:b567d56a59d7 1065 if(error) break;
embeddedartists 0:b567d56a59d7 1066
embeddedartists 0:b567d56a59d7 1067 if(bitlen_ll[256] == 0) ERROR_BREAK(64); /*the length of the end code 256 must be larger than 0*/
embeddedartists 0:b567d56a59d7 1068
embeddedartists 0:b567d56a59d7 1069 /*now we've finally got HLIT and HDIST, so generate the code trees, and the function is done*/
embeddedartists 0:b567d56a59d7 1070 error = HuffmanTree_makeFromLengths(tree_ll, bitlen_ll, NUM_DEFLATE_CODE_SYMBOLS, 15);
embeddedartists 0:b567d56a59d7 1071 if(error) break;
embeddedartists 0:b567d56a59d7 1072 error = HuffmanTree_makeFromLengths(tree_d, bitlen_d, NUM_DISTANCE_SYMBOLS, 15);
embeddedartists 0:b567d56a59d7 1073
embeddedartists 0:b567d56a59d7 1074 break; /*end of error-while*/
embeddedartists 0:b567d56a59d7 1075 }
embeddedartists 0:b567d56a59d7 1076
embeddedartists 0:b567d56a59d7 1077 lodepng_free(bitlen_cl);
embeddedartists 0:b567d56a59d7 1078 lodepng_free(bitlen_ll);
embeddedartists 0:b567d56a59d7 1079 lodepng_free(bitlen_d);
embeddedartists 0:b567d56a59d7 1080 HuffmanTree_cleanup(&tree_cl);
embeddedartists 0:b567d56a59d7 1081
embeddedartists 0:b567d56a59d7 1082 return error;
embeddedartists 0:b567d56a59d7 1083 }
embeddedartists 0:b567d56a59d7 1084
embeddedartists 0:b567d56a59d7 1085 /*inflate a block with dynamic of fixed Huffman tree*/
embeddedartists 0:b567d56a59d7 1086 static unsigned inflateHuffmanBlock(ucvector* out, const unsigned char* in, size_t* bp,
embeddedartists 0:b567d56a59d7 1087 size_t* pos, size_t inlength, unsigned btype)
embeddedartists 0:b567d56a59d7 1088 {
embeddedartists 0:b567d56a59d7 1089 unsigned error = 0;
embeddedartists 0:b567d56a59d7 1090 HuffmanTree tree_ll; /*the huffman tree for literal and length codes*/
embeddedartists 0:b567d56a59d7 1091 HuffmanTree tree_d; /*the huffman tree for distance codes*/
embeddedartists 0:b567d56a59d7 1092 size_t inbitlength = inlength * 8;
embeddedartists 0:b567d56a59d7 1093
embeddedartists 0:b567d56a59d7 1094 HuffmanTree_init(&tree_ll);
embeddedartists 0:b567d56a59d7 1095 HuffmanTree_init(&tree_d);
embeddedartists 0:b567d56a59d7 1096
embeddedartists 0:b567d56a59d7 1097 if(btype == 1) getTreeInflateFixed(&tree_ll, &tree_d);
embeddedartists 0:b567d56a59d7 1098 else if(btype == 2) error = getTreeInflateDynamic(&tree_ll, &tree_d, in, bp, inlength);
embeddedartists 0:b567d56a59d7 1099
embeddedartists 0:b567d56a59d7 1100 while(!error) /*decode all symbols until end reached, breaks at end code*/
embeddedartists 0:b567d56a59d7 1101 {
embeddedartists 0:b567d56a59d7 1102 /*code_ll is literal, length or end code*/
embeddedartists 0:b567d56a59d7 1103 unsigned code_ll = huffmanDecodeSymbol(in, bp, &tree_ll, inbitlength);
embeddedartists 0:b567d56a59d7 1104 if(code_ll <= 255) /*literal symbol*/
embeddedartists 0:b567d56a59d7 1105 {
embeddedartists 0:b567d56a59d7 1106 if((*pos) >= out->size)
embeddedartists 0:b567d56a59d7 1107 {
embeddedartists 0:b567d56a59d7 1108 /*reserve more room at once*/
embeddedartists 0:b567d56a59d7 1109 if(!ucvector_resize(out, ((*pos) + 1) * 2)) ERROR_BREAK(83 /*alloc fail*/);
embeddedartists 0:b567d56a59d7 1110 }
embeddedartists 0:b567d56a59d7 1111 out->data[(*pos)] = (unsigned char)(code_ll);
embeddedartists 0:b567d56a59d7 1112 (*pos)++;
embeddedartists 0:b567d56a59d7 1113 }
embeddedartists 0:b567d56a59d7 1114 else if(code_ll >= FIRST_LENGTH_CODE_INDEX && code_ll <= LAST_LENGTH_CODE_INDEX) /*length code*/
embeddedartists 0:b567d56a59d7 1115 {
embeddedartists 0:b567d56a59d7 1116 unsigned code_d, distance;
embeddedartists 0:b567d56a59d7 1117 unsigned numextrabits_l, numextrabits_d; /*extra bits for length and distance*/
embeddedartists 0:b567d56a59d7 1118 size_t start, forward, backward, length;
embeddedartists 0:b567d56a59d7 1119
embeddedartists 0:b567d56a59d7 1120 /*part 1: get length base*/
embeddedartists 0:b567d56a59d7 1121 length = LENGTHBASE[code_ll - FIRST_LENGTH_CODE_INDEX];
embeddedartists 0:b567d56a59d7 1122
embeddedartists 0:b567d56a59d7 1123 /*part 2: get extra bits and add the value of that to length*/
embeddedartists 0:b567d56a59d7 1124 numextrabits_l = LENGTHEXTRA[code_ll - FIRST_LENGTH_CODE_INDEX];
embeddedartists 0:b567d56a59d7 1125 if(*bp >= inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/
embeddedartists 0:b567d56a59d7 1126 length += readBitsFromStream(bp, in, numextrabits_l);
embeddedartists 0:b567d56a59d7 1127
embeddedartists 0:b567d56a59d7 1128 /*part 3: get distance code*/
embeddedartists 0:b567d56a59d7 1129 code_d = huffmanDecodeSymbol(in, bp, &tree_d, inbitlength);
embeddedartists 0:b567d56a59d7 1130 if(code_d > 29)
embeddedartists 0:b567d56a59d7 1131 {
embeddedartists 0:b567d56a59d7 1132 if(code_ll == (unsigned)(-1)) /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/
embeddedartists 0:b567d56a59d7 1133 {
embeddedartists 0:b567d56a59d7 1134 /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol
embeddedartists 0:b567d56a59d7 1135 (10=no endcode, 11=wrong jump outside of tree)*/
embeddedartists 0:b567d56a59d7 1136 error = (*bp) > inlength * 8 ? 10 : 11;
embeddedartists 0:b567d56a59d7 1137 }
embeddedartists 0:b567d56a59d7 1138 else error = 18; /*error: invalid distance code (30-31 are never used)*/
embeddedartists 0:b567d56a59d7 1139 break;
embeddedartists 0:b567d56a59d7 1140 }
embeddedartists 0:b567d56a59d7 1141 distance = DISTANCEBASE[code_d];
embeddedartists 0:b567d56a59d7 1142
embeddedartists 0:b567d56a59d7 1143 /*part 4: get extra bits from distance*/
embeddedartists 0:b567d56a59d7 1144 numextrabits_d = DISTANCEEXTRA[code_d];
embeddedartists 0:b567d56a59d7 1145 if(*bp >= inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/
embeddedartists 0:b567d56a59d7 1146
embeddedartists 0:b567d56a59d7 1147 distance += readBitsFromStream(bp, in, numextrabits_d);
embeddedartists 0:b567d56a59d7 1148
embeddedartists 0:b567d56a59d7 1149 /*part 5: fill in all the out[n] values based on the length and dist*/
embeddedartists 0:b567d56a59d7 1150 start = (*pos);
embeddedartists 0:b567d56a59d7 1151 if(distance > start) ERROR_BREAK(52); /*too long backward distance*/
embeddedartists 0:b567d56a59d7 1152 backward = start - distance;
embeddedartists 0:b567d56a59d7 1153 if((*pos) + length >= out->size)
embeddedartists 0:b567d56a59d7 1154 {
embeddedartists 0:b567d56a59d7 1155 /*reserve more room at once*/
embeddedartists 0:b567d56a59d7 1156 if(!ucvector_resize(out, ((*pos) + length) * 2)) ERROR_BREAK(83 /*alloc fail*/);
embeddedartists 0:b567d56a59d7 1157 }
embeddedartists 0:b567d56a59d7 1158
embeddedartists 0:b567d56a59d7 1159 for(forward = 0; forward < length; forward++)
embeddedartists 0:b567d56a59d7 1160 {
embeddedartists 0:b567d56a59d7 1161 out->data[(*pos)] = out->data[backward];
embeddedartists 0:b567d56a59d7 1162 (*pos)++;
embeddedartists 0:b567d56a59d7 1163 backward++;
embeddedartists 0:b567d56a59d7 1164 if(backward >= start) backward = start - distance;
embeddedartists 0:b567d56a59d7 1165 }
embeddedartists 0:b567d56a59d7 1166 }
embeddedartists 0:b567d56a59d7 1167 else if(code_ll == 256)
embeddedartists 0:b567d56a59d7 1168 {
embeddedartists 0:b567d56a59d7 1169 break; /*end code, break the loop*/
embeddedartists 0:b567d56a59d7 1170 }
embeddedartists 0:b567d56a59d7 1171 else /*if(code == (unsigned)(-1))*/ /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/
embeddedartists 0:b567d56a59d7 1172 {
embeddedartists 0:b567d56a59d7 1173 /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol
embeddedartists 0:b567d56a59d7 1174 (10=no endcode, 11=wrong jump outside of tree)*/
embeddedartists 0:b567d56a59d7 1175 error = (*bp) > inlength * 8 ? 10 : 11;
embeddedartists 0:b567d56a59d7 1176 break;
embeddedartists 0:b567d56a59d7 1177 }
embeddedartists 0:b567d56a59d7 1178 }
embeddedartists 0:b567d56a59d7 1179
embeddedartists 0:b567d56a59d7 1180 HuffmanTree_cleanup(&tree_ll);
embeddedartists 0:b567d56a59d7 1181 HuffmanTree_cleanup(&tree_d);
embeddedartists 0:b567d56a59d7 1182
embeddedartists 0:b567d56a59d7 1183 return error;
embeddedartists 0:b567d56a59d7 1184 }
embeddedartists 0:b567d56a59d7 1185
embeddedartists 0:b567d56a59d7 1186 static unsigned inflateNoCompression(ucvector* out, const unsigned char* in, size_t* bp, size_t* pos, size_t inlength)
embeddedartists 0:b567d56a59d7 1187 {
embeddedartists 0:b567d56a59d7 1188 /*go to first boundary of byte*/
embeddedartists 0:b567d56a59d7 1189 size_t p;
embeddedartists 0:b567d56a59d7 1190 unsigned LEN, NLEN, n, error = 0;
embeddedartists 0:b567d56a59d7 1191 while(((*bp) & 0x7) != 0) (*bp)++;
embeddedartists 0:b567d56a59d7 1192 p = (*bp) / 8; /*byte position*/
embeddedartists 0:b567d56a59d7 1193
embeddedartists 0:b567d56a59d7 1194 /*read LEN (2 bytes) and NLEN (2 bytes)*/
embeddedartists 0:b567d56a59d7 1195 if(p >= inlength - 4) return 52; /*error, bit pointer will jump past memory*/
embeddedartists 0:b567d56a59d7 1196 LEN = in[p] + 256 * in[p + 1]; p += 2;
embeddedartists 0:b567d56a59d7 1197 NLEN = in[p] + 256 * in[p + 1]; p += 2;
embeddedartists 0:b567d56a59d7 1198
embeddedartists 0:b567d56a59d7 1199 /*check if 16-bit NLEN is really the one's complement of LEN*/
embeddedartists 0:b567d56a59d7 1200 if(LEN + NLEN != 65535) return 21; /*error: NLEN is not one's complement of LEN*/
embeddedartists 0:b567d56a59d7 1201
embeddedartists 0:b567d56a59d7 1202 if((*pos) + LEN >= out->size)
embeddedartists 0:b567d56a59d7 1203 {
embeddedartists 0:b567d56a59d7 1204 if(!ucvector_resize(out, (*pos) + LEN)) return 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 1205 }
embeddedartists 0:b567d56a59d7 1206
embeddedartists 0:b567d56a59d7 1207 /*read the literal data: LEN bytes are now stored in the out buffer*/
embeddedartists 0:b567d56a59d7 1208 if(p + LEN > inlength) return 23; /*error: reading outside of in buffer*/
embeddedartists 0:b567d56a59d7 1209 for(n = 0; n < LEN; n++) out->data[(*pos)++] = in[p++];
embeddedartists 0:b567d56a59d7 1210
embeddedartists 0:b567d56a59d7 1211 (*bp) = p * 8;
embeddedartists 0:b567d56a59d7 1212
embeddedartists 0:b567d56a59d7 1213 return error;
embeddedartists 0:b567d56a59d7 1214 }
embeddedartists 0:b567d56a59d7 1215
embeddedartists 0:b567d56a59d7 1216 static unsigned lodepng_inflatev(ucvector* out,
embeddedartists 0:b567d56a59d7 1217 const unsigned char* in, size_t insize,
embeddedartists 0:b567d56a59d7 1218 const LodePNGDecompressSettings* settings)
embeddedartists 0:b567d56a59d7 1219 {
embeddedartists 0:b567d56a59d7 1220 /*bit pointer in the "in" data, current byte is bp >> 3, current bit is bp & 0x7 (from lsb to msb of the byte)*/
embeddedartists 0:b567d56a59d7 1221 size_t bp = 0;
embeddedartists 0:b567d56a59d7 1222 unsigned BFINAL = 0;
embeddedartists 0:b567d56a59d7 1223 size_t pos = 0; /*byte position in the out buffer*/
embeddedartists 0:b567d56a59d7 1224
embeddedartists 0:b567d56a59d7 1225 unsigned error = 0;
embeddedartists 0:b567d56a59d7 1226
embeddedartists 0:b567d56a59d7 1227 (void)settings;
embeddedartists 0:b567d56a59d7 1228
embeddedartists 0:b567d56a59d7 1229 while(!BFINAL)
embeddedartists 0:b567d56a59d7 1230 {
embeddedartists 0:b567d56a59d7 1231 unsigned BTYPE;
embeddedartists 0:b567d56a59d7 1232 if(bp + 2 >= insize * 8) return 52; /*error, bit pointer will jump past memory*/
embeddedartists 0:b567d56a59d7 1233 BFINAL = readBitFromStream(&bp, in);
embeddedartists 0:b567d56a59d7 1234 BTYPE = 1 * readBitFromStream(&bp, in);
embeddedartists 0:b567d56a59d7 1235 BTYPE += 2 * readBitFromStream(&bp, in);
embeddedartists 0:b567d56a59d7 1236
embeddedartists 0:b567d56a59d7 1237 if(BTYPE == 3) return 20; /*error: invalid BTYPE*/
embeddedartists 0:b567d56a59d7 1238 else if(BTYPE == 0) error = inflateNoCompression(out, in, &bp, &pos, insize); /*no compression*/
embeddedartists 0:b567d56a59d7 1239 else error = inflateHuffmanBlock(out, in, &bp, &pos, insize, BTYPE); /*compression, BTYPE 01 or 10*/
embeddedartists 0:b567d56a59d7 1240
embeddedartists 0:b567d56a59d7 1241 if(error) return error;
embeddedartists 0:b567d56a59d7 1242 }
embeddedartists 0:b567d56a59d7 1243
embeddedartists 0:b567d56a59d7 1244 /*Only now we know the true size of out, resize it to that*/
embeddedartists 0:b567d56a59d7 1245 if(!ucvector_resize(out, pos)) error = 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 1246
embeddedartists 0:b567d56a59d7 1247 return error;
embeddedartists 0:b567d56a59d7 1248 }
embeddedartists 0:b567d56a59d7 1249
embeddedartists 0:b567d56a59d7 1250 unsigned lodepng_inflate(unsigned char** out, size_t* outsize,
embeddedartists 0:b567d56a59d7 1251 const unsigned char* in, size_t insize,
embeddedartists 0:b567d56a59d7 1252 const LodePNGDecompressSettings* settings)
embeddedartists 0:b567d56a59d7 1253 {
embeddedartists 0:b567d56a59d7 1254 unsigned error;
embeddedartists 0:b567d56a59d7 1255 ucvector v;
embeddedartists 0:b567d56a59d7 1256 ucvector_init_buffer(&v, *out, *outsize);
embeddedartists 0:b567d56a59d7 1257 error = lodepng_inflatev(&v, in, insize, settings);
embeddedartists 0:b567d56a59d7 1258 *out = v.data;
embeddedartists 0:b567d56a59d7 1259 *outsize = v.size;
embeddedartists 0:b567d56a59d7 1260 return error;
embeddedartists 0:b567d56a59d7 1261 }
embeddedartists 0:b567d56a59d7 1262
embeddedartists 0:b567d56a59d7 1263 static unsigned inflate(unsigned char** out, size_t* outsize,
embeddedartists 0:b567d56a59d7 1264 const unsigned char* in, size_t insize,
embeddedartists 0:b567d56a59d7 1265 const LodePNGDecompressSettings* settings)
embeddedartists 0:b567d56a59d7 1266 {
embeddedartists 0:b567d56a59d7 1267 if(settings->custom_inflate)
embeddedartists 0:b567d56a59d7 1268 {
embeddedartists 0:b567d56a59d7 1269 return settings->custom_inflate(out, outsize, in, insize, settings);
embeddedartists 0:b567d56a59d7 1270 }
embeddedartists 0:b567d56a59d7 1271 else
embeddedartists 0:b567d56a59d7 1272 {
embeddedartists 0:b567d56a59d7 1273 return lodepng_inflate(out, outsize, in, insize, settings);
embeddedartists 0:b567d56a59d7 1274 }
embeddedartists 0:b567d56a59d7 1275 }
embeddedartists 0:b567d56a59d7 1276
embeddedartists 0:b567d56a59d7 1277 #endif /*LODEPNG_COMPILE_DECODER*/
embeddedartists 0:b567d56a59d7 1278
embeddedartists 0:b567d56a59d7 1279 #ifdef LODEPNG_COMPILE_ENCODER
embeddedartists 0:b567d56a59d7 1280
embeddedartists 0:b567d56a59d7 1281 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 1282 /* / Deflator (Compressor) / */
embeddedartists 0:b567d56a59d7 1283 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 1284
embeddedartists 0:b567d56a59d7 1285 static const size_t MAX_SUPPORTED_DEFLATE_LENGTH = 258;
embeddedartists 0:b567d56a59d7 1286
embeddedartists 0:b567d56a59d7 1287 /*bitlen is the size in bits of the code*/
embeddedartists 0:b567d56a59d7 1288 static void addHuffmanSymbol(size_t* bp, ucvector* compressed, unsigned code, unsigned bitlen)
embeddedartists 0:b567d56a59d7 1289 {
embeddedartists 0:b567d56a59d7 1290 addBitsToStreamReversed(bp, compressed, code, bitlen);
embeddedartists 0:b567d56a59d7 1291 }
embeddedartists 0:b567d56a59d7 1292
embeddedartists 0:b567d56a59d7 1293 /*search the index in the array, that has the largest value smaller than or equal to the given value,
embeddedartists 0:b567d56a59d7 1294 given array must be sorted (if no value is smaller, it returns the size of the given array)*/
embeddedartists 0:b567d56a59d7 1295 static size_t searchCodeIndex(const unsigned* array, size_t array_size, size_t value)
embeddedartists 0:b567d56a59d7 1296 {
embeddedartists 0:b567d56a59d7 1297 /*linear search implementation*/
embeddedartists 0:b567d56a59d7 1298 /*for(size_t i = 1; i < array_size; i++) if(array[i] > value) return i - 1;
embeddedartists 0:b567d56a59d7 1299 return array_size - 1;*/
embeddedartists 0:b567d56a59d7 1300
embeddedartists 0:b567d56a59d7 1301 /*binary search implementation (not that much faster) (precondition: array_size > 0)*/
embeddedartists 0:b567d56a59d7 1302 size_t left = 1;
embeddedartists 0:b567d56a59d7 1303 size_t right = array_size - 1;
embeddedartists 0:b567d56a59d7 1304 while(left <= right)
embeddedartists 0:b567d56a59d7 1305 {
embeddedartists 0:b567d56a59d7 1306 size_t mid = (left + right) / 2;
embeddedartists 0:b567d56a59d7 1307 if(array[mid] <= value) left = mid + 1; /*the value to find is more to the right*/
embeddedartists 0:b567d56a59d7 1308 else if(array[mid - 1] > value) right = mid - 1; /*the value to find is more to the left*/
embeddedartists 0:b567d56a59d7 1309 else return mid - 1;
embeddedartists 0:b567d56a59d7 1310 }
embeddedartists 0:b567d56a59d7 1311 return array_size - 1;
embeddedartists 0:b567d56a59d7 1312 }
embeddedartists 0:b567d56a59d7 1313
embeddedartists 0:b567d56a59d7 1314 static void addLengthDistance(uivector* values, size_t length, size_t distance)
embeddedartists 0:b567d56a59d7 1315 {
embeddedartists 0:b567d56a59d7 1316 /*values in encoded vector are those used by deflate:
embeddedartists 0:b567d56a59d7 1317 0-255: literal bytes
embeddedartists 0:b567d56a59d7 1318 256: end
embeddedartists 0:b567d56a59d7 1319 257-285: length/distance pair (length code, followed by extra length bits, distance code, extra distance bits)
embeddedartists 0:b567d56a59d7 1320 286-287: invalid*/
embeddedartists 0:b567d56a59d7 1321
embeddedartists 0:b567d56a59d7 1322 unsigned length_code = (unsigned)searchCodeIndex(LENGTHBASE, 29, length);
embeddedartists 0:b567d56a59d7 1323 unsigned extra_length = (unsigned)(length - LENGTHBASE[length_code]);
embeddedartists 0:b567d56a59d7 1324 unsigned dist_code = (unsigned)searchCodeIndex(DISTANCEBASE, 30, distance);
embeddedartists 0:b567d56a59d7 1325 unsigned extra_distance = (unsigned)(distance - DISTANCEBASE[dist_code]);
embeddedartists 0:b567d56a59d7 1326
embeddedartists 0:b567d56a59d7 1327 uivector_push_back(values, length_code + FIRST_LENGTH_CODE_INDEX);
embeddedartists 0:b567d56a59d7 1328 uivector_push_back(values, extra_length);
embeddedartists 0:b567d56a59d7 1329 uivector_push_back(values, dist_code);
embeddedartists 0:b567d56a59d7 1330 uivector_push_back(values, extra_distance);
embeddedartists 0:b567d56a59d7 1331 }
embeddedartists 0:b567d56a59d7 1332
embeddedartists 0:b567d56a59d7 1333 static const unsigned HASH_BIT_MASK = 65535;
embeddedartists 0:b567d56a59d7 1334 static const unsigned HASH_NUM_VALUES = 65536;
embeddedartists 0:b567d56a59d7 1335 static const unsigned HASH_NUM_CHARACTERS = 3;
embeddedartists 0:b567d56a59d7 1336 static const unsigned HASH_SHIFT = 2;
embeddedartists 0:b567d56a59d7 1337 /*
embeddedartists 0:b567d56a59d7 1338 The HASH_NUM_CHARACTERS value is used to make encoding faster by using longer
embeddedartists 0:b567d56a59d7 1339 sequences to generate a hash value from the stream bytes. Setting it to 3
embeddedartists 0:b567d56a59d7 1340 gives exactly the same compression as the brute force method, since deflate's
embeddedartists 0:b567d56a59d7 1341 run length encoding starts with lengths of 3. Setting it to higher values,
embeddedartists 0:b567d56a59d7 1342 like 6, can make the encoding faster (not always though!), but will cause the
embeddedartists 0:b567d56a59d7 1343 encoding to miss any length between 3 and this value, so that the compression
embeddedartists 0:b567d56a59d7 1344 may be worse (but this can vary too depending on the image, sometimes it is
embeddedartists 0:b567d56a59d7 1345 even a bit better instead).
embeddedartists 0:b567d56a59d7 1346 The HASH_NUM_VALUES is the amount of unique possible hash values that
embeddedartists 0:b567d56a59d7 1347 combinations of bytes can give, the higher it is the more memory is needed, but
embeddedartists 0:b567d56a59d7 1348 if it's too low the advantage of hashing is gone.
embeddedartists 0:b567d56a59d7 1349 */
embeddedartists 0:b567d56a59d7 1350
embeddedartists 0:b567d56a59d7 1351 typedef struct Hash
embeddedartists 0:b567d56a59d7 1352 {
embeddedartists 0:b567d56a59d7 1353 int* head; /*hash value to head circular pos*/
embeddedartists 0:b567d56a59d7 1354 int* val; /*circular pos to hash value*/
embeddedartists 0:b567d56a59d7 1355 /*circular pos to prev circular pos*/
embeddedartists 0:b567d56a59d7 1356 unsigned short* chain;
embeddedartists 0:b567d56a59d7 1357 unsigned short* zeros;
embeddedartists 0:b567d56a59d7 1358 } Hash;
embeddedartists 0:b567d56a59d7 1359
embeddedartists 0:b567d56a59d7 1360 static unsigned hash_init(Hash* hash, unsigned windowsize)
embeddedartists 0:b567d56a59d7 1361 {
embeddedartists 0:b567d56a59d7 1362 unsigned i;
embeddedartists 0:b567d56a59d7 1363 hash->head = (int*)lodepng_malloc(sizeof(int) * HASH_NUM_VALUES);
embeddedartists 0:b567d56a59d7 1364 hash->val = (int*)lodepng_malloc(sizeof(int) * windowsize);
embeddedartists 0:b567d56a59d7 1365 hash->chain = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize);
embeddedartists 0:b567d56a59d7 1366 hash->zeros = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize);
embeddedartists 0:b567d56a59d7 1367
embeddedartists 0:b567d56a59d7 1368 if(!hash->head || !hash->val || !hash->chain || !hash->zeros) return 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 1369
embeddedartists 0:b567d56a59d7 1370 /*initialize hash table*/
embeddedartists 0:b567d56a59d7 1371 for(i = 0; i < HASH_NUM_VALUES; i++) hash->head[i] = -1;
embeddedartists 0:b567d56a59d7 1372 for(i = 0; i < windowsize; i++) hash->val[i] = -1;
embeddedartists 0:b567d56a59d7 1373 for(i = 0; i < windowsize; i++) hash->chain[i] = i; /*same value as index indicates uninitialized*/
embeddedartists 0:b567d56a59d7 1374
embeddedartists 0:b567d56a59d7 1375 return 0;
embeddedartists 0:b567d56a59d7 1376 }
embeddedartists 0:b567d56a59d7 1377
embeddedartists 0:b567d56a59d7 1378 static void hash_cleanup(Hash* hash)
embeddedartists 0:b567d56a59d7 1379 {
embeddedartists 0:b567d56a59d7 1380 lodepng_free(hash->head);
embeddedartists 0:b567d56a59d7 1381 lodepng_free(hash->val);
embeddedartists 0:b567d56a59d7 1382 lodepng_free(hash->chain);
embeddedartists 0:b567d56a59d7 1383 lodepng_free(hash->zeros);
embeddedartists 0:b567d56a59d7 1384 }
embeddedartists 0:b567d56a59d7 1385
embeddedartists 0:b567d56a59d7 1386 static unsigned getHash(const unsigned char* data, size_t size, size_t pos)
embeddedartists 0:b567d56a59d7 1387 {
embeddedartists 0:b567d56a59d7 1388 unsigned result = 0;
embeddedartists 0:b567d56a59d7 1389 if (HASH_NUM_CHARACTERS == 3 && pos + 2 < size) {
embeddedartists 0:b567d56a59d7 1390 result ^= (data[pos + 0] << (0 * HASH_SHIFT));
embeddedartists 0:b567d56a59d7 1391 result ^= (data[pos + 1] << (1 * HASH_SHIFT));
embeddedartists 0:b567d56a59d7 1392 result ^= (data[pos + 2] << (2 * HASH_SHIFT));
embeddedartists 0:b567d56a59d7 1393 } else {
embeddedartists 0:b567d56a59d7 1394 size_t amount, i;
embeddedartists 0:b567d56a59d7 1395 if(pos >= size) return 0;
embeddedartists 0:b567d56a59d7 1396 amount = HASH_NUM_CHARACTERS;
embeddedartists 0:b567d56a59d7 1397 if(pos + amount >= size) amount = size - pos;
embeddedartists 0:b567d56a59d7 1398 for(i = 0; i < amount; i++) result ^= (data[pos + i] << (i * HASH_SHIFT));
embeddedartists 0:b567d56a59d7 1399 }
embeddedartists 0:b567d56a59d7 1400 return result & HASH_BIT_MASK;
embeddedartists 0:b567d56a59d7 1401 }
embeddedartists 0:b567d56a59d7 1402
embeddedartists 0:b567d56a59d7 1403 static unsigned countZeros(const unsigned char* data, size_t size, size_t pos)
embeddedartists 0:b567d56a59d7 1404 {
embeddedartists 0:b567d56a59d7 1405 const unsigned char* start = data + pos;
embeddedartists 0:b567d56a59d7 1406 const unsigned char* end = start + MAX_SUPPORTED_DEFLATE_LENGTH;
embeddedartists 0:b567d56a59d7 1407 if(end > data + size) end = data + size;
embeddedartists 0:b567d56a59d7 1408 data = start;
embeddedartists 0:b567d56a59d7 1409 while (data != end && *data == 0) data++;
embeddedartists 0:b567d56a59d7 1410 /*subtracting two addresses returned as 32-bit number (max value is MAX_SUPPORTED_DEFLATE_LENGTH)*/
embeddedartists 0:b567d56a59d7 1411 return (unsigned)(data - start);
embeddedartists 0:b567d56a59d7 1412 }
embeddedartists 0:b567d56a59d7 1413
embeddedartists 0:b567d56a59d7 1414 /*wpos = pos & (windowsize - 1)*/
embeddedartists 0:b567d56a59d7 1415 static void updateHashChain(Hash* hash, size_t wpos, int hashval)
embeddedartists 0:b567d56a59d7 1416 {
embeddedartists 0:b567d56a59d7 1417 hash->val[wpos] = hashval;
embeddedartists 0:b567d56a59d7 1418 if(hash->head[hashval] != -1) hash->chain[wpos] = hash->head[hashval];
embeddedartists 0:b567d56a59d7 1419 hash->head[hashval] = wpos;
embeddedartists 0:b567d56a59d7 1420 }
embeddedartists 0:b567d56a59d7 1421
embeddedartists 0:b567d56a59d7 1422 /*
embeddedartists 0:b567d56a59d7 1423 LZ77-encode the data. Return value is error code. The input are raw bytes, the output
embeddedartists 0:b567d56a59d7 1424 is in the form of unsigned integers with codes representing for example literal bytes, or
embeddedartists 0:b567d56a59d7 1425 length/distance pairs.
embeddedartists 0:b567d56a59d7 1426 It uses a hash table technique to let it encode faster. When doing LZ77 encoding, a
embeddedartists 0:b567d56a59d7 1427 sliding window (of windowsize) is used, and all past bytes in that window can be used as
embeddedartists 0:b567d56a59d7 1428 the "dictionary". A brute force search through all possible distances would be slow, and
embeddedartists 0:b567d56a59d7 1429 this hash technique is one out of several ways to speed this up.
embeddedartists 0:b567d56a59d7 1430 */
embeddedartists 0:b567d56a59d7 1431 static unsigned encodeLZ77(uivector* out, Hash* hash,
embeddedartists 0:b567d56a59d7 1432 const unsigned char* in, size_t inpos, size_t insize, unsigned windowsize,
embeddedartists 0:b567d56a59d7 1433 unsigned minmatch, unsigned nicematch, unsigned lazymatching)
embeddedartists 0:b567d56a59d7 1434 {
embeddedartists 0:b567d56a59d7 1435 unsigned pos, i, error = 0;
embeddedartists 0:b567d56a59d7 1436 /*for large window lengths, assume the user wants no compression loss. Otherwise, max hash chain length speedup.*/
embeddedartists 0:b567d56a59d7 1437 unsigned maxchainlength = windowsize >= 8192 ? windowsize : windowsize / 8;
embeddedartists 0:b567d56a59d7 1438 unsigned maxlazymatch = windowsize >= 8192 ? MAX_SUPPORTED_DEFLATE_LENGTH : 64;
embeddedartists 0:b567d56a59d7 1439
embeddedartists 0:b567d56a59d7 1440 unsigned usezeros = 1; /*not sure if setting it to false for windowsize < 8192 is better or worse*/
embeddedartists 0:b567d56a59d7 1441 unsigned numzeros = 0;
embeddedartists 0:b567d56a59d7 1442
embeddedartists 0:b567d56a59d7 1443 unsigned offset; /*the offset represents the distance in LZ77 terminology*/
embeddedartists 0:b567d56a59d7 1444 unsigned length;
embeddedartists 0:b567d56a59d7 1445 unsigned lazy = 0;
embeddedartists 0:b567d56a59d7 1446 unsigned lazylength = 0, lazyoffset = 0;
embeddedartists 0:b567d56a59d7 1447 unsigned hashval;
embeddedartists 0:b567d56a59d7 1448 unsigned current_offset, current_length;
embeddedartists 0:b567d56a59d7 1449 const unsigned char *lastptr, *foreptr, *backptr;
embeddedartists 0:b567d56a59d7 1450 unsigned hashpos, prevpos;
embeddedartists 0:b567d56a59d7 1451
embeddedartists 0:b567d56a59d7 1452 if(windowsize <= 0 || windowsize > 32768) return 60; /*error: windowsize smaller/larger than allowed*/
embeddedartists 0:b567d56a59d7 1453 if((windowsize & (windowsize - 1)) != 0) return 90; /*error: must be power of two*/
embeddedartists 0:b567d56a59d7 1454
embeddedartists 0:b567d56a59d7 1455 if(nicematch > MAX_SUPPORTED_DEFLATE_LENGTH) nicematch = MAX_SUPPORTED_DEFLATE_LENGTH;
embeddedartists 0:b567d56a59d7 1456
embeddedartists 0:b567d56a59d7 1457 for(pos = inpos; pos < insize; pos++)
embeddedartists 0:b567d56a59d7 1458 {
embeddedartists 0:b567d56a59d7 1459 size_t wpos = pos & (windowsize - 1); /*position for in 'circular' hash buffers*/
embeddedartists 0:b567d56a59d7 1460 unsigned chainlength = 0;
embeddedartists 0:b567d56a59d7 1461
embeddedartists 0:b567d56a59d7 1462 hashval = getHash(in, insize, pos);
embeddedartists 0:b567d56a59d7 1463 updateHashChain(hash, wpos, hashval);
embeddedartists 0:b567d56a59d7 1464
embeddedartists 0:b567d56a59d7 1465 if(usezeros && hashval == 0)
embeddedartists 0:b567d56a59d7 1466 {
embeddedartists 0:b567d56a59d7 1467 if (numzeros == 0) numzeros = countZeros(in, insize, pos);
embeddedartists 0:b567d56a59d7 1468 else if (pos + numzeros >= insize || in[pos + numzeros - 1] != 0) numzeros--;
embeddedartists 0:b567d56a59d7 1469 hash->zeros[wpos] = numzeros;
embeddedartists 0:b567d56a59d7 1470 }
embeddedartists 0:b567d56a59d7 1471 else
embeddedartists 0:b567d56a59d7 1472 {
embeddedartists 0:b567d56a59d7 1473 numzeros = 0;
embeddedartists 0:b567d56a59d7 1474 }
embeddedartists 0:b567d56a59d7 1475
embeddedartists 0:b567d56a59d7 1476 /*the length and offset found for the current position*/
embeddedartists 0:b567d56a59d7 1477 length = 0;
embeddedartists 0:b567d56a59d7 1478 offset = 0;
embeddedartists 0:b567d56a59d7 1479
embeddedartists 0:b567d56a59d7 1480 prevpos = hash->head[hashval];
embeddedartists 0:b567d56a59d7 1481 hashpos = hash->chain[prevpos];
embeddedartists 0:b567d56a59d7 1482
embeddedartists 0:b567d56a59d7 1483 lastptr = &in[insize < pos + MAX_SUPPORTED_DEFLATE_LENGTH ? insize : pos + MAX_SUPPORTED_DEFLATE_LENGTH];
embeddedartists 0:b567d56a59d7 1484
embeddedartists 0:b567d56a59d7 1485 /*search for the longest string*/
embeddedartists 0:b567d56a59d7 1486 for(;;)
embeddedartists 0:b567d56a59d7 1487 {
embeddedartists 0:b567d56a59d7 1488 /*stop when went completely around the circular buffer*/
embeddedartists 0:b567d56a59d7 1489 if(prevpos < wpos && hashpos > prevpos && hashpos <= wpos) break;
embeddedartists 0:b567d56a59d7 1490 if(prevpos > wpos && (hashpos <= wpos || hashpos > prevpos)) break;
embeddedartists 0:b567d56a59d7 1491 if(chainlength++ >= maxchainlength) break;
embeddedartists 0:b567d56a59d7 1492
embeddedartists 0:b567d56a59d7 1493 current_offset = hashpos <= wpos ? wpos - hashpos : wpos - hashpos + windowsize;
embeddedartists 0:b567d56a59d7 1494 if(current_offset > 0)
embeddedartists 0:b567d56a59d7 1495 {
embeddedartists 0:b567d56a59d7 1496 /*test the next characters*/
embeddedartists 0:b567d56a59d7 1497 foreptr = &in[pos];
embeddedartists 0:b567d56a59d7 1498 backptr = &in[pos - current_offset];
embeddedartists 0:b567d56a59d7 1499
embeddedartists 0:b567d56a59d7 1500 /*common case in PNGs is lots of zeros. Quickly skip over them as a speedup*/
embeddedartists 0:b567d56a59d7 1501 if(usezeros && hashval == 0 && hash->val[hashpos] == 0 /*hashval[hashpos] may be out of date*/)
embeddedartists 0:b567d56a59d7 1502 {
embeddedartists 0:b567d56a59d7 1503 unsigned skip = hash->zeros[hashpos];
embeddedartists 0:b567d56a59d7 1504 if(skip > numzeros) skip = numzeros;
embeddedartists 0:b567d56a59d7 1505 backptr += skip;
embeddedartists 0:b567d56a59d7 1506 foreptr += skip;
embeddedartists 0:b567d56a59d7 1507 }
embeddedartists 0:b567d56a59d7 1508
embeddedartists 0:b567d56a59d7 1509 while(foreptr != lastptr && *backptr == *foreptr) /*maximum supported length by deflate is max length*/
embeddedartists 0:b567d56a59d7 1510 {
embeddedartists 0:b567d56a59d7 1511 ++backptr;
embeddedartists 0:b567d56a59d7 1512 ++foreptr;
embeddedartists 0:b567d56a59d7 1513 }
embeddedartists 0:b567d56a59d7 1514 current_length = (unsigned)(foreptr - &in[pos]);
embeddedartists 0:b567d56a59d7 1515
embeddedartists 0:b567d56a59d7 1516 if(current_length > length)
embeddedartists 0:b567d56a59d7 1517 {
embeddedartists 0:b567d56a59d7 1518 length = current_length; /*the longest length*/
embeddedartists 0:b567d56a59d7 1519 offset = current_offset; /*the offset that is related to this longest length*/
embeddedartists 0:b567d56a59d7 1520 /*jump out once a length of max length is found (speed gain). This also jumps
embeddedartists 0:b567d56a59d7 1521 out if length is MAX_SUPPORTED_DEFLATE_LENGTH*/
embeddedartists 0:b567d56a59d7 1522 if(current_length >= nicematch) break;
embeddedartists 0:b567d56a59d7 1523 }
embeddedartists 0:b567d56a59d7 1524 }
embeddedartists 0:b567d56a59d7 1525
embeddedartists 0:b567d56a59d7 1526 if(hashpos == hash->chain[hashpos]) break;
embeddedartists 0:b567d56a59d7 1527
embeddedartists 0:b567d56a59d7 1528 prevpos = hashpos;
embeddedartists 0:b567d56a59d7 1529 hashpos = hash->chain[hashpos];
embeddedartists 0:b567d56a59d7 1530 }
embeddedartists 0:b567d56a59d7 1531
embeddedartists 0:b567d56a59d7 1532 if(lazymatching)
embeddedartists 0:b567d56a59d7 1533 {
embeddedartists 0:b567d56a59d7 1534 if(!lazy && length >= 3 && length <= maxlazymatch && length < MAX_SUPPORTED_DEFLATE_LENGTH)
embeddedartists 0:b567d56a59d7 1535 {
embeddedartists 0:b567d56a59d7 1536 lazy = 1;
embeddedartists 0:b567d56a59d7 1537 lazylength = length;
embeddedartists 0:b567d56a59d7 1538 lazyoffset = offset;
embeddedartists 0:b567d56a59d7 1539 continue; /*try the next byte*/
embeddedartists 0:b567d56a59d7 1540 }
embeddedartists 0:b567d56a59d7 1541 if(lazy)
embeddedartists 0:b567d56a59d7 1542 {
embeddedartists 0:b567d56a59d7 1543 lazy = 0;
embeddedartists 0:b567d56a59d7 1544 if(pos == 0) ERROR_BREAK(81);
embeddedartists 0:b567d56a59d7 1545 if(length > lazylength + 1)
embeddedartists 0:b567d56a59d7 1546 {
embeddedartists 0:b567d56a59d7 1547 /*push the previous character as literal*/
embeddedartists 0:b567d56a59d7 1548 if(!uivector_push_back(out, in[pos - 1])) ERROR_BREAK(83 /*alloc fail*/);
embeddedartists 0:b567d56a59d7 1549 }
embeddedartists 0:b567d56a59d7 1550 else
embeddedartists 0:b567d56a59d7 1551 {
embeddedartists 0:b567d56a59d7 1552 length = lazylength;
embeddedartists 0:b567d56a59d7 1553 offset = lazyoffset;
embeddedartists 0:b567d56a59d7 1554 hash->head[hashval] = -1; /*the same hashchain update will be done, this ensures no wrong alteration*/
embeddedartists 0:b567d56a59d7 1555 pos--;
embeddedartists 0:b567d56a59d7 1556 }
embeddedartists 0:b567d56a59d7 1557 }
embeddedartists 0:b567d56a59d7 1558 }
embeddedartists 0:b567d56a59d7 1559 if(length >= 3 && offset > windowsize) ERROR_BREAK(86 /*too big (or overflown negative) offset*/);
embeddedartists 0:b567d56a59d7 1560
embeddedartists 0:b567d56a59d7 1561 /*encode it as length/distance pair or literal value*/
embeddedartists 0:b567d56a59d7 1562 if(length < 3) /*only lengths of 3 or higher are supported as length/distance pair*/
embeddedartists 0:b567d56a59d7 1563 {
embeddedartists 0:b567d56a59d7 1564 if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/);
embeddedartists 0:b567d56a59d7 1565 }
embeddedartists 0:b567d56a59d7 1566 else if(length < minmatch || (length == 3 && offset > 4096))
embeddedartists 0:b567d56a59d7 1567 {
embeddedartists 0:b567d56a59d7 1568 /*compensate for the fact that longer offsets have more extra bits, a
embeddedartists 0:b567d56a59d7 1569 length of only 3 may be not worth it then*/
embeddedartists 0:b567d56a59d7 1570 if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/);
embeddedartists 0:b567d56a59d7 1571 }
embeddedartists 0:b567d56a59d7 1572 else
embeddedartists 0:b567d56a59d7 1573 {
embeddedartists 0:b567d56a59d7 1574 addLengthDistance(out, length, offset);
embeddedartists 0:b567d56a59d7 1575 for(i = 1; i < length; i++)
embeddedartists 0:b567d56a59d7 1576 {
embeddedartists 0:b567d56a59d7 1577 pos++;
embeddedartists 0:b567d56a59d7 1578 wpos = pos & (windowsize - 1);
embeddedartists 0:b567d56a59d7 1579 hashval = getHash(in, insize, pos);
embeddedartists 0:b567d56a59d7 1580 updateHashChain(hash, wpos, hashval);
embeddedartists 0:b567d56a59d7 1581 if(usezeros && hashval == 0)
embeddedartists 0:b567d56a59d7 1582 {
embeddedartists 0:b567d56a59d7 1583 if (numzeros == 0) numzeros = countZeros(in, insize, pos);
embeddedartists 0:b567d56a59d7 1584 else if (pos + numzeros >= insize || in[pos + numzeros - 1] != 0) numzeros--;
embeddedartists 0:b567d56a59d7 1585 hash->zeros[wpos] = numzeros;
embeddedartists 0:b567d56a59d7 1586 }
embeddedartists 0:b567d56a59d7 1587 else
embeddedartists 0:b567d56a59d7 1588 {
embeddedartists 0:b567d56a59d7 1589 numzeros = 0;
embeddedartists 0:b567d56a59d7 1590 }
embeddedartists 0:b567d56a59d7 1591 }
embeddedartists 0:b567d56a59d7 1592 }
embeddedartists 0:b567d56a59d7 1593 } /*end of the loop through each character of input*/
embeddedartists 0:b567d56a59d7 1594
embeddedartists 0:b567d56a59d7 1595 return error;
embeddedartists 0:b567d56a59d7 1596 }
embeddedartists 0:b567d56a59d7 1597
embeddedartists 0:b567d56a59d7 1598 /* /////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 1599
embeddedartists 0:b567d56a59d7 1600 static unsigned deflateNoCompression(ucvector* out, const unsigned char* data, size_t datasize)
embeddedartists 0:b567d56a59d7 1601 {
embeddedartists 0:b567d56a59d7 1602 /*non compressed deflate block data: 1 bit BFINAL,2 bits BTYPE,(5 bits): it jumps to start of next byte,
embeddedartists 0:b567d56a59d7 1603 2 bytes LEN, 2 bytes NLEN, LEN bytes literal DATA*/
embeddedartists 0:b567d56a59d7 1604
embeddedartists 0:b567d56a59d7 1605 size_t i, j, numdeflateblocks = (datasize + 65534) / 65535;
embeddedartists 0:b567d56a59d7 1606 unsigned datapos = 0;
embeddedartists 0:b567d56a59d7 1607 for(i = 0; i < numdeflateblocks; i++)
embeddedartists 0:b567d56a59d7 1608 {
embeddedartists 0:b567d56a59d7 1609 unsigned BFINAL, BTYPE, LEN, NLEN;
embeddedartists 0:b567d56a59d7 1610 unsigned char firstbyte;
embeddedartists 0:b567d56a59d7 1611
embeddedartists 0:b567d56a59d7 1612 BFINAL = (i == numdeflateblocks - 1);
embeddedartists 0:b567d56a59d7 1613 BTYPE = 0;
embeddedartists 0:b567d56a59d7 1614
embeddedartists 0:b567d56a59d7 1615 firstbyte = (unsigned char)(BFINAL + ((BTYPE & 1) << 1) + ((BTYPE & 2) << 1));
embeddedartists 0:b567d56a59d7 1616 ucvector_push_back(out, firstbyte);
embeddedartists 0:b567d56a59d7 1617
embeddedartists 0:b567d56a59d7 1618 LEN = 65535;
embeddedartists 0:b567d56a59d7 1619 if(datasize - datapos < 65535) LEN = (unsigned)datasize - datapos;
embeddedartists 0:b567d56a59d7 1620 NLEN = 65535 - LEN;
embeddedartists 0:b567d56a59d7 1621
embeddedartists 0:b567d56a59d7 1622 ucvector_push_back(out, (unsigned char)(LEN % 256));
embeddedartists 0:b567d56a59d7 1623 ucvector_push_back(out, (unsigned char)(LEN / 256));
embeddedartists 0:b567d56a59d7 1624 ucvector_push_back(out, (unsigned char)(NLEN % 256));
embeddedartists 0:b567d56a59d7 1625 ucvector_push_back(out, (unsigned char)(NLEN / 256));
embeddedartists 0:b567d56a59d7 1626
embeddedartists 0:b567d56a59d7 1627 /*Decompressed data*/
embeddedartists 0:b567d56a59d7 1628 for(j = 0; j < 65535 && datapos < datasize; j++)
embeddedartists 0:b567d56a59d7 1629 {
embeddedartists 0:b567d56a59d7 1630 ucvector_push_back(out, data[datapos++]);
embeddedartists 0:b567d56a59d7 1631 }
embeddedartists 0:b567d56a59d7 1632 }
embeddedartists 0:b567d56a59d7 1633
embeddedartists 0:b567d56a59d7 1634 return 0;
embeddedartists 0:b567d56a59d7 1635 }
embeddedartists 0:b567d56a59d7 1636
embeddedartists 0:b567d56a59d7 1637 /*
embeddedartists 0:b567d56a59d7 1638 write the lz77-encoded data, which has lit, len and dist codes, to compressed stream using huffman trees.
embeddedartists 0:b567d56a59d7 1639 tree_ll: the tree for lit and len codes.
embeddedartists 0:b567d56a59d7 1640 tree_d: the tree for distance codes.
embeddedartists 0:b567d56a59d7 1641 */
embeddedartists 0:b567d56a59d7 1642 static void writeLZ77data(size_t* bp, ucvector* out, const uivector* lz77_encoded,
embeddedartists 0:b567d56a59d7 1643 const HuffmanTree* tree_ll, const HuffmanTree* tree_d)
embeddedartists 0:b567d56a59d7 1644 {
embeddedartists 0:b567d56a59d7 1645 size_t i = 0;
embeddedartists 0:b567d56a59d7 1646 for(i = 0; i < lz77_encoded->size; i++)
embeddedartists 0:b567d56a59d7 1647 {
embeddedartists 0:b567d56a59d7 1648 unsigned val = lz77_encoded->data[i];
embeddedartists 0:b567d56a59d7 1649 addHuffmanSymbol(bp, out, HuffmanTree_getCode(tree_ll, val), HuffmanTree_getLength(tree_ll, val));
embeddedartists 0:b567d56a59d7 1650 if(val > 256) /*for a length code, 3 more things have to be added*/
embeddedartists 0:b567d56a59d7 1651 {
embeddedartists 0:b567d56a59d7 1652 unsigned length_index = val - FIRST_LENGTH_CODE_INDEX;
embeddedartists 0:b567d56a59d7 1653 unsigned n_length_extra_bits = LENGTHEXTRA[length_index];
embeddedartists 0:b567d56a59d7 1654 unsigned length_extra_bits = lz77_encoded->data[++i];
embeddedartists 0:b567d56a59d7 1655
embeddedartists 0:b567d56a59d7 1656 unsigned distance_code = lz77_encoded->data[++i];
embeddedartists 0:b567d56a59d7 1657
embeddedartists 0:b567d56a59d7 1658 unsigned distance_index = distance_code;
embeddedartists 0:b567d56a59d7 1659 unsigned n_distance_extra_bits = DISTANCEEXTRA[distance_index];
embeddedartists 0:b567d56a59d7 1660 unsigned distance_extra_bits = lz77_encoded->data[++i];
embeddedartists 0:b567d56a59d7 1661
embeddedartists 0:b567d56a59d7 1662 addBitsToStream(bp, out, length_extra_bits, n_length_extra_bits);
embeddedartists 0:b567d56a59d7 1663 addHuffmanSymbol(bp, out, HuffmanTree_getCode(tree_d, distance_code),
embeddedartists 0:b567d56a59d7 1664 HuffmanTree_getLength(tree_d, distance_code));
embeddedartists 0:b567d56a59d7 1665 addBitsToStream(bp, out, distance_extra_bits, n_distance_extra_bits);
embeddedartists 0:b567d56a59d7 1666 }
embeddedartists 0:b567d56a59d7 1667 }
embeddedartists 0:b567d56a59d7 1668 }
embeddedartists 0:b567d56a59d7 1669
embeddedartists 0:b567d56a59d7 1670 /*Deflate for a block of type "dynamic", that is, with freely, optimally, created huffman trees*/
embeddedartists 0:b567d56a59d7 1671 static unsigned deflateDynamic(ucvector* out, size_t* bp, Hash* hash,
embeddedartists 0:b567d56a59d7 1672 const unsigned char* data, size_t datapos, size_t dataend,
embeddedartists 0:b567d56a59d7 1673 const LodePNGCompressSettings* settings, int final)
embeddedartists 0:b567d56a59d7 1674 {
embeddedartists 0:b567d56a59d7 1675 unsigned error = 0;
embeddedartists 0:b567d56a59d7 1676
embeddedartists 0:b567d56a59d7 1677 /*
embeddedartists 0:b567d56a59d7 1678 A block is compressed as follows: The PNG data is lz77 encoded, resulting in
embeddedartists 0:b567d56a59d7 1679 literal bytes and length/distance pairs. This is then huffman compressed with
embeddedartists 0:b567d56a59d7 1680 two huffman trees. One huffman tree is used for the lit and len values ("ll"),
embeddedartists 0:b567d56a59d7 1681 another huffman tree is used for the dist values ("d"). These two trees are
embeddedartists 0:b567d56a59d7 1682 stored using their code lengths, and to compress even more these code lengths
embeddedartists 0:b567d56a59d7 1683 are also run-length encoded and huffman compressed. This gives a huffman tree
embeddedartists 0:b567d56a59d7 1684 of code lengths "cl". The code lenghts used to describe this third tree are
embeddedartists 0:b567d56a59d7 1685 the code length code lengths ("clcl").
embeddedartists 0:b567d56a59d7 1686 */
embeddedartists 0:b567d56a59d7 1687
embeddedartists 0:b567d56a59d7 1688 /*The lz77 encoded data, represented with integers since there will also be length and distance codes in it*/
embeddedartists 0:b567d56a59d7 1689 uivector lz77_encoded;
embeddedartists 0:b567d56a59d7 1690 HuffmanTree tree_ll; /*tree for lit,len values*/
embeddedartists 0:b567d56a59d7 1691 HuffmanTree tree_d; /*tree for distance codes*/
embeddedartists 0:b567d56a59d7 1692 HuffmanTree tree_cl; /*tree for encoding the code lengths representing tree_ll and tree_d*/
embeddedartists 0:b567d56a59d7 1693 uivector frequencies_ll; /*frequency of lit,len codes*/
embeddedartists 0:b567d56a59d7 1694 uivector frequencies_d; /*frequency of dist codes*/
embeddedartists 0:b567d56a59d7 1695 uivector frequencies_cl; /*frequency of code length codes*/
embeddedartists 0:b567d56a59d7 1696 uivector bitlen_lld; /*lit,len,dist code lenghts (int bits), literally (without repeat codes).*/
embeddedartists 0:b567d56a59d7 1697 uivector bitlen_lld_e; /*bitlen_lld encoded with repeat codes (this is a rudemtary run length compression)*/
embeddedartists 0:b567d56a59d7 1698 /*bitlen_cl is the code length code lengths ("clcl"). The bit lengths of codes to represent tree_cl
embeddedartists 0:b567d56a59d7 1699 (these are written as is in the file, it would be crazy to compress these using yet another huffman
embeddedartists 0:b567d56a59d7 1700 tree that needs to be represented by yet another set of code lengths)*/
embeddedartists 0:b567d56a59d7 1701 uivector bitlen_cl;
embeddedartists 0:b567d56a59d7 1702 size_t datasize = dataend - datapos;
embeddedartists 0:b567d56a59d7 1703
embeddedartists 0:b567d56a59d7 1704 /*
embeddedartists 0:b567d56a59d7 1705 Due to the huffman compression of huffman tree representations ("two levels"), there are some anologies:
embeddedartists 0:b567d56a59d7 1706 bitlen_lld is to tree_cl what data is to tree_ll and tree_d.
embeddedartists 0:b567d56a59d7 1707 bitlen_lld_e is to bitlen_lld what lz77_encoded is to data.
embeddedartists 0:b567d56a59d7 1708 bitlen_cl is to bitlen_lld_e what bitlen_lld is to lz77_encoded.
embeddedartists 0:b567d56a59d7 1709 */
embeddedartists 0:b567d56a59d7 1710
embeddedartists 0:b567d56a59d7 1711 unsigned BFINAL = final;
embeddedartists 0:b567d56a59d7 1712 size_t numcodes_ll, numcodes_d, i;
embeddedartists 0:b567d56a59d7 1713 unsigned HLIT, HDIST, HCLEN;
embeddedartists 0:b567d56a59d7 1714
embeddedartists 0:b567d56a59d7 1715 uivector_init(&lz77_encoded);
embeddedartists 0:b567d56a59d7 1716 HuffmanTree_init(&tree_ll);
embeddedartists 0:b567d56a59d7 1717 HuffmanTree_init(&tree_d);
embeddedartists 0:b567d56a59d7 1718 HuffmanTree_init(&tree_cl);
embeddedartists 0:b567d56a59d7 1719 uivector_init(&frequencies_ll);
embeddedartists 0:b567d56a59d7 1720 uivector_init(&frequencies_d);
embeddedartists 0:b567d56a59d7 1721 uivector_init(&frequencies_cl);
embeddedartists 0:b567d56a59d7 1722 uivector_init(&bitlen_lld);
embeddedartists 0:b567d56a59d7 1723 uivector_init(&bitlen_lld_e);
embeddedartists 0:b567d56a59d7 1724 uivector_init(&bitlen_cl);
embeddedartists 0:b567d56a59d7 1725
embeddedartists 0:b567d56a59d7 1726 /*This while loop never loops due to a break at the end, it is here to
embeddedartists 0:b567d56a59d7 1727 allow breaking out of it to the cleanup phase on error conditions.*/
embeddedartists 0:b567d56a59d7 1728 while(!error)
embeddedartists 0:b567d56a59d7 1729 {
embeddedartists 0:b567d56a59d7 1730 if(settings->use_lz77)
embeddedartists 0:b567d56a59d7 1731 {
embeddedartists 0:b567d56a59d7 1732 error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize,
embeddedartists 0:b567d56a59d7 1733 settings->minmatch, settings->nicematch, settings->lazymatching);
embeddedartists 0:b567d56a59d7 1734 if(error) break;
embeddedartists 0:b567d56a59d7 1735 }
embeddedartists 0:b567d56a59d7 1736 else
embeddedartists 0:b567d56a59d7 1737 {
embeddedartists 0:b567d56a59d7 1738 if(!uivector_resize(&lz77_encoded, datasize)) ERROR_BREAK(83 /*alloc fail*/);
embeddedartists 0:b567d56a59d7 1739 for(i = datapos; i < dataend; i++) lz77_encoded.data[i] = data[i]; /*no LZ77, but still will be Huffman compressed*/
embeddedartists 0:b567d56a59d7 1740 }
embeddedartists 0:b567d56a59d7 1741
embeddedartists 0:b567d56a59d7 1742 if(!uivector_resizev(&frequencies_ll, 286, 0)) ERROR_BREAK(83 /*alloc fail*/);
embeddedartists 0:b567d56a59d7 1743 if(!uivector_resizev(&frequencies_d, 30, 0)) ERROR_BREAK(83 /*alloc fail*/);
embeddedartists 0:b567d56a59d7 1744
embeddedartists 0:b567d56a59d7 1745 /*Count the frequencies of lit, len and dist codes*/
embeddedartists 0:b567d56a59d7 1746 for(i = 0; i < lz77_encoded.size; i++)
embeddedartists 0:b567d56a59d7 1747 {
embeddedartists 0:b567d56a59d7 1748 unsigned symbol = lz77_encoded.data[i];
embeddedartists 0:b567d56a59d7 1749 frequencies_ll.data[symbol]++;
embeddedartists 0:b567d56a59d7 1750 if(symbol > 256)
embeddedartists 0:b567d56a59d7 1751 {
embeddedartists 0:b567d56a59d7 1752 unsigned dist = lz77_encoded.data[i + 2];
embeddedartists 0:b567d56a59d7 1753 frequencies_d.data[dist]++;
embeddedartists 0:b567d56a59d7 1754 i += 3;
embeddedartists 0:b567d56a59d7 1755 }
embeddedartists 0:b567d56a59d7 1756 }
embeddedartists 0:b567d56a59d7 1757 frequencies_ll.data[256] = 1; /*there will be exactly 1 end code, at the end of the block*/
embeddedartists 0:b567d56a59d7 1758
embeddedartists 0:b567d56a59d7 1759 /*Make both huffman trees, one for the lit and len codes, one for the dist codes*/
embeddedartists 0:b567d56a59d7 1760 error = HuffmanTree_makeFromFrequencies(&tree_ll, frequencies_ll.data, 257, frequencies_ll.size, 15);
embeddedartists 0:b567d56a59d7 1761 if(error) break;
embeddedartists 0:b567d56a59d7 1762 /*2, not 1, is chosen for mincodes: some buggy PNG decoders require at least 2 symbols in the dist tree*/
embeddedartists 0:b567d56a59d7 1763 error = HuffmanTree_makeFromFrequencies(&tree_d, frequencies_d.data, 2, frequencies_d.size, 15);
embeddedartists 0:b567d56a59d7 1764 if(error) break;
embeddedartists 0:b567d56a59d7 1765
embeddedartists 0:b567d56a59d7 1766 numcodes_ll = tree_ll.numcodes; if(numcodes_ll > 286) numcodes_ll = 286;
embeddedartists 0:b567d56a59d7 1767 numcodes_d = tree_d.numcodes; if(numcodes_d > 30) numcodes_d = 30;
embeddedartists 0:b567d56a59d7 1768 /*store the code lengths of both generated trees in bitlen_lld*/
embeddedartists 0:b567d56a59d7 1769 for(i = 0; i < numcodes_ll; i++) uivector_push_back(&bitlen_lld, HuffmanTree_getLength(&tree_ll, (unsigned)i));
embeddedartists 0:b567d56a59d7 1770 for(i = 0; i < numcodes_d; i++) uivector_push_back(&bitlen_lld, HuffmanTree_getLength(&tree_d, (unsigned)i));
embeddedartists 0:b567d56a59d7 1771
embeddedartists 0:b567d56a59d7 1772 /*run-length compress bitlen_ldd into bitlen_lld_e by using repeat codes 16 (copy length 3-6 times),
embeddedartists 0:b567d56a59d7 1773 17 (3-10 zeroes), 18 (11-138 zeroes)*/
embeddedartists 0:b567d56a59d7 1774 for(i = 0; i < (unsigned)bitlen_lld.size; i++)
embeddedartists 0:b567d56a59d7 1775 {
embeddedartists 0:b567d56a59d7 1776 unsigned j = 0; /*amount of repititions*/
embeddedartists 0:b567d56a59d7 1777 while(i + j + 1 < (unsigned)bitlen_lld.size && bitlen_lld.data[i + j + 1] == bitlen_lld.data[i]) j++;
embeddedartists 0:b567d56a59d7 1778
embeddedartists 0:b567d56a59d7 1779 if(bitlen_lld.data[i] == 0 && j >= 2) /*repeat code for zeroes*/
embeddedartists 0:b567d56a59d7 1780 {
embeddedartists 0:b567d56a59d7 1781 j++; /*include the first zero*/
embeddedartists 0:b567d56a59d7 1782 if(j <= 10) /*repeat code 17 supports max 10 zeroes*/
embeddedartists 0:b567d56a59d7 1783 {
embeddedartists 0:b567d56a59d7 1784 uivector_push_back(&bitlen_lld_e, 17);
embeddedartists 0:b567d56a59d7 1785 uivector_push_back(&bitlen_lld_e, j - 3);
embeddedartists 0:b567d56a59d7 1786 }
embeddedartists 0:b567d56a59d7 1787 else /*repeat code 18 supports max 138 zeroes*/
embeddedartists 0:b567d56a59d7 1788 {
embeddedartists 0:b567d56a59d7 1789 if(j > 138) j = 138;
embeddedartists 0:b567d56a59d7 1790 uivector_push_back(&bitlen_lld_e, 18);
embeddedartists 0:b567d56a59d7 1791 uivector_push_back(&bitlen_lld_e, j - 11);
embeddedartists 0:b567d56a59d7 1792 }
embeddedartists 0:b567d56a59d7 1793 i += (j - 1);
embeddedartists 0:b567d56a59d7 1794 }
embeddedartists 0:b567d56a59d7 1795 else if(j >= 3) /*repeat code for value other than zero*/
embeddedartists 0:b567d56a59d7 1796 {
embeddedartists 0:b567d56a59d7 1797 size_t k;
embeddedartists 0:b567d56a59d7 1798 unsigned num = j / 6, rest = j % 6;
embeddedartists 0:b567d56a59d7 1799 uivector_push_back(&bitlen_lld_e, bitlen_lld.data[i]);
embeddedartists 0:b567d56a59d7 1800 for(k = 0; k < num; k++)
embeddedartists 0:b567d56a59d7 1801 {
embeddedartists 0:b567d56a59d7 1802 uivector_push_back(&bitlen_lld_e, 16);
embeddedartists 0:b567d56a59d7 1803 uivector_push_back(&bitlen_lld_e, 6 - 3);
embeddedartists 0:b567d56a59d7 1804 }
embeddedartists 0:b567d56a59d7 1805 if(rest >= 3)
embeddedartists 0:b567d56a59d7 1806 {
embeddedartists 0:b567d56a59d7 1807 uivector_push_back(&bitlen_lld_e, 16);
embeddedartists 0:b567d56a59d7 1808 uivector_push_back(&bitlen_lld_e, rest - 3);
embeddedartists 0:b567d56a59d7 1809 }
embeddedartists 0:b567d56a59d7 1810 else j -= rest;
embeddedartists 0:b567d56a59d7 1811 i += j;
embeddedartists 0:b567d56a59d7 1812 }
embeddedartists 0:b567d56a59d7 1813 else /*too short to benefit from repeat code*/
embeddedartists 0:b567d56a59d7 1814 {
embeddedartists 0:b567d56a59d7 1815 uivector_push_back(&bitlen_lld_e, bitlen_lld.data[i]);
embeddedartists 0:b567d56a59d7 1816 }
embeddedartists 0:b567d56a59d7 1817 }
embeddedartists 0:b567d56a59d7 1818
embeddedartists 0:b567d56a59d7 1819 /*generate tree_cl, the huffmantree of huffmantrees*/
embeddedartists 0:b567d56a59d7 1820
embeddedartists 0:b567d56a59d7 1821 if(!uivector_resizev(&frequencies_cl, NUM_CODE_LENGTH_CODES, 0)) ERROR_BREAK(83 /*alloc fail*/);
embeddedartists 0:b567d56a59d7 1822 for(i = 0; i < bitlen_lld_e.size; i++)
embeddedartists 0:b567d56a59d7 1823 {
embeddedartists 0:b567d56a59d7 1824 frequencies_cl.data[bitlen_lld_e.data[i]]++;
embeddedartists 0:b567d56a59d7 1825 /*after a repeat code come the bits that specify the number of repetitions,
embeddedartists 0:b567d56a59d7 1826 those don't need to be in the frequencies_cl calculation*/
embeddedartists 0:b567d56a59d7 1827 if(bitlen_lld_e.data[i] >= 16) i++;
embeddedartists 0:b567d56a59d7 1828 }
embeddedartists 0:b567d56a59d7 1829
embeddedartists 0:b567d56a59d7 1830 error = HuffmanTree_makeFromFrequencies(&tree_cl, frequencies_cl.data,
embeddedartists 0:b567d56a59d7 1831 frequencies_cl.size, frequencies_cl.size, 7);
embeddedartists 0:b567d56a59d7 1832 if(error) break;
embeddedartists 0:b567d56a59d7 1833
embeddedartists 0:b567d56a59d7 1834 if(!uivector_resize(&bitlen_cl, tree_cl.numcodes)) ERROR_BREAK(83 /*alloc fail*/);
embeddedartists 0:b567d56a59d7 1835 for(i = 0; i < tree_cl.numcodes; i++)
embeddedartists 0:b567d56a59d7 1836 {
embeddedartists 0:b567d56a59d7 1837 /*lenghts of code length tree is in the order as specified by deflate*/
embeddedartists 0:b567d56a59d7 1838 bitlen_cl.data[i] = HuffmanTree_getLength(&tree_cl, CLCL_ORDER[i]);
embeddedartists 0:b567d56a59d7 1839 }
embeddedartists 0:b567d56a59d7 1840 while(bitlen_cl.data[bitlen_cl.size - 1] == 0 && bitlen_cl.size > 4)
embeddedartists 0:b567d56a59d7 1841 {
embeddedartists 0:b567d56a59d7 1842 /*remove zeros at the end, but minimum size must be 4*/
embeddedartists 0:b567d56a59d7 1843 if(!uivector_resize(&bitlen_cl, bitlen_cl.size - 1)) ERROR_BREAK(83 /*alloc fail*/);
embeddedartists 0:b567d56a59d7 1844 }
embeddedartists 0:b567d56a59d7 1845 if(error) break;
embeddedartists 0:b567d56a59d7 1846
embeddedartists 0:b567d56a59d7 1847 /*
embeddedartists 0:b567d56a59d7 1848 Write everything into the output
embeddedartists 0:b567d56a59d7 1849
embeddedartists 0:b567d56a59d7 1850 After the BFINAL and BTYPE, the dynamic block consists out of the following:
embeddedartists 0:b567d56a59d7 1851 - 5 bits HLIT, 5 bits HDIST, 4 bits HCLEN
embeddedartists 0:b567d56a59d7 1852 - (HCLEN+4)*3 bits code lengths of code length alphabet
embeddedartists 0:b567d56a59d7 1853 - HLIT + 257 code lenghts of lit/length alphabet (encoded using the code length
embeddedartists 0:b567d56a59d7 1854 alphabet, + possible repetition codes 16, 17, 18)
embeddedartists 0:b567d56a59d7 1855 - HDIST + 1 code lengths of distance alphabet (encoded using the code length
embeddedartists 0:b567d56a59d7 1856 alphabet, + possible repetition codes 16, 17, 18)
embeddedartists 0:b567d56a59d7 1857 - compressed data
embeddedartists 0:b567d56a59d7 1858 - 256 (end code)
embeddedartists 0:b567d56a59d7 1859 */
embeddedartists 0:b567d56a59d7 1860
embeddedartists 0:b567d56a59d7 1861 /*Write block type*/
embeddedartists 0:b567d56a59d7 1862 addBitToStream(bp, out, BFINAL);
embeddedartists 0:b567d56a59d7 1863 addBitToStream(bp, out, 0); /*first bit of BTYPE "dynamic"*/
embeddedartists 0:b567d56a59d7 1864 addBitToStream(bp, out, 1); /*second bit of BTYPE "dynamic"*/
embeddedartists 0:b567d56a59d7 1865
embeddedartists 0:b567d56a59d7 1866 /*write the HLIT, HDIST and HCLEN values*/
embeddedartists 0:b567d56a59d7 1867 HLIT = (unsigned)(numcodes_ll - 257);
embeddedartists 0:b567d56a59d7 1868 HDIST = (unsigned)(numcodes_d - 1);
embeddedartists 0:b567d56a59d7 1869 HCLEN = (unsigned)bitlen_cl.size - 4;
embeddedartists 0:b567d56a59d7 1870 /*trim zeroes for HCLEN. HLIT and HDIST were already trimmed at tree creation*/
embeddedartists 0:b567d56a59d7 1871 while(!bitlen_cl.data[HCLEN + 4 - 1] && HCLEN > 0) HCLEN--;
embeddedartists 0:b567d56a59d7 1872 addBitsToStream(bp, out, HLIT, 5);
embeddedartists 0:b567d56a59d7 1873 addBitsToStream(bp, out, HDIST, 5);
embeddedartists 0:b567d56a59d7 1874 addBitsToStream(bp, out, HCLEN, 4);
embeddedartists 0:b567d56a59d7 1875
embeddedartists 0:b567d56a59d7 1876 /*write the code lenghts of the code length alphabet*/
embeddedartists 0:b567d56a59d7 1877 for(i = 0; i < HCLEN + 4; i++) addBitsToStream(bp, out, bitlen_cl.data[i], 3);
embeddedartists 0:b567d56a59d7 1878
embeddedartists 0:b567d56a59d7 1879 /*write the lenghts of the lit/len AND the dist alphabet*/
embeddedartists 0:b567d56a59d7 1880 for(i = 0; i < bitlen_lld_e.size; i++)
embeddedartists 0:b567d56a59d7 1881 {
embeddedartists 0:b567d56a59d7 1882 addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_cl, bitlen_lld_e.data[i]),
embeddedartists 0:b567d56a59d7 1883 HuffmanTree_getLength(&tree_cl, bitlen_lld_e.data[i]));
embeddedartists 0:b567d56a59d7 1884 /*extra bits of repeat codes*/
embeddedartists 0:b567d56a59d7 1885 if(bitlen_lld_e.data[i] == 16) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 2);
embeddedartists 0:b567d56a59d7 1886 else if(bitlen_lld_e.data[i] == 17) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 3);
embeddedartists 0:b567d56a59d7 1887 else if(bitlen_lld_e.data[i] == 18) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 7);
embeddedartists 0:b567d56a59d7 1888 }
embeddedartists 0:b567d56a59d7 1889
embeddedartists 0:b567d56a59d7 1890 /*write the compressed data symbols*/
embeddedartists 0:b567d56a59d7 1891 writeLZ77data(bp, out, &lz77_encoded, &tree_ll, &tree_d);
embeddedartists 0:b567d56a59d7 1892 /*error: the length of the end code 256 must be larger than 0*/
embeddedartists 0:b567d56a59d7 1893 if(HuffmanTree_getLength(&tree_ll, 256) == 0) ERROR_BREAK(64);
embeddedartists 0:b567d56a59d7 1894
embeddedartists 0:b567d56a59d7 1895 /*write the end code*/
embeddedartists 0:b567d56a59d7 1896 addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, 256), HuffmanTree_getLength(&tree_ll, 256));
embeddedartists 0:b567d56a59d7 1897
embeddedartists 0:b567d56a59d7 1898 break; /*end of error-while*/
embeddedartists 0:b567d56a59d7 1899 }
embeddedartists 0:b567d56a59d7 1900
embeddedartists 0:b567d56a59d7 1901 /*cleanup*/
embeddedartists 0:b567d56a59d7 1902 uivector_cleanup(&lz77_encoded);
embeddedartists 0:b567d56a59d7 1903 HuffmanTree_cleanup(&tree_ll);
embeddedartists 0:b567d56a59d7 1904 HuffmanTree_cleanup(&tree_d);
embeddedartists 0:b567d56a59d7 1905 HuffmanTree_cleanup(&tree_cl);
embeddedartists 0:b567d56a59d7 1906 uivector_cleanup(&frequencies_ll);
embeddedartists 0:b567d56a59d7 1907 uivector_cleanup(&frequencies_d);
embeddedartists 0:b567d56a59d7 1908 uivector_cleanup(&frequencies_cl);
embeddedartists 0:b567d56a59d7 1909 uivector_cleanup(&bitlen_lld_e);
embeddedartists 0:b567d56a59d7 1910 uivector_cleanup(&bitlen_lld);
embeddedartists 0:b567d56a59d7 1911 uivector_cleanup(&bitlen_cl);
embeddedartists 0:b567d56a59d7 1912
embeddedartists 0:b567d56a59d7 1913 return error;
embeddedartists 0:b567d56a59d7 1914 }
embeddedartists 0:b567d56a59d7 1915
embeddedartists 0:b567d56a59d7 1916 static unsigned deflateFixed(ucvector* out, size_t* bp, Hash* hash,
embeddedartists 0:b567d56a59d7 1917 const unsigned char* data,
embeddedartists 0:b567d56a59d7 1918 size_t datapos, size_t dataend,
embeddedartists 0:b567d56a59d7 1919 const LodePNGCompressSettings* settings, int final)
embeddedartists 0:b567d56a59d7 1920 {
embeddedartists 0:b567d56a59d7 1921 HuffmanTree tree_ll; /*tree for literal values and length codes*/
embeddedartists 0:b567d56a59d7 1922 HuffmanTree tree_d; /*tree for distance codes*/
embeddedartists 0:b567d56a59d7 1923
embeddedartists 0:b567d56a59d7 1924 unsigned BFINAL = final;
embeddedartists 0:b567d56a59d7 1925 unsigned error = 0;
embeddedartists 0:b567d56a59d7 1926 size_t i;
embeddedartists 0:b567d56a59d7 1927
embeddedartists 0:b567d56a59d7 1928 HuffmanTree_init(&tree_ll);
embeddedartists 0:b567d56a59d7 1929 HuffmanTree_init(&tree_d);
embeddedartists 0:b567d56a59d7 1930
embeddedartists 0:b567d56a59d7 1931 generateFixedLitLenTree(&tree_ll);
embeddedartists 0:b567d56a59d7 1932 generateFixedDistanceTree(&tree_d);
embeddedartists 0:b567d56a59d7 1933
embeddedartists 0:b567d56a59d7 1934 addBitToStream(bp, out, BFINAL);
embeddedartists 0:b567d56a59d7 1935 addBitToStream(bp, out, 1); /*first bit of BTYPE*/
embeddedartists 0:b567d56a59d7 1936 addBitToStream(bp, out, 0); /*second bit of BTYPE*/
embeddedartists 0:b567d56a59d7 1937
embeddedartists 0:b567d56a59d7 1938 if(settings->use_lz77) /*LZ77 encoded*/
embeddedartists 0:b567d56a59d7 1939 {
embeddedartists 0:b567d56a59d7 1940 uivector lz77_encoded;
embeddedartists 0:b567d56a59d7 1941 uivector_init(&lz77_encoded);
embeddedartists 0:b567d56a59d7 1942 error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize,
embeddedartists 0:b567d56a59d7 1943 settings->minmatch, settings->nicematch, settings->lazymatching);
embeddedartists 0:b567d56a59d7 1944 if(!error) writeLZ77data(bp, out, &lz77_encoded, &tree_ll, &tree_d);
embeddedartists 0:b567d56a59d7 1945 uivector_cleanup(&lz77_encoded);
embeddedartists 0:b567d56a59d7 1946 }
embeddedartists 0:b567d56a59d7 1947 else /*no LZ77, but still will be Huffman compressed*/
embeddedartists 0:b567d56a59d7 1948 {
embeddedartists 0:b567d56a59d7 1949 for(i = datapos; i < dataend; i++)
embeddedartists 0:b567d56a59d7 1950 {
embeddedartists 0:b567d56a59d7 1951 addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, data[i]), HuffmanTree_getLength(&tree_ll, data[i]));
embeddedartists 0:b567d56a59d7 1952 }
embeddedartists 0:b567d56a59d7 1953 }
embeddedartists 0:b567d56a59d7 1954 /*add END code*/
embeddedartists 0:b567d56a59d7 1955 if(!error) addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, 256), HuffmanTree_getLength(&tree_ll, 256));
embeddedartists 0:b567d56a59d7 1956
embeddedartists 0:b567d56a59d7 1957 /*cleanup*/
embeddedartists 0:b567d56a59d7 1958 HuffmanTree_cleanup(&tree_ll);
embeddedartists 0:b567d56a59d7 1959 HuffmanTree_cleanup(&tree_d);
embeddedartists 0:b567d56a59d7 1960
embeddedartists 0:b567d56a59d7 1961 return error;
embeddedartists 0:b567d56a59d7 1962 }
embeddedartists 0:b567d56a59d7 1963
embeddedartists 0:b567d56a59d7 1964 static unsigned lodepng_deflatev(ucvector* out, const unsigned char* in, size_t insize,
embeddedartists 0:b567d56a59d7 1965 const LodePNGCompressSettings* settings)
embeddedartists 0:b567d56a59d7 1966 {
embeddedartists 0:b567d56a59d7 1967 unsigned error = 0;
embeddedartists 0:b567d56a59d7 1968 size_t i, blocksize, numdeflateblocks;
embeddedartists 0:b567d56a59d7 1969 size_t bp = 0; /*the bit pointer*/
embeddedartists 0:b567d56a59d7 1970 Hash hash;
embeddedartists 0:b567d56a59d7 1971
embeddedartists 0:b567d56a59d7 1972 if(settings->btype > 2) return 61;
embeddedartists 0:b567d56a59d7 1973 else if(settings->btype == 0) return deflateNoCompression(out, in, insize);
embeddedartists 0:b567d56a59d7 1974 else if(settings->btype == 1) blocksize = insize;
embeddedartists 0:b567d56a59d7 1975 else /*if(settings->btype == 2)*/
embeddedartists 0:b567d56a59d7 1976 {
embeddedartists 0:b567d56a59d7 1977 blocksize = insize / 8 + 8;
embeddedartists 0:b567d56a59d7 1978 if(blocksize < 65535) blocksize = 65535;
embeddedartists 0:b567d56a59d7 1979 }
embeddedartists 0:b567d56a59d7 1980
embeddedartists 0:b567d56a59d7 1981 numdeflateblocks = (insize + blocksize - 1) / blocksize;
embeddedartists 0:b567d56a59d7 1982 if(numdeflateblocks == 0) numdeflateblocks = 1;
embeddedartists 0:b567d56a59d7 1983
embeddedartists 0:b567d56a59d7 1984 error = hash_init(&hash, settings->windowsize);
embeddedartists 0:b567d56a59d7 1985 if(error) return error;
embeddedartists 0:b567d56a59d7 1986
embeddedartists 0:b567d56a59d7 1987 for(i = 0; i < numdeflateblocks && !error; i++)
embeddedartists 0:b567d56a59d7 1988 {
embeddedartists 0:b567d56a59d7 1989 int final = i == numdeflateblocks - 1;
embeddedartists 0:b567d56a59d7 1990 size_t start = i * blocksize;
embeddedartists 0:b567d56a59d7 1991 size_t end = start + blocksize;
embeddedartists 0:b567d56a59d7 1992 if(end > insize) end = insize;
embeddedartists 0:b567d56a59d7 1993
embeddedartists 0:b567d56a59d7 1994 if(settings->btype == 1) error = deflateFixed(out, &bp, &hash, in, start, end, settings, final);
embeddedartists 0:b567d56a59d7 1995 else if(settings->btype == 2) error = deflateDynamic(out, &bp, &hash, in, start, end, settings, final);
embeddedartists 0:b567d56a59d7 1996 }
embeddedartists 0:b567d56a59d7 1997
embeddedartists 0:b567d56a59d7 1998 hash_cleanup(&hash);
embeddedartists 0:b567d56a59d7 1999
embeddedartists 0:b567d56a59d7 2000 return error;
embeddedartists 0:b567d56a59d7 2001 }
embeddedartists 0:b567d56a59d7 2002
embeddedartists 0:b567d56a59d7 2003 unsigned lodepng_deflate(unsigned char** out, size_t* outsize,
embeddedartists 0:b567d56a59d7 2004 const unsigned char* in, size_t insize,
embeddedartists 0:b567d56a59d7 2005 const LodePNGCompressSettings* settings)
embeddedartists 0:b567d56a59d7 2006 {
embeddedartists 0:b567d56a59d7 2007 unsigned error;
embeddedartists 0:b567d56a59d7 2008 ucvector v;
embeddedartists 0:b567d56a59d7 2009 ucvector_init_buffer(&v, *out, *outsize);
embeddedartists 0:b567d56a59d7 2010 error = lodepng_deflatev(&v, in, insize, settings);
embeddedartists 0:b567d56a59d7 2011 *out = v.data;
embeddedartists 0:b567d56a59d7 2012 *outsize = v.size;
embeddedartists 0:b567d56a59d7 2013 return error;
embeddedartists 0:b567d56a59d7 2014 }
embeddedartists 0:b567d56a59d7 2015
embeddedartists 0:b567d56a59d7 2016 static unsigned deflate(unsigned char** out, size_t* outsize,
embeddedartists 0:b567d56a59d7 2017 const unsigned char* in, size_t insize,
embeddedartists 0:b567d56a59d7 2018 const LodePNGCompressSettings* settings)
embeddedartists 0:b567d56a59d7 2019 {
embeddedartists 0:b567d56a59d7 2020 if(settings->custom_deflate)
embeddedartists 0:b567d56a59d7 2021 {
embeddedartists 0:b567d56a59d7 2022 return settings->custom_deflate(out, outsize, in, insize, settings);
embeddedartists 0:b567d56a59d7 2023 }
embeddedartists 0:b567d56a59d7 2024 else
embeddedartists 0:b567d56a59d7 2025 {
embeddedartists 0:b567d56a59d7 2026 return lodepng_deflate(out, outsize, in, insize, settings);
embeddedartists 0:b567d56a59d7 2027 }
embeddedartists 0:b567d56a59d7 2028 }
embeddedartists 0:b567d56a59d7 2029
embeddedartists 0:b567d56a59d7 2030 #endif /*LODEPNG_COMPILE_DECODER*/
embeddedartists 0:b567d56a59d7 2031
embeddedartists 0:b567d56a59d7 2032 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 2033 /* / Adler32 */
embeddedartists 0:b567d56a59d7 2034 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 2035
embeddedartists 0:b567d56a59d7 2036 static unsigned update_adler32(unsigned adler, const unsigned char* data, unsigned len)
embeddedartists 0:b567d56a59d7 2037 {
embeddedartists 0:b567d56a59d7 2038 unsigned s1 = adler & 0xffff;
embeddedartists 0:b567d56a59d7 2039 unsigned s2 = (adler >> 16) & 0xffff;
embeddedartists 0:b567d56a59d7 2040
embeddedartists 0:b567d56a59d7 2041 while(len > 0)
embeddedartists 0:b567d56a59d7 2042 {
embeddedartists 0:b567d56a59d7 2043 /*at least 5550 sums can be done before the sums overflow, saving a lot of module divisions*/
embeddedartists 0:b567d56a59d7 2044 unsigned amount = len > 5550 ? 5550 : len;
embeddedartists 0:b567d56a59d7 2045 len -= amount;
embeddedartists 0:b567d56a59d7 2046 while(amount > 0)
embeddedartists 0:b567d56a59d7 2047 {
embeddedartists 0:b567d56a59d7 2048 s1 += (*data++);
embeddedartists 0:b567d56a59d7 2049 s2 += s1;
embeddedartists 0:b567d56a59d7 2050 amount--;
embeddedartists 0:b567d56a59d7 2051 }
embeddedartists 0:b567d56a59d7 2052 s1 %= 65521;
embeddedartists 0:b567d56a59d7 2053 s2 %= 65521;
embeddedartists 0:b567d56a59d7 2054 }
embeddedartists 0:b567d56a59d7 2055
embeddedartists 0:b567d56a59d7 2056 return (s2 << 16) | s1;
embeddedartists 0:b567d56a59d7 2057 }
embeddedartists 0:b567d56a59d7 2058
embeddedartists 0:b567d56a59d7 2059 /*Return the adler32 of the bytes data[0..len-1]*/
embeddedartists 0:b567d56a59d7 2060 static unsigned adler32(const unsigned char* data, unsigned len)
embeddedartists 0:b567d56a59d7 2061 {
embeddedartists 0:b567d56a59d7 2062 return update_adler32(1L, data, len);
embeddedartists 0:b567d56a59d7 2063 }
embeddedartists 0:b567d56a59d7 2064
embeddedartists 0:b567d56a59d7 2065 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 2066 /* / Zlib / */
embeddedartists 0:b567d56a59d7 2067 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 2068
embeddedartists 0:b567d56a59d7 2069 #ifdef LODEPNG_COMPILE_DECODER
embeddedartists 0:b567d56a59d7 2070
embeddedartists 0:b567d56a59d7 2071 unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in,
embeddedartists 0:b567d56a59d7 2072 size_t insize, const LodePNGDecompressSettings* settings)
embeddedartists 0:b567d56a59d7 2073 {
embeddedartists 0:b567d56a59d7 2074 unsigned error = 0;
embeddedartists 0:b567d56a59d7 2075 unsigned CM, CINFO, FDICT;
embeddedartists 0:b567d56a59d7 2076
embeddedartists 0:b567d56a59d7 2077 if(insize < 2) return 53; /*error, size of zlib data too small*/
embeddedartists 0:b567d56a59d7 2078 /*read information from zlib header*/
embeddedartists 0:b567d56a59d7 2079 if((in[0] * 256 + in[1]) % 31 != 0)
embeddedartists 0:b567d56a59d7 2080 {
embeddedartists 0:b567d56a59d7 2081 /*error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way*/
embeddedartists 0:b567d56a59d7 2082 return 24;
embeddedartists 0:b567d56a59d7 2083 }
embeddedartists 0:b567d56a59d7 2084
embeddedartists 0:b567d56a59d7 2085 CM = in[0] & 15;
embeddedartists 0:b567d56a59d7 2086 CINFO = (in[0] >> 4) & 15;
embeddedartists 0:b567d56a59d7 2087 /*FCHECK = in[1] & 31;*/ /*FCHECK is already tested above*/
embeddedartists 0:b567d56a59d7 2088 FDICT = (in[1] >> 5) & 1;
embeddedartists 0:b567d56a59d7 2089 /*FLEVEL = (in[1] >> 6) & 3;*/ /*FLEVEL is not used here*/
embeddedartists 0:b567d56a59d7 2090
embeddedartists 0:b567d56a59d7 2091 if(CM != 8 || CINFO > 7)
embeddedartists 0:b567d56a59d7 2092 {
embeddedartists 0:b567d56a59d7 2093 /*error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec*/
embeddedartists 0:b567d56a59d7 2094 return 25;
embeddedartists 0:b567d56a59d7 2095 }
embeddedartists 0:b567d56a59d7 2096 if(FDICT != 0)
embeddedartists 0:b567d56a59d7 2097 {
embeddedartists 0:b567d56a59d7 2098 /*error: the specification of PNG says about the zlib stream:
embeddedartists 0:b567d56a59d7 2099 "The additional flags shall not specify a preset dictionary."*/
embeddedartists 0:b567d56a59d7 2100 return 26;
embeddedartists 0:b567d56a59d7 2101 }
embeddedartists 0:b567d56a59d7 2102
embeddedartists 0:b567d56a59d7 2103 error = inflate(out, outsize, in + 2, insize - 2, settings);
embeddedartists 0:b567d56a59d7 2104 if(error) return error;
embeddedartists 0:b567d56a59d7 2105
embeddedartists 0:b567d56a59d7 2106 if(!settings->ignore_adler32)
embeddedartists 0:b567d56a59d7 2107 {
embeddedartists 0:b567d56a59d7 2108 unsigned ADLER32 = lodepng_read32bitInt(&in[insize - 4]);
embeddedartists 0:b567d56a59d7 2109 unsigned checksum = adler32(*out, (unsigned)(*outsize));
embeddedartists 0:b567d56a59d7 2110 if(checksum != ADLER32) return 58; /*error, adler checksum not correct, data must be corrupted*/
embeddedartists 0:b567d56a59d7 2111 }
embeddedartists 0:b567d56a59d7 2112
embeddedartists 0:b567d56a59d7 2113 return 0; /*no error*/
embeddedartists 0:b567d56a59d7 2114 }
embeddedartists 0:b567d56a59d7 2115
embeddedartists 0:b567d56a59d7 2116 static unsigned zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in,
embeddedartists 0:b567d56a59d7 2117 size_t insize, const LodePNGDecompressSettings* settings)
embeddedartists 0:b567d56a59d7 2118 {
embeddedartists 0:b567d56a59d7 2119 if(settings->custom_zlib)
embeddedartists 0:b567d56a59d7 2120 {
embeddedartists 0:b567d56a59d7 2121 return settings->custom_zlib(out, outsize, in, insize, settings);
embeddedartists 0:b567d56a59d7 2122 }
embeddedartists 0:b567d56a59d7 2123 else
embeddedartists 0:b567d56a59d7 2124 {
embeddedartists 0:b567d56a59d7 2125 return lodepng_zlib_decompress(out, outsize, in, insize, settings);
embeddedartists 0:b567d56a59d7 2126 }
embeddedartists 0:b567d56a59d7 2127 }
embeddedartists 0:b567d56a59d7 2128
embeddedartists 0:b567d56a59d7 2129 #endif /*LODEPNG_COMPILE_DECODER*/
embeddedartists 0:b567d56a59d7 2130
embeddedartists 0:b567d56a59d7 2131 #ifdef LODEPNG_COMPILE_ENCODER
embeddedartists 0:b567d56a59d7 2132
embeddedartists 0:b567d56a59d7 2133 unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in,
embeddedartists 0:b567d56a59d7 2134 size_t insize, const LodePNGCompressSettings* settings)
embeddedartists 0:b567d56a59d7 2135 {
embeddedartists 0:b567d56a59d7 2136 /*initially, *out must be NULL and outsize 0, if you just give some random *out
embeddedartists 0:b567d56a59d7 2137 that's pointing to a non allocated buffer, this'll crash*/
embeddedartists 0:b567d56a59d7 2138 ucvector outv;
embeddedartists 0:b567d56a59d7 2139 size_t i;
embeddedartists 0:b567d56a59d7 2140 unsigned error;
embeddedartists 0:b567d56a59d7 2141 unsigned char* deflatedata = 0;
embeddedartists 0:b567d56a59d7 2142 size_t deflatesize = 0;
embeddedartists 0:b567d56a59d7 2143
embeddedartists 0:b567d56a59d7 2144 unsigned ADLER32;
embeddedartists 0:b567d56a59d7 2145 /*zlib data: 1 byte CMF (CM+CINFO), 1 byte FLG, deflate data, 4 byte ADLER32 checksum of the Decompressed data*/
embeddedartists 0:b567d56a59d7 2146 unsigned CMF = 120; /*0b01111000: CM 8, CINFO 7. With CINFO 7, any window size up to 32768 can be used.*/
embeddedartists 0:b567d56a59d7 2147 unsigned FLEVEL = 0;
embeddedartists 0:b567d56a59d7 2148 unsigned FDICT = 0;
embeddedartists 0:b567d56a59d7 2149 unsigned CMFFLG = 256 * CMF + FDICT * 32 + FLEVEL * 64;
embeddedartists 0:b567d56a59d7 2150 unsigned FCHECK = 31 - CMFFLG % 31;
embeddedartists 0:b567d56a59d7 2151 CMFFLG += FCHECK;
embeddedartists 0:b567d56a59d7 2152
embeddedartists 0:b567d56a59d7 2153 /*ucvector-controlled version of the output buffer, for dynamic array*/
embeddedartists 0:b567d56a59d7 2154 ucvector_init_buffer(&outv, *out, *outsize);
embeddedartists 0:b567d56a59d7 2155
embeddedartists 0:b567d56a59d7 2156 ucvector_push_back(&outv, (unsigned char)(CMFFLG / 256));
embeddedartists 0:b567d56a59d7 2157 ucvector_push_back(&outv, (unsigned char)(CMFFLG % 256));
embeddedartists 0:b567d56a59d7 2158
embeddedartists 0:b567d56a59d7 2159 error = deflate(&deflatedata, &deflatesize, in, insize, settings);
embeddedartists 0:b567d56a59d7 2160
embeddedartists 0:b567d56a59d7 2161 if(!error)
embeddedartists 0:b567d56a59d7 2162 {
embeddedartists 0:b567d56a59d7 2163 ADLER32 = adler32(in, (unsigned)insize);
embeddedartists 0:b567d56a59d7 2164 for(i = 0; i < deflatesize; i++) ucvector_push_back(&outv, deflatedata[i]);
embeddedartists 0:b567d56a59d7 2165 lodepng_free(deflatedata);
embeddedartists 0:b567d56a59d7 2166 lodepng_add32bitInt(&outv, ADLER32);
embeddedartists 0:b567d56a59d7 2167 }
embeddedartists 0:b567d56a59d7 2168
embeddedartists 0:b567d56a59d7 2169 *out = outv.data;
embeddedartists 0:b567d56a59d7 2170 *outsize = outv.size;
embeddedartists 0:b567d56a59d7 2171
embeddedartists 0:b567d56a59d7 2172 return error;
embeddedartists 0:b567d56a59d7 2173 }
embeddedartists 0:b567d56a59d7 2174
embeddedartists 0:b567d56a59d7 2175 /* compress using the default or custom zlib function */
embeddedartists 0:b567d56a59d7 2176 static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in,
embeddedartists 0:b567d56a59d7 2177 size_t insize, const LodePNGCompressSettings* settings)
embeddedartists 0:b567d56a59d7 2178 {
embeddedartists 0:b567d56a59d7 2179 if(settings->custom_zlib)
embeddedartists 0:b567d56a59d7 2180 {
embeddedartists 0:b567d56a59d7 2181 return settings->custom_zlib(out, outsize, in, insize, settings);
embeddedartists 0:b567d56a59d7 2182 }
embeddedartists 0:b567d56a59d7 2183 else
embeddedartists 0:b567d56a59d7 2184 {
embeddedartists 0:b567d56a59d7 2185 return lodepng_zlib_compress(out, outsize, in, insize, settings);
embeddedartists 0:b567d56a59d7 2186 }
embeddedartists 0:b567d56a59d7 2187 }
embeddedartists 0:b567d56a59d7 2188
embeddedartists 0:b567d56a59d7 2189 #endif /*LODEPNG_COMPILE_ENCODER*/
embeddedartists 0:b567d56a59d7 2190
embeddedartists 0:b567d56a59d7 2191 #else /*no LODEPNG_COMPILE_ZLIB*/
embeddedartists 0:b567d56a59d7 2192
embeddedartists 0:b567d56a59d7 2193 #ifdef LODEPNG_COMPILE_DECODER
embeddedartists 0:b567d56a59d7 2194 static unsigned zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in,
embeddedartists 0:b567d56a59d7 2195 size_t insize, const LodePNGDecompressSettings* settings)
embeddedartists 0:b567d56a59d7 2196 {
embeddedartists 0:b567d56a59d7 2197 if (!settings->custom_zlib) return 87; /*no custom zlib function provided */
embeddedartists 0:b567d56a59d7 2198 return settings->custom_zlib(out, outsize, in, insize, settings);
embeddedartists 0:b567d56a59d7 2199 }
embeddedartists 0:b567d56a59d7 2200 #endif /*LODEPNG_COMPILE_DECODER*/
embeddedartists 0:b567d56a59d7 2201 #ifdef LODEPNG_COMPILE_ENCODER
embeddedartists 0:b567d56a59d7 2202 static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in,
embeddedartists 0:b567d56a59d7 2203 size_t insize, const LodePNGCompressSettings* settings)
embeddedartists 0:b567d56a59d7 2204 {
embeddedartists 0:b567d56a59d7 2205 if (!settings->custom_zlib) return 87; /*no custom zlib function provided */
embeddedartists 0:b567d56a59d7 2206 return settings->custom_zlib(out, outsize, in, insize, settings);
embeddedartists 0:b567d56a59d7 2207 }
embeddedartists 0:b567d56a59d7 2208 #endif /*LODEPNG_COMPILE_ENCODER*/
embeddedartists 0:b567d56a59d7 2209
embeddedartists 0:b567d56a59d7 2210 #endif /*LODEPNG_COMPILE_ZLIB*/
embeddedartists 0:b567d56a59d7 2211
embeddedartists 0:b567d56a59d7 2212 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 2213
embeddedartists 0:b567d56a59d7 2214 #ifdef LODEPNG_COMPILE_ENCODER
embeddedartists 0:b567d56a59d7 2215
embeddedartists 0:b567d56a59d7 2216 /*this is a good tradeoff between speed and compression ratio*/
embeddedartists 0:b567d56a59d7 2217 #define DEFAULT_WINDOWSIZE 2048
embeddedartists 0:b567d56a59d7 2218
embeddedartists 0:b567d56a59d7 2219 void lodepng_compress_settings_init(LodePNGCompressSettings* settings)
embeddedartists 0:b567d56a59d7 2220 {
embeddedartists 0:b567d56a59d7 2221 /*compress with dynamic huffman tree (not in the mathematical sense, just not the predefined one)*/
embeddedartists 0:b567d56a59d7 2222 settings->btype = 2;
embeddedartists 0:b567d56a59d7 2223 settings->use_lz77 = 1;
embeddedartists 0:b567d56a59d7 2224 settings->windowsize = DEFAULT_WINDOWSIZE;
embeddedartists 0:b567d56a59d7 2225 settings->minmatch = 3;
embeddedartists 0:b567d56a59d7 2226 settings->nicematch = 128;
embeddedartists 0:b567d56a59d7 2227 settings->lazymatching = 1;
embeddedartists 0:b567d56a59d7 2228
embeddedartists 0:b567d56a59d7 2229 settings->custom_zlib = 0;
embeddedartists 0:b567d56a59d7 2230 settings->custom_deflate = 0;
embeddedartists 0:b567d56a59d7 2231 settings->custom_context = 0;
embeddedartists 0:b567d56a59d7 2232 }
embeddedartists 0:b567d56a59d7 2233
embeddedartists 0:b567d56a59d7 2234 const LodePNGCompressSettings lodepng_default_compress_settings = {2, 1, DEFAULT_WINDOWSIZE, 3, 128, 1, 0, 0, 0};
embeddedartists 0:b567d56a59d7 2235
embeddedartists 0:b567d56a59d7 2236
embeddedartists 0:b567d56a59d7 2237 #endif /*LODEPNG_COMPILE_ENCODER*/
embeddedartists 0:b567d56a59d7 2238
embeddedartists 0:b567d56a59d7 2239 #ifdef LODEPNG_COMPILE_DECODER
embeddedartists 0:b567d56a59d7 2240
embeddedartists 0:b567d56a59d7 2241 void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings)
embeddedartists 0:b567d56a59d7 2242 {
embeddedartists 0:b567d56a59d7 2243 settings->ignore_adler32 = 0;
embeddedartists 0:b567d56a59d7 2244
embeddedartists 0:b567d56a59d7 2245 settings->custom_zlib = 0;
embeddedartists 0:b567d56a59d7 2246 settings->custom_inflate = 0;
embeddedartists 0:b567d56a59d7 2247 settings->custom_context = 0;
embeddedartists 0:b567d56a59d7 2248 }
embeddedartists 0:b567d56a59d7 2249
embeddedartists 0:b567d56a59d7 2250 const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0, 0, 0};
embeddedartists 0:b567d56a59d7 2251
embeddedartists 0:b567d56a59d7 2252 #endif /*LODEPNG_COMPILE_DECODER*/
embeddedartists 0:b567d56a59d7 2253
embeddedartists 0:b567d56a59d7 2254 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 2255 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 2256 /* // End of Zlib related code. Begin of PNG related code. // */
embeddedartists 0:b567d56a59d7 2257 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 2258 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 2259
embeddedartists 0:b567d56a59d7 2260 #ifdef LODEPNG_COMPILE_PNG
embeddedartists 0:b567d56a59d7 2261
embeddedartists 0:b567d56a59d7 2262 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 2263 /* / CRC32 / */
embeddedartists 0:b567d56a59d7 2264 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 2265
embeddedartists 0:b567d56a59d7 2266 /* CRC polynomial: 0xedb88320 */
embeddedartists 0:b567d56a59d7 2267 static unsigned lodepng_crc32_table[256] = {
embeddedartists 0:b567d56a59d7 2268 0u, 1996959894u, 3993919788u, 2567524794u, 124634137u, 1886057615u, 3915621685u, 2657392035u,
embeddedartists 0:b567d56a59d7 2269 249268274u, 2044508324u, 3772115230u, 2547177864u, 162941995u, 2125561021u, 3887607047u, 2428444049u,
embeddedartists 0:b567d56a59d7 2270 498536548u, 1789927666u, 4089016648u, 2227061214u, 450548861u, 1843258603u, 4107580753u, 2211677639u,
embeddedartists 0:b567d56a59d7 2271 325883990u, 1684777152u, 4251122042u, 2321926636u, 335633487u, 1661365465u, 4195302755u, 2366115317u,
embeddedartists 0:b567d56a59d7 2272 997073096u, 1281953886u, 3579855332u, 2724688242u, 1006888145u, 1258607687u, 3524101629u, 2768942443u,
embeddedartists 0:b567d56a59d7 2273 901097722u, 1119000684u, 3686517206u, 2898065728u, 853044451u, 1172266101u, 3705015759u, 2882616665u,
embeddedartists 0:b567d56a59d7 2274 651767980u, 1373503546u, 3369554304u, 3218104598u, 565507253u, 1454621731u, 3485111705u, 3099436303u,
embeddedartists 0:b567d56a59d7 2275 671266974u, 1594198024u, 3322730930u, 2970347812u, 795835527u, 1483230225u, 3244367275u, 3060149565u,
embeddedartists 0:b567d56a59d7 2276 1994146192u, 31158534u, 2563907772u, 4023717930u, 1907459465u, 112637215u, 2680153253u, 3904427059u,
embeddedartists 0:b567d56a59d7 2277 2013776290u, 251722036u, 2517215374u, 3775830040u, 2137656763u, 141376813u, 2439277719u, 3865271297u,
embeddedartists 0:b567d56a59d7 2278 1802195444u, 476864866u, 2238001368u, 4066508878u, 1812370925u, 453092731u, 2181625025u, 4111451223u,
embeddedartists 0:b567d56a59d7 2279 1706088902u, 314042704u, 2344532202u, 4240017532u, 1658658271u, 366619977u, 2362670323u, 4224994405u,
embeddedartists 0:b567d56a59d7 2280 1303535960u, 984961486u, 2747007092u, 3569037538u, 1256170817u, 1037604311u, 2765210733u, 3554079995u,
embeddedartists 0:b567d56a59d7 2281 1131014506u, 879679996u, 2909243462u, 3663771856u, 1141124467u, 855842277u, 2852801631u, 3708648649u,
embeddedartists 0:b567d56a59d7 2282 1342533948u, 654459306u, 3188396048u, 3373015174u, 1466479909u, 544179635u, 3110523913u, 3462522015u,
embeddedartists 0:b567d56a59d7 2283 1591671054u, 702138776u, 2966460450u, 3352799412u, 1504918807u, 783551873u, 3082640443u, 3233442989u,
embeddedartists 0:b567d56a59d7 2284 3988292384u, 2596254646u, 62317068u, 1957810842u, 3939845945u, 2647816111u, 81470997u, 1943803523u,
embeddedartists 0:b567d56a59d7 2285 3814918930u, 2489596804u, 225274430u, 2053790376u, 3826175755u, 2466906013u, 167816743u, 2097651377u,
embeddedartists 0:b567d56a59d7 2286 4027552580u, 2265490386u, 503444072u, 1762050814u, 4150417245u, 2154129355u, 426522225u, 1852507879u,
embeddedartists 0:b567d56a59d7 2287 4275313526u, 2312317920u, 282753626u, 1742555852u, 4189708143u, 2394877945u, 397917763u, 1622183637u,
embeddedartists 0:b567d56a59d7 2288 3604390888u, 2714866558u, 953729732u, 1340076626u, 3518719985u, 2797360999u, 1068828381u, 1219638859u,
embeddedartists 0:b567d56a59d7 2289 3624741850u, 2936675148u, 906185462u, 1090812512u, 3747672003u, 2825379669u, 829329135u, 1181335161u,
embeddedartists 0:b567d56a59d7 2290 3412177804u, 3160834842u, 628085408u, 1382605366u, 3423369109u, 3138078467u, 570562233u, 1426400815u,
embeddedartists 0:b567d56a59d7 2291 3317316542u, 2998733608u, 733239954u, 1555261956u, 3268935591u, 3050360625u, 752459403u, 1541320221u,
embeddedartists 0:b567d56a59d7 2292 2607071920u, 3965973030u, 1969922972u, 40735498u, 2617837225u, 3943577151u, 1913087877u, 83908371u,
embeddedartists 0:b567d56a59d7 2293 2512341634u, 3803740692u, 2075208622u, 213261112u, 2463272603u, 3855990285u, 2094854071u, 198958881u,
embeddedartists 0:b567d56a59d7 2294 2262029012u, 4057260610u, 1759359992u, 534414190u, 2176718541u, 4139329115u, 1873836001u, 414664567u,
embeddedartists 0:b567d56a59d7 2295 2282248934u, 4279200368u, 1711684554u, 285281116u, 2405801727u, 4167216745u, 1634467795u, 376229701u,
embeddedartists 0:b567d56a59d7 2296 2685067896u, 3608007406u, 1308918612u, 956543938u, 2808555105u, 3495958263u, 1231636301u, 1047427035u,
embeddedartists 0:b567d56a59d7 2297 2932959818u, 3654703836u, 1088359270u, 936918000u, 2847714899u, 3736837829u, 1202900863u, 817233897u,
embeddedartists 0:b567d56a59d7 2298 3183342108u, 3401237130u, 1404277552u, 615818150u, 3134207493u, 3453421203u, 1423857449u, 601450431u,
embeddedartists 0:b567d56a59d7 2299 3009837614u, 3294710456u, 1567103746u, 711928724u, 3020668471u, 3272380065u, 1510334235u, 755167117u
embeddedartists 0:b567d56a59d7 2300 };
embeddedartists 0:b567d56a59d7 2301
embeddedartists 0:b567d56a59d7 2302 /*Return the CRC of the bytes buf[0..len-1].*/
embeddedartists 0:b567d56a59d7 2303 unsigned lodepng_crc32(const unsigned char* buf, size_t len)
embeddedartists 0:b567d56a59d7 2304 {
embeddedartists 0:b567d56a59d7 2305 unsigned c = 0xffffffffL;
embeddedartists 0:b567d56a59d7 2306 size_t n;
embeddedartists 0:b567d56a59d7 2307
embeddedartists 0:b567d56a59d7 2308 for(n = 0; n < len; n++)
embeddedartists 0:b567d56a59d7 2309 {
embeddedartists 0:b567d56a59d7 2310 c = lodepng_crc32_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
embeddedartists 0:b567d56a59d7 2311 }
embeddedartists 0:b567d56a59d7 2312 return c ^ 0xffffffffL;
embeddedartists 0:b567d56a59d7 2313 }
embeddedartists 0:b567d56a59d7 2314
embeddedartists 0:b567d56a59d7 2315 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 2316 /* / Reading and writing single bits and bytes from/to stream for LodePNG / */
embeddedartists 0:b567d56a59d7 2317 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 2318
embeddedartists 0:b567d56a59d7 2319 static unsigned char readBitFromReversedStream(size_t* bitpointer, const unsigned char* bitstream)
embeddedartists 0:b567d56a59d7 2320 {
embeddedartists 0:b567d56a59d7 2321 unsigned char result = (unsigned char)((bitstream[(*bitpointer) >> 3] >> (7 - ((*bitpointer) & 0x7))) & 1);
embeddedartists 0:b567d56a59d7 2322 (*bitpointer)++;
embeddedartists 0:b567d56a59d7 2323 return result;
embeddedartists 0:b567d56a59d7 2324 }
embeddedartists 0:b567d56a59d7 2325
embeddedartists 0:b567d56a59d7 2326 static unsigned readBitsFromReversedStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits)
embeddedartists 0:b567d56a59d7 2327 {
embeddedartists 0:b567d56a59d7 2328 unsigned result = 0;
embeddedartists 0:b567d56a59d7 2329 size_t i;
embeddedartists 0:b567d56a59d7 2330 for(i = nbits - 1; i < nbits; i--)
embeddedartists 0:b567d56a59d7 2331 {
embeddedartists 0:b567d56a59d7 2332 result += (unsigned)readBitFromReversedStream(bitpointer, bitstream) << i;
embeddedartists 0:b567d56a59d7 2333 }
embeddedartists 0:b567d56a59d7 2334 return result;
embeddedartists 0:b567d56a59d7 2335 }
embeddedartists 0:b567d56a59d7 2336
embeddedartists 0:b567d56a59d7 2337 #ifdef LODEPNG_COMPILE_DECODER
embeddedartists 0:b567d56a59d7 2338 static void setBitOfReversedStream0(size_t* bitpointer, unsigned char* bitstream, unsigned char bit)
embeddedartists 0:b567d56a59d7 2339 {
embeddedartists 0:b567d56a59d7 2340 /*the current bit in bitstream must be 0 for this to work*/
embeddedartists 0:b567d56a59d7 2341 if(bit)
embeddedartists 0:b567d56a59d7 2342 {
embeddedartists 0:b567d56a59d7 2343 /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/
embeddedartists 0:b567d56a59d7 2344 bitstream[(*bitpointer) >> 3] |= (bit << (7 - ((*bitpointer) & 0x7)));
embeddedartists 0:b567d56a59d7 2345 }
embeddedartists 0:b567d56a59d7 2346 (*bitpointer)++;
embeddedartists 0:b567d56a59d7 2347 }
embeddedartists 0:b567d56a59d7 2348 #endif /*LODEPNG_COMPILE_DECODER*/
embeddedartists 0:b567d56a59d7 2349
embeddedartists 0:b567d56a59d7 2350 static void setBitOfReversedStream(size_t* bitpointer, unsigned char* bitstream, unsigned char bit)
embeddedartists 0:b567d56a59d7 2351 {
embeddedartists 0:b567d56a59d7 2352 /*the current bit in bitstream may be 0 or 1 for this to work*/
embeddedartists 0:b567d56a59d7 2353 if(bit == 0) bitstream[(*bitpointer) >> 3] &= (unsigned char)(~(1 << (7 - ((*bitpointer) & 0x7))));
embeddedartists 0:b567d56a59d7 2354 else bitstream[(*bitpointer) >> 3] |= (1 << (7 - ((*bitpointer) & 0x7)));
embeddedartists 0:b567d56a59d7 2355 (*bitpointer)++;
embeddedartists 0:b567d56a59d7 2356 }
embeddedartists 0:b567d56a59d7 2357
embeddedartists 0:b567d56a59d7 2358 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 2359 /* / PNG chunks / */
embeddedartists 0:b567d56a59d7 2360 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 2361
embeddedartists 0:b567d56a59d7 2362 unsigned lodepng_chunk_length(const unsigned char* chunk)
embeddedartists 0:b567d56a59d7 2363 {
embeddedartists 0:b567d56a59d7 2364 return lodepng_read32bitInt(&chunk[0]);
embeddedartists 0:b567d56a59d7 2365 }
embeddedartists 0:b567d56a59d7 2366
embeddedartists 0:b567d56a59d7 2367 void lodepng_chunk_type(char type[5], const unsigned char* chunk)
embeddedartists 0:b567d56a59d7 2368 {
embeddedartists 0:b567d56a59d7 2369 unsigned i;
embeddedartists 0:b567d56a59d7 2370 for(i = 0; i < 4; i++) type[i] = chunk[4 + i];
embeddedartists 0:b567d56a59d7 2371 type[4] = 0; /*null termination char*/
embeddedartists 0:b567d56a59d7 2372 }
embeddedartists 0:b567d56a59d7 2373
embeddedartists 0:b567d56a59d7 2374 unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type)
embeddedartists 0:b567d56a59d7 2375 {
embeddedartists 0:b567d56a59d7 2376 if(strlen(type) != 4) return 0;
embeddedartists 0:b567d56a59d7 2377 return (chunk[4] == type[0] && chunk[5] == type[1] && chunk[6] == type[2] && chunk[7] == type[3]);
embeddedartists 0:b567d56a59d7 2378 }
embeddedartists 0:b567d56a59d7 2379
embeddedartists 0:b567d56a59d7 2380 unsigned char lodepng_chunk_ancillary(const unsigned char* chunk)
embeddedartists 0:b567d56a59d7 2381 {
embeddedartists 0:b567d56a59d7 2382 return((chunk[4] & 32) != 0);
embeddedartists 0:b567d56a59d7 2383 }
embeddedartists 0:b567d56a59d7 2384
embeddedartists 0:b567d56a59d7 2385 unsigned char lodepng_chunk_private(const unsigned char* chunk)
embeddedartists 0:b567d56a59d7 2386 {
embeddedartists 0:b567d56a59d7 2387 return((chunk[6] & 32) != 0);
embeddedartists 0:b567d56a59d7 2388 }
embeddedartists 0:b567d56a59d7 2389
embeddedartists 0:b567d56a59d7 2390 unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk)
embeddedartists 0:b567d56a59d7 2391 {
embeddedartists 0:b567d56a59d7 2392 return((chunk[7] & 32) != 0);
embeddedartists 0:b567d56a59d7 2393 }
embeddedartists 0:b567d56a59d7 2394
embeddedartists 0:b567d56a59d7 2395 unsigned char* lodepng_chunk_data(unsigned char* chunk)
embeddedartists 0:b567d56a59d7 2396 {
embeddedartists 0:b567d56a59d7 2397 return &chunk[8];
embeddedartists 0:b567d56a59d7 2398 }
embeddedartists 0:b567d56a59d7 2399
embeddedartists 0:b567d56a59d7 2400 const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk)
embeddedartists 0:b567d56a59d7 2401 {
embeddedartists 0:b567d56a59d7 2402 return &chunk[8];
embeddedartists 0:b567d56a59d7 2403 }
embeddedartists 0:b567d56a59d7 2404
embeddedartists 0:b567d56a59d7 2405 unsigned lodepng_chunk_check_crc(const unsigned char* chunk)
embeddedartists 0:b567d56a59d7 2406 {
embeddedartists 0:b567d56a59d7 2407 unsigned length = lodepng_chunk_length(chunk);
embeddedartists 0:b567d56a59d7 2408 unsigned CRC = lodepng_read32bitInt(&chunk[length + 8]);
embeddedartists 0:b567d56a59d7 2409 /*the CRC is taken of the data and the 4 chunk type letters, not the length*/
embeddedartists 0:b567d56a59d7 2410 unsigned checksum = lodepng_crc32(&chunk[4], length + 4);
embeddedartists 0:b567d56a59d7 2411 if(CRC != checksum) return 1;
embeddedartists 0:b567d56a59d7 2412 else return 0;
embeddedartists 0:b567d56a59d7 2413 }
embeddedartists 0:b567d56a59d7 2414
embeddedartists 0:b567d56a59d7 2415 void lodepng_chunk_generate_crc(unsigned char* chunk)
embeddedartists 0:b567d56a59d7 2416 {
embeddedartists 0:b567d56a59d7 2417 unsigned length = lodepng_chunk_length(chunk);
embeddedartists 0:b567d56a59d7 2418 unsigned CRC = lodepng_crc32(&chunk[4], length + 4);
embeddedartists 0:b567d56a59d7 2419 lodepng_set32bitInt(chunk + 8 + length, CRC);
embeddedartists 0:b567d56a59d7 2420 }
embeddedartists 0:b567d56a59d7 2421
embeddedartists 0:b567d56a59d7 2422 unsigned char* lodepng_chunk_next(unsigned char* chunk)
embeddedartists 0:b567d56a59d7 2423 {
embeddedartists 0:b567d56a59d7 2424 unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12;
embeddedartists 0:b567d56a59d7 2425 return &chunk[total_chunk_length];
embeddedartists 0:b567d56a59d7 2426 }
embeddedartists 0:b567d56a59d7 2427
embeddedartists 0:b567d56a59d7 2428 const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk)
embeddedartists 0:b567d56a59d7 2429 {
embeddedartists 0:b567d56a59d7 2430 unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12;
embeddedartists 0:b567d56a59d7 2431 return &chunk[total_chunk_length];
embeddedartists 0:b567d56a59d7 2432 }
embeddedartists 0:b567d56a59d7 2433
embeddedartists 0:b567d56a59d7 2434 unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk)
embeddedartists 0:b567d56a59d7 2435 {
embeddedartists 0:b567d56a59d7 2436 unsigned i;
embeddedartists 0:b567d56a59d7 2437 unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12;
embeddedartists 0:b567d56a59d7 2438 unsigned char *chunk_start, *new_buffer;
embeddedartists 0:b567d56a59d7 2439 size_t new_length = (*outlength) + total_chunk_length;
embeddedartists 0:b567d56a59d7 2440 if(new_length < total_chunk_length || new_length < (*outlength)) return 77; /*integer overflow happened*/
embeddedartists 0:b567d56a59d7 2441
embeddedartists 0:b567d56a59d7 2442 new_buffer = (unsigned char*)lodepng_realloc(*out, new_length);
embeddedartists 0:b567d56a59d7 2443 if(!new_buffer) return 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 2444 (*out) = new_buffer;
embeddedartists 0:b567d56a59d7 2445 (*outlength) = new_length;
embeddedartists 0:b567d56a59d7 2446 chunk_start = &(*out)[new_length - total_chunk_length];
embeddedartists 0:b567d56a59d7 2447
embeddedartists 0:b567d56a59d7 2448 for(i = 0; i < total_chunk_length; i++) chunk_start[i] = chunk[i];
embeddedartists 0:b567d56a59d7 2449
embeddedartists 0:b567d56a59d7 2450 return 0;
embeddedartists 0:b567d56a59d7 2451 }
embeddedartists 0:b567d56a59d7 2452
embeddedartists 0:b567d56a59d7 2453 unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length,
embeddedartists 0:b567d56a59d7 2454 const char* type, const unsigned char* data)
embeddedartists 0:b567d56a59d7 2455 {
embeddedartists 0:b567d56a59d7 2456 unsigned i;
embeddedartists 0:b567d56a59d7 2457 unsigned char *chunk, *new_buffer;
embeddedartists 0:b567d56a59d7 2458 size_t new_length = (*outlength) + length + 12;
embeddedartists 0:b567d56a59d7 2459 if(new_length < length + 12 || new_length < (*outlength)) return 77; /*integer overflow happened*/
embeddedartists 0:b567d56a59d7 2460 new_buffer = (unsigned char*)lodepng_realloc(*out, new_length);
embeddedartists 0:b567d56a59d7 2461 if(!new_buffer) return 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 2462 (*out) = new_buffer;
embeddedartists 0:b567d56a59d7 2463 (*outlength) = new_length;
embeddedartists 0:b567d56a59d7 2464 chunk = &(*out)[(*outlength) - length - 12];
embeddedartists 0:b567d56a59d7 2465
embeddedartists 0:b567d56a59d7 2466 /*1: length*/
embeddedartists 0:b567d56a59d7 2467 lodepng_set32bitInt(chunk, (unsigned)length);
embeddedartists 0:b567d56a59d7 2468
embeddedartists 0:b567d56a59d7 2469 /*2: chunk name (4 letters)*/
embeddedartists 0:b567d56a59d7 2470 chunk[4] = type[0];
embeddedartists 0:b567d56a59d7 2471 chunk[5] = type[1];
embeddedartists 0:b567d56a59d7 2472 chunk[6] = type[2];
embeddedartists 0:b567d56a59d7 2473 chunk[7] = type[3];
embeddedartists 0:b567d56a59d7 2474
embeddedartists 0:b567d56a59d7 2475 /*3: the data*/
embeddedartists 0:b567d56a59d7 2476 for(i = 0; i < length; i++) chunk[8 + i] = data[i];
embeddedartists 0:b567d56a59d7 2477
embeddedartists 0:b567d56a59d7 2478 /*4: CRC (of the chunkname characters and the data)*/
embeddedartists 0:b567d56a59d7 2479 lodepng_chunk_generate_crc(chunk);
embeddedartists 0:b567d56a59d7 2480
embeddedartists 0:b567d56a59d7 2481 return 0;
embeddedartists 0:b567d56a59d7 2482 }
embeddedartists 0:b567d56a59d7 2483
embeddedartists 0:b567d56a59d7 2484 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 2485 /* / Color types and such / */
embeddedartists 0:b567d56a59d7 2486 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 2487
embeddedartists 0:b567d56a59d7 2488 /*return type is a LodePNG error code*/
embeddedartists 0:b567d56a59d7 2489 static unsigned checkColorValidity(LodePNGColorType colortype, unsigned bd) /*bd = bitdepth*/
embeddedartists 0:b567d56a59d7 2490 {
embeddedartists 0:b567d56a59d7 2491 switch(colortype)
embeddedartists 0:b567d56a59d7 2492 {
embeddedartists 0:b567d56a59d7 2493 case 0: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16)) return 37; break; /*grey*/
embeddedartists 0:b567d56a59d7 2494 case 2: if(!( bd == 8 || bd == 16)) return 37; break; /*RGB*/
embeddedartists 0:b567d56a59d7 2495 case 3: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 )) return 37; break; /*palette*/
embeddedartists 0:b567d56a59d7 2496 case 4: if(!( bd == 8 || bd == 16)) return 37; break; /*grey + alpha*/
embeddedartists 0:b567d56a59d7 2497 case 6: if(!( bd == 8 || bd == 16)) return 37; break; /*RGBA*/
embeddedartists 0:b567d56a59d7 2498 default: return 31;
embeddedartists 0:b567d56a59d7 2499 }
embeddedartists 0:b567d56a59d7 2500 return 0; /*allowed color type / bits combination*/
embeddedartists 0:b567d56a59d7 2501 }
embeddedartists 0:b567d56a59d7 2502
embeddedartists 0:b567d56a59d7 2503 static unsigned getNumColorChannels(LodePNGColorType colortype)
embeddedartists 0:b567d56a59d7 2504 {
embeddedartists 0:b567d56a59d7 2505 switch(colortype)
embeddedartists 0:b567d56a59d7 2506 {
embeddedartists 0:b567d56a59d7 2507 case 0: return 1; /*grey*/
embeddedartists 0:b567d56a59d7 2508 case 2: return 3; /*RGB*/
embeddedartists 0:b567d56a59d7 2509 case 3: return 1; /*palette*/
embeddedartists 0:b567d56a59d7 2510 case 4: return 2; /*grey + alpha*/
embeddedartists 0:b567d56a59d7 2511 case 6: return 4; /*RGBA*/
embeddedartists 0:b567d56a59d7 2512 }
embeddedartists 0:b567d56a59d7 2513 return 0; /*unexisting color type*/
embeddedartists 0:b567d56a59d7 2514 }
embeddedartists 0:b567d56a59d7 2515
embeddedartists 0:b567d56a59d7 2516 static unsigned lodepng_get_bpp_lct(LodePNGColorType colortype, unsigned bitdepth)
embeddedartists 0:b567d56a59d7 2517 {
embeddedartists 0:b567d56a59d7 2518 /*bits per pixel is amount of channels * bits per channel*/
embeddedartists 0:b567d56a59d7 2519 return getNumColorChannels(colortype) * bitdepth;
embeddedartists 0:b567d56a59d7 2520 }
embeddedartists 0:b567d56a59d7 2521
embeddedartists 0:b567d56a59d7 2522 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 2523
embeddedartists 0:b567d56a59d7 2524 void lodepng_color_mode_init(LodePNGColorMode* info)
embeddedartists 0:b567d56a59d7 2525 {
embeddedartists 0:b567d56a59d7 2526 info->key_defined = 0;
embeddedartists 0:b567d56a59d7 2527 info->key_r = info->key_g = info->key_b = 0;
embeddedartists 0:b567d56a59d7 2528 info->colortype = LCT_RGBA;
embeddedartists 0:b567d56a59d7 2529 info->bitdepth = 8;
embeddedartists 0:b567d56a59d7 2530 info->palette = 0;
embeddedartists 0:b567d56a59d7 2531 info->palettesize = 0;
embeddedartists 0:b567d56a59d7 2532 }
embeddedartists 0:b567d56a59d7 2533
embeddedartists 0:b567d56a59d7 2534 void lodepng_color_mode_cleanup(LodePNGColorMode* info)
embeddedartists 0:b567d56a59d7 2535 {
embeddedartists 0:b567d56a59d7 2536 lodepng_palette_clear(info);
embeddedartists 0:b567d56a59d7 2537 }
embeddedartists 0:b567d56a59d7 2538
embeddedartists 0:b567d56a59d7 2539 unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source)
embeddedartists 0:b567d56a59d7 2540 {
embeddedartists 0:b567d56a59d7 2541 size_t i;
embeddedartists 0:b567d56a59d7 2542 lodepng_color_mode_cleanup(dest);
embeddedartists 0:b567d56a59d7 2543 *dest = *source;
embeddedartists 0:b567d56a59d7 2544 if(source->palette)
embeddedartists 0:b567d56a59d7 2545 {
embeddedartists 0:b567d56a59d7 2546 dest->palette = (unsigned char*)lodepng_malloc(1024);
embeddedartists 0:b567d56a59d7 2547 if(!dest->palette && source->palettesize) return 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 2548 for(i = 0; i < source->palettesize * 4; i++) dest->palette[i] = source->palette[i];
embeddedartists 0:b567d56a59d7 2549 }
embeddedartists 0:b567d56a59d7 2550 return 0;
embeddedartists 0:b567d56a59d7 2551 }
embeddedartists 0:b567d56a59d7 2552
embeddedartists 0:b567d56a59d7 2553 static int lodepng_color_mode_equal(const LodePNGColorMode* a, const LodePNGColorMode* b)
embeddedartists 0:b567d56a59d7 2554 {
embeddedartists 0:b567d56a59d7 2555 size_t i;
embeddedartists 0:b567d56a59d7 2556 if(a->colortype != b->colortype) return 0;
embeddedartists 0:b567d56a59d7 2557 if(a->bitdepth != b->bitdepth) return 0;
embeddedartists 0:b567d56a59d7 2558 if(a->key_defined != b->key_defined) return 0;
embeddedartists 0:b567d56a59d7 2559 if(a->key_defined)
embeddedartists 0:b567d56a59d7 2560 {
embeddedartists 0:b567d56a59d7 2561 if(a->key_r != b->key_r) return 0;
embeddedartists 0:b567d56a59d7 2562 if(a->key_g != b->key_g) return 0;
embeddedartists 0:b567d56a59d7 2563 if(a->key_b != b->key_b) return 0;
embeddedartists 0:b567d56a59d7 2564 }
embeddedartists 0:b567d56a59d7 2565 if(a->palettesize != b->palettesize) return 0;
embeddedartists 0:b567d56a59d7 2566 for(i = 0; i < a->palettesize * 4; i++)
embeddedartists 0:b567d56a59d7 2567 {
embeddedartists 0:b567d56a59d7 2568 if(a->palette[i] != b->palette[i]) return 0;
embeddedartists 0:b567d56a59d7 2569 }
embeddedartists 0:b567d56a59d7 2570 return 1;
embeddedartists 0:b567d56a59d7 2571 }
embeddedartists 0:b567d56a59d7 2572
embeddedartists 0:b567d56a59d7 2573 void lodepng_palette_clear(LodePNGColorMode* info)
embeddedartists 0:b567d56a59d7 2574 {
embeddedartists 0:b567d56a59d7 2575 if(info->palette) lodepng_free(info->palette);
embeddedartists 0:b567d56a59d7 2576 info->palette = 0;
embeddedartists 0:b567d56a59d7 2577 info->palettesize = 0;
embeddedartists 0:b567d56a59d7 2578 }
embeddedartists 0:b567d56a59d7 2579
embeddedartists 0:b567d56a59d7 2580 unsigned lodepng_palette_add(LodePNGColorMode* info,
embeddedartists 0:b567d56a59d7 2581 unsigned char r, unsigned char g, unsigned char b, unsigned char a)
embeddedartists 0:b567d56a59d7 2582 {
embeddedartists 0:b567d56a59d7 2583 unsigned char* data;
embeddedartists 0:b567d56a59d7 2584 /*the same resize technique as C++ std::vectors is used, and here it's made so that for a palette with
embeddedartists 0:b567d56a59d7 2585 the max of 256 colors, it'll have the exact alloc size*/
embeddedartists 0:b567d56a59d7 2586 if(!info->palette) /*allocate palette if empty*/
embeddedartists 0:b567d56a59d7 2587 {
embeddedartists 0:b567d56a59d7 2588 /*room for 256 colors with 4 bytes each*/
embeddedartists 0:b567d56a59d7 2589 data = (unsigned char*)lodepng_realloc(info->palette, 1024);
embeddedartists 0:b567d56a59d7 2590 if(!data) return 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 2591 else info->palette = data;
embeddedartists 0:b567d56a59d7 2592 }
embeddedartists 0:b567d56a59d7 2593 info->palette[4 * info->palettesize + 0] = r;
embeddedartists 0:b567d56a59d7 2594 info->palette[4 * info->palettesize + 1] = g;
embeddedartists 0:b567d56a59d7 2595 info->palette[4 * info->palettesize + 2] = b;
embeddedartists 0:b567d56a59d7 2596 info->palette[4 * info->palettesize + 3] = a;
embeddedartists 0:b567d56a59d7 2597 info->palettesize++;
embeddedartists 0:b567d56a59d7 2598 return 0;
embeddedartists 0:b567d56a59d7 2599 }
embeddedartists 0:b567d56a59d7 2600
embeddedartists 0:b567d56a59d7 2601 unsigned lodepng_get_bpp(const LodePNGColorMode* info)
embeddedartists 0:b567d56a59d7 2602 {
embeddedartists 0:b567d56a59d7 2603 /*calculate bits per pixel out of colortype and bitdepth*/
embeddedartists 0:b567d56a59d7 2604 return lodepng_get_bpp_lct(info->colortype, info->bitdepth);
embeddedartists 0:b567d56a59d7 2605 }
embeddedartists 0:b567d56a59d7 2606
embeddedartists 0:b567d56a59d7 2607 unsigned lodepng_get_channels(const LodePNGColorMode* info)
embeddedartists 0:b567d56a59d7 2608 {
embeddedartists 0:b567d56a59d7 2609 return getNumColorChannels(info->colortype);
embeddedartists 0:b567d56a59d7 2610 }
embeddedartists 0:b567d56a59d7 2611
embeddedartists 0:b567d56a59d7 2612 unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info)
embeddedartists 0:b567d56a59d7 2613 {
embeddedartists 0:b567d56a59d7 2614 return info->colortype == LCT_GREY || info->colortype == LCT_GREY_ALPHA;
embeddedartists 0:b567d56a59d7 2615 }
embeddedartists 0:b567d56a59d7 2616
embeddedartists 0:b567d56a59d7 2617 unsigned lodepng_is_alpha_type(const LodePNGColorMode* info)
embeddedartists 0:b567d56a59d7 2618 {
embeddedartists 0:b567d56a59d7 2619 return (info->colortype & 4) != 0; /*4 or 6*/
embeddedartists 0:b567d56a59d7 2620 }
embeddedartists 0:b567d56a59d7 2621
embeddedartists 0:b567d56a59d7 2622 unsigned lodepng_is_palette_type(const LodePNGColorMode* info)
embeddedartists 0:b567d56a59d7 2623 {
embeddedartists 0:b567d56a59d7 2624 return info->colortype == LCT_PALETTE;
embeddedartists 0:b567d56a59d7 2625 }
embeddedartists 0:b567d56a59d7 2626
embeddedartists 0:b567d56a59d7 2627 unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info)
embeddedartists 0:b567d56a59d7 2628 {
embeddedartists 0:b567d56a59d7 2629 size_t i;
embeddedartists 0:b567d56a59d7 2630 for(i = 0; i < info->palettesize; i++)
embeddedartists 0:b567d56a59d7 2631 {
embeddedartists 0:b567d56a59d7 2632 if(info->palette[i * 4 + 3] < 255) return 1;
embeddedartists 0:b567d56a59d7 2633 }
embeddedartists 0:b567d56a59d7 2634 return 0;
embeddedartists 0:b567d56a59d7 2635 }
embeddedartists 0:b567d56a59d7 2636
embeddedartists 0:b567d56a59d7 2637 unsigned lodepng_can_have_alpha(const LodePNGColorMode* info)
embeddedartists 0:b567d56a59d7 2638 {
embeddedartists 0:b567d56a59d7 2639 return info->key_defined
embeddedartists 0:b567d56a59d7 2640 || lodepng_is_alpha_type(info)
embeddedartists 0:b567d56a59d7 2641 || lodepng_has_palette_alpha(info);
embeddedartists 0:b567d56a59d7 2642 }
embeddedartists 0:b567d56a59d7 2643
embeddedartists 0:b567d56a59d7 2644 size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color)
embeddedartists 0:b567d56a59d7 2645 {
embeddedartists 0:b567d56a59d7 2646 return (w * h * lodepng_get_bpp(color) + 7) / 8;
embeddedartists 0:b567d56a59d7 2647 }
embeddedartists 0:b567d56a59d7 2648
embeddedartists 0:b567d56a59d7 2649 size_t lodepng_get_raw_size_lct(unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth)
embeddedartists 0:b567d56a59d7 2650 {
embeddedartists 0:b567d56a59d7 2651 return (w * h * lodepng_get_bpp_lct(colortype, bitdepth) + 7) / 8;
embeddedartists 0:b567d56a59d7 2652 }
embeddedartists 0:b567d56a59d7 2653
embeddedartists 0:b567d56a59d7 2654 #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
embeddedartists 0:b567d56a59d7 2655
embeddedartists 0:b567d56a59d7 2656 static void LodePNGUnknownChunks_init(LodePNGInfo* info)
embeddedartists 0:b567d56a59d7 2657 {
embeddedartists 0:b567d56a59d7 2658 unsigned i;
embeddedartists 0:b567d56a59d7 2659 for(i = 0; i < 3; i++) info->unknown_chunks_data[i] = 0;
embeddedartists 0:b567d56a59d7 2660 for(i = 0; i < 3; i++) info->unknown_chunks_size[i] = 0;
embeddedartists 0:b567d56a59d7 2661 }
embeddedartists 0:b567d56a59d7 2662
embeddedartists 0:b567d56a59d7 2663 static void LodePNGUnknownChunks_cleanup(LodePNGInfo* info)
embeddedartists 0:b567d56a59d7 2664 {
embeddedartists 0:b567d56a59d7 2665 unsigned i;
embeddedartists 0:b567d56a59d7 2666 for(i = 0; i < 3; i++) lodepng_free(info->unknown_chunks_data[i]);
embeddedartists 0:b567d56a59d7 2667 }
embeddedartists 0:b567d56a59d7 2668
embeddedartists 0:b567d56a59d7 2669 static unsigned LodePNGUnknownChunks_copy(LodePNGInfo* dest, const LodePNGInfo* src)
embeddedartists 0:b567d56a59d7 2670 {
embeddedartists 0:b567d56a59d7 2671 unsigned i;
embeddedartists 0:b567d56a59d7 2672
embeddedartists 0:b567d56a59d7 2673 LodePNGUnknownChunks_cleanup(dest);
embeddedartists 0:b567d56a59d7 2674
embeddedartists 0:b567d56a59d7 2675 for(i = 0; i < 3; i++)
embeddedartists 0:b567d56a59d7 2676 {
embeddedartists 0:b567d56a59d7 2677 size_t j;
embeddedartists 0:b567d56a59d7 2678 dest->unknown_chunks_size[i] = src->unknown_chunks_size[i];
embeddedartists 0:b567d56a59d7 2679 dest->unknown_chunks_data[i] = (unsigned char*)lodepng_malloc(src->unknown_chunks_size[i]);
embeddedartists 0:b567d56a59d7 2680 if(!dest->unknown_chunks_data[i] && dest->unknown_chunks_size[i]) return 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 2681 for(j = 0; j < src->unknown_chunks_size[i]; j++)
embeddedartists 0:b567d56a59d7 2682 {
embeddedartists 0:b567d56a59d7 2683 dest->unknown_chunks_data[i][j] = src->unknown_chunks_data[i][j];
embeddedartists 0:b567d56a59d7 2684 }
embeddedartists 0:b567d56a59d7 2685 }
embeddedartists 0:b567d56a59d7 2686
embeddedartists 0:b567d56a59d7 2687 return 0;
embeddedartists 0:b567d56a59d7 2688 }
embeddedartists 0:b567d56a59d7 2689
embeddedartists 0:b567d56a59d7 2690 /******************************************************************************/
embeddedartists 0:b567d56a59d7 2691
embeddedartists 0:b567d56a59d7 2692 static void LodePNGText_init(LodePNGInfo* info)
embeddedartists 0:b567d56a59d7 2693 {
embeddedartists 0:b567d56a59d7 2694 info->text_num = 0;
embeddedartists 0:b567d56a59d7 2695 info->text_keys = NULL;
embeddedartists 0:b567d56a59d7 2696 info->text_strings = NULL;
embeddedartists 0:b567d56a59d7 2697 }
embeddedartists 0:b567d56a59d7 2698
embeddedartists 0:b567d56a59d7 2699 static void LodePNGText_cleanup(LodePNGInfo* info)
embeddedartists 0:b567d56a59d7 2700 {
embeddedartists 0:b567d56a59d7 2701 size_t i;
embeddedartists 0:b567d56a59d7 2702 for(i = 0; i < info->text_num; i++)
embeddedartists 0:b567d56a59d7 2703 {
embeddedartists 0:b567d56a59d7 2704 string_cleanup(&info->text_keys[i]);
embeddedartists 0:b567d56a59d7 2705 string_cleanup(&info->text_strings[i]);
embeddedartists 0:b567d56a59d7 2706 }
embeddedartists 0:b567d56a59d7 2707 lodepng_free(info->text_keys);
embeddedartists 0:b567d56a59d7 2708 lodepng_free(info->text_strings);
embeddedartists 0:b567d56a59d7 2709 }
embeddedartists 0:b567d56a59d7 2710
embeddedartists 0:b567d56a59d7 2711 static unsigned LodePNGText_copy(LodePNGInfo* dest, const LodePNGInfo* source)
embeddedartists 0:b567d56a59d7 2712 {
embeddedartists 0:b567d56a59d7 2713 size_t i = 0;
embeddedartists 0:b567d56a59d7 2714 dest->text_keys = 0;
embeddedartists 0:b567d56a59d7 2715 dest->text_strings = 0;
embeddedartists 0:b567d56a59d7 2716 dest->text_num = 0;
embeddedartists 0:b567d56a59d7 2717 for(i = 0; i < source->text_num; i++)
embeddedartists 0:b567d56a59d7 2718 {
embeddedartists 0:b567d56a59d7 2719 CERROR_TRY_RETURN(lodepng_add_text(dest, source->text_keys[i], source->text_strings[i]));
embeddedartists 0:b567d56a59d7 2720 }
embeddedartists 0:b567d56a59d7 2721 return 0;
embeddedartists 0:b567d56a59d7 2722 }
embeddedartists 0:b567d56a59d7 2723
embeddedartists 0:b567d56a59d7 2724 void lodepng_clear_text(LodePNGInfo* info)
embeddedartists 0:b567d56a59d7 2725 {
embeddedartists 0:b567d56a59d7 2726 LodePNGText_cleanup(info);
embeddedartists 0:b567d56a59d7 2727 }
embeddedartists 0:b567d56a59d7 2728
embeddedartists 0:b567d56a59d7 2729 unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str)
embeddedartists 0:b567d56a59d7 2730 {
embeddedartists 0:b567d56a59d7 2731 char** new_keys = (char**)(lodepng_realloc(info->text_keys, sizeof(char*) * (info->text_num + 1)));
embeddedartists 0:b567d56a59d7 2732 char** new_strings = (char**)(lodepng_realloc(info->text_strings, sizeof(char*) * (info->text_num + 1)));
embeddedartists 0:b567d56a59d7 2733 if(!new_keys || !new_strings)
embeddedartists 0:b567d56a59d7 2734 {
embeddedartists 0:b567d56a59d7 2735 lodepng_free(new_keys);
embeddedartists 0:b567d56a59d7 2736 lodepng_free(new_strings);
embeddedartists 0:b567d56a59d7 2737 return 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 2738 }
embeddedartists 0:b567d56a59d7 2739
embeddedartists 0:b567d56a59d7 2740 info->text_num++;
embeddedartists 0:b567d56a59d7 2741 info->text_keys = new_keys;
embeddedartists 0:b567d56a59d7 2742 info->text_strings = new_strings;
embeddedartists 0:b567d56a59d7 2743
embeddedartists 0:b567d56a59d7 2744 string_init(&info->text_keys[info->text_num - 1]);
embeddedartists 0:b567d56a59d7 2745 string_set(&info->text_keys[info->text_num - 1], key);
embeddedartists 0:b567d56a59d7 2746
embeddedartists 0:b567d56a59d7 2747 string_init(&info->text_strings[info->text_num - 1]);
embeddedartists 0:b567d56a59d7 2748 string_set(&info->text_strings[info->text_num - 1], str);
embeddedartists 0:b567d56a59d7 2749
embeddedartists 0:b567d56a59d7 2750 return 0;
embeddedartists 0:b567d56a59d7 2751 }
embeddedartists 0:b567d56a59d7 2752
embeddedartists 0:b567d56a59d7 2753 /******************************************************************************/
embeddedartists 0:b567d56a59d7 2754
embeddedartists 0:b567d56a59d7 2755 static void LodePNGIText_init(LodePNGInfo* info)
embeddedartists 0:b567d56a59d7 2756 {
embeddedartists 0:b567d56a59d7 2757 info->itext_num = 0;
embeddedartists 0:b567d56a59d7 2758 info->itext_keys = NULL;
embeddedartists 0:b567d56a59d7 2759 info->itext_langtags = NULL;
embeddedartists 0:b567d56a59d7 2760 info->itext_transkeys = NULL;
embeddedartists 0:b567d56a59d7 2761 info->itext_strings = NULL;
embeddedartists 0:b567d56a59d7 2762 }
embeddedartists 0:b567d56a59d7 2763
embeddedartists 0:b567d56a59d7 2764 static void LodePNGIText_cleanup(LodePNGInfo* info)
embeddedartists 0:b567d56a59d7 2765 {
embeddedartists 0:b567d56a59d7 2766 size_t i;
embeddedartists 0:b567d56a59d7 2767 for(i = 0; i < info->itext_num; i++)
embeddedartists 0:b567d56a59d7 2768 {
embeddedartists 0:b567d56a59d7 2769 string_cleanup(&info->itext_keys[i]);
embeddedartists 0:b567d56a59d7 2770 string_cleanup(&info->itext_langtags[i]);
embeddedartists 0:b567d56a59d7 2771 string_cleanup(&info->itext_transkeys[i]);
embeddedartists 0:b567d56a59d7 2772 string_cleanup(&info->itext_strings[i]);
embeddedartists 0:b567d56a59d7 2773 }
embeddedartists 0:b567d56a59d7 2774 lodepng_free(info->itext_keys);
embeddedartists 0:b567d56a59d7 2775 lodepng_free(info->itext_langtags);
embeddedartists 0:b567d56a59d7 2776 lodepng_free(info->itext_transkeys);
embeddedartists 0:b567d56a59d7 2777 lodepng_free(info->itext_strings);
embeddedartists 0:b567d56a59d7 2778 }
embeddedartists 0:b567d56a59d7 2779
embeddedartists 0:b567d56a59d7 2780 static unsigned LodePNGIText_copy(LodePNGInfo* dest, const LodePNGInfo* source)
embeddedartists 0:b567d56a59d7 2781 {
embeddedartists 0:b567d56a59d7 2782 size_t i = 0;
embeddedartists 0:b567d56a59d7 2783 dest->itext_keys = 0;
embeddedartists 0:b567d56a59d7 2784 dest->itext_langtags = 0;
embeddedartists 0:b567d56a59d7 2785 dest->itext_transkeys = 0;
embeddedartists 0:b567d56a59d7 2786 dest->itext_strings = 0;
embeddedartists 0:b567d56a59d7 2787 dest->itext_num = 0;
embeddedartists 0:b567d56a59d7 2788 for(i = 0; i < source->itext_num; i++)
embeddedartists 0:b567d56a59d7 2789 {
embeddedartists 0:b567d56a59d7 2790 CERROR_TRY_RETURN(lodepng_add_itext(dest, source->itext_keys[i], source->itext_langtags[i],
embeddedartists 0:b567d56a59d7 2791 source->itext_transkeys[i], source->itext_strings[i]));
embeddedartists 0:b567d56a59d7 2792 }
embeddedartists 0:b567d56a59d7 2793 return 0;
embeddedartists 0:b567d56a59d7 2794 }
embeddedartists 0:b567d56a59d7 2795
embeddedartists 0:b567d56a59d7 2796 void lodepng_clear_itext(LodePNGInfo* info)
embeddedartists 0:b567d56a59d7 2797 {
embeddedartists 0:b567d56a59d7 2798 LodePNGIText_cleanup(info);
embeddedartists 0:b567d56a59d7 2799 }
embeddedartists 0:b567d56a59d7 2800
embeddedartists 0:b567d56a59d7 2801 unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag,
embeddedartists 0:b567d56a59d7 2802 const char* transkey, const char* str)
embeddedartists 0:b567d56a59d7 2803 {
embeddedartists 0:b567d56a59d7 2804 char** new_keys = (char**)(lodepng_realloc(info->itext_keys, sizeof(char*) * (info->itext_num + 1)));
embeddedartists 0:b567d56a59d7 2805 char** new_langtags = (char**)(lodepng_realloc(info->itext_langtags, sizeof(char*) * (info->itext_num + 1)));
embeddedartists 0:b567d56a59d7 2806 char** new_transkeys = (char**)(lodepng_realloc(info->itext_transkeys, sizeof(char*) * (info->itext_num + 1)));
embeddedartists 0:b567d56a59d7 2807 char** new_strings = (char**)(lodepng_realloc(info->itext_strings, sizeof(char*) * (info->itext_num + 1)));
embeddedartists 0:b567d56a59d7 2808 if(!new_keys || !new_langtags || !new_transkeys || !new_strings)
embeddedartists 0:b567d56a59d7 2809 {
embeddedartists 0:b567d56a59d7 2810 lodepng_free(new_keys);
embeddedartists 0:b567d56a59d7 2811 lodepng_free(new_langtags);
embeddedartists 0:b567d56a59d7 2812 lodepng_free(new_transkeys);
embeddedartists 0:b567d56a59d7 2813 lodepng_free(new_strings);
embeddedartists 0:b567d56a59d7 2814 return 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 2815 }
embeddedartists 0:b567d56a59d7 2816
embeddedartists 0:b567d56a59d7 2817 info->itext_num++;
embeddedartists 0:b567d56a59d7 2818 info->itext_keys = new_keys;
embeddedartists 0:b567d56a59d7 2819 info->itext_langtags = new_langtags;
embeddedartists 0:b567d56a59d7 2820 info->itext_transkeys = new_transkeys;
embeddedartists 0:b567d56a59d7 2821 info->itext_strings = new_strings;
embeddedartists 0:b567d56a59d7 2822
embeddedartists 0:b567d56a59d7 2823 string_init(&info->itext_keys[info->itext_num - 1]);
embeddedartists 0:b567d56a59d7 2824 string_set(&info->itext_keys[info->itext_num - 1], key);
embeddedartists 0:b567d56a59d7 2825
embeddedartists 0:b567d56a59d7 2826 string_init(&info->itext_langtags[info->itext_num - 1]);
embeddedartists 0:b567d56a59d7 2827 string_set(&info->itext_langtags[info->itext_num - 1], langtag);
embeddedartists 0:b567d56a59d7 2828
embeddedartists 0:b567d56a59d7 2829 string_init(&info->itext_transkeys[info->itext_num - 1]);
embeddedartists 0:b567d56a59d7 2830 string_set(&info->itext_transkeys[info->itext_num - 1], transkey);
embeddedartists 0:b567d56a59d7 2831
embeddedartists 0:b567d56a59d7 2832 string_init(&info->itext_strings[info->itext_num - 1]);
embeddedartists 0:b567d56a59d7 2833 string_set(&info->itext_strings[info->itext_num - 1], str);
embeddedartists 0:b567d56a59d7 2834
embeddedartists 0:b567d56a59d7 2835 return 0;
embeddedartists 0:b567d56a59d7 2836 }
embeddedartists 0:b567d56a59d7 2837 #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
embeddedartists 0:b567d56a59d7 2838
embeddedartists 0:b567d56a59d7 2839 void lodepng_info_init(LodePNGInfo* info)
embeddedartists 0:b567d56a59d7 2840 {
embeddedartists 0:b567d56a59d7 2841 lodepng_color_mode_init(&info->color);
embeddedartists 0:b567d56a59d7 2842 info->interlace_method = 0;
embeddedartists 0:b567d56a59d7 2843 info->compression_method = 0;
embeddedartists 0:b567d56a59d7 2844 info->filter_method = 0;
embeddedartists 0:b567d56a59d7 2845 #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
embeddedartists 0:b567d56a59d7 2846 info->background_defined = 0;
embeddedartists 0:b567d56a59d7 2847 info->background_r = info->background_g = info->background_b = 0;
embeddedartists 0:b567d56a59d7 2848
embeddedartists 0:b567d56a59d7 2849 LodePNGText_init(info);
embeddedartists 0:b567d56a59d7 2850 LodePNGIText_init(info);
embeddedartists 0:b567d56a59d7 2851
embeddedartists 0:b567d56a59d7 2852 info->time_defined = 0;
embeddedartists 0:b567d56a59d7 2853 info->phys_defined = 0;
embeddedartists 0:b567d56a59d7 2854
embeddedartists 0:b567d56a59d7 2855 LodePNGUnknownChunks_init(info);
embeddedartists 0:b567d56a59d7 2856 #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
embeddedartists 0:b567d56a59d7 2857 }
embeddedartists 0:b567d56a59d7 2858
embeddedartists 0:b567d56a59d7 2859 void lodepng_info_cleanup(LodePNGInfo* info)
embeddedartists 0:b567d56a59d7 2860 {
embeddedartists 0:b567d56a59d7 2861 lodepng_color_mode_cleanup(&info->color);
embeddedartists 0:b567d56a59d7 2862 #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
embeddedartists 0:b567d56a59d7 2863 LodePNGText_cleanup(info);
embeddedartists 0:b567d56a59d7 2864 LodePNGIText_cleanup(info);
embeddedartists 0:b567d56a59d7 2865
embeddedartists 0:b567d56a59d7 2866 LodePNGUnknownChunks_cleanup(info);
embeddedartists 0:b567d56a59d7 2867 #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
embeddedartists 0:b567d56a59d7 2868 }
embeddedartists 0:b567d56a59d7 2869
embeddedartists 0:b567d56a59d7 2870 unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source)
embeddedartists 0:b567d56a59d7 2871 {
embeddedartists 0:b567d56a59d7 2872 lodepng_info_cleanup(dest);
embeddedartists 0:b567d56a59d7 2873 *dest = *source;
embeddedartists 0:b567d56a59d7 2874 lodepng_color_mode_init(&dest->color);
embeddedartists 0:b567d56a59d7 2875 CERROR_TRY_RETURN(lodepng_color_mode_copy(&dest->color, &source->color));
embeddedartists 0:b567d56a59d7 2876
embeddedartists 0:b567d56a59d7 2877 #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
embeddedartists 0:b567d56a59d7 2878 CERROR_TRY_RETURN(LodePNGText_copy(dest, source));
embeddedartists 0:b567d56a59d7 2879 CERROR_TRY_RETURN(LodePNGIText_copy(dest, source));
embeddedartists 0:b567d56a59d7 2880
embeddedartists 0:b567d56a59d7 2881 LodePNGUnknownChunks_init(dest);
embeddedartists 0:b567d56a59d7 2882 CERROR_TRY_RETURN(LodePNGUnknownChunks_copy(dest, source));
embeddedartists 0:b567d56a59d7 2883 #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
embeddedartists 0:b567d56a59d7 2884 return 0;
embeddedartists 0:b567d56a59d7 2885 }
embeddedartists 0:b567d56a59d7 2886
embeddedartists 0:b567d56a59d7 2887 void lodepng_info_swap(LodePNGInfo* a, LodePNGInfo* b)
embeddedartists 0:b567d56a59d7 2888 {
embeddedartists 0:b567d56a59d7 2889 LodePNGInfo temp = *a;
embeddedartists 0:b567d56a59d7 2890 *a = *b;
embeddedartists 0:b567d56a59d7 2891 *b = temp;
embeddedartists 0:b567d56a59d7 2892 }
embeddedartists 0:b567d56a59d7 2893
embeddedartists 0:b567d56a59d7 2894 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 2895
embeddedartists 0:b567d56a59d7 2896 /*index: bitgroup index, bits: bitgroup size(1, 2 or 4), in: bitgroup value, out: octet array to add bits to*/
embeddedartists 0:b567d56a59d7 2897 static void addColorBits(unsigned char* out, size_t index, unsigned bits, unsigned in)
embeddedartists 0:b567d56a59d7 2898 {
embeddedartists 0:b567d56a59d7 2899 unsigned m = bits == 1 ? 7 : bits == 2 ? 3 : 1; /*8 / bits - 1*/
embeddedartists 0:b567d56a59d7 2900 /*p = the partial index in the byte, e.g. with 4 palettebits it is 0 for first half or 1 for second half*/
embeddedartists 0:b567d56a59d7 2901 unsigned p = index & m;
embeddedartists 0:b567d56a59d7 2902 in &= (1 << bits) - 1; /*filter out any other bits of the input value*/
embeddedartists 0:b567d56a59d7 2903 in = in << (bits * (m - p));
embeddedartists 0:b567d56a59d7 2904 if(p == 0) out[index * bits / 8] = in;
embeddedartists 0:b567d56a59d7 2905 else out[index * bits / 8] |= in;
embeddedartists 0:b567d56a59d7 2906 }
embeddedartists 0:b567d56a59d7 2907
embeddedartists 0:b567d56a59d7 2908 typedef struct ColorTree ColorTree;
embeddedartists 0:b567d56a59d7 2909
embeddedartists 0:b567d56a59d7 2910 /*
embeddedartists 0:b567d56a59d7 2911 One node of a color tree
embeddedartists 0:b567d56a59d7 2912 This is the data structure used to count the number of unique colors and to get a palette
embeddedartists 0:b567d56a59d7 2913 index for a color. It's like an octree, but because the alpha channel is used too, each
embeddedartists 0:b567d56a59d7 2914 node has 16 instead of 8 children.
embeddedartists 0:b567d56a59d7 2915 */
embeddedartists 0:b567d56a59d7 2916 struct ColorTree
embeddedartists 0:b567d56a59d7 2917 {
embeddedartists 0:b567d56a59d7 2918 ColorTree* children[16]; /*up to 16 pointers to ColorTree of next level*/
embeddedartists 0:b567d56a59d7 2919 int index; /*the payload. Only has a meaningful value if this is in the last level*/
embeddedartists 0:b567d56a59d7 2920 };
embeddedartists 0:b567d56a59d7 2921
embeddedartists 0:b567d56a59d7 2922 static void color_tree_init(ColorTree* tree)
embeddedartists 0:b567d56a59d7 2923 {
embeddedartists 0:b567d56a59d7 2924 int i;
embeddedartists 0:b567d56a59d7 2925 for(i = 0; i < 16; i++) tree->children[i] = 0;
embeddedartists 0:b567d56a59d7 2926 tree->index = -1;
embeddedartists 0:b567d56a59d7 2927 }
embeddedartists 0:b567d56a59d7 2928
embeddedartists 0:b567d56a59d7 2929 static void color_tree_cleanup(ColorTree* tree)
embeddedartists 0:b567d56a59d7 2930 {
embeddedartists 0:b567d56a59d7 2931 int i;
embeddedartists 0:b567d56a59d7 2932 for(i = 0; i < 16; i++)
embeddedartists 0:b567d56a59d7 2933 {
embeddedartists 0:b567d56a59d7 2934 if(tree->children[i])
embeddedartists 0:b567d56a59d7 2935 {
embeddedartists 0:b567d56a59d7 2936 color_tree_cleanup(tree->children[i]);
embeddedartists 0:b567d56a59d7 2937 lodepng_free(tree->children[i]);
embeddedartists 0:b567d56a59d7 2938 }
embeddedartists 0:b567d56a59d7 2939 }
embeddedartists 0:b567d56a59d7 2940 }
embeddedartists 0:b567d56a59d7 2941
embeddedartists 0:b567d56a59d7 2942 /*returns -1 if color not present, its index otherwise*/
embeddedartists 0:b567d56a59d7 2943 static int color_tree_get(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
embeddedartists 0:b567d56a59d7 2944 {
embeddedartists 0:b567d56a59d7 2945 int bit = 0;
embeddedartists 0:b567d56a59d7 2946 for(bit = 0; bit < 8; bit++)
embeddedartists 0:b567d56a59d7 2947 {
embeddedartists 0:b567d56a59d7 2948 int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1);
embeddedartists 0:b567d56a59d7 2949 if(!tree->children[i]) return -1;
embeddedartists 0:b567d56a59d7 2950 else tree = tree->children[i];
embeddedartists 0:b567d56a59d7 2951 }
embeddedartists 0:b567d56a59d7 2952 return tree ? tree->index : -1;
embeddedartists 0:b567d56a59d7 2953 }
embeddedartists 0:b567d56a59d7 2954
embeddedartists 0:b567d56a59d7 2955 #ifdef LODEPNG_COMPILE_ENCODER
embeddedartists 0:b567d56a59d7 2956 static int color_tree_has(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
embeddedartists 0:b567d56a59d7 2957 {
embeddedartists 0:b567d56a59d7 2958 return color_tree_get(tree, r, g, b, a) >= 0;
embeddedartists 0:b567d56a59d7 2959 }
embeddedartists 0:b567d56a59d7 2960 #endif /*LODEPNG_COMPILE_ENCODER*/
embeddedartists 0:b567d56a59d7 2961
embeddedartists 0:b567d56a59d7 2962 /*color is not allowed to already exist.
embeddedartists 0:b567d56a59d7 2963 Index should be >= 0 (it's signed to be compatible with using -1 for "doesn't exist")*/
embeddedartists 0:b567d56a59d7 2964 static void color_tree_add(ColorTree* tree,
embeddedartists 0:b567d56a59d7 2965 unsigned char r, unsigned char g, unsigned char b, unsigned char a, int index)
embeddedartists 0:b567d56a59d7 2966 {
embeddedartists 0:b567d56a59d7 2967 int bit;
embeddedartists 0:b567d56a59d7 2968 for(bit = 0; bit < 8; bit++)
embeddedartists 0:b567d56a59d7 2969 {
embeddedartists 0:b567d56a59d7 2970 int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1);
embeddedartists 0:b567d56a59d7 2971 if(!tree->children[i])
embeddedartists 0:b567d56a59d7 2972 {
embeddedartists 0:b567d56a59d7 2973 tree->children[i] = (ColorTree*)lodepng_malloc(sizeof(ColorTree));
embeddedartists 0:b567d56a59d7 2974 color_tree_init(tree->children[i]);
embeddedartists 0:b567d56a59d7 2975 }
embeddedartists 0:b567d56a59d7 2976 tree = tree->children[i];
embeddedartists 0:b567d56a59d7 2977 }
embeddedartists 0:b567d56a59d7 2978 tree->index = index;
embeddedartists 0:b567d56a59d7 2979 }
embeddedartists 0:b567d56a59d7 2980
embeddedartists 0:b567d56a59d7 2981 /*put a pixel, given its RGBA color, into image of any color type*/
embeddedartists 0:b567d56a59d7 2982 static unsigned rgba8ToPixel(unsigned char* out, size_t i,
embeddedartists 0:b567d56a59d7 2983 const LodePNGColorMode* mode, ColorTree* tree /*for palette*/,
embeddedartists 0:b567d56a59d7 2984 unsigned char r, unsigned char g, unsigned char b, unsigned char a)
embeddedartists 0:b567d56a59d7 2985 {
embeddedartists 0:b567d56a59d7 2986 if(mode->colortype == LCT_GREY)
embeddedartists 0:b567d56a59d7 2987 {
embeddedartists 0:b567d56a59d7 2988 unsigned char grey = r; /*((unsigned short)r + g + b) / 3*/;
embeddedartists 0:b567d56a59d7 2989 if(mode->bitdepth == 8) out[i] = grey;
embeddedartists 0:b567d56a59d7 2990 else if(mode->bitdepth == 16) out[i * 2 + 0] = out[i * 2 + 1] = grey;
embeddedartists 0:b567d56a59d7 2991 else
embeddedartists 0:b567d56a59d7 2992 {
embeddedartists 0:b567d56a59d7 2993 /*take the most significant bits of grey*/
embeddedartists 0:b567d56a59d7 2994 grey = (grey >> (8 - mode->bitdepth)) & ((1 << mode->bitdepth) - 1);
embeddedartists 0:b567d56a59d7 2995 addColorBits(out, i, mode->bitdepth, grey);
embeddedartists 0:b567d56a59d7 2996 }
embeddedartists 0:b567d56a59d7 2997 }
embeddedartists 0:b567d56a59d7 2998 else if(mode->colortype == LCT_RGB)
embeddedartists 0:b567d56a59d7 2999 {
embeddedartists 0:b567d56a59d7 3000 if(mode->bitdepth == 8)
embeddedartists 0:b567d56a59d7 3001 {
embeddedartists 0:b567d56a59d7 3002 out[i * 3 + 0] = r;
embeddedartists 0:b567d56a59d7 3003 out[i * 3 + 1] = g;
embeddedartists 0:b567d56a59d7 3004 out[i * 3 + 2] = b;
embeddedartists 0:b567d56a59d7 3005 }
embeddedartists 0:b567d56a59d7 3006 else
embeddedartists 0:b567d56a59d7 3007 {
embeddedartists 0:b567d56a59d7 3008 out[i * 6 + 0] = out[i * 6 + 1] = r;
embeddedartists 0:b567d56a59d7 3009 out[i * 6 + 2] = out[i * 6 + 3] = g;
embeddedartists 0:b567d56a59d7 3010 out[i * 6 + 4] = out[i * 6 + 5] = b;
embeddedartists 0:b567d56a59d7 3011 }
embeddedartists 0:b567d56a59d7 3012 }
embeddedartists 0:b567d56a59d7 3013 else if(mode->colortype == LCT_PALETTE)
embeddedartists 0:b567d56a59d7 3014 {
embeddedartists 0:b567d56a59d7 3015 int index = color_tree_get(tree, r, g, b, a);
embeddedartists 0:b567d56a59d7 3016 if(index < 0) return 82; /*color not in palette*/
embeddedartists 0:b567d56a59d7 3017 if(mode->bitdepth == 8) out[i] = index;
embeddedartists 0:b567d56a59d7 3018 else addColorBits(out, i, mode->bitdepth, index);
embeddedartists 0:b567d56a59d7 3019 }
embeddedartists 0:b567d56a59d7 3020 else if(mode->colortype == LCT_GREY_ALPHA)
embeddedartists 0:b567d56a59d7 3021 {
embeddedartists 0:b567d56a59d7 3022 unsigned char grey = r; /*((unsigned short)r + g + b) / 3*/;
embeddedartists 0:b567d56a59d7 3023 if(mode->bitdepth == 8)
embeddedartists 0:b567d56a59d7 3024 {
embeddedartists 0:b567d56a59d7 3025 out[i * 2 + 0] = grey;
embeddedartists 0:b567d56a59d7 3026 out[i * 2 + 1] = a;
embeddedartists 0:b567d56a59d7 3027 }
embeddedartists 0:b567d56a59d7 3028 else if(mode->bitdepth == 16)
embeddedartists 0:b567d56a59d7 3029 {
embeddedartists 0:b567d56a59d7 3030 out[i * 4 + 0] = out[i * 4 + 1] = grey;
embeddedartists 0:b567d56a59d7 3031 out[i * 4 + 2] = out[i * 4 + 3] = a;
embeddedartists 0:b567d56a59d7 3032 }
embeddedartists 0:b567d56a59d7 3033 }
embeddedartists 0:b567d56a59d7 3034 else if(mode->colortype == LCT_RGBA)
embeddedartists 0:b567d56a59d7 3035 {
embeddedartists 0:b567d56a59d7 3036 if(mode->bitdepth == 8)
embeddedartists 0:b567d56a59d7 3037 {
embeddedartists 0:b567d56a59d7 3038 out[i * 4 + 0] = r;
embeddedartists 0:b567d56a59d7 3039 out[i * 4 + 1] = g;
embeddedartists 0:b567d56a59d7 3040 out[i * 4 + 2] = b;
embeddedartists 0:b567d56a59d7 3041 out[i * 4 + 3] = a;
embeddedartists 0:b567d56a59d7 3042 }
embeddedartists 0:b567d56a59d7 3043 else
embeddedartists 0:b567d56a59d7 3044 {
embeddedartists 0:b567d56a59d7 3045 out[i * 8 + 0] = out[i * 8 + 1] = r;
embeddedartists 0:b567d56a59d7 3046 out[i * 8 + 2] = out[i * 8 + 3] = g;
embeddedartists 0:b567d56a59d7 3047 out[i * 8 + 4] = out[i * 8 + 5] = b;
embeddedartists 0:b567d56a59d7 3048 out[i * 8 + 6] = out[i * 8 + 7] = a;
embeddedartists 0:b567d56a59d7 3049 }
embeddedartists 0:b567d56a59d7 3050 }
embeddedartists 0:b567d56a59d7 3051
embeddedartists 0:b567d56a59d7 3052 return 0; /*no error*/
embeddedartists 0:b567d56a59d7 3053 }
embeddedartists 0:b567d56a59d7 3054
embeddedartists 0:b567d56a59d7 3055 /*put a pixel, given its RGBA16 color, into image of any color 16-bitdepth type*/
embeddedartists 0:b567d56a59d7 3056 static unsigned rgba16ToPixel(unsigned char* out, size_t i,
embeddedartists 0:b567d56a59d7 3057 const LodePNGColorMode* mode,
embeddedartists 0:b567d56a59d7 3058 unsigned short r, unsigned short g, unsigned short b, unsigned short a)
embeddedartists 0:b567d56a59d7 3059 {
embeddedartists 0:b567d56a59d7 3060 if(mode->bitdepth != 16) return 85; /*must be 16 for this function*/
embeddedartists 0:b567d56a59d7 3061 if(mode->colortype == LCT_GREY)
embeddedartists 0:b567d56a59d7 3062 {
embeddedartists 0:b567d56a59d7 3063 unsigned short grey = r; /*((unsigned)r + g + b) / 3*/;
embeddedartists 0:b567d56a59d7 3064 out[i * 2 + 0] = (grey >> 8) & 255;
embeddedartists 0:b567d56a59d7 3065 out[i * 2 + 1] = grey & 255;
embeddedartists 0:b567d56a59d7 3066 }
embeddedartists 0:b567d56a59d7 3067 else if(mode->colortype == LCT_RGB)
embeddedartists 0:b567d56a59d7 3068 {
embeddedartists 0:b567d56a59d7 3069 out[i * 6 + 0] = (r >> 8) & 255;
embeddedartists 0:b567d56a59d7 3070 out[i * 6 + 1] = r & 255;
embeddedartists 0:b567d56a59d7 3071 out[i * 6 + 2] = (g >> 8) & 255;
embeddedartists 0:b567d56a59d7 3072 out[i * 6 + 3] = g & 255;
embeddedartists 0:b567d56a59d7 3073 out[i * 6 + 4] = (b >> 8) & 255;
embeddedartists 0:b567d56a59d7 3074 out[i * 6 + 5] = b & 255;
embeddedartists 0:b567d56a59d7 3075 }
embeddedartists 0:b567d56a59d7 3076 else if(mode->colortype == LCT_GREY_ALPHA)
embeddedartists 0:b567d56a59d7 3077 {
embeddedartists 0:b567d56a59d7 3078 unsigned short grey = r; /*((unsigned)r + g + b) / 3*/;
embeddedartists 0:b567d56a59d7 3079 out[i * 4 + 0] = (grey >> 8) & 255;
embeddedartists 0:b567d56a59d7 3080 out[i * 4 + 1] = grey & 255;
embeddedartists 0:b567d56a59d7 3081 out[i * 4 + 2] = (a >> 8) & 255;
embeddedartists 0:b567d56a59d7 3082 out[i * 4 + 3] = a & 255;
embeddedartists 0:b567d56a59d7 3083 }
embeddedartists 0:b567d56a59d7 3084 else if(mode->colortype == LCT_RGBA)
embeddedartists 0:b567d56a59d7 3085 {
embeddedartists 0:b567d56a59d7 3086 out[i * 8 + 0] = (r >> 8) & 255;
embeddedartists 0:b567d56a59d7 3087 out[i * 8 + 1] = r & 255;
embeddedartists 0:b567d56a59d7 3088 out[i * 8 + 2] = (g >> 8) & 255;
embeddedartists 0:b567d56a59d7 3089 out[i * 8 + 3] = g & 255;
embeddedartists 0:b567d56a59d7 3090 out[i * 8 + 4] = (b >> 8) & 255;
embeddedartists 0:b567d56a59d7 3091 out[i * 8 + 5] = b & 255;
embeddedartists 0:b567d56a59d7 3092 out[i * 8 + 6] = (a >> 8) & 255;
embeddedartists 0:b567d56a59d7 3093 out[i * 8 + 7] = a & 255;
embeddedartists 0:b567d56a59d7 3094 }
embeddedartists 0:b567d56a59d7 3095
embeddedartists 0:b567d56a59d7 3096 return 0; /*no error*/
embeddedartists 0:b567d56a59d7 3097 }
embeddedartists 0:b567d56a59d7 3098
embeddedartists 0:b567d56a59d7 3099 /*Get RGBA8 color of pixel with index i (y * width + x) from the raw image with given color type.*/
embeddedartists 0:b567d56a59d7 3100 static unsigned getPixelColorRGBA8(unsigned char* r, unsigned char* g,
embeddedartists 0:b567d56a59d7 3101 unsigned char* b, unsigned char* a,
embeddedartists 0:b567d56a59d7 3102 const unsigned char* in, size_t i,
embeddedartists 0:b567d56a59d7 3103 const LodePNGColorMode* mode,
embeddedartists 0:b567d56a59d7 3104 unsigned fix_png)
embeddedartists 0:b567d56a59d7 3105 {
embeddedartists 0:b567d56a59d7 3106 if(mode->colortype == LCT_GREY)
embeddedartists 0:b567d56a59d7 3107 {
embeddedartists 0:b567d56a59d7 3108 if(mode->bitdepth == 8)
embeddedartists 0:b567d56a59d7 3109 {
embeddedartists 0:b567d56a59d7 3110 *r = *g = *b = in[i];
embeddedartists 0:b567d56a59d7 3111 if(mode->key_defined && *r == mode->key_r) *a = 0;
embeddedartists 0:b567d56a59d7 3112 else *a = 255;
embeddedartists 0:b567d56a59d7 3113 }
embeddedartists 0:b567d56a59d7 3114 else if(mode->bitdepth == 16)
embeddedartists 0:b567d56a59d7 3115 {
embeddedartists 0:b567d56a59d7 3116 *r = *g = *b = in[i * 2 + 0];
embeddedartists 0:b567d56a59d7 3117 if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0;
embeddedartists 0:b567d56a59d7 3118 else *a = 255;
embeddedartists 0:b567d56a59d7 3119 }
embeddedartists 0:b567d56a59d7 3120 else
embeddedartists 0:b567d56a59d7 3121 {
embeddedartists 0:b567d56a59d7 3122 unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/
embeddedartists 0:b567d56a59d7 3123 size_t j = i * mode->bitdepth;
embeddedartists 0:b567d56a59d7 3124 unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth);
embeddedartists 0:b567d56a59d7 3125 *r = *g = *b = (value * 255) / highest;
embeddedartists 0:b567d56a59d7 3126 if(mode->key_defined && value == mode->key_r) *a = 0;
embeddedartists 0:b567d56a59d7 3127 else *a = 255;
embeddedartists 0:b567d56a59d7 3128 }
embeddedartists 0:b567d56a59d7 3129 }
embeddedartists 0:b567d56a59d7 3130 else if(mode->colortype == LCT_RGB)
embeddedartists 0:b567d56a59d7 3131 {
embeddedartists 0:b567d56a59d7 3132 if(mode->bitdepth == 8)
embeddedartists 0:b567d56a59d7 3133 {
embeddedartists 0:b567d56a59d7 3134 *r = in[i * 3 + 0]; *g = in[i * 3 + 1]; *b = in[i * 3 + 2];
embeddedartists 0:b567d56a59d7 3135 if(mode->key_defined && *r == mode->key_r && *g == mode->key_g && *b == mode->key_b) *a = 0;
embeddedartists 0:b567d56a59d7 3136 else *a = 255;
embeddedartists 0:b567d56a59d7 3137 }
embeddedartists 0:b567d56a59d7 3138 else
embeddedartists 0:b567d56a59d7 3139 {
embeddedartists 0:b567d56a59d7 3140 *r = in[i * 6 + 0];
embeddedartists 0:b567d56a59d7 3141 *g = in[i * 6 + 2];
embeddedartists 0:b567d56a59d7 3142 *b = in[i * 6 + 4];
embeddedartists 0:b567d56a59d7 3143 if(mode->key_defined && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r
embeddedartists 0:b567d56a59d7 3144 && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g
embeddedartists 0:b567d56a59d7 3145 && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0;
embeddedartists 0:b567d56a59d7 3146 else *a = 255;
embeddedartists 0:b567d56a59d7 3147 }
embeddedartists 0:b567d56a59d7 3148 }
embeddedartists 0:b567d56a59d7 3149 else if(mode->colortype == LCT_PALETTE)
embeddedartists 0:b567d56a59d7 3150 {
embeddedartists 0:b567d56a59d7 3151 unsigned index;
embeddedartists 0:b567d56a59d7 3152 if(mode->bitdepth == 8) index = in[i];
embeddedartists 0:b567d56a59d7 3153 else
embeddedartists 0:b567d56a59d7 3154 {
embeddedartists 0:b567d56a59d7 3155 size_t j = i * mode->bitdepth;
embeddedartists 0:b567d56a59d7 3156 index = readBitsFromReversedStream(&j, in, mode->bitdepth);
embeddedartists 0:b567d56a59d7 3157 }
embeddedartists 0:b567d56a59d7 3158
embeddedartists 0:b567d56a59d7 3159 if(index >= mode->palettesize)
embeddedartists 0:b567d56a59d7 3160 {
embeddedartists 0:b567d56a59d7 3161 /*This is an error according to the PNG spec, but fix_png can ignore it*/
embeddedartists 0:b567d56a59d7 3162 if(!fix_png) return (mode->bitdepth == 8 ? 46 : 47); /*index out of palette*/
embeddedartists 0:b567d56a59d7 3163 *r = *g = *b = 0;
embeddedartists 0:b567d56a59d7 3164 *a = 255;
embeddedartists 0:b567d56a59d7 3165 }
embeddedartists 0:b567d56a59d7 3166 else
embeddedartists 0:b567d56a59d7 3167 {
embeddedartists 0:b567d56a59d7 3168 *r = mode->palette[index * 4 + 0];
embeddedartists 0:b567d56a59d7 3169 *g = mode->palette[index * 4 + 1];
embeddedartists 0:b567d56a59d7 3170 *b = mode->palette[index * 4 + 2];
embeddedartists 0:b567d56a59d7 3171 *a = mode->palette[index * 4 + 3];
embeddedartists 0:b567d56a59d7 3172 }
embeddedartists 0:b567d56a59d7 3173 }
embeddedartists 0:b567d56a59d7 3174 else if(mode->colortype == LCT_GREY_ALPHA)
embeddedartists 0:b567d56a59d7 3175 {
embeddedartists 0:b567d56a59d7 3176 if(mode->bitdepth == 8)
embeddedartists 0:b567d56a59d7 3177 {
embeddedartists 0:b567d56a59d7 3178 *r = *g = *b = in[i * 2 + 0];
embeddedartists 0:b567d56a59d7 3179 *a = in[i * 2 + 1];
embeddedartists 0:b567d56a59d7 3180 }
embeddedartists 0:b567d56a59d7 3181 else
embeddedartists 0:b567d56a59d7 3182 {
embeddedartists 0:b567d56a59d7 3183 *r = *g = *b = in[i * 4 + 0];
embeddedartists 0:b567d56a59d7 3184 *a = in[i * 4 + 2];
embeddedartists 0:b567d56a59d7 3185 }
embeddedartists 0:b567d56a59d7 3186 }
embeddedartists 0:b567d56a59d7 3187 else if(mode->colortype == LCT_RGBA)
embeddedartists 0:b567d56a59d7 3188 {
embeddedartists 0:b567d56a59d7 3189 if(mode->bitdepth == 8)
embeddedartists 0:b567d56a59d7 3190 {
embeddedartists 0:b567d56a59d7 3191 *r = in[i * 4 + 0];
embeddedartists 0:b567d56a59d7 3192 *g = in[i * 4 + 1];
embeddedartists 0:b567d56a59d7 3193 *b = in[i * 4 + 2];
embeddedartists 0:b567d56a59d7 3194 *a = in[i * 4 + 3];
embeddedartists 0:b567d56a59d7 3195 }
embeddedartists 0:b567d56a59d7 3196 else
embeddedartists 0:b567d56a59d7 3197 {
embeddedartists 0:b567d56a59d7 3198 *r = in[i * 8 + 0];
embeddedartists 0:b567d56a59d7 3199 *g = in[i * 8 + 2];
embeddedartists 0:b567d56a59d7 3200 *b = in[i * 8 + 4];
embeddedartists 0:b567d56a59d7 3201 *a = in[i * 8 + 6];
embeddedartists 0:b567d56a59d7 3202 }
embeddedartists 0:b567d56a59d7 3203 }
embeddedartists 0:b567d56a59d7 3204
embeddedartists 0:b567d56a59d7 3205 return 0; /*no error*/
embeddedartists 0:b567d56a59d7 3206 }
embeddedartists 0:b567d56a59d7 3207
embeddedartists 0:b567d56a59d7 3208 /*Similar to getPixelColorRGBA8, but with all the for loops inside of the color
embeddedartists 0:b567d56a59d7 3209 mode test cases, optimized to convert the colors much faster, when converting
embeddedartists 0:b567d56a59d7 3210 to RGBA or RGB with 8 bit per cannel. buffer must be RGBA or RGB output with
embeddedartists 0:b567d56a59d7 3211 enough memory, if has_alpha is true the output is RGBA. mode has the color mode
embeddedartists 0:b567d56a59d7 3212 of the input buffer.*/
embeddedartists 0:b567d56a59d7 3213 static unsigned getPixelColorsRGBA8(unsigned char* buffer, size_t numpixels,
embeddedartists 0:b567d56a59d7 3214 unsigned has_alpha, const unsigned char* in,
embeddedartists 0:b567d56a59d7 3215 const LodePNGColorMode* mode,
embeddedartists 0:b567d56a59d7 3216 unsigned fix_png)
embeddedartists 0:b567d56a59d7 3217 {
embeddedartists 0:b567d56a59d7 3218 unsigned num_channels = has_alpha ? 4 : 3;
embeddedartists 0:b567d56a59d7 3219 size_t i;
embeddedartists 0:b567d56a59d7 3220 if(mode->colortype == LCT_GREY)
embeddedartists 0:b567d56a59d7 3221 {
embeddedartists 0:b567d56a59d7 3222 if(mode->bitdepth == 8)
embeddedartists 0:b567d56a59d7 3223 {
embeddedartists 0:b567d56a59d7 3224 for(i = 0; i < numpixels; i++, buffer += num_channels)
embeddedartists 0:b567d56a59d7 3225 {
embeddedartists 0:b567d56a59d7 3226 buffer[0] = buffer[1] = buffer[2] = in[i];
embeddedartists 0:b567d56a59d7 3227 if(has_alpha) buffer[3] = mode->key_defined && in[i] == mode->key_r ? 0 : 255;
embeddedartists 0:b567d56a59d7 3228 }
embeddedartists 0:b567d56a59d7 3229 }
embeddedartists 0:b567d56a59d7 3230 else if(mode->bitdepth == 16)
embeddedartists 0:b567d56a59d7 3231 {
embeddedartists 0:b567d56a59d7 3232 for(i = 0; i < numpixels; i++, buffer += num_channels)
embeddedartists 0:b567d56a59d7 3233 {
embeddedartists 0:b567d56a59d7 3234 buffer[0] = buffer[1] = buffer[2] = in[i * 2];
embeddedartists 0:b567d56a59d7 3235 if(has_alpha) buffer[3] = mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r ? 0 : 255;
embeddedartists 0:b567d56a59d7 3236 }
embeddedartists 0:b567d56a59d7 3237 }
embeddedartists 0:b567d56a59d7 3238 else
embeddedartists 0:b567d56a59d7 3239 {
embeddedartists 0:b567d56a59d7 3240 unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/
embeddedartists 0:b567d56a59d7 3241 size_t j = 0;
embeddedartists 0:b567d56a59d7 3242 for(i = 0; i < numpixels; i++, buffer += num_channels)
embeddedartists 0:b567d56a59d7 3243 {
embeddedartists 0:b567d56a59d7 3244 unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth);
embeddedartists 0:b567d56a59d7 3245 buffer[0] = buffer[1] = buffer[2] = (value * 255) / highest;
embeddedartists 0:b567d56a59d7 3246 if(has_alpha) buffer[3] = mode->key_defined && value == mode->key_r ? 0 : 255;
embeddedartists 0:b567d56a59d7 3247 }
embeddedartists 0:b567d56a59d7 3248 }
embeddedartists 0:b567d56a59d7 3249 }
embeddedartists 0:b567d56a59d7 3250 else if(mode->colortype == LCT_RGB)
embeddedartists 0:b567d56a59d7 3251 {
embeddedartists 0:b567d56a59d7 3252 if(mode->bitdepth == 8)
embeddedartists 0:b567d56a59d7 3253 {
embeddedartists 0:b567d56a59d7 3254 for(i = 0; i < numpixels; i++, buffer += num_channels)
embeddedartists 0:b567d56a59d7 3255 {
embeddedartists 0:b567d56a59d7 3256 buffer[0] = in[i * 3 + 0];
embeddedartists 0:b567d56a59d7 3257 buffer[1] = in[i * 3 + 1];
embeddedartists 0:b567d56a59d7 3258 buffer[2] = in[i * 3 + 2];
embeddedartists 0:b567d56a59d7 3259 if(has_alpha) buffer[3] = mode->key_defined && buffer[0] == mode->key_r
embeddedartists 0:b567d56a59d7 3260 && buffer[1]== mode->key_g && buffer[2] == mode->key_b ? 0 : 255;
embeddedartists 0:b567d56a59d7 3261 }
embeddedartists 0:b567d56a59d7 3262 }
embeddedartists 0:b567d56a59d7 3263 else
embeddedartists 0:b567d56a59d7 3264 {
embeddedartists 0:b567d56a59d7 3265 for(i = 0; i < numpixels; i++, buffer += num_channels)
embeddedartists 0:b567d56a59d7 3266 {
embeddedartists 0:b567d56a59d7 3267 buffer[0] = in[i * 6 + 0];
embeddedartists 0:b567d56a59d7 3268 buffer[1] = in[i * 6 + 2];
embeddedartists 0:b567d56a59d7 3269 buffer[2] = in[i * 6 + 4];
embeddedartists 0:b567d56a59d7 3270 if(has_alpha) buffer[3] = mode->key_defined
embeddedartists 0:b567d56a59d7 3271 && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r
embeddedartists 0:b567d56a59d7 3272 && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g
embeddedartists 0:b567d56a59d7 3273 && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b ? 0 : 255;
embeddedartists 0:b567d56a59d7 3274 }
embeddedartists 0:b567d56a59d7 3275 }
embeddedartists 0:b567d56a59d7 3276 }
embeddedartists 0:b567d56a59d7 3277 else if(mode->colortype == LCT_PALETTE)
embeddedartists 0:b567d56a59d7 3278 {
embeddedartists 0:b567d56a59d7 3279 unsigned index;
embeddedartists 0:b567d56a59d7 3280 size_t j = 0;
embeddedartists 0:b567d56a59d7 3281 for(i = 0; i < numpixels; i++, buffer += num_channels)
embeddedartists 0:b567d56a59d7 3282 {
embeddedartists 0:b567d56a59d7 3283 if(mode->bitdepth == 8) index = in[i];
embeddedartists 0:b567d56a59d7 3284 else index = readBitsFromReversedStream(&j, in, mode->bitdepth);
embeddedartists 0:b567d56a59d7 3285
embeddedartists 0:b567d56a59d7 3286 if(index >= mode->palettesize)
embeddedartists 0:b567d56a59d7 3287 {
embeddedartists 0:b567d56a59d7 3288 /*This is an error according to the PNG spec, but fix_png can ignore it*/
embeddedartists 0:b567d56a59d7 3289 if(!fix_png) return (mode->bitdepth == 8 ? 46 : 47); /*index out of palette*/
embeddedartists 0:b567d56a59d7 3290 buffer[0] = buffer[1] = buffer[2] = 0;
embeddedartists 0:b567d56a59d7 3291 if(has_alpha) buffer[3] = 255;
embeddedartists 0:b567d56a59d7 3292 }
embeddedartists 0:b567d56a59d7 3293 else
embeddedartists 0:b567d56a59d7 3294 {
embeddedartists 0:b567d56a59d7 3295 buffer[0] = mode->palette[index * 4 + 0];
embeddedartists 0:b567d56a59d7 3296 buffer[1] = mode->palette[index * 4 + 1];
embeddedartists 0:b567d56a59d7 3297 buffer[2] = mode->palette[index * 4 + 2];
embeddedartists 0:b567d56a59d7 3298 if(has_alpha) buffer[3] = mode->palette[index * 4 + 3];
embeddedartists 0:b567d56a59d7 3299 }
embeddedartists 0:b567d56a59d7 3300 }
embeddedartists 0:b567d56a59d7 3301 }
embeddedartists 0:b567d56a59d7 3302 else if(mode->colortype == LCT_GREY_ALPHA)
embeddedartists 0:b567d56a59d7 3303 {
embeddedartists 0:b567d56a59d7 3304 if(mode->bitdepth == 8)
embeddedartists 0:b567d56a59d7 3305 {
embeddedartists 0:b567d56a59d7 3306 for(i = 0; i < numpixels; i++, buffer += num_channels)
embeddedartists 0:b567d56a59d7 3307 {
embeddedartists 0:b567d56a59d7 3308 buffer[0] = buffer[1] = buffer[2] = in[i * 2 + 0];
embeddedartists 0:b567d56a59d7 3309 if(has_alpha) buffer[3] = in[i * 2 + 1];
embeddedartists 0:b567d56a59d7 3310 }
embeddedartists 0:b567d56a59d7 3311 }
embeddedartists 0:b567d56a59d7 3312 else
embeddedartists 0:b567d56a59d7 3313 {
embeddedartists 0:b567d56a59d7 3314 for(i = 0; i < numpixels; i++, buffer += num_channels)
embeddedartists 0:b567d56a59d7 3315 {
embeddedartists 0:b567d56a59d7 3316 buffer[0] = buffer[1] = buffer[2] = in[i * 4 + 0];
embeddedartists 0:b567d56a59d7 3317 if(has_alpha) buffer[3] = in[i * 4 + 2];
embeddedartists 0:b567d56a59d7 3318 }
embeddedartists 0:b567d56a59d7 3319 }
embeddedartists 0:b567d56a59d7 3320 }
embeddedartists 0:b567d56a59d7 3321 else if(mode->colortype == LCT_RGBA)
embeddedartists 0:b567d56a59d7 3322 {
embeddedartists 0:b567d56a59d7 3323 if(mode->bitdepth == 8)
embeddedartists 0:b567d56a59d7 3324 {
embeddedartists 0:b567d56a59d7 3325 for(i = 0; i < numpixels; i++, buffer += num_channels)
embeddedartists 0:b567d56a59d7 3326 {
embeddedartists 0:b567d56a59d7 3327 buffer[0] = in[i * 4 + 0];
embeddedartists 0:b567d56a59d7 3328 buffer[1] = in[i * 4 + 1];
embeddedartists 0:b567d56a59d7 3329 buffer[2] = in[i * 4 + 2];
embeddedartists 0:b567d56a59d7 3330 if(has_alpha) buffer[3] = in[i * 4 + 3];
embeddedartists 0:b567d56a59d7 3331 }
embeddedartists 0:b567d56a59d7 3332 }
embeddedartists 0:b567d56a59d7 3333 else
embeddedartists 0:b567d56a59d7 3334 {
embeddedartists 0:b567d56a59d7 3335 for(i = 0; i < numpixels; i++, buffer += num_channels)
embeddedartists 0:b567d56a59d7 3336 {
embeddedartists 0:b567d56a59d7 3337 buffer[0] = in[i * 8 + 0];
embeddedartists 0:b567d56a59d7 3338 buffer[1] = in[i * 8 + 2];
embeddedartists 0:b567d56a59d7 3339 buffer[2] = in[i * 8 + 4];
embeddedartists 0:b567d56a59d7 3340 if(has_alpha) buffer[3] = in[i * 8 + 6];
embeddedartists 0:b567d56a59d7 3341 }
embeddedartists 0:b567d56a59d7 3342 }
embeddedartists 0:b567d56a59d7 3343 }
embeddedartists 0:b567d56a59d7 3344
embeddedartists 0:b567d56a59d7 3345 return 0; /*no error*/
embeddedartists 0:b567d56a59d7 3346 }
embeddedartists 0:b567d56a59d7 3347
embeddedartists 0:b567d56a59d7 3348 /*Get RGBA16 color of pixel with index i (y * width + x) from the raw image with
embeddedartists 0:b567d56a59d7 3349 given color type, but the given color type must be 16-bit itself.*/
embeddedartists 0:b567d56a59d7 3350 static unsigned getPixelColorRGBA16(unsigned short* r, unsigned short* g, unsigned short* b, unsigned short* a,
embeddedartists 0:b567d56a59d7 3351 const unsigned char* in, size_t i, const LodePNGColorMode* mode)
embeddedartists 0:b567d56a59d7 3352 {
embeddedartists 0:b567d56a59d7 3353 if(mode->bitdepth != 16) return 85; /*error: this function only supports 16-bit input*/
embeddedartists 0:b567d56a59d7 3354
embeddedartists 0:b567d56a59d7 3355 if(mode->colortype == LCT_GREY)
embeddedartists 0:b567d56a59d7 3356 {
embeddedartists 0:b567d56a59d7 3357 *r = *g = *b = 256 * in[i * 2 + 0] + in[i * 2 + 1];
embeddedartists 0:b567d56a59d7 3358 if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0;
embeddedartists 0:b567d56a59d7 3359 else *a = 65535;
embeddedartists 0:b567d56a59d7 3360 }
embeddedartists 0:b567d56a59d7 3361 else if(mode->colortype == LCT_RGB)
embeddedartists 0:b567d56a59d7 3362 {
embeddedartists 0:b567d56a59d7 3363 *r = 256 * in[i * 6 + 0] + in[i * 6 + 1];
embeddedartists 0:b567d56a59d7 3364 *g = 256 * in[i * 6 + 2] + in[i * 6 + 3];
embeddedartists 0:b567d56a59d7 3365 *b = 256 * in[i * 6 + 4] + in[i * 6 + 5];
embeddedartists 0:b567d56a59d7 3366 if(mode->key_defined && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r
embeddedartists 0:b567d56a59d7 3367 && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g
embeddedartists 0:b567d56a59d7 3368 && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0;
embeddedartists 0:b567d56a59d7 3369 else *a = 65535;
embeddedartists 0:b567d56a59d7 3370 }
embeddedartists 0:b567d56a59d7 3371 else if(mode->colortype == LCT_GREY_ALPHA)
embeddedartists 0:b567d56a59d7 3372 {
embeddedartists 0:b567d56a59d7 3373 *r = *g = *b = 256 * in[i * 4 + 0] + in[i * 4 + 1];
embeddedartists 0:b567d56a59d7 3374 *a = 256 * in[i * 4 + 2] + in[i * 4 + 3];
embeddedartists 0:b567d56a59d7 3375 }
embeddedartists 0:b567d56a59d7 3376 else if(mode->colortype == LCT_RGBA)
embeddedartists 0:b567d56a59d7 3377 {
embeddedartists 0:b567d56a59d7 3378 *r = 256 * in[i * 8 + 0] + in[i * 8 + 1];
embeddedartists 0:b567d56a59d7 3379 *g = 256 * in[i * 8 + 2] + in[i * 8 + 3];
embeddedartists 0:b567d56a59d7 3380 *b = 256 * in[i * 8 + 4] + in[i * 8 + 5];
embeddedartists 0:b567d56a59d7 3381 *a = 256 * in[i * 8 + 6] + in[i * 8 + 7];
embeddedartists 0:b567d56a59d7 3382 }
embeddedartists 0:b567d56a59d7 3383 else return 85; /*error: this function only supports 16-bit input, not palettes*/
embeddedartists 0:b567d56a59d7 3384
embeddedartists 0:b567d56a59d7 3385 return 0; /*no error*/
embeddedartists 0:b567d56a59d7 3386 }
embeddedartists 0:b567d56a59d7 3387
embeddedartists 0:b567d56a59d7 3388 /*
embeddedartists 0:b567d56a59d7 3389 converts from any color type to 24-bit or 32-bit (later maybe more supported). return value = LodePNG error code
embeddedartists 0:b567d56a59d7 3390 the out buffer must have (w * h * bpp + 7) / 8 bytes, where bpp is the bits per pixel of the output color type
embeddedartists 0:b567d56a59d7 3391 (lodepng_get_bpp) for < 8 bpp images, there may _not_ be padding bits at the end of scanlines.
embeddedartists 0:b567d56a59d7 3392 */
embeddedartists 0:b567d56a59d7 3393 unsigned lodepng_convert(unsigned char* out, const unsigned char* in,
embeddedartists 0:b567d56a59d7 3394 LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in,
embeddedartists 0:b567d56a59d7 3395 unsigned w, unsigned h, unsigned fix_png)
embeddedartists 0:b567d56a59d7 3396 {
embeddedartists 0:b567d56a59d7 3397 unsigned error = 0;
embeddedartists 0:b567d56a59d7 3398 size_t i;
embeddedartists 0:b567d56a59d7 3399 ColorTree tree;
embeddedartists 0:b567d56a59d7 3400 size_t numpixels = w * h;
embeddedartists 0:b567d56a59d7 3401
embeddedartists 0:b567d56a59d7 3402 if(lodepng_color_mode_equal(mode_out, mode_in))
embeddedartists 0:b567d56a59d7 3403 {
embeddedartists 0:b567d56a59d7 3404 size_t numbytes = lodepng_get_raw_size(w, h, mode_in);
embeddedartists 0:b567d56a59d7 3405 for(i = 0; i < numbytes; i++) out[i] = in[i];
embeddedartists 0:b567d56a59d7 3406 return error;
embeddedartists 0:b567d56a59d7 3407 }
embeddedartists 0:b567d56a59d7 3408
embeddedartists 0:b567d56a59d7 3409 if(mode_out->colortype == LCT_PALETTE)
embeddedartists 0:b567d56a59d7 3410 {
embeddedartists 0:b567d56a59d7 3411 size_t palsize = 1 << mode_out->bitdepth;
embeddedartists 0:b567d56a59d7 3412 if(mode_out->palettesize < palsize) palsize = mode_out->palettesize;
embeddedartists 0:b567d56a59d7 3413 color_tree_init(&tree);
embeddedartists 0:b567d56a59d7 3414 for(i = 0; i < palsize; i++)
embeddedartists 0:b567d56a59d7 3415 {
embeddedartists 0:b567d56a59d7 3416 unsigned char* p = &mode_out->palette[i * 4];
embeddedartists 0:b567d56a59d7 3417 color_tree_add(&tree, p[0], p[1], p[2], p[3], i);
embeddedartists 0:b567d56a59d7 3418 }
embeddedartists 0:b567d56a59d7 3419 }
embeddedartists 0:b567d56a59d7 3420
embeddedartists 0:b567d56a59d7 3421 if(mode_in->bitdepth == 16 && mode_out->bitdepth == 16)
embeddedartists 0:b567d56a59d7 3422 {
embeddedartists 0:b567d56a59d7 3423 for(i = 0; i < numpixels; i++)
embeddedartists 0:b567d56a59d7 3424 {
embeddedartists 0:b567d56a59d7 3425 unsigned short r = 0, g = 0, b = 0, a = 0;
embeddedartists 0:b567d56a59d7 3426 error = getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in);
embeddedartists 0:b567d56a59d7 3427 if(error) break;
embeddedartists 0:b567d56a59d7 3428 error = rgba16ToPixel(out, i, mode_out, r, g, b, a);
embeddedartists 0:b567d56a59d7 3429 if(error) break;
embeddedartists 0:b567d56a59d7 3430 }
embeddedartists 0:b567d56a59d7 3431 }
embeddedartists 0:b567d56a59d7 3432 else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGBA)
embeddedartists 0:b567d56a59d7 3433 {
embeddedartists 0:b567d56a59d7 3434 error = getPixelColorsRGBA8(out, numpixels, 1, in, mode_in, fix_png);
embeddedartists 0:b567d56a59d7 3435 }
embeddedartists 0:b567d56a59d7 3436 else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGB)
embeddedartists 0:b567d56a59d7 3437 {
embeddedartists 0:b567d56a59d7 3438 error = getPixelColorsRGBA8(out, numpixels, 0, in, mode_in, fix_png);
embeddedartists 0:b567d56a59d7 3439 }
embeddedartists 0:b567d56a59d7 3440 else
embeddedartists 0:b567d56a59d7 3441 {
embeddedartists 0:b567d56a59d7 3442 unsigned char r = 0, g = 0, b = 0, a = 0;
embeddedartists 0:b567d56a59d7 3443 for(i = 0; i < numpixels; i++)
embeddedartists 0:b567d56a59d7 3444 {
embeddedartists 0:b567d56a59d7 3445 error = getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in, fix_png);
embeddedartists 0:b567d56a59d7 3446 if(error) break;
embeddedartists 0:b567d56a59d7 3447 error = rgba8ToPixel(out, i, mode_out, &tree, r, g, b, a);
embeddedartists 0:b567d56a59d7 3448 if(error) break;
embeddedartists 0:b567d56a59d7 3449 }
embeddedartists 0:b567d56a59d7 3450 }
embeddedartists 0:b567d56a59d7 3451
embeddedartists 0:b567d56a59d7 3452 if(mode_out->colortype == LCT_PALETTE)
embeddedartists 0:b567d56a59d7 3453 {
embeddedartists 0:b567d56a59d7 3454 color_tree_cleanup(&tree);
embeddedartists 0:b567d56a59d7 3455 }
embeddedartists 0:b567d56a59d7 3456
embeddedartists 0:b567d56a59d7 3457 return error;
embeddedartists 0:b567d56a59d7 3458 }
embeddedartists 0:b567d56a59d7 3459
embeddedartists 0:b567d56a59d7 3460 #ifdef LODEPNG_COMPILE_ENCODER
embeddedartists 0:b567d56a59d7 3461
embeddedartists 0:b567d56a59d7 3462 typedef struct ColorProfile
embeddedartists 0:b567d56a59d7 3463 {
embeddedartists 0:b567d56a59d7 3464 unsigned char sixteenbit; /*needs more than 8 bits per channel*/
embeddedartists 0:b567d56a59d7 3465 unsigned char sixteenbit_done;
embeddedartists 0:b567d56a59d7 3466
embeddedartists 0:b567d56a59d7 3467
embeddedartists 0:b567d56a59d7 3468 unsigned char colored; /*not greyscale*/
embeddedartists 0:b567d56a59d7 3469 unsigned char colored_done;
embeddedartists 0:b567d56a59d7 3470
embeddedartists 0:b567d56a59d7 3471 unsigned char key; /*a color key is required, or more*/
embeddedartists 0:b567d56a59d7 3472 unsigned short key_r; /*these values are always in 16-bit bitdepth in the profile*/
embeddedartists 0:b567d56a59d7 3473 unsigned short key_g;
embeddedartists 0:b567d56a59d7 3474 unsigned short key_b;
embeddedartists 0:b567d56a59d7 3475 unsigned char alpha; /*alpha channel, or alpha palette, required*/
embeddedartists 0:b567d56a59d7 3476 unsigned char alpha_done;
embeddedartists 0:b567d56a59d7 3477
embeddedartists 0:b567d56a59d7 3478 unsigned numcolors;
embeddedartists 0:b567d56a59d7 3479 ColorTree tree; /*for listing the counted colors, up to 256*/
embeddedartists 0:b567d56a59d7 3480 unsigned char* palette; /*size 1024. Remember up to the first 256 RGBA colors*/
embeddedartists 0:b567d56a59d7 3481 unsigned maxnumcolors; /*if more than that amount counted*/
embeddedartists 0:b567d56a59d7 3482 unsigned char numcolors_done;
embeddedartists 0:b567d56a59d7 3483
embeddedartists 0:b567d56a59d7 3484 unsigned greybits; /*amount of bits required for greyscale (1, 2, 4, 8). Does not take 16 bit into account.*/
embeddedartists 0:b567d56a59d7 3485 unsigned char greybits_done;
embeddedartists 0:b567d56a59d7 3486
embeddedartists 0:b567d56a59d7 3487 } ColorProfile;
embeddedartists 0:b567d56a59d7 3488
embeddedartists 0:b567d56a59d7 3489 static void color_profile_init(ColorProfile* profile, const LodePNGColorMode* mode)
embeddedartists 0:b567d56a59d7 3490 {
embeddedartists 0:b567d56a59d7 3491 profile->sixteenbit = 0;
embeddedartists 0:b567d56a59d7 3492 profile->sixteenbit_done = mode->bitdepth == 16 ? 0 : 1;
embeddedartists 0:b567d56a59d7 3493
embeddedartists 0:b567d56a59d7 3494 profile->colored = 0;
embeddedartists 0:b567d56a59d7 3495 profile->colored_done = lodepng_is_greyscale_type(mode) ? 1 : 0;
embeddedartists 0:b567d56a59d7 3496
embeddedartists 0:b567d56a59d7 3497 profile->key = 0;
embeddedartists 0:b567d56a59d7 3498 profile->alpha = 0;
embeddedartists 0:b567d56a59d7 3499 profile->alpha_done = lodepng_can_have_alpha(mode) ? 0 : 1;
embeddedartists 0:b567d56a59d7 3500
embeddedartists 0:b567d56a59d7 3501 profile->numcolors = 0;
embeddedartists 0:b567d56a59d7 3502 color_tree_init(&profile->tree);
embeddedartists 0:b567d56a59d7 3503 profile->palette = (unsigned char*)lodepng_malloc(1024);
embeddedartists 0:b567d56a59d7 3504 profile->maxnumcolors = 257;
embeddedartists 0:b567d56a59d7 3505 if(lodepng_get_bpp(mode) <= 8)
embeddedartists 0:b567d56a59d7 3506 {
embeddedartists 0:b567d56a59d7 3507 int bpp = lodepng_get_bpp(mode);
embeddedartists 0:b567d56a59d7 3508 profile->maxnumcolors = bpp == 1 ? 2 : (bpp == 2 ? 4 : (bpp == 4 ? 16 : 256));
embeddedartists 0:b567d56a59d7 3509 }
embeddedartists 0:b567d56a59d7 3510 profile->numcolors_done = 0;
embeddedartists 0:b567d56a59d7 3511
embeddedartists 0:b567d56a59d7 3512 profile->greybits = 1;
embeddedartists 0:b567d56a59d7 3513 profile->greybits_done = lodepng_get_bpp(mode) == 1 ? 1 : 0;
embeddedartists 0:b567d56a59d7 3514 }
embeddedartists 0:b567d56a59d7 3515
embeddedartists 0:b567d56a59d7 3516 static void color_profile_cleanup(ColorProfile* profile)
embeddedartists 0:b567d56a59d7 3517 {
embeddedartists 0:b567d56a59d7 3518 color_tree_cleanup(&profile->tree);
embeddedartists 0:b567d56a59d7 3519 lodepng_free(profile->palette);
embeddedartists 0:b567d56a59d7 3520 }
embeddedartists 0:b567d56a59d7 3521
embeddedartists 0:b567d56a59d7 3522 /*function used for debug purposes with C++*/
embeddedartists 0:b567d56a59d7 3523 /*void printColorProfile(ColorProfile* p)
embeddedartists 0:b567d56a59d7 3524 {
embeddedartists 0:b567d56a59d7 3525 std::cout << "sixteenbit: " << (int)p->sixteenbit << std::endl;
embeddedartists 0:b567d56a59d7 3526 std::cout << "sixteenbit_done: " << (int)p->sixteenbit_done << std::endl;
embeddedartists 0:b567d56a59d7 3527 std::cout << "colored: " << (int)p->colored << std::endl;
embeddedartists 0:b567d56a59d7 3528 std::cout << "colored_done: " << (int)p->colored_done << std::endl;
embeddedartists 0:b567d56a59d7 3529 std::cout << "key: " << (int)p->key << std::endl;
embeddedartists 0:b567d56a59d7 3530 std::cout << "key_r: " << (int)p->key_r << std::endl;
embeddedartists 0:b567d56a59d7 3531 std::cout << "key_g: " << (int)p->key_g << std::endl;
embeddedartists 0:b567d56a59d7 3532 std::cout << "key_b: " << (int)p->key_b << std::endl;
embeddedartists 0:b567d56a59d7 3533 std::cout << "alpha: " << (int)p->alpha << std::endl;
embeddedartists 0:b567d56a59d7 3534 std::cout << "alpha_done: " << (int)p->alpha_done << std::endl;
embeddedartists 0:b567d56a59d7 3535 std::cout << "numcolors: " << (int)p->numcolors << std::endl;
embeddedartists 0:b567d56a59d7 3536 std::cout << "maxnumcolors: " << (int)p->maxnumcolors << std::endl;
embeddedartists 0:b567d56a59d7 3537 std::cout << "numcolors_done: " << (int)p->numcolors_done << std::endl;
embeddedartists 0:b567d56a59d7 3538 std::cout << "greybits: " << (int)p->greybits << std::endl;
embeddedartists 0:b567d56a59d7 3539 std::cout << "greybits_done: " << (int)p->greybits_done << std::endl;
embeddedartists 0:b567d56a59d7 3540 }*/
embeddedartists 0:b567d56a59d7 3541
embeddedartists 0:b567d56a59d7 3542 /*Returns how many bits needed to represent given value (max 8 bit)*/
embeddedartists 0:b567d56a59d7 3543 unsigned getValueRequiredBits(unsigned short value)
embeddedartists 0:b567d56a59d7 3544 {
embeddedartists 0:b567d56a59d7 3545 if(value == 0 || value == 255) return 1;
embeddedartists 0:b567d56a59d7 3546 /*The scaling of 2-bit and 4-bit values uses multiples of 85 and 17*/
embeddedartists 0:b567d56a59d7 3547 if(value % 17 == 0) return value % 85 == 0 ? 2 : 4;
embeddedartists 0:b567d56a59d7 3548 return 8;
embeddedartists 0:b567d56a59d7 3549 }
embeddedartists 0:b567d56a59d7 3550
embeddedartists 0:b567d56a59d7 3551 /*profile must already have been inited with mode.
embeddedartists 0:b567d56a59d7 3552 It's ok to set some parameters of profile to done already.*/
embeddedartists 0:b567d56a59d7 3553 static unsigned get_color_profile(ColorProfile* profile,
embeddedartists 0:b567d56a59d7 3554 const unsigned char* in,
embeddedartists 0:b567d56a59d7 3555 size_t numpixels /*must be full image size, for certain filesize based choices*/,
embeddedartists 0:b567d56a59d7 3556 const LodePNGColorMode* mode,
embeddedartists 0:b567d56a59d7 3557 unsigned fix_png)
embeddedartists 0:b567d56a59d7 3558 {
embeddedartists 0:b567d56a59d7 3559 unsigned error = 0;
embeddedartists 0:b567d56a59d7 3560 size_t i;
embeddedartists 0:b567d56a59d7 3561
embeddedartists 0:b567d56a59d7 3562 if(mode->bitdepth == 16)
embeddedartists 0:b567d56a59d7 3563 {
embeddedartists 0:b567d56a59d7 3564 for(i = 0; i < numpixels; i++)
embeddedartists 0:b567d56a59d7 3565 {
embeddedartists 0:b567d56a59d7 3566 unsigned short r, g, b, a;
embeddedartists 0:b567d56a59d7 3567 error = getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode);
embeddedartists 0:b567d56a59d7 3568 if(error) break;
embeddedartists 0:b567d56a59d7 3569
embeddedartists 0:b567d56a59d7 3570 /*a color is considered good for 8-bit if the first byte and the second byte are equal,
embeddedartists 0:b567d56a59d7 3571 (so if it's divisible through 257), NOT necessarily if the second byte is 0*/
embeddedartists 0:b567d56a59d7 3572 if(!profile->sixteenbit_done
embeddedartists 0:b567d56a59d7 3573 && (((r & 255) != ((r >> 8) & 255))
embeddedartists 0:b567d56a59d7 3574 || ((g & 255) != ((g >> 8) & 255))
embeddedartists 0:b567d56a59d7 3575 || ((b & 255) != ((b >> 8) & 255))))
embeddedartists 0:b567d56a59d7 3576 {
embeddedartists 0:b567d56a59d7 3577 profile->sixteenbit = 1;
embeddedartists 0:b567d56a59d7 3578 profile->sixteenbit_done = 1;
embeddedartists 0:b567d56a59d7 3579 profile->greybits_done = 1; /*greybits is not applicable anymore at 16-bit*/
embeddedartists 0:b567d56a59d7 3580 profile->numcolors_done = 1; /*counting colors no longer useful, palette doesn't support 16-bit*/
embeddedartists 0:b567d56a59d7 3581 }
embeddedartists 0:b567d56a59d7 3582
embeddedartists 0:b567d56a59d7 3583 if(!profile->colored_done && (r != g || r != b))
embeddedartists 0:b567d56a59d7 3584 {
embeddedartists 0:b567d56a59d7 3585 profile->colored = 1;
embeddedartists 0:b567d56a59d7 3586 profile->colored_done = 1;
embeddedartists 0:b567d56a59d7 3587 profile->greybits_done = 1; /*greybits is not applicable anymore*/
embeddedartists 0:b567d56a59d7 3588 }
embeddedartists 0:b567d56a59d7 3589
embeddedartists 0:b567d56a59d7 3590 if(!profile->alpha_done && a != 65535)
embeddedartists 0:b567d56a59d7 3591 {
embeddedartists 0:b567d56a59d7 3592 /*only use color key if numpixels large enough to justify tRNS chunk size*/
embeddedartists 0:b567d56a59d7 3593 if(a == 0 && numpixels > 16 && !(profile->key && (r != profile->key_r || g != profile->key_g || b != profile->key_b)))
embeddedartists 0:b567d56a59d7 3594 {
embeddedartists 0:b567d56a59d7 3595 if(!profile->alpha && !profile->key)
embeddedartists 0:b567d56a59d7 3596 {
embeddedartists 0:b567d56a59d7 3597 profile->key = 1;
embeddedartists 0:b567d56a59d7 3598 profile->key_r = r;
embeddedartists 0:b567d56a59d7 3599 profile->key_g = g;
embeddedartists 0:b567d56a59d7 3600 profile->key_b = b;
embeddedartists 0:b567d56a59d7 3601 }
embeddedartists 0:b567d56a59d7 3602 }
embeddedartists 0:b567d56a59d7 3603 else
embeddedartists 0:b567d56a59d7 3604 {
embeddedartists 0:b567d56a59d7 3605 profile->alpha = 1;
embeddedartists 0:b567d56a59d7 3606 profile->alpha_done = 1;
embeddedartists 0:b567d56a59d7 3607 profile->greybits_done = 1; /*greybits is not applicable anymore*/
embeddedartists 0:b567d56a59d7 3608 }
embeddedartists 0:b567d56a59d7 3609 }
embeddedartists 0:b567d56a59d7 3610
embeddedartists 0:b567d56a59d7 3611 /* Color key cannot be used if an opaque pixel also has that RGB color. */
embeddedartists 0:b567d56a59d7 3612 if(!profile->alpha_done && a == 65535 && profile->key
embeddedartists 0:b567d56a59d7 3613 && r == profile->key_r && g == profile->key_g && b == profile->key_b)
embeddedartists 0:b567d56a59d7 3614 {
embeddedartists 0:b567d56a59d7 3615 profile->alpha = 1;
embeddedartists 0:b567d56a59d7 3616 profile->alpha_done = 1;
embeddedartists 0:b567d56a59d7 3617 profile->greybits_done = 1; /*greybits is not applicable anymore*/
embeddedartists 0:b567d56a59d7 3618 }
embeddedartists 0:b567d56a59d7 3619
embeddedartists 0:b567d56a59d7 3620 if(!profile->greybits_done)
embeddedartists 0:b567d56a59d7 3621 {
embeddedartists 0:b567d56a59d7 3622 /*assuming 8-bit r, this test does not care about 16-bit*/
embeddedartists 0:b567d56a59d7 3623 unsigned bits = getValueRequiredBits(r);
embeddedartists 0:b567d56a59d7 3624 if(bits > profile->greybits) profile->greybits = bits;
embeddedartists 0:b567d56a59d7 3625 if(profile->greybits >= 8) profile->greybits_done = 1;
embeddedartists 0:b567d56a59d7 3626 }
embeddedartists 0:b567d56a59d7 3627
embeddedartists 0:b567d56a59d7 3628 if(!profile->numcolors_done)
embeddedartists 0:b567d56a59d7 3629 {
embeddedartists 0:b567d56a59d7 3630 /*assuming 8-bit rgba, this test does not care about 16-bit*/
embeddedartists 0:b567d56a59d7 3631 if(!color_tree_has(&profile->tree, (unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a))
embeddedartists 0:b567d56a59d7 3632 {
embeddedartists 0:b567d56a59d7 3633 color_tree_add(&profile->tree, (unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a,
embeddedartists 0:b567d56a59d7 3634 profile->numcolors);
embeddedartists 0:b567d56a59d7 3635 if(profile->numcolors < 256)
embeddedartists 0:b567d56a59d7 3636 {
embeddedartists 0:b567d56a59d7 3637 unsigned char* p = profile->palette;
embeddedartists 0:b567d56a59d7 3638 unsigned i = profile->numcolors;
embeddedartists 0:b567d56a59d7 3639 p[i * 4 + 0] = (unsigned char)r;
embeddedartists 0:b567d56a59d7 3640 p[i * 4 + 1] = (unsigned char)g;
embeddedartists 0:b567d56a59d7 3641 p[i * 4 + 2] = (unsigned char)b;
embeddedartists 0:b567d56a59d7 3642 p[i * 4 + 3] = (unsigned char)a;
embeddedartists 0:b567d56a59d7 3643 }
embeddedartists 0:b567d56a59d7 3644 profile->numcolors++;
embeddedartists 0:b567d56a59d7 3645 if(profile->numcolors >= profile->maxnumcolors) profile->numcolors_done = 1;
embeddedartists 0:b567d56a59d7 3646 }
embeddedartists 0:b567d56a59d7 3647 }
embeddedartists 0:b567d56a59d7 3648
embeddedartists 0:b567d56a59d7 3649 if(profile->alpha_done && profile->numcolors_done
embeddedartists 0:b567d56a59d7 3650 && profile->colored_done && profile->sixteenbit_done && profile->greybits_done)
embeddedartists 0:b567d56a59d7 3651 {
embeddedartists 0:b567d56a59d7 3652 break;
embeddedartists 0:b567d56a59d7 3653 }
embeddedartists 0:b567d56a59d7 3654 };
embeddedartists 0:b567d56a59d7 3655 }
embeddedartists 0:b567d56a59d7 3656 else /* < 16-bit */
embeddedartists 0:b567d56a59d7 3657 {
embeddedartists 0:b567d56a59d7 3658 for(i = 0; i < numpixels; i++)
embeddedartists 0:b567d56a59d7 3659 {
embeddedartists 0:b567d56a59d7 3660 unsigned char r = 0, g = 0, b = 0, a = 0;
embeddedartists 0:b567d56a59d7 3661 error = getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode, fix_png);
embeddedartists 0:b567d56a59d7 3662 if(error) break;
embeddedartists 0:b567d56a59d7 3663
embeddedartists 0:b567d56a59d7 3664 if(!profile->colored_done && (r != g || r != b))
embeddedartists 0:b567d56a59d7 3665 {
embeddedartists 0:b567d56a59d7 3666 profile->colored = 1;
embeddedartists 0:b567d56a59d7 3667 profile->colored_done = 1;
embeddedartists 0:b567d56a59d7 3668 profile->greybits_done = 1; /*greybits is not applicable anymore*/
embeddedartists 0:b567d56a59d7 3669 }
embeddedartists 0:b567d56a59d7 3670
embeddedartists 0:b567d56a59d7 3671 if(!profile->alpha_done && a != 255)
embeddedartists 0:b567d56a59d7 3672 {
embeddedartists 0:b567d56a59d7 3673 if(a == 0 && !(profile->key && (r != profile->key_r || g != profile->key_g || b != profile->key_b)))
embeddedartists 0:b567d56a59d7 3674 {
embeddedartists 0:b567d56a59d7 3675 if(!profile->key)
embeddedartists 0:b567d56a59d7 3676 {
embeddedartists 0:b567d56a59d7 3677 profile->key = 1;
embeddedartists 0:b567d56a59d7 3678 profile->key_r = r;
embeddedartists 0:b567d56a59d7 3679 profile->key_g = g;
embeddedartists 0:b567d56a59d7 3680 profile->key_b = b;
embeddedartists 0:b567d56a59d7 3681 }
embeddedartists 0:b567d56a59d7 3682 }
embeddedartists 0:b567d56a59d7 3683 else
embeddedartists 0:b567d56a59d7 3684 {
embeddedartists 0:b567d56a59d7 3685 profile->alpha = 1;
embeddedartists 0:b567d56a59d7 3686 profile->alpha_done = 1;
embeddedartists 0:b567d56a59d7 3687 profile->greybits_done = 1; /*greybits is not applicable anymore*/
embeddedartists 0:b567d56a59d7 3688 }
embeddedartists 0:b567d56a59d7 3689 }
embeddedartists 0:b567d56a59d7 3690
embeddedartists 0:b567d56a59d7 3691 /* Color key cannot be used if an opaque pixel also has that RGB color. */
embeddedartists 0:b567d56a59d7 3692 if(!profile->alpha_done && a == 255 && profile->key
embeddedartists 0:b567d56a59d7 3693 && r == profile->key_r && g == profile->key_g && b == profile->key_b)
embeddedartists 0:b567d56a59d7 3694 {
embeddedartists 0:b567d56a59d7 3695 profile->alpha = 1;
embeddedartists 0:b567d56a59d7 3696 profile->alpha_done = 1;
embeddedartists 0:b567d56a59d7 3697 profile->greybits_done = 1; /*greybits is not applicable anymore*/
embeddedartists 0:b567d56a59d7 3698 }
embeddedartists 0:b567d56a59d7 3699
embeddedartists 0:b567d56a59d7 3700 if(!profile->greybits_done)
embeddedartists 0:b567d56a59d7 3701 {
embeddedartists 0:b567d56a59d7 3702 unsigned bits = getValueRequiredBits(r);
embeddedartists 0:b567d56a59d7 3703 if(bits > profile->greybits) profile->greybits = bits;
embeddedartists 0:b567d56a59d7 3704 if(profile->greybits >= 8) profile->greybits_done = 1;
embeddedartists 0:b567d56a59d7 3705 }
embeddedartists 0:b567d56a59d7 3706
embeddedartists 0:b567d56a59d7 3707 if(!profile->numcolors_done)
embeddedartists 0:b567d56a59d7 3708 {
embeddedartists 0:b567d56a59d7 3709 if(!color_tree_has(&profile->tree, r, g, b, a))
embeddedartists 0:b567d56a59d7 3710 {
embeddedartists 0:b567d56a59d7 3711
embeddedartists 0:b567d56a59d7 3712 color_tree_add(&profile->tree, r, g, b, a, profile->numcolors);
embeddedartists 0:b567d56a59d7 3713 if(profile->numcolors < 256)
embeddedartists 0:b567d56a59d7 3714 {
embeddedartists 0:b567d56a59d7 3715 unsigned char* p = profile->palette;
embeddedartists 0:b567d56a59d7 3716 unsigned i = profile->numcolors;
embeddedartists 0:b567d56a59d7 3717 p[i * 4 + 0] = r;
embeddedartists 0:b567d56a59d7 3718 p[i * 4 + 1] = g;
embeddedartists 0:b567d56a59d7 3719 p[i * 4 + 2] = b;
embeddedartists 0:b567d56a59d7 3720 p[i * 4 + 3] = a;
embeddedartists 0:b567d56a59d7 3721 }
embeddedartists 0:b567d56a59d7 3722 profile->numcolors++;
embeddedartists 0:b567d56a59d7 3723 if(profile->numcolors >= profile->maxnumcolors) profile->numcolors_done = 1;
embeddedartists 0:b567d56a59d7 3724 }
embeddedartists 0:b567d56a59d7 3725 }
embeddedartists 0:b567d56a59d7 3726
embeddedartists 0:b567d56a59d7 3727 if(profile->alpha_done && profile->numcolors_done && profile->colored_done && profile->greybits_done)
embeddedartists 0:b567d56a59d7 3728 {
embeddedartists 0:b567d56a59d7 3729 break;
embeddedartists 0:b567d56a59d7 3730 }
embeddedartists 0:b567d56a59d7 3731 };
embeddedartists 0:b567d56a59d7 3732 }
embeddedartists 0:b567d56a59d7 3733
embeddedartists 0:b567d56a59d7 3734 /*make the profile's key always 16-bit for consistency*/
embeddedartists 0:b567d56a59d7 3735 if(mode->bitdepth < 16)
embeddedartists 0:b567d56a59d7 3736 {
embeddedartists 0:b567d56a59d7 3737 /*repeat each byte twice*/
embeddedartists 0:b567d56a59d7 3738 profile->key_r *= 257;
embeddedartists 0:b567d56a59d7 3739 profile->key_g *= 257;
embeddedartists 0:b567d56a59d7 3740 profile->key_b *= 257;
embeddedartists 0:b567d56a59d7 3741 }
embeddedartists 0:b567d56a59d7 3742
embeddedartists 0:b567d56a59d7 3743 return error;
embeddedartists 0:b567d56a59d7 3744 }
embeddedartists 0:b567d56a59d7 3745
embeddedartists 0:b567d56a59d7 3746 static void setColorKeyFrom16bit(LodePNGColorMode* mode_out, unsigned r, unsigned g, unsigned b, unsigned bitdepth)
embeddedartists 0:b567d56a59d7 3747 {
embeddedartists 0:b567d56a59d7 3748 unsigned mask = (1 << bitdepth) - 1;
embeddedartists 0:b567d56a59d7 3749 mode_out->key_defined = 1;
embeddedartists 0:b567d56a59d7 3750 mode_out->key_r = r & mask;
embeddedartists 0:b567d56a59d7 3751 mode_out->key_g = g & mask;
embeddedartists 0:b567d56a59d7 3752 mode_out->key_b = b & mask;
embeddedartists 0:b567d56a59d7 3753 }
embeddedartists 0:b567d56a59d7 3754
embeddedartists 0:b567d56a59d7 3755 /*updates values of mode with a potentially smaller color model. mode_out should
embeddedartists 0:b567d56a59d7 3756 contain the user chosen color model, but will be overwritten with the new chosen one.*/
embeddedartists 0:b567d56a59d7 3757 unsigned lodepng_auto_choose_color(LodePNGColorMode* mode_out,
embeddedartists 0:b567d56a59d7 3758 const unsigned char* image, unsigned w, unsigned h,
embeddedartists 0:b567d56a59d7 3759 const LodePNGColorMode* mode_in,
embeddedartists 0:b567d56a59d7 3760 LodePNGAutoConvert auto_convert)
embeddedartists 0:b567d56a59d7 3761 {
embeddedartists 0:b567d56a59d7 3762 ColorProfile profile;
embeddedartists 0:b567d56a59d7 3763 unsigned error = 0;
embeddedartists 0:b567d56a59d7 3764 int no_nibbles = auto_convert == LAC_AUTO_NO_NIBBLES || auto_convert == LAC_AUTO_NO_NIBBLES_NO_PALETTE;
embeddedartists 0:b567d56a59d7 3765 int no_palette = auto_convert == LAC_AUTO_NO_PALETTE || auto_convert == LAC_AUTO_NO_NIBBLES_NO_PALETTE;
embeddedartists 0:b567d56a59d7 3766
embeddedartists 0:b567d56a59d7 3767 if(auto_convert == LAC_ALPHA)
embeddedartists 0:b567d56a59d7 3768 {
embeddedartists 0:b567d56a59d7 3769 if(mode_out->colortype != LCT_RGBA && mode_out->colortype != LCT_GREY_ALPHA) return 0;
embeddedartists 0:b567d56a59d7 3770 }
embeddedartists 0:b567d56a59d7 3771
embeddedartists 0:b567d56a59d7 3772 color_profile_init(&profile, mode_in);
embeddedartists 0:b567d56a59d7 3773 if(auto_convert == LAC_ALPHA)
embeddedartists 0:b567d56a59d7 3774 {
embeddedartists 0:b567d56a59d7 3775 profile.colored_done = 1;
embeddedartists 0:b567d56a59d7 3776 profile.greybits_done = 1;
embeddedartists 0:b567d56a59d7 3777 profile.numcolors_done = 1;
embeddedartists 0:b567d56a59d7 3778 profile.sixteenbit_done = 1;
embeddedartists 0:b567d56a59d7 3779 }
embeddedartists 0:b567d56a59d7 3780 error = get_color_profile(&profile, image, w * h, mode_in, 0 /*fix_png*/);
embeddedartists 0:b567d56a59d7 3781 if(!error && auto_convert == LAC_ALPHA)
embeddedartists 0:b567d56a59d7 3782 {
embeddedartists 0:b567d56a59d7 3783 if(!profile.alpha)
embeddedartists 0:b567d56a59d7 3784 {
embeddedartists 0:b567d56a59d7 3785 mode_out->colortype = (mode_out->colortype == LCT_RGBA ? LCT_RGB : LCT_GREY);
embeddedartists 0:b567d56a59d7 3786 if(profile.key) setColorKeyFrom16bit(mode_out, profile.key_r, profile.key_g, profile.key_b, mode_out->bitdepth);
embeddedartists 0:b567d56a59d7 3787 }
embeddedartists 0:b567d56a59d7 3788 }
embeddedartists 0:b567d56a59d7 3789 else if(!error && auto_convert != LAC_ALPHA)
embeddedartists 0:b567d56a59d7 3790 {
embeddedartists 0:b567d56a59d7 3791 mode_out->key_defined = 0;
embeddedartists 0:b567d56a59d7 3792
embeddedartists 0:b567d56a59d7 3793 if(profile.sixteenbit)
embeddedartists 0:b567d56a59d7 3794 {
embeddedartists 0:b567d56a59d7 3795 mode_out->bitdepth = 16;
embeddedartists 0:b567d56a59d7 3796 if(profile.alpha)
embeddedartists 0:b567d56a59d7 3797 {
embeddedartists 0:b567d56a59d7 3798 mode_out->colortype = profile.colored ? LCT_RGBA : LCT_GREY_ALPHA;
embeddedartists 0:b567d56a59d7 3799 }
embeddedartists 0:b567d56a59d7 3800 else
embeddedartists 0:b567d56a59d7 3801 {
embeddedartists 0:b567d56a59d7 3802 mode_out->colortype = profile.colored ? LCT_RGB : LCT_GREY;
embeddedartists 0:b567d56a59d7 3803 if(profile.key) setColorKeyFrom16bit(mode_out, profile.key_r, profile.key_g, profile.key_b, mode_out->bitdepth);
embeddedartists 0:b567d56a59d7 3804 }
embeddedartists 0:b567d56a59d7 3805 }
embeddedartists 0:b567d56a59d7 3806 else /*less than 16 bits per channel*/
embeddedartists 0:b567d56a59d7 3807 {
embeddedartists 0:b567d56a59d7 3808 /*don't add palette overhead if image hasn't got a lot of pixels*/
embeddedartists 0:b567d56a59d7 3809 unsigned n = profile.numcolors;
embeddedartists 0:b567d56a59d7 3810 int palette_ok = !no_palette && n <= 256 && (n * 2 < w * h);
embeddedartists 0:b567d56a59d7 3811 unsigned palettebits = n <= 2 ? 1 : (n <= 4 ? 2 : (n <= 16 ? 4 : 8));
embeddedartists 0:b567d56a59d7 3812 int grey_ok = !profile.colored && !profile.alpha; /*grey without alpha, with potentially low bits*/
embeddedartists 0:b567d56a59d7 3813 if(palette_ok || grey_ok)
embeddedartists 0:b567d56a59d7 3814 {
embeddedartists 0:b567d56a59d7 3815 if(!palette_ok || (grey_ok && profile.greybits <= palettebits))
embeddedartists 0:b567d56a59d7 3816 {
embeddedartists 0:b567d56a59d7 3817 unsigned grey = profile.key_r;
embeddedartists 0:b567d56a59d7 3818 mode_out->colortype = LCT_GREY;
embeddedartists 0:b567d56a59d7 3819 mode_out->bitdepth = profile.greybits;
embeddedartists 0:b567d56a59d7 3820 if(profile.key) setColorKeyFrom16bit(mode_out, grey, grey, grey, mode_out->bitdepth);
embeddedartists 0:b567d56a59d7 3821 }
embeddedartists 0:b567d56a59d7 3822 else
embeddedartists 0:b567d56a59d7 3823 {
embeddedartists 0:b567d56a59d7 3824 /*fill in the palette*/
embeddedartists 0:b567d56a59d7 3825 unsigned i;
embeddedartists 0:b567d56a59d7 3826 unsigned char* p = profile.palette;
embeddedartists 0:b567d56a59d7 3827 /*remove potential earlier palette*/
embeddedartists 0:b567d56a59d7 3828 lodepng_palette_clear(mode_out);
embeddedartists 0:b567d56a59d7 3829 for(i = 0; i < profile.numcolors; i++)
embeddedartists 0:b567d56a59d7 3830 {
embeddedartists 0:b567d56a59d7 3831 error = lodepng_palette_add(mode_out, p[i * 4 + 0], p[i * 4 + 1], p[i * 4 + 2], p[i * 4 + 3]);
embeddedartists 0:b567d56a59d7 3832 if(error) break;
embeddedartists 0:b567d56a59d7 3833 }
embeddedartists 0:b567d56a59d7 3834
embeddedartists 0:b567d56a59d7 3835 mode_out->colortype = LCT_PALETTE;
embeddedartists 0:b567d56a59d7 3836 mode_out->bitdepth = palettebits;
embeddedartists 0:b567d56a59d7 3837 }
embeddedartists 0:b567d56a59d7 3838 }
embeddedartists 0:b567d56a59d7 3839 else /*8-bit per channel*/
embeddedartists 0:b567d56a59d7 3840 {
embeddedartists 0:b567d56a59d7 3841 mode_out->bitdepth = 8;
embeddedartists 0:b567d56a59d7 3842 if(profile.alpha)
embeddedartists 0:b567d56a59d7 3843 {
embeddedartists 0:b567d56a59d7 3844 mode_out->colortype = profile.colored ? LCT_RGBA : LCT_GREY_ALPHA;
embeddedartists 0:b567d56a59d7 3845 }
embeddedartists 0:b567d56a59d7 3846 else
embeddedartists 0:b567d56a59d7 3847 {
embeddedartists 0:b567d56a59d7 3848 mode_out->colortype = profile.colored ? LCT_RGB : LCT_GREY /*LCT_GREY normally won't occur, already done earlier*/;
embeddedartists 0:b567d56a59d7 3849 if(profile.key) setColorKeyFrom16bit(mode_out, profile.key_r, profile.key_g, profile.key_b, mode_out->bitdepth);
embeddedartists 0:b567d56a59d7 3850 }
embeddedartists 0:b567d56a59d7 3851 }
embeddedartists 0:b567d56a59d7 3852 }
embeddedartists 0:b567d56a59d7 3853 }
embeddedartists 0:b567d56a59d7 3854
embeddedartists 0:b567d56a59d7 3855 color_profile_cleanup(&profile);
embeddedartists 0:b567d56a59d7 3856
embeddedartists 0:b567d56a59d7 3857 if(mode_out->colortype == LCT_PALETTE && mode_in->palettesize == mode_out->palettesize)
embeddedartists 0:b567d56a59d7 3858 {
embeddedartists 0:b567d56a59d7 3859 /*In this case keep the palette order of the input, so that the user can choose an optimal one*/
embeddedartists 0:b567d56a59d7 3860 size_t i;
embeddedartists 0:b567d56a59d7 3861 for(i = 0; i < mode_in->palettesize * 4; i++)
embeddedartists 0:b567d56a59d7 3862 {
embeddedartists 0:b567d56a59d7 3863 mode_out->palette[i] = mode_in->palette[i];
embeddedartists 0:b567d56a59d7 3864 }
embeddedartists 0:b567d56a59d7 3865 }
embeddedartists 0:b567d56a59d7 3866
embeddedartists 0:b567d56a59d7 3867 if(no_nibbles && mode_out->bitdepth < 8)
embeddedartists 0:b567d56a59d7 3868 {
embeddedartists 0:b567d56a59d7 3869 /*palette can keep its small amount of colors, as long as no indices use it*/
embeddedartists 0:b567d56a59d7 3870 mode_out->bitdepth = 8;
embeddedartists 0:b567d56a59d7 3871 }
embeddedartists 0:b567d56a59d7 3872
embeddedartists 0:b567d56a59d7 3873 return error;
embeddedartists 0:b567d56a59d7 3874 }
embeddedartists 0:b567d56a59d7 3875
embeddedartists 0:b567d56a59d7 3876 #endif /* #ifdef LODEPNG_COMPILE_ENCODER */
embeddedartists 0:b567d56a59d7 3877
embeddedartists 0:b567d56a59d7 3878 /*
embeddedartists 0:b567d56a59d7 3879 Paeth predicter, used by PNG filter type 4
embeddedartists 0:b567d56a59d7 3880 The parameters are of type short, but should come from unsigned chars, the shorts
embeddedartists 0:b567d56a59d7 3881 are only needed to make the paeth calculation correct.
embeddedartists 0:b567d56a59d7 3882 */
embeddedartists 0:b567d56a59d7 3883 static unsigned char paethPredictor(short a, short b, short c)
embeddedartists 0:b567d56a59d7 3884 {
embeddedartists 0:b567d56a59d7 3885 short pa = abs(b - c);
embeddedartists 0:b567d56a59d7 3886 short pb = abs(a - c);
embeddedartists 0:b567d56a59d7 3887 short pc = abs(a + b - c - c);
embeddedartists 0:b567d56a59d7 3888
embeddedartists 0:b567d56a59d7 3889 if(pc < pa && pc < pb) return (unsigned char)c;
embeddedartists 0:b567d56a59d7 3890 else if(pb < pa) return (unsigned char)b;
embeddedartists 0:b567d56a59d7 3891 else return (unsigned char)a;
embeddedartists 0:b567d56a59d7 3892 }
embeddedartists 0:b567d56a59d7 3893
embeddedartists 0:b567d56a59d7 3894 /*shared values used by multiple Adam7 related functions*/
embeddedartists 0:b567d56a59d7 3895
embeddedartists 0:b567d56a59d7 3896 static const unsigned ADAM7_IX[7] = { 0, 4, 0, 2, 0, 1, 0 }; /*x start values*/
embeddedartists 0:b567d56a59d7 3897 static const unsigned ADAM7_IY[7] = { 0, 0, 4, 0, 2, 0, 1 }; /*y start values*/
embeddedartists 0:b567d56a59d7 3898 static const unsigned ADAM7_DX[7] = { 8, 8, 4, 4, 2, 2, 1 }; /*x delta values*/
embeddedartists 0:b567d56a59d7 3899 static const unsigned ADAM7_DY[7] = { 8, 8, 8, 4, 4, 2, 2 }; /*y delta values*/
embeddedartists 0:b567d56a59d7 3900
embeddedartists 0:b567d56a59d7 3901 /*
embeddedartists 0:b567d56a59d7 3902 Outputs various dimensions and positions in the image related to the Adam7 reduced images.
embeddedartists 0:b567d56a59d7 3903 passw: output containing the width of the 7 passes
embeddedartists 0:b567d56a59d7 3904 passh: output containing the height of the 7 passes
embeddedartists 0:b567d56a59d7 3905 filter_passstart: output containing the index of the start and end of each
embeddedartists 0:b567d56a59d7 3906 reduced image with filter bytes
embeddedartists 0:b567d56a59d7 3907 padded_passstart output containing the index of the start and end of each
embeddedartists 0:b567d56a59d7 3908 reduced image when without filter bytes but with padded scanlines
embeddedartists 0:b567d56a59d7 3909 passstart: output containing the index of the start and end of each reduced
embeddedartists 0:b567d56a59d7 3910 image without padding between scanlines, but still padding between the images
embeddedartists 0:b567d56a59d7 3911 w, h: width and height of non-interlaced image
embeddedartists 0:b567d56a59d7 3912 bpp: bits per pixel
embeddedartists 0:b567d56a59d7 3913 "padded" is only relevant if bpp is less than 8 and a scanline or image does not
embeddedartists 0:b567d56a59d7 3914 end at a full byte
embeddedartists 0:b567d56a59d7 3915 */
embeddedartists 0:b567d56a59d7 3916 static void Adam7_getpassvalues(unsigned passw[7], unsigned passh[7], size_t filter_passstart[8],
embeddedartists 0:b567d56a59d7 3917 size_t padded_passstart[8], size_t passstart[8], unsigned w, unsigned h, unsigned bpp)
embeddedartists 0:b567d56a59d7 3918 {
embeddedartists 0:b567d56a59d7 3919 /*the passstart values have 8 values: the 8th one indicates the byte after the end of the 7th (= last) pass*/
embeddedartists 0:b567d56a59d7 3920 unsigned i;
embeddedartists 0:b567d56a59d7 3921
embeddedartists 0:b567d56a59d7 3922 /*calculate width and height in pixels of each pass*/
embeddedartists 0:b567d56a59d7 3923 for(i = 0; i < 7; i++)
embeddedartists 0:b567d56a59d7 3924 {
embeddedartists 0:b567d56a59d7 3925 passw[i] = (w + ADAM7_DX[i] - ADAM7_IX[i] - 1) / ADAM7_DX[i];
embeddedartists 0:b567d56a59d7 3926 passh[i] = (h + ADAM7_DY[i] - ADAM7_IY[i] - 1) / ADAM7_DY[i];
embeddedartists 0:b567d56a59d7 3927 if(passw[i] == 0) passh[i] = 0;
embeddedartists 0:b567d56a59d7 3928 if(passh[i] == 0) passw[i] = 0;
embeddedartists 0:b567d56a59d7 3929 }
embeddedartists 0:b567d56a59d7 3930
embeddedartists 0:b567d56a59d7 3931 filter_passstart[0] = padded_passstart[0] = passstart[0] = 0;
embeddedartists 0:b567d56a59d7 3932 for(i = 0; i < 7; i++)
embeddedartists 0:b567d56a59d7 3933 {
embeddedartists 0:b567d56a59d7 3934 /*if passw[i] is 0, it's 0 bytes, not 1 (no filtertype-byte)*/
embeddedartists 0:b567d56a59d7 3935 filter_passstart[i + 1] = filter_passstart[i]
embeddedartists 0:b567d56a59d7 3936 + ((passw[i] && passh[i]) ? passh[i] * (1 + (passw[i] * bpp + 7) / 8) : 0);
embeddedartists 0:b567d56a59d7 3937 /*bits padded if needed to fill full byte at end of each scanline*/
embeddedartists 0:b567d56a59d7 3938 padded_passstart[i + 1] = padded_passstart[i] + passh[i] * ((passw[i] * bpp + 7) / 8);
embeddedartists 0:b567d56a59d7 3939 /*only padded at end of reduced image*/
embeddedartists 0:b567d56a59d7 3940 passstart[i + 1] = passstart[i] + (passh[i] * passw[i] * bpp + 7) / 8;
embeddedartists 0:b567d56a59d7 3941 }
embeddedartists 0:b567d56a59d7 3942 }
embeddedartists 0:b567d56a59d7 3943
embeddedartists 0:b567d56a59d7 3944 #ifdef LODEPNG_COMPILE_DECODER
embeddedartists 0:b567d56a59d7 3945
embeddedartists 0:b567d56a59d7 3946 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 3947 /* / PNG Decoder / */
embeddedartists 0:b567d56a59d7 3948 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 3949
embeddedartists 0:b567d56a59d7 3950 /*read the information from the header and store it in the LodePNGInfo. return value is error*/
embeddedartists 0:b567d56a59d7 3951 unsigned lodepng_inspect(unsigned* w, unsigned* h, LodePNGState* state,
embeddedartists 0:b567d56a59d7 3952 const unsigned char* in, size_t insize)
embeddedartists 0:b567d56a59d7 3953 {
embeddedartists 0:b567d56a59d7 3954 LodePNGInfo* info = &state->info_png;
embeddedartists 0:b567d56a59d7 3955 if(insize == 0 || in == 0)
embeddedartists 0:b567d56a59d7 3956 {
embeddedartists 0:b567d56a59d7 3957 CERROR_RETURN_ERROR(state->error, 48); /*error: the given data is empty*/
embeddedartists 0:b567d56a59d7 3958 }
embeddedartists 0:b567d56a59d7 3959 if(insize < 29)
embeddedartists 0:b567d56a59d7 3960 {
embeddedartists 0:b567d56a59d7 3961 CERROR_RETURN_ERROR(state->error, 27); /*error: the data length is smaller than the length of a PNG header*/
embeddedartists 0:b567d56a59d7 3962 }
embeddedartists 0:b567d56a59d7 3963
embeddedartists 0:b567d56a59d7 3964 /*when decoding a new PNG image, make sure all parameters created after previous decoding are reset*/
embeddedartists 0:b567d56a59d7 3965 lodepng_info_cleanup(info);
embeddedartists 0:b567d56a59d7 3966 lodepng_info_init(info);
embeddedartists 0:b567d56a59d7 3967
embeddedartists 0:b567d56a59d7 3968 if(in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71
embeddedartists 0:b567d56a59d7 3969 || in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10)
embeddedartists 0:b567d56a59d7 3970 {
embeddedartists 0:b567d56a59d7 3971 CERROR_RETURN_ERROR(state->error, 28); /*error: the first 8 bytes are not the correct PNG signature*/
embeddedartists 0:b567d56a59d7 3972 }
embeddedartists 0:b567d56a59d7 3973 if(in[12] != 'I' || in[13] != 'H' || in[14] != 'D' || in[15] != 'R')
embeddedartists 0:b567d56a59d7 3974 {
embeddedartists 0:b567d56a59d7 3975 CERROR_RETURN_ERROR(state->error, 29); /*error: it doesn't start with a IHDR chunk!*/
embeddedartists 0:b567d56a59d7 3976 }
embeddedartists 0:b567d56a59d7 3977
embeddedartists 0:b567d56a59d7 3978 /*read the values given in the header*/
embeddedartists 0:b567d56a59d7 3979 *w = lodepng_read32bitInt(&in[16]);
embeddedartists 0:b567d56a59d7 3980 *h = lodepng_read32bitInt(&in[20]);
embeddedartists 0:b567d56a59d7 3981 info->color.bitdepth = in[24];
embeddedartists 0:b567d56a59d7 3982 info->color.colortype = (LodePNGColorType)in[25];
embeddedartists 0:b567d56a59d7 3983 info->compression_method = in[26];
embeddedartists 0:b567d56a59d7 3984 info->filter_method = in[27];
embeddedartists 0:b567d56a59d7 3985 info->interlace_method = in[28];
embeddedartists 0:b567d56a59d7 3986
embeddedartists 0:b567d56a59d7 3987 if(!state->decoder.ignore_crc)
embeddedartists 0:b567d56a59d7 3988 {
embeddedartists 0:b567d56a59d7 3989 unsigned CRC = lodepng_read32bitInt(&in[29]);
embeddedartists 0:b567d56a59d7 3990 unsigned checksum = lodepng_crc32(&in[12], 17);
embeddedartists 0:b567d56a59d7 3991 if(CRC != checksum)
embeddedartists 0:b567d56a59d7 3992 {
embeddedartists 0:b567d56a59d7 3993 CERROR_RETURN_ERROR(state->error, 57); /*invalid CRC*/
embeddedartists 0:b567d56a59d7 3994 }
embeddedartists 0:b567d56a59d7 3995 }
embeddedartists 0:b567d56a59d7 3996
embeddedartists 0:b567d56a59d7 3997 /*error: only compression method 0 is allowed in the specification*/
embeddedartists 0:b567d56a59d7 3998 if(info->compression_method != 0) CERROR_RETURN_ERROR(state->error, 32);
embeddedartists 0:b567d56a59d7 3999 /*error: only filter method 0 is allowed in the specification*/
embeddedartists 0:b567d56a59d7 4000 if(info->filter_method != 0) CERROR_RETURN_ERROR(state->error, 33);
embeddedartists 0:b567d56a59d7 4001 /*error: only interlace methods 0 and 1 exist in the specification*/
embeddedartists 0:b567d56a59d7 4002 if(info->interlace_method > 1) CERROR_RETURN_ERROR(state->error, 34);
embeddedartists 0:b567d56a59d7 4003
embeddedartists 0:b567d56a59d7 4004 state->error = checkColorValidity(info->color.colortype, info->color.bitdepth);
embeddedartists 0:b567d56a59d7 4005 return state->error;
embeddedartists 0:b567d56a59d7 4006 }
embeddedartists 0:b567d56a59d7 4007
embeddedartists 0:b567d56a59d7 4008 static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scanline, const unsigned char* precon,
embeddedartists 0:b567d56a59d7 4009 size_t bytewidth, unsigned char filterType, size_t length)
embeddedartists 0:b567d56a59d7 4010 {
embeddedartists 0:b567d56a59d7 4011 /*
embeddedartists 0:b567d56a59d7 4012 For PNG filter method 0
embeddedartists 0:b567d56a59d7 4013 unfilter a PNG image scanline by scanline. when the pixels are smaller than 1 byte,
embeddedartists 0:b567d56a59d7 4014 the filter works byte per byte (bytewidth = 1)
embeddedartists 0:b567d56a59d7 4015 precon is the previous unfiltered scanline, recon the result, scanline the current one
embeddedartists 0:b567d56a59d7 4016 the incoming scanlines do NOT include the filtertype byte, that one is given in the parameter filterType instead
embeddedartists 0:b567d56a59d7 4017 recon and scanline MAY be the same memory address! precon must be disjoint.
embeddedartists 0:b567d56a59d7 4018 */
embeddedartists 0:b567d56a59d7 4019
embeddedartists 0:b567d56a59d7 4020 size_t i;
embeddedartists 0:b567d56a59d7 4021 switch(filterType)
embeddedartists 0:b567d56a59d7 4022 {
embeddedartists 0:b567d56a59d7 4023 case 0:
embeddedartists 0:b567d56a59d7 4024 for(i = 0; i < length; i++) recon[i] = scanline[i];
embeddedartists 0:b567d56a59d7 4025 break;
embeddedartists 0:b567d56a59d7 4026 case 1:
embeddedartists 0:b567d56a59d7 4027 for(i = 0; i < bytewidth; i++) recon[i] = scanline[i];
embeddedartists 0:b567d56a59d7 4028 for(i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth];
embeddedartists 0:b567d56a59d7 4029 break;
embeddedartists 0:b567d56a59d7 4030 case 2:
embeddedartists 0:b567d56a59d7 4031 if(precon)
embeddedartists 0:b567d56a59d7 4032 {
embeddedartists 0:b567d56a59d7 4033 for(i = 0; i < length; i++) recon[i] = scanline[i] + precon[i];
embeddedartists 0:b567d56a59d7 4034 }
embeddedartists 0:b567d56a59d7 4035 else
embeddedartists 0:b567d56a59d7 4036 {
embeddedartists 0:b567d56a59d7 4037 for(i = 0; i < length; i++) recon[i] = scanline[i];
embeddedartists 0:b567d56a59d7 4038 }
embeddedartists 0:b567d56a59d7 4039 break;
embeddedartists 0:b567d56a59d7 4040 case 3:
embeddedartists 0:b567d56a59d7 4041 if(precon)
embeddedartists 0:b567d56a59d7 4042 {
embeddedartists 0:b567d56a59d7 4043 for(i = 0; i < bytewidth; i++) recon[i] = scanline[i] + precon[i] / 2;
embeddedartists 0:b567d56a59d7 4044 for(i = bytewidth; i < length; i++) recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) / 2);
embeddedartists 0:b567d56a59d7 4045 }
embeddedartists 0:b567d56a59d7 4046 else
embeddedartists 0:b567d56a59d7 4047 {
embeddedartists 0:b567d56a59d7 4048 for(i = 0; i < bytewidth; i++) recon[i] = scanline[i];
embeddedartists 0:b567d56a59d7 4049 for(i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth] / 2;
embeddedartists 0:b567d56a59d7 4050 }
embeddedartists 0:b567d56a59d7 4051 break;
embeddedartists 0:b567d56a59d7 4052 case 4:
embeddedartists 0:b567d56a59d7 4053 if(precon)
embeddedartists 0:b567d56a59d7 4054 {
embeddedartists 0:b567d56a59d7 4055 for(i = 0; i < bytewidth; i++)
embeddedartists 0:b567d56a59d7 4056 {
embeddedartists 0:b567d56a59d7 4057 recon[i] = (scanline[i] + precon[i]); /*paethPredictor(0, precon[i], 0) is always precon[i]*/
embeddedartists 0:b567d56a59d7 4058 }
embeddedartists 0:b567d56a59d7 4059 for(i = bytewidth; i < length; i++)
embeddedartists 0:b567d56a59d7 4060 {
embeddedartists 0:b567d56a59d7 4061 recon[i] = (scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth]));
embeddedartists 0:b567d56a59d7 4062 }
embeddedartists 0:b567d56a59d7 4063 }
embeddedartists 0:b567d56a59d7 4064 else
embeddedartists 0:b567d56a59d7 4065 {
embeddedartists 0:b567d56a59d7 4066 for(i = 0; i < bytewidth; i++)
embeddedartists 0:b567d56a59d7 4067 {
embeddedartists 0:b567d56a59d7 4068 recon[i] = scanline[i];
embeddedartists 0:b567d56a59d7 4069 }
embeddedartists 0:b567d56a59d7 4070 for(i = bytewidth; i < length; i++)
embeddedartists 0:b567d56a59d7 4071 {
embeddedartists 0:b567d56a59d7 4072 /*paethPredictor(recon[i - bytewidth], 0, 0) is always recon[i - bytewidth]*/
embeddedartists 0:b567d56a59d7 4073 recon[i] = (scanline[i] + recon[i - bytewidth]);
embeddedartists 0:b567d56a59d7 4074 }
embeddedartists 0:b567d56a59d7 4075 }
embeddedartists 0:b567d56a59d7 4076 break;
embeddedartists 0:b567d56a59d7 4077 default: return 36; /*error: unexisting filter type given*/
embeddedartists 0:b567d56a59d7 4078 }
embeddedartists 0:b567d56a59d7 4079 return 0;
embeddedartists 0:b567d56a59d7 4080 }
embeddedartists 0:b567d56a59d7 4081
embeddedartists 0:b567d56a59d7 4082 static unsigned unfilter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp)
embeddedartists 0:b567d56a59d7 4083 {
embeddedartists 0:b567d56a59d7 4084 /*
embeddedartists 0:b567d56a59d7 4085 For PNG filter method 0
embeddedartists 0:b567d56a59d7 4086 this function unfilters a single image (e.g. without interlacing this is called once, with Adam7 seven times)
embeddedartists 0:b567d56a59d7 4087 out must have enough bytes allocated already, in must have the scanlines + 1 filtertype byte per scanline
embeddedartists 0:b567d56a59d7 4088 w and h are image dimensions or dimensions of reduced image, bpp is bits per pixel
embeddedartists 0:b567d56a59d7 4089 in and out are allowed to be the same memory address (but aren't the same size since in has the extra filter bytes)
embeddedartists 0:b567d56a59d7 4090 */
embeddedartists 0:b567d56a59d7 4091
embeddedartists 0:b567d56a59d7 4092 unsigned y;
embeddedartists 0:b567d56a59d7 4093 unsigned char* prevline = 0;
embeddedartists 0:b567d56a59d7 4094
embeddedartists 0:b567d56a59d7 4095 /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/
embeddedartists 0:b567d56a59d7 4096 size_t bytewidth = (bpp + 7) / 8;
embeddedartists 0:b567d56a59d7 4097 size_t linebytes = (w * bpp + 7) / 8;
embeddedartists 0:b567d56a59d7 4098
embeddedartists 0:b567d56a59d7 4099 for(y = 0; y < h; y++)
embeddedartists 0:b567d56a59d7 4100 {
embeddedartists 0:b567d56a59d7 4101 size_t outindex = linebytes * y;
embeddedartists 0:b567d56a59d7 4102 size_t inindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/
embeddedartists 0:b567d56a59d7 4103 unsigned char filterType = in[inindex];
embeddedartists 0:b567d56a59d7 4104
embeddedartists 0:b567d56a59d7 4105 CERROR_TRY_RETURN(unfilterScanline(&out[outindex], &in[inindex + 1], prevline, bytewidth, filterType, linebytes));
embeddedartists 0:b567d56a59d7 4106
embeddedartists 0:b567d56a59d7 4107 prevline = &out[outindex];
embeddedartists 0:b567d56a59d7 4108 }
embeddedartists 0:b567d56a59d7 4109
embeddedartists 0:b567d56a59d7 4110 return 0;
embeddedartists 0:b567d56a59d7 4111 }
embeddedartists 0:b567d56a59d7 4112
embeddedartists 0:b567d56a59d7 4113 /*
embeddedartists 0:b567d56a59d7 4114 in: Adam7 interlaced image, with no padding bits between scanlines, but between
embeddedartists 0:b567d56a59d7 4115 reduced images so that each reduced image starts at a byte.
embeddedartists 0:b567d56a59d7 4116 out: the same pixels, but re-ordered so that they're now a non-interlaced image with size w*h
embeddedartists 0:b567d56a59d7 4117 bpp: bits per pixel
embeddedartists 0:b567d56a59d7 4118 out has the following size in bits: w * h * bpp.
embeddedartists 0:b567d56a59d7 4119 in is possibly bigger due to padding bits between reduced images.
embeddedartists 0:b567d56a59d7 4120 out must be big enough AND must be 0 everywhere if bpp < 8 in the current implementation
embeddedartists 0:b567d56a59d7 4121 (because that's likely a little bit faster)
embeddedartists 0:b567d56a59d7 4122 NOTE: comments about padding bits are only relevant if bpp < 8
embeddedartists 0:b567d56a59d7 4123 */
embeddedartists 0:b567d56a59d7 4124 static void Adam7_deinterlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp)
embeddedartists 0:b567d56a59d7 4125 {
embeddedartists 0:b567d56a59d7 4126 unsigned passw[7], passh[7];
embeddedartists 0:b567d56a59d7 4127 size_t filter_passstart[8], padded_passstart[8], passstart[8];
embeddedartists 0:b567d56a59d7 4128 unsigned i;
embeddedartists 0:b567d56a59d7 4129
embeddedartists 0:b567d56a59d7 4130 Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp);
embeddedartists 0:b567d56a59d7 4131
embeddedartists 0:b567d56a59d7 4132 if(bpp >= 8)
embeddedartists 0:b567d56a59d7 4133 {
embeddedartists 0:b567d56a59d7 4134 for(i = 0; i < 7; i++)
embeddedartists 0:b567d56a59d7 4135 {
embeddedartists 0:b567d56a59d7 4136 unsigned x, y, b;
embeddedartists 0:b567d56a59d7 4137 size_t bytewidth = bpp / 8;
embeddedartists 0:b567d56a59d7 4138 for(y = 0; y < passh[i]; y++)
embeddedartists 0:b567d56a59d7 4139 for(x = 0; x < passw[i]; x++)
embeddedartists 0:b567d56a59d7 4140 {
embeddedartists 0:b567d56a59d7 4141 size_t pixelinstart = passstart[i] + (y * passw[i] + x) * bytewidth;
embeddedartists 0:b567d56a59d7 4142 size_t pixeloutstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth;
embeddedartists 0:b567d56a59d7 4143 for(b = 0; b < bytewidth; b++)
embeddedartists 0:b567d56a59d7 4144 {
embeddedartists 0:b567d56a59d7 4145 out[pixeloutstart + b] = in[pixelinstart + b];
embeddedartists 0:b567d56a59d7 4146 }
embeddedartists 0:b567d56a59d7 4147 }
embeddedartists 0:b567d56a59d7 4148 }
embeddedartists 0:b567d56a59d7 4149 }
embeddedartists 0:b567d56a59d7 4150 else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/
embeddedartists 0:b567d56a59d7 4151 {
embeddedartists 0:b567d56a59d7 4152 for(i = 0; i < 7; i++)
embeddedartists 0:b567d56a59d7 4153 {
embeddedartists 0:b567d56a59d7 4154 unsigned x, y, b;
embeddedartists 0:b567d56a59d7 4155 unsigned ilinebits = bpp * passw[i];
embeddedartists 0:b567d56a59d7 4156 unsigned olinebits = bpp * w;
embeddedartists 0:b567d56a59d7 4157 size_t obp, ibp; /*bit pointers (for out and in buffer)*/
embeddedartists 0:b567d56a59d7 4158 for(y = 0; y < passh[i]; y++)
embeddedartists 0:b567d56a59d7 4159 for(x = 0; x < passw[i]; x++)
embeddedartists 0:b567d56a59d7 4160 {
embeddedartists 0:b567d56a59d7 4161 ibp = (8 * passstart[i]) + (y * ilinebits + x * bpp);
embeddedartists 0:b567d56a59d7 4162 obp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp;
embeddedartists 0:b567d56a59d7 4163 for(b = 0; b < bpp; b++)
embeddedartists 0:b567d56a59d7 4164 {
embeddedartists 0:b567d56a59d7 4165 unsigned char bit = readBitFromReversedStream(&ibp, in);
embeddedartists 0:b567d56a59d7 4166 /*note that this function assumes the out buffer is completely 0, use setBitOfReversedStream otherwise*/
embeddedartists 0:b567d56a59d7 4167 setBitOfReversedStream0(&obp, out, bit);
embeddedartists 0:b567d56a59d7 4168 }
embeddedartists 0:b567d56a59d7 4169 }
embeddedartists 0:b567d56a59d7 4170 }
embeddedartists 0:b567d56a59d7 4171 }
embeddedartists 0:b567d56a59d7 4172 }
embeddedartists 0:b567d56a59d7 4173
embeddedartists 0:b567d56a59d7 4174 static void removePaddingBits(unsigned char* out, const unsigned char* in,
embeddedartists 0:b567d56a59d7 4175 size_t olinebits, size_t ilinebits, unsigned h)
embeddedartists 0:b567d56a59d7 4176 {
embeddedartists 0:b567d56a59d7 4177 /*
embeddedartists 0:b567d56a59d7 4178 After filtering there are still padding bits if scanlines have non multiple of 8 bit amounts. They need
embeddedartists 0:b567d56a59d7 4179 to be removed (except at last scanline of (Adam7-reduced) image) before working with pure image buffers
embeddedartists 0:b567d56a59d7 4180 for the Adam7 code, the color convert code and the output to the user.
embeddedartists 0:b567d56a59d7 4181 in and out are allowed to be the same buffer, in may also be higher but still overlapping; in must
embeddedartists 0:b567d56a59d7 4182 have >= ilinebits*h bits, out must have >= olinebits*h bits, olinebits must be <= ilinebits
embeddedartists 0:b567d56a59d7 4183 also used to move bits after earlier such operations happened, e.g. in a sequence of reduced images from Adam7
embeddedartists 0:b567d56a59d7 4184 only useful if (ilinebits - olinebits) is a value in the range 1..7
embeddedartists 0:b567d56a59d7 4185 */
embeddedartists 0:b567d56a59d7 4186 unsigned y;
embeddedartists 0:b567d56a59d7 4187 size_t diff = ilinebits - olinebits;
embeddedartists 0:b567d56a59d7 4188 size_t ibp = 0, obp = 0; /*input and output bit pointers*/
embeddedartists 0:b567d56a59d7 4189 for(y = 0; y < h; y++)
embeddedartists 0:b567d56a59d7 4190 {
embeddedartists 0:b567d56a59d7 4191 size_t x;
embeddedartists 0:b567d56a59d7 4192 for(x = 0; x < olinebits; x++)
embeddedartists 0:b567d56a59d7 4193 {
embeddedartists 0:b567d56a59d7 4194 unsigned char bit = readBitFromReversedStream(&ibp, in);
embeddedartists 0:b567d56a59d7 4195 setBitOfReversedStream(&obp, out, bit);
embeddedartists 0:b567d56a59d7 4196 }
embeddedartists 0:b567d56a59d7 4197 ibp += diff;
embeddedartists 0:b567d56a59d7 4198 }
embeddedartists 0:b567d56a59d7 4199 }
embeddedartists 0:b567d56a59d7 4200
embeddedartists 0:b567d56a59d7 4201 /*out must be buffer big enough to contain full image, and in must contain the full decompressed data from
embeddedartists 0:b567d56a59d7 4202 the IDAT chunks (with filter index bytes and possible padding bits)
embeddedartists 0:b567d56a59d7 4203 return value is error*/
embeddedartists 0:b567d56a59d7 4204 static unsigned postProcessScanlines(unsigned char* out, unsigned char* in,
embeddedartists 0:b567d56a59d7 4205 unsigned w, unsigned h, const LodePNGInfo* info_png)
embeddedartists 0:b567d56a59d7 4206 {
embeddedartists 0:b567d56a59d7 4207 /*
embeddedartists 0:b567d56a59d7 4208 This function converts the filtered-padded-interlaced data into pure 2D image buffer with the PNG's colortype.
embeddedartists 0:b567d56a59d7 4209 Steps:
embeddedartists 0:b567d56a59d7 4210 *) if no Adam7: 1) unfilter 2) remove padding bits (= posible extra bits per scanline if bpp < 8)
embeddedartists 0:b567d56a59d7 4211 *) if adam7: 1) 7x unfilter 2) 7x remove padding bits 3) Adam7_deinterlace
embeddedartists 0:b567d56a59d7 4212 NOTE: the in buffer will be overwritten with intermediate data!
embeddedartists 0:b567d56a59d7 4213 */
embeddedartists 0:b567d56a59d7 4214 unsigned bpp = lodepng_get_bpp(&info_png->color);
embeddedartists 0:b567d56a59d7 4215 if(bpp == 0) return 31; /*error: invalid colortype*/
embeddedartists 0:b567d56a59d7 4216
embeddedartists 0:b567d56a59d7 4217 if(info_png->interlace_method == 0)
embeddedartists 0:b567d56a59d7 4218 {
embeddedartists 0:b567d56a59d7 4219 if(bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8)
embeddedartists 0:b567d56a59d7 4220 {
embeddedartists 0:b567d56a59d7 4221 CERROR_TRY_RETURN(unfilter(in, in, w, h, bpp));
embeddedartists 0:b567d56a59d7 4222 removePaddingBits(out, in, w * bpp, ((w * bpp + 7) / 8) * 8, h);
embeddedartists 0:b567d56a59d7 4223 }
embeddedartists 0:b567d56a59d7 4224 /*we can immediatly filter into the out buffer, no other steps needed*/
embeddedartists 0:b567d56a59d7 4225 else CERROR_TRY_RETURN(unfilter(out, in, w, h, bpp));
embeddedartists 0:b567d56a59d7 4226 }
embeddedartists 0:b567d56a59d7 4227 else /*interlace_method is 1 (Adam7)*/
embeddedartists 0:b567d56a59d7 4228 {
embeddedartists 0:b567d56a59d7 4229 unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8];
embeddedartists 0:b567d56a59d7 4230 unsigned i;
embeddedartists 0:b567d56a59d7 4231
embeddedartists 0:b567d56a59d7 4232 Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp);
embeddedartists 0:b567d56a59d7 4233
embeddedartists 0:b567d56a59d7 4234 for(i = 0; i < 7; i++)
embeddedartists 0:b567d56a59d7 4235 {
embeddedartists 0:b567d56a59d7 4236 CERROR_TRY_RETURN(unfilter(&in[padded_passstart[i]], &in[filter_passstart[i]], passw[i], passh[i], bpp));
embeddedartists 0:b567d56a59d7 4237 /*TODO: possible efficiency improvement: if in this reduced image the bits fit nicely in 1 scanline,
embeddedartists 0:b567d56a59d7 4238 move bytes instead of bits or move not at all*/
embeddedartists 0:b567d56a59d7 4239 if(bpp < 8)
embeddedartists 0:b567d56a59d7 4240 {
embeddedartists 0:b567d56a59d7 4241 /*remove padding bits in scanlines; after this there still may be padding
embeddedartists 0:b567d56a59d7 4242 bits between the different reduced images: each reduced image still starts nicely at a byte*/
embeddedartists 0:b567d56a59d7 4243 removePaddingBits(&in[passstart[i]], &in[padded_passstart[i]], passw[i] * bpp,
embeddedartists 0:b567d56a59d7 4244 ((passw[i] * bpp + 7) / 8) * 8, passh[i]);
embeddedartists 0:b567d56a59d7 4245 }
embeddedartists 0:b567d56a59d7 4246 }
embeddedartists 0:b567d56a59d7 4247
embeddedartists 0:b567d56a59d7 4248 Adam7_deinterlace(out, in, w, h, bpp);
embeddedartists 0:b567d56a59d7 4249 }
embeddedartists 0:b567d56a59d7 4250
embeddedartists 0:b567d56a59d7 4251 return 0;
embeddedartists 0:b567d56a59d7 4252 }
embeddedartists 0:b567d56a59d7 4253
embeddedartists 0:b567d56a59d7 4254 static unsigned readChunk_PLTE(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength)
embeddedartists 0:b567d56a59d7 4255 {
embeddedartists 0:b567d56a59d7 4256 unsigned pos = 0, i;
embeddedartists 0:b567d56a59d7 4257 if(color->palette) lodepng_free(color->palette);
embeddedartists 0:b567d56a59d7 4258 color->palettesize = chunkLength / 3;
embeddedartists 0:b567d56a59d7 4259 color->palette = (unsigned char*)lodepng_malloc(4 * color->palettesize);
embeddedartists 0:b567d56a59d7 4260 if(!color->palette && color->palettesize)
embeddedartists 0:b567d56a59d7 4261 {
embeddedartists 0:b567d56a59d7 4262 color->palettesize = 0;
embeddedartists 0:b567d56a59d7 4263 return 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 4264 }
embeddedartists 0:b567d56a59d7 4265 if(color->palettesize > 256) return 38; /*error: palette too big*/
embeddedartists 0:b567d56a59d7 4266
embeddedartists 0:b567d56a59d7 4267 for(i = 0; i < color->palettesize; i++)
embeddedartists 0:b567d56a59d7 4268 {
embeddedartists 0:b567d56a59d7 4269 color->palette[4 * i + 0] = data[pos++]; /*R*/
embeddedartists 0:b567d56a59d7 4270 color->palette[4 * i + 1] = data[pos++]; /*G*/
embeddedartists 0:b567d56a59d7 4271 color->palette[4 * i + 2] = data[pos++]; /*B*/
embeddedartists 0:b567d56a59d7 4272 color->palette[4 * i + 3] = 255; /*alpha*/
embeddedartists 0:b567d56a59d7 4273 }
embeddedartists 0:b567d56a59d7 4274
embeddedartists 0:b567d56a59d7 4275 return 0; /* OK */
embeddedartists 0:b567d56a59d7 4276 }
embeddedartists 0:b567d56a59d7 4277
embeddedartists 0:b567d56a59d7 4278 static unsigned readChunk_tRNS(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength)
embeddedartists 0:b567d56a59d7 4279 {
embeddedartists 0:b567d56a59d7 4280 unsigned i;
embeddedartists 0:b567d56a59d7 4281 if(color->colortype == LCT_PALETTE)
embeddedartists 0:b567d56a59d7 4282 {
embeddedartists 0:b567d56a59d7 4283 /*error: more alpha values given than there are palette entries*/
embeddedartists 0:b567d56a59d7 4284 if(chunkLength > color->palettesize) return 38;
embeddedartists 0:b567d56a59d7 4285
embeddedartists 0:b567d56a59d7 4286 for(i = 0; i < chunkLength; i++) color->palette[4 * i + 3] = data[i];
embeddedartists 0:b567d56a59d7 4287 }
embeddedartists 0:b567d56a59d7 4288 else if(color->colortype == LCT_GREY)
embeddedartists 0:b567d56a59d7 4289 {
embeddedartists 0:b567d56a59d7 4290 /*error: this chunk must be 2 bytes for greyscale image*/
embeddedartists 0:b567d56a59d7 4291 if(chunkLength != 2) return 30;
embeddedartists 0:b567d56a59d7 4292
embeddedartists 0:b567d56a59d7 4293 color->key_defined = 1;
embeddedartists 0:b567d56a59d7 4294 color->key_r = color->key_g = color->key_b = 256 * data[0] + data[1];
embeddedartists 0:b567d56a59d7 4295 }
embeddedartists 0:b567d56a59d7 4296 else if(color->colortype == LCT_RGB)
embeddedartists 0:b567d56a59d7 4297 {
embeddedartists 0:b567d56a59d7 4298 /*error: this chunk must be 6 bytes for RGB image*/
embeddedartists 0:b567d56a59d7 4299 if(chunkLength != 6) return 41;
embeddedartists 0:b567d56a59d7 4300
embeddedartists 0:b567d56a59d7 4301 color->key_defined = 1;
embeddedartists 0:b567d56a59d7 4302 color->key_r = 256 * data[0] + data[1];
embeddedartists 0:b567d56a59d7 4303 color->key_g = 256 * data[2] + data[3];
embeddedartists 0:b567d56a59d7 4304 color->key_b = 256 * data[4] + data[5];
embeddedartists 0:b567d56a59d7 4305 }
embeddedartists 0:b567d56a59d7 4306 else return 42; /*error: tRNS chunk not allowed for other color models*/
embeddedartists 0:b567d56a59d7 4307
embeddedartists 0:b567d56a59d7 4308 return 0; /* OK */
embeddedartists 0:b567d56a59d7 4309 }
embeddedartists 0:b567d56a59d7 4310
embeddedartists 0:b567d56a59d7 4311
embeddedartists 0:b567d56a59d7 4312 #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
embeddedartists 0:b567d56a59d7 4313 /*background color chunk (bKGD)*/
embeddedartists 0:b567d56a59d7 4314 static unsigned readChunk_bKGD(LodePNGInfo* info, const unsigned char* data, size_t chunkLength)
embeddedartists 0:b567d56a59d7 4315 {
embeddedartists 0:b567d56a59d7 4316 if(info->color.colortype == LCT_PALETTE)
embeddedartists 0:b567d56a59d7 4317 {
embeddedartists 0:b567d56a59d7 4318 /*error: this chunk must be 1 byte for indexed color image*/
embeddedartists 0:b567d56a59d7 4319 if(chunkLength != 1) return 43;
embeddedartists 0:b567d56a59d7 4320
embeddedartists 0:b567d56a59d7 4321 info->background_defined = 1;
embeddedartists 0:b567d56a59d7 4322 info->background_r = info->background_g = info->background_b = data[0];
embeddedartists 0:b567d56a59d7 4323 }
embeddedartists 0:b567d56a59d7 4324 else if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA)
embeddedartists 0:b567d56a59d7 4325 {
embeddedartists 0:b567d56a59d7 4326 /*error: this chunk must be 2 bytes for greyscale image*/
embeddedartists 0:b567d56a59d7 4327 if(chunkLength != 2) return 44;
embeddedartists 0:b567d56a59d7 4328
embeddedartists 0:b567d56a59d7 4329 info->background_defined = 1;
embeddedartists 0:b567d56a59d7 4330 info->background_r = info->background_g = info->background_b
embeddedartists 0:b567d56a59d7 4331 = 256 * data[0] + data[1];
embeddedartists 0:b567d56a59d7 4332 }
embeddedartists 0:b567d56a59d7 4333 else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA)
embeddedartists 0:b567d56a59d7 4334 {
embeddedartists 0:b567d56a59d7 4335 /*error: this chunk must be 6 bytes for greyscale image*/
embeddedartists 0:b567d56a59d7 4336 if(chunkLength != 6) return 45;
embeddedartists 0:b567d56a59d7 4337
embeddedartists 0:b567d56a59d7 4338 info->background_defined = 1;
embeddedartists 0:b567d56a59d7 4339 info->background_r = 256 * data[0] + data[1];
embeddedartists 0:b567d56a59d7 4340 info->background_g = 256 * data[2] + data[3];
embeddedartists 0:b567d56a59d7 4341 info->background_b = 256 * data[4] + data[5];
embeddedartists 0:b567d56a59d7 4342 }
embeddedartists 0:b567d56a59d7 4343
embeddedartists 0:b567d56a59d7 4344 return 0; /* OK */
embeddedartists 0:b567d56a59d7 4345 }
embeddedartists 0:b567d56a59d7 4346
embeddedartists 0:b567d56a59d7 4347 /*text chunk (tEXt)*/
embeddedartists 0:b567d56a59d7 4348 static unsigned readChunk_tEXt(LodePNGInfo* info, const unsigned char* data, size_t chunkLength)
embeddedartists 0:b567d56a59d7 4349 {
embeddedartists 0:b567d56a59d7 4350 unsigned error = 0;
embeddedartists 0:b567d56a59d7 4351 char *key = 0, *str = 0;
embeddedartists 0:b567d56a59d7 4352 unsigned i;
embeddedartists 0:b567d56a59d7 4353
embeddedartists 0:b567d56a59d7 4354 while(!error) /*not really a while loop, only used to break on error*/
embeddedartists 0:b567d56a59d7 4355 {
embeddedartists 0:b567d56a59d7 4356 unsigned length, string2_begin;
embeddedartists 0:b567d56a59d7 4357
embeddedartists 0:b567d56a59d7 4358 length = 0;
embeddedartists 0:b567d56a59d7 4359 while(length < chunkLength && data[length] != 0) length++;
embeddedartists 0:b567d56a59d7 4360 /*even though it's not allowed by the standard, no error is thrown if
embeddedartists 0:b567d56a59d7 4361 there's no null termination char, if the text is empty*/
embeddedartists 0:b567d56a59d7 4362 if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/
embeddedartists 0:b567d56a59d7 4363
embeddedartists 0:b567d56a59d7 4364 key = (char*)lodepng_malloc(length + 1);
embeddedartists 0:b567d56a59d7 4365 if(!key) CERROR_BREAK(error, 83); /*alloc fail*/
embeddedartists 0:b567d56a59d7 4366
embeddedartists 0:b567d56a59d7 4367 key[length] = 0;
embeddedartists 0:b567d56a59d7 4368 for(i = 0; i < length; i++) key[i] = data[i];
embeddedartists 0:b567d56a59d7 4369
embeddedartists 0:b567d56a59d7 4370 string2_begin = length + 1; /*skip keyword null terminator*/
embeddedartists 0:b567d56a59d7 4371
embeddedartists 0:b567d56a59d7 4372 length = chunkLength < string2_begin ? 0 : chunkLength - string2_begin;
embeddedartists 0:b567d56a59d7 4373 str = (char*)lodepng_malloc(length + 1);
embeddedartists 0:b567d56a59d7 4374 if(!str) CERROR_BREAK(error, 83); /*alloc fail*/
embeddedartists 0:b567d56a59d7 4375
embeddedartists 0:b567d56a59d7 4376 str[length] = 0;
embeddedartists 0:b567d56a59d7 4377 for(i = 0; i < length; i++) str[i] = data[string2_begin + i];
embeddedartists 0:b567d56a59d7 4378
embeddedartists 0:b567d56a59d7 4379 error = lodepng_add_text(info, key, str);
embeddedartists 0:b567d56a59d7 4380
embeddedartists 0:b567d56a59d7 4381 break;
embeddedartists 0:b567d56a59d7 4382 }
embeddedartists 0:b567d56a59d7 4383
embeddedartists 0:b567d56a59d7 4384 lodepng_free(key);
embeddedartists 0:b567d56a59d7 4385 lodepng_free(str);
embeddedartists 0:b567d56a59d7 4386
embeddedartists 0:b567d56a59d7 4387 return error;
embeddedartists 0:b567d56a59d7 4388 }
embeddedartists 0:b567d56a59d7 4389
embeddedartists 0:b567d56a59d7 4390 /*compressed text chunk (zTXt)*/
embeddedartists 0:b567d56a59d7 4391 static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings,
embeddedartists 0:b567d56a59d7 4392 const unsigned char* data, size_t chunkLength)
embeddedartists 0:b567d56a59d7 4393 {
embeddedartists 0:b567d56a59d7 4394 unsigned error = 0;
embeddedartists 0:b567d56a59d7 4395 unsigned i;
embeddedartists 0:b567d56a59d7 4396
embeddedartists 0:b567d56a59d7 4397 unsigned length, string2_begin;
embeddedartists 0:b567d56a59d7 4398 char *key = 0;
embeddedartists 0:b567d56a59d7 4399 ucvector decoded;
embeddedartists 0:b567d56a59d7 4400
embeddedartists 0:b567d56a59d7 4401 ucvector_init(&decoded);
embeddedartists 0:b567d56a59d7 4402
embeddedartists 0:b567d56a59d7 4403 while(!error) /*not really a while loop, only used to break on error*/
embeddedartists 0:b567d56a59d7 4404 {
embeddedartists 0:b567d56a59d7 4405 for(length = 0; length < chunkLength && data[length] != 0; length++) ;
embeddedartists 0:b567d56a59d7 4406 if(length + 2 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/
embeddedartists 0:b567d56a59d7 4407 if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/
embeddedartists 0:b567d56a59d7 4408
embeddedartists 0:b567d56a59d7 4409 key = (char*)lodepng_malloc(length + 1);
embeddedartists 0:b567d56a59d7 4410 if(!key) CERROR_BREAK(error, 83); /*alloc fail*/
embeddedartists 0:b567d56a59d7 4411
embeddedartists 0:b567d56a59d7 4412 key[length] = 0;
embeddedartists 0:b567d56a59d7 4413 for(i = 0; i < length; i++) key[i] = data[i];
embeddedartists 0:b567d56a59d7 4414
embeddedartists 0:b567d56a59d7 4415 if(data[length + 1] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/
embeddedartists 0:b567d56a59d7 4416
embeddedartists 0:b567d56a59d7 4417 string2_begin = length + 2;
embeddedartists 0:b567d56a59d7 4418 if(string2_begin > chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/
embeddedartists 0:b567d56a59d7 4419
embeddedartists 0:b567d56a59d7 4420 length = chunkLength - string2_begin;
embeddedartists 0:b567d56a59d7 4421 /*will fail if zlib error, e.g. if length is too small*/
embeddedartists 0:b567d56a59d7 4422 error = zlib_decompress(&decoded.data, &decoded.size,
embeddedartists 0:b567d56a59d7 4423 (unsigned char*)(&data[string2_begin]),
embeddedartists 0:b567d56a59d7 4424 length, zlibsettings);
embeddedartists 0:b567d56a59d7 4425 if(error) break;
embeddedartists 0:b567d56a59d7 4426 ucvector_push_back(&decoded, 0);
embeddedartists 0:b567d56a59d7 4427
embeddedartists 0:b567d56a59d7 4428 error = lodepng_add_text(info, key, (char*)decoded.data);
embeddedartists 0:b567d56a59d7 4429
embeddedartists 0:b567d56a59d7 4430 break;
embeddedartists 0:b567d56a59d7 4431 }
embeddedartists 0:b567d56a59d7 4432
embeddedartists 0:b567d56a59d7 4433 lodepng_free(key);
embeddedartists 0:b567d56a59d7 4434 ucvector_cleanup(&decoded);
embeddedartists 0:b567d56a59d7 4435
embeddedartists 0:b567d56a59d7 4436 return error;
embeddedartists 0:b567d56a59d7 4437 }
embeddedartists 0:b567d56a59d7 4438
embeddedartists 0:b567d56a59d7 4439 /*international text chunk (iTXt)*/
embeddedartists 0:b567d56a59d7 4440 static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings,
embeddedartists 0:b567d56a59d7 4441 const unsigned char* data, size_t chunkLength)
embeddedartists 0:b567d56a59d7 4442 {
embeddedartists 0:b567d56a59d7 4443 unsigned error = 0;
embeddedartists 0:b567d56a59d7 4444 unsigned i;
embeddedartists 0:b567d56a59d7 4445
embeddedartists 0:b567d56a59d7 4446 unsigned length, begin, compressed;
embeddedartists 0:b567d56a59d7 4447 char *key = 0, *langtag = 0, *transkey = 0;
embeddedartists 0:b567d56a59d7 4448 ucvector decoded;
embeddedartists 0:b567d56a59d7 4449 ucvector_init(&decoded);
embeddedartists 0:b567d56a59d7 4450
embeddedartists 0:b567d56a59d7 4451 while(!error) /*not really a while loop, only used to break on error*/
embeddedartists 0:b567d56a59d7 4452 {
embeddedartists 0:b567d56a59d7 4453 /*Quick check if the chunk length isn't too small. Even without check
embeddedartists 0:b567d56a59d7 4454 it'd still fail with other error checks below if it's too short. This just gives a different error code.*/
embeddedartists 0:b567d56a59d7 4455 if(chunkLength < 5) CERROR_BREAK(error, 30); /*iTXt chunk too short*/
embeddedartists 0:b567d56a59d7 4456
embeddedartists 0:b567d56a59d7 4457 /*read the key*/
embeddedartists 0:b567d56a59d7 4458 for(length = 0; length < chunkLength && data[length] != 0; length++) ;
embeddedartists 0:b567d56a59d7 4459 if(length + 3 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination char, corrupt?*/
embeddedartists 0:b567d56a59d7 4460 if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/
embeddedartists 0:b567d56a59d7 4461
embeddedartists 0:b567d56a59d7 4462 key = (char*)lodepng_malloc(length + 1);
embeddedartists 0:b567d56a59d7 4463 if(!key) CERROR_BREAK(error, 83); /*alloc fail*/
embeddedartists 0:b567d56a59d7 4464
embeddedartists 0:b567d56a59d7 4465 key[length] = 0;
embeddedartists 0:b567d56a59d7 4466 for(i = 0; i < length; i++) key[i] = data[i];
embeddedartists 0:b567d56a59d7 4467
embeddedartists 0:b567d56a59d7 4468 /*read the compression method*/
embeddedartists 0:b567d56a59d7 4469 compressed = data[length + 1];
embeddedartists 0:b567d56a59d7 4470 if(data[length + 2] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/
embeddedartists 0:b567d56a59d7 4471
embeddedartists 0:b567d56a59d7 4472 /*even though it's not allowed by the standard, no error is thrown if
embeddedartists 0:b567d56a59d7 4473 there's no null termination char, if the text is empty for the next 3 texts*/
embeddedartists 0:b567d56a59d7 4474
embeddedartists 0:b567d56a59d7 4475 /*read the langtag*/
embeddedartists 0:b567d56a59d7 4476 begin = length + 3;
embeddedartists 0:b567d56a59d7 4477 length = 0;
embeddedartists 0:b567d56a59d7 4478 for(i = begin; i < chunkLength && data[i] != 0; i++) length++;
embeddedartists 0:b567d56a59d7 4479
embeddedartists 0:b567d56a59d7 4480 langtag = (char*)lodepng_malloc(length + 1);
embeddedartists 0:b567d56a59d7 4481 if(!langtag) CERROR_BREAK(error, 83); /*alloc fail*/
embeddedartists 0:b567d56a59d7 4482
embeddedartists 0:b567d56a59d7 4483 langtag[length] = 0;
embeddedartists 0:b567d56a59d7 4484 for(i = 0; i < length; i++) langtag[i] = data[begin + i];
embeddedartists 0:b567d56a59d7 4485
embeddedartists 0:b567d56a59d7 4486 /*read the transkey*/
embeddedartists 0:b567d56a59d7 4487 begin += length + 1;
embeddedartists 0:b567d56a59d7 4488 length = 0;
embeddedartists 0:b567d56a59d7 4489 for(i = begin; i < chunkLength && data[i] != 0; i++) length++;
embeddedartists 0:b567d56a59d7 4490
embeddedartists 0:b567d56a59d7 4491 transkey = (char*)lodepng_malloc(length + 1);
embeddedartists 0:b567d56a59d7 4492 if(!transkey) CERROR_BREAK(error, 83); /*alloc fail*/
embeddedartists 0:b567d56a59d7 4493
embeddedartists 0:b567d56a59d7 4494 transkey[length] = 0;
embeddedartists 0:b567d56a59d7 4495 for(i = 0; i < length; i++) transkey[i] = data[begin + i];
embeddedartists 0:b567d56a59d7 4496
embeddedartists 0:b567d56a59d7 4497 /*read the actual text*/
embeddedartists 0:b567d56a59d7 4498 begin += length + 1;
embeddedartists 0:b567d56a59d7 4499
embeddedartists 0:b567d56a59d7 4500 length = chunkLength < begin ? 0 : chunkLength - begin;
embeddedartists 0:b567d56a59d7 4501
embeddedartists 0:b567d56a59d7 4502 if(compressed)
embeddedartists 0:b567d56a59d7 4503 {
embeddedartists 0:b567d56a59d7 4504 /*will fail if zlib error, e.g. if length is too small*/
embeddedartists 0:b567d56a59d7 4505 error = zlib_decompress(&decoded.data, &decoded.size,
embeddedartists 0:b567d56a59d7 4506 (unsigned char*)(&data[begin]),
embeddedartists 0:b567d56a59d7 4507 length, zlibsettings);
embeddedartists 0:b567d56a59d7 4508 if(error) break;
embeddedartists 0:b567d56a59d7 4509 if(decoded.allocsize < decoded.size) decoded.allocsize = decoded.size;
embeddedartists 0:b567d56a59d7 4510 ucvector_push_back(&decoded, 0);
embeddedartists 0:b567d56a59d7 4511 }
embeddedartists 0:b567d56a59d7 4512 else
embeddedartists 0:b567d56a59d7 4513 {
embeddedartists 0:b567d56a59d7 4514 if(!ucvector_resize(&decoded, length + 1)) CERROR_BREAK(error, 83 /*alloc fail*/);
embeddedartists 0:b567d56a59d7 4515
embeddedartists 0:b567d56a59d7 4516 decoded.data[length] = 0;
embeddedartists 0:b567d56a59d7 4517 for(i = 0; i < length; i++) decoded.data[i] = data[begin + i];
embeddedartists 0:b567d56a59d7 4518 }
embeddedartists 0:b567d56a59d7 4519
embeddedartists 0:b567d56a59d7 4520 error = lodepng_add_itext(info, key, langtag, transkey, (char*)decoded.data);
embeddedartists 0:b567d56a59d7 4521
embeddedartists 0:b567d56a59d7 4522 break;
embeddedartists 0:b567d56a59d7 4523 }
embeddedartists 0:b567d56a59d7 4524
embeddedartists 0:b567d56a59d7 4525 lodepng_free(key);
embeddedartists 0:b567d56a59d7 4526 lodepng_free(langtag);
embeddedartists 0:b567d56a59d7 4527 lodepng_free(transkey);
embeddedartists 0:b567d56a59d7 4528 ucvector_cleanup(&decoded);
embeddedartists 0:b567d56a59d7 4529
embeddedartists 0:b567d56a59d7 4530 return error;
embeddedartists 0:b567d56a59d7 4531 }
embeddedartists 0:b567d56a59d7 4532
embeddedartists 0:b567d56a59d7 4533 static unsigned readChunk_tIME(LodePNGInfo* info, const unsigned char* data, size_t chunkLength)
embeddedartists 0:b567d56a59d7 4534 {
embeddedartists 0:b567d56a59d7 4535 if(chunkLength != 7) return 73; /*invalid tIME chunk size*/
embeddedartists 0:b567d56a59d7 4536
embeddedartists 0:b567d56a59d7 4537 info->time_defined = 1;
embeddedartists 0:b567d56a59d7 4538 info->time.year = 256 * data[0] + data[+ 1];
embeddedartists 0:b567d56a59d7 4539 info->time.month = data[2];
embeddedartists 0:b567d56a59d7 4540 info->time.day = data[3];
embeddedartists 0:b567d56a59d7 4541 info->time.hour = data[4];
embeddedartists 0:b567d56a59d7 4542 info->time.minute = data[5];
embeddedartists 0:b567d56a59d7 4543 info->time.second = data[6];
embeddedartists 0:b567d56a59d7 4544
embeddedartists 0:b567d56a59d7 4545 return 0; /* OK */
embeddedartists 0:b567d56a59d7 4546 }
embeddedartists 0:b567d56a59d7 4547
embeddedartists 0:b567d56a59d7 4548 static unsigned readChunk_pHYs(LodePNGInfo* info, const unsigned char* data, size_t chunkLength)
embeddedartists 0:b567d56a59d7 4549 {
embeddedartists 0:b567d56a59d7 4550 if(chunkLength != 9) return 74; /*invalid pHYs chunk size*/
embeddedartists 0:b567d56a59d7 4551
embeddedartists 0:b567d56a59d7 4552 info->phys_defined = 1;
embeddedartists 0:b567d56a59d7 4553 info->phys_x = 16777216 * data[0] + 65536 * data[1] + 256 * data[2] + data[3];
embeddedartists 0:b567d56a59d7 4554 info->phys_y = 16777216 * data[4] + 65536 * data[5] + 256 * data[6] + data[7];
embeddedartists 0:b567d56a59d7 4555 info->phys_unit = data[8];
embeddedartists 0:b567d56a59d7 4556
embeddedartists 0:b567d56a59d7 4557 return 0; /* OK */
embeddedartists 0:b567d56a59d7 4558 }
embeddedartists 0:b567d56a59d7 4559 #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
embeddedartists 0:b567d56a59d7 4560
embeddedartists 0:b567d56a59d7 4561 /*read a PNG, the result will be in the same color type as the PNG (hence "generic")*/
embeddedartists 0:b567d56a59d7 4562 static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h,
embeddedartists 0:b567d56a59d7 4563 LodePNGState* state,
embeddedartists 0:b567d56a59d7 4564 const unsigned char* in, size_t insize)
embeddedartists 0:b567d56a59d7 4565 {
embeddedartists 0:b567d56a59d7 4566 unsigned char IEND = 0;
embeddedartists 0:b567d56a59d7 4567 const unsigned char* chunk;
embeddedartists 0:b567d56a59d7 4568 size_t i;
embeddedartists 0:b567d56a59d7 4569 ucvector idat; /*the data from idat chunks*/
embeddedartists 0:b567d56a59d7 4570 ucvector scanlines;
embeddedartists 0:b567d56a59d7 4571
embeddedartists 0:b567d56a59d7 4572 /*for unknown chunk order*/
embeddedartists 0:b567d56a59d7 4573 unsigned unknown = 0;
embeddedartists 0:b567d56a59d7 4574 #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
embeddedartists 0:b567d56a59d7 4575 unsigned critical_pos = 1; /*1 = after IHDR, 2 = after PLTE, 3 = after IDAT*/
embeddedartists 0:b567d56a59d7 4576 #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
embeddedartists 0:b567d56a59d7 4577
embeddedartists 0:b567d56a59d7 4578 /*provide some proper output values if error will happen*/
embeddedartists 0:b567d56a59d7 4579 *out = 0;
embeddedartists 0:b567d56a59d7 4580
embeddedartists 0:b567d56a59d7 4581 state->error = lodepng_inspect(w, h, state, in, insize); /*reads header and resets other parameters in state->info_png*/
embeddedartists 0:b567d56a59d7 4582 if(state->error) return;
embeddedartists 0:b567d56a59d7 4583
embeddedartists 0:b567d56a59d7 4584 ucvector_init(&idat);
embeddedartists 0:b567d56a59d7 4585 chunk = &in[33]; /*first byte of the first chunk after the header*/
embeddedartists 0:b567d56a59d7 4586
embeddedartists 0:b567d56a59d7 4587 /*loop through the chunks, ignoring unknown chunks and stopping at IEND chunk.
embeddedartists 0:b567d56a59d7 4588 IDAT data is put at the start of the in buffer*/
embeddedartists 0:b567d56a59d7 4589 while(!IEND && !state->error)
embeddedartists 0:b567d56a59d7 4590 {
embeddedartists 0:b567d56a59d7 4591 unsigned chunkLength;
embeddedartists 0:b567d56a59d7 4592 const unsigned char* data; /*the data in the chunk*/
embeddedartists 0:b567d56a59d7 4593
embeddedartists 0:b567d56a59d7 4594 /*error: size of the in buffer too small to contain next chunk*/
embeddedartists 0:b567d56a59d7 4595 if((size_t)((chunk - in) + 12) > insize || chunk < in) CERROR_BREAK(state->error, 30);
embeddedartists 0:b567d56a59d7 4596
embeddedartists 0:b567d56a59d7 4597 /*length of the data of the chunk, excluding the length bytes, chunk type and CRC bytes*/
embeddedartists 0:b567d56a59d7 4598 chunkLength = lodepng_chunk_length(chunk);
embeddedartists 0:b567d56a59d7 4599 /*error: chunk length larger than the max PNG chunk size*/
embeddedartists 0:b567d56a59d7 4600 if(chunkLength > 2147483647) CERROR_BREAK(state->error, 63);
embeddedartists 0:b567d56a59d7 4601
embeddedartists 0:b567d56a59d7 4602 if((size_t)((chunk - in) + chunkLength + 12) > insize || (chunk + chunkLength + 12) < in)
embeddedartists 0:b567d56a59d7 4603 {
embeddedartists 0:b567d56a59d7 4604 CERROR_BREAK(state->error, 64); /*error: size of the in buffer too small to contain next chunk*/
embeddedartists 0:b567d56a59d7 4605 }
embeddedartists 0:b567d56a59d7 4606
embeddedartists 0:b567d56a59d7 4607 data = lodepng_chunk_data_const(chunk);
embeddedartists 0:b567d56a59d7 4608
embeddedartists 0:b567d56a59d7 4609 /*IDAT chunk, containing compressed image data*/
embeddedartists 0:b567d56a59d7 4610 if(lodepng_chunk_type_equals(chunk, "IDAT"))
embeddedartists 0:b567d56a59d7 4611 {
embeddedartists 0:b567d56a59d7 4612 size_t oldsize = idat.size;
embeddedartists 0:b567d56a59d7 4613 if(!ucvector_resize(&idat, oldsize + chunkLength)) CERROR_BREAK(state->error, 83 /*alloc fail*/);
embeddedartists 0:b567d56a59d7 4614 for(i = 0; i < chunkLength; i++) idat.data[oldsize + i] = data[i];
embeddedartists 0:b567d56a59d7 4615 #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
embeddedartists 0:b567d56a59d7 4616 critical_pos = 3;
embeddedartists 0:b567d56a59d7 4617 #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
embeddedartists 0:b567d56a59d7 4618 }
embeddedartists 0:b567d56a59d7 4619 /*IEND chunk*/
embeddedartists 0:b567d56a59d7 4620 else if(lodepng_chunk_type_equals(chunk, "IEND"))
embeddedartists 0:b567d56a59d7 4621 {
embeddedartists 0:b567d56a59d7 4622 IEND = 1;
embeddedartists 0:b567d56a59d7 4623 }
embeddedartists 0:b567d56a59d7 4624 /*palette chunk (PLTE)*/
embeddedartists 0:b567d56a59d7 4625 else if(lodepng_chunk_type_equals(chunk, "PLTE"))
embeddedartists 0:b567d56a59d7 4626 {
embeddedartists 0:b567d56a59d7 4627 state->error = readChunk_PLTE(&state->info_png.color, data, chunkLength);
embeddedartists 0:b567d56a59d7 4628 if(state->error) break;
embeddedartists 0:b567d56a59d7 4629 #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
embeddedartists 0:b567d56a59d7 4630 critical_pos = 2;
embeddedartists 0:b567d56a59d7 4631 #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
embeddedartists 0:b567d56a59d7 4632 }
embeddedartists 0:b567d56a59d7 4633 /*palette transparency chunk (tRNS)*/
embeddedartists 0:b567d56a59d7 4634 else if(lodepng_chunk_type_equals(chunk, "tRNS"))
embeddedartists 0:b567d56a59d7 4635 {
embeddedartists 0:b567d56a59d7 4636 state->error = readChunk_tRNS(&state->info_png.color, data, chunkLength);
embeddedartists 0:b567d56a59d7 4637 if(state->error) break;
embeddedartists 0:b567d56a59d7 4638 }
embeddedartists 0:b567d56a59d7 4639 #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
embeddedartists 0:b567d56a59d7 4640 /*background color chunk (bKGD)*/
embeddedartists 0:b567d56a59d7 4641 else if(lodepng_chunk_type_equals(chunk, "bKGD"))
embeddedartists 0:b567d56a59d7 4642 {
embeddedartists 0:b567d56a59d7 4643 state->error = readChunk_bKGD(&state->info_png, data, chunkLength);
embeddedartists 0:b567d56a59d7 4644 if(state->error) break;
embeddedartists 0:b567d56a59d7 4645 }
embeddedartists 0:b567d56a59d7 4646 /*text chunk (tEXt)*/
embeddedartists 0:b567d56a59d7 4647 else if(lodepng_chunk_type_equals(chunk, "tEXt"))
embeddedartists 0:b567d56a59d7 4648 {
embeddedartists 0:b567d56a59d7 4649 if(state->decoder.read_text_chunks)
embeddedartists 0:b567d56a59d7 4650 {
embeddedartists 0:b567d56a59d7 4651 state->error = readChunk_tEXt(&state->info_png, data, chunkLength);
embeddedartists 0:b567d56a59d7 4652 if(state->error) break;
embeddedartists 0:b567d56a59d7 4653 }
embeddedartists 0:b567d56a59d7 4654 }
embeddedartists 0:b567d56a59d7 4655 /*compressed text chunk (zTXt)*/
embeddedartists 0:b567d56a59d7 4656 else if(lodepng_chunk_type_equals(chunk, "zTXt"))
embeddedartists 0:b567d56a59d7 4657 {
embeddedartists 0:b567d56a59d7 4658 if(state->decoder.read_text_chunks)
embeddedartists 0:b567d56a59d7 4659 {
embeddedartists 0:b567d56a59d7 4660 state->error = readChunk_zTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength);
embeddedartists 0:b567d56a59d7 4661 if(state->error) break;
embeddedartists 0:b567d56a59d7 4662 }
embeddedartists 0:b567d56a59d7 4663 }
embeddedartists 0:b567d56a59d7 4664 /*international text chunk (iTXt)*/
embeddedartists 0:b567d56a59d7 4665 else if(lodepng_chunk_type_equals(chunk, "iTXt"))
embeddedartists 0:b567d56a59d7 4666 {
embeddedartists 0:b567d56a59d7 4667 if(state->decoder.read_text_chunks)
embeddedartists 0:b567d56a59d7 4668 {
embeddedartists 0:b567d56a59d7 4669 state->error = readChunk_iTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength);
embeddedartists 0:b567d56a59d7 4670 if(state->error) break;
embeddedartists 0:b567d56a59d7 4671 }
embeddedartists 0:b567d56a59d7 4672 }
embeddedartists 0:b567d56a59d7 4673 else if(lodepng_chunk_type_equals(chunk, "tIME"))
embeddedartists 0:b567d56a59d7 4674 {
embeddedartists 0:b567d56a59d7 4675 state->error = readChunk_tIME(&state->info_png, data, chunkLength);
embeddedartists 0:b567d56a59d7 4676 if(state->error) break;
embeddedartists 0:b567d56a59d7 4677 }
embeddedartists 0:b567d56a59d7 4678 else if(lodepng_chunk_type_equals(chunk, "pHYs"))
embeddedartists 0:b567d56a59d7 4679 {
embeddedartists 0:b567d56a59d7 4680 state->error = readChunk_pHYs(&state->info_png, data, chunkLength);
embeddedartists 0:b567d56a59d7 4681 if(state->error) break;
embeddedartists 0:b567d56a59d7 4682 }
embeddedartists 0:b567d56a59d7 4683 #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
embeddedartists 0:b567d56a59d7 4684 else /*it's not an implemented chunk type, so ignore it: skip over the data*/
embeddedartists 0:b567d56a59d7 4685 {
embeddedartists 0:b567d56a59d7 4686 /*error: unknown critical chunk (5th bit of first byte of chunk type is 0)*/
embeddedartists 0:b567d56a59d7 4687 if(!lodepng_chunk_ancillary(chunk)) CERROR_BREAK(state->error, 69);
embeddedartists 0:b567d56a59d7 4688
embeddedartists 0:b567d56a59d7 4689 unknown = 1;
embeddedartists 0:b567d56a59d7 4690 #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
embeddedartists 0:b567d56a59d7 4691 if(state->decoder.remember_unknown_chunks)
embeddedartists 0:b567d56a59d7 4692 {
embeddedartists 0:b567d56a59d7 4693 state->error = lodepng_chunk_append(&state->info_png.unknown_chunks_data[critical_pos - 1],
embeddedartists 0:b567d56a59d7 4694 &state->info_png.unknown_chunks_size[critical_pos - 1], chunk);
embeddedartists 0:b567d56a59d7 4695 if(state->error) break;
embeddedartists 0:b567d56a59d7 4696 }
embeddedartists 0:b567d56a59d7 4697 #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
embeddedartists 0:b567d56a59d7 4698 }
embeddedartists 0:b567d56a59d7 4699
embeddedartists 0:b567d56a59d7 4700 if(!state->decoder.ignore_crc && !unknown) /*check CRC if wanted, only on known chunk types*/
embeddedartists 0:b567d56a59d7 4701 {
embeddedartists 0:b567d56a59d7 4702 if(lodepng_chunk_check_crc(chunk)) CERROR_BREAK(state->error, 57); /*invalid CRC*/
embeddedartists 0:b567d56a59d7 4703 }
embeddedartists 0:b567d56a59d7 4704
embeddedartists 0:b567d56a59d7 4705 if(!IEND) chunk = lodepng_chunk_next_const(chunk);
embeddedartists 0:b567d56a59d7 4706 }
embeddedartists 0:b567d56a59d7 4707
embeddedartists 0:b567d56a59d7 4708 ucvector_init(&scanlines);
embeddedartists 0:b567d56a59d7 4709 if(!state->error)
embeddedartists 0:b567d56a59d7 4710 {
embeddedartists 0:b567d56a59d7 4711 /*maximum final image length is already reserved in the vector's length - this is not really necessary*/
embeddedartists 0:b567d56a59d7 4712 if(!ucvector_resize(&scanlines, lodepng_get_raw_size(*w, *h, &state->info_png.color) + *h))
embeddedartists 0:b567d56a59d7 4713 {
embeddedartists 0:b567d56a59d7 4714 state->error = 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 4715 }
embeddedartists 0:b567d56a59d7 4716 }
embeddedartists 0:b567d56a59d7 4717 if(!state->error)
embeddedartists 0:b567d56a59d7 4718 {
embeddedartists 0:b567d56a59d7 4719 /*decompress with the Zlib decompressor*/
embeddedartists 0:b567d56a59d7 4720 state->error = zlib_decompress(&scanlines.data, &scanlines.size, idat.data,
embeddedartists 0:b567d56a59d7 4721 idat.size, &state->decoder.zlibsettings);
embeddedartists 0:b567d56a59d7 4722 }
embeddedartists 0:b567d56a59d7 4723 ucvector_cleanup(&idat);
embeddedartists 0:b567d56a59d7 4724
embeddedartists 0:b567d56a59d7 4725 if(!state->error)
embeddedartists 0:b567d56a59d7 4726 {
embeddedartists 0:b567d56a59d7 4727 ucvector outv;
embeddedartists 0:b567d56a59d7 4728 ucvector_init(&outv);
embeddedartists 0:b567d56a59d7 4729 if(!ucvector_resizev(&outv,
embeddedartists 0:b567d56a59d7 4730 lodepng_get_raw_size(*w, *h, &state->info_png.color), 0)) state->error = 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 4731 if(!state->error) state->error = postProcessScanlines(outv.data, scanlines.data, *w, *h, &state->info_png);
embeddedartists 0:b567d56a59d7 4732 *out = outv.data;
embeddedartists 0:b567d56a59d7 4733 }
embeddedartists 0:b567d56a59d7 4734 ucvector_cleanup(&scanlines);
embeddedartists 0:b567d56a59d7 4735 }
embeddedartists 0:b567d56a59d7 4736
embeddedartists 0:b567d56a59d7 4737 unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h,
embeddedartists 0:b567d56a59d7 4738 LodePNGState* state,
embeddedartists 0:b567d56a59d7 4739 const unsigned char* in, size_t insize)
embeddedartists 0:b567d56a59d7 4740 {
embeddedartists 0:b567d56a59d7 4741 *out = 0;
embeddedartists 0:b567d56a59d7 4742 decodeGeneric(out, w, h, state, in, insize);
embeddedartists 0:b567d56a59d7 4743 if(state->error) return state->error;
embeddedartists 0:b567d56a59d7 4744 if(!state->decoder.color_convert || lodepng_color_mode_equal(&state->info_raw, &state->info_png.color))
embeddedartists 0:b567d56a59d7 4745 {
embeddedartists 0:b567d56a59d7 4746 /*same color type, no copying or converting of data needed*/
embeddedartists 0:b567d56a59d7 4747 /*store the info_png color settings on the info_raw so that the info_raw still reflects what colortype
embeddedartists 0:b567d56a59d7 4748 the raw image has to the end user*/
embeddedartists 0:b567d56a59d7 4749 if(!state->decoder.color_convert)
embeddedartists 0:b567d56a59d7 4750 {
embeddedartists 0:b567d56a59d7 4751 state->error = lodepng_color_mode_copy(&state->info_raw, &state->info_png.color);
embeddedartists 0:b567d56a59d7 4752 if(state->error) return state->error;
embeddedartists 0:b567d56a59d7 4753 }
embeddedartists 0:b567d56a59d7 4754 }
embeddedartists 0:b567d56a59d7 4755 else
embeddedartists 0:b567d56a59d7 4756 {
embeddedartists 0:b567d56a59d7 4757 /*color conversion needed; sort of copy of the data*/
embeddedartists 0:b567d56a59d7 4758 unsigned char* data = *out;
embeddedartists 0:b567d56a59d7 4759 size_t outsize;
embeddedartists 0:b567d56a59d7 4760
embeddedartists 0:b567d56a59d7 4761 /*TODO: check if this works according to the statement in the documentation: "The converter can convert
embeddedartists 0:b567d56a59d7 4762 from greyscale input color type, to 8-bit greyscale or greyscale with alpha"*/
embeddedartists 0:b567d56a59d7 4763 if(!(state->info_raw.colortype == LCT_RGB || state->info_raw.colortype == LCT_RGBA)
embeddedartists 0:b567d56a59d7 4764 && !(state->info_raw.bitdepth == 8))
embeddedartists 0:b567d56a59d7 4765 {
embeddedartists 0:b567d56a59d7 4766 return 56; /*unsupported color mode conversion*/
embeddedartists 0:b567d56a59d7 4767 }
embeddedartists 0:b567d56a59d7 4768
embeddedartists 0:b567d56a59d7 4769 outsize = lodepng_get_raw_size(*w, *h, &state->info_raw);
embeddedartists 0:b567d56a59d7 4770 *out = (unsigned char*)lodepng_malloc(outsize);
embeddedartists 0:b567d56a59d7 4771 if(!(*out))
embeddedartists 0:b567d56a59d7 4772 {
embeddedartists 0:b567d56a59d7 4773 state->error = 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 4774 }
embeddedartists 0:b567d56a59d7 4775 else state->error = lodepng_convert(*out, data, &state->info_raw, &state->info_png.color, *w, *h, state->decoder.fix_png);
embeddedartists 0:b567d56a59d7 4776 lodepng_free(data);
embeddedartists 0:b567d56a59d7 4777 }
embeddedartists 0:b567d56a59d7 4778 return state->error;
embeddedartists 0:b567d56a59d7 4779 }
embeddedartists 0:b567d56a59d7 4780
embeddedartists 0:b567d56a59d7 4781 unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in,
embeddedartists 0:b567d56a59d7 4782 size_t insize, LodePNGColorType colortype, unsigned bitdepth)
embeddedartists 0:b567d56a59d7 4783 {
embeddedartists 0:b567d56a59d7 4784 unsigned error;
embeddedartists 0:b567d56a59d7 4785 LodePNGState state;
embeddedartists 0:b567d56a59d7 4786 lodepng_state_init(&state);
embeddedartists 0:b567d56a59d7 4787 state.info_raw.colortype = colortype;
embeddedartists 0:b567d56a59d7 4788 state.info_raw.bitdepth = bitdepth;
embeddedartists 0:b567d56a59d7 4789 error = lodepng_decode(out, w, h, &state, in, insize);
embeddedartists 0:b567d56a59d7 4790 lodepng_state_cleanup(&state);
embeddedartists 0:b567d56a59d7 4791 return error;
embeddedartists 0:b567d56a59d7 4792 }
embeddedartists 0:b567d56a59d7 4793
embeddedartists 0:b567d56a59d7 4794 unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize)
embeddedartists 0:b567d56a59d7 4795 {
embeddedartists 0:b567d56a59d7 4796 return lodepng_decode_memory(out, w, h, in, insize, LCT_RGBA, 8);
embeddedartists 0:b567d56a59d7 4797 }
embeddedartists 0:b567d56a59d7 4798
embeddedartists 0:b567d56a59d7 4799 unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize)
embeddedartists 0:b567d56a59d7 4800 {
embeddedartists 0:b567d56a59d7 4801 return lodepng_decode_memory(out, w, h, in, insize, LCT_RGB, 8);
embeddedartists 0:b567d56a59d7 4802 }
embeddedartists 0:b567d56a59d7 4803
embeddedartists 0:b567d56a59d7 4804 #ifdef LODEPNG_COMPILE_DISK
embeddedartists 0:b567d56a59d7 4805 unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename,
embeddedartists 0:b567d56a59d7 4806 LodePNGColorType colortype, unsigned bitdepth)
embeddedartists 0:b567d56a59d7 4807 {
embeddedartists 0:b567d56a59d7 4808 unsigned char* buffer;
embeddedartists 0:b567d56a59d7 4809 size_t buffersize;
embeddedartists 0:b567d56a59d7 4810 unsigned error;
embeddedartists 0:b567d56a59d7 4811 error = lodepng_load_file(&buffer, &buffersize, filename);
embeddedartists 0:b567d56a59d7 4812 if(!error) error = lodepng_decode_memory(out, w, h, buffer, buffersize, colortype, bitdepth);
embeddedartists 0:b567d56a59d7 4813 lodepng_free(buffer);
embeddedartists 0:b567d56a59d7 4814 return error;
embeddedartists 0:b567d56a59d7 4815 }
embeddedartists 0:b567d56a59d7 4816
embeddedartists 0:b567d56a59d7 4817 unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename)
embeddedartists 0:b567d56a59d7 4818 {
embeddedartists 0:b567d56a59d7 4819 return lodepng_decode_file(out, w, h, filename, LCT_RGBA, 8);
embeddedartists 0:b567d56a59d7 4820 }
embeddedartists 0:b567d56a59d7 4821
embeddedartists 0:b567d56a59d7 4822 unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename)
embeddedartists 0:b567d56a59d7 4823 {
embeddedartists 0:b567d56a59d7 4824 return lodepng_decode_file(out, w, h, filename, LCT_RGB, 8);
embeddedartists 0:b567d56a59d7 4825 }
embeddedartists 0:b567d56a59d7 4826 #endif /*LODEPNG_COMPILE_DISK*/
embeddedartists 0:b567d56a59d7 4827
embeddedartists 0:b567d56a59d7 4828 void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings)
embeddedartists 0:b567d56a59d7 4829 {
embeddedartists 0:b567d56a59d7 4830 settings->color_convert = 1;
embeddedartists 0:b567d56a59d7 4831 #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
embeddedartists 0:b567d56a59d7 4832 settings->read_text_chunks = 1;
embeddedartists 0:b567d56a59d7 4833 settings->remember_unknown_chunks = 0;
embeddedartists 0:b567d56a59d7 4834 #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
embeddedartists 0:b567d56a59d7 4835 settings->ignore_crc = 0;
embeddedartists 0:b567d56a59d7 4836 settings->fix_png = 0;
embeddedartists 0:b567d56a59d7 4837 lodepng_decompress_settings_init(&settings->zlibsettings);
embeddedartists 0:b567d56a59d7 4838 }
embeddedartists 0:b567d56a59d7 4839
embeddedartists 0:b567d56a59d7 4840 #endif /*LODEPNG_COMPILE_DECODER*/
embeddedartists 0:b567d56a59d7 4841
embeddedartists 0:b567d56a59d7 4842 #if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER)
embeddedartists 0:b567d56a59d7 4843
embeddedartists 0:b567d56a59d7 4844 void lodepng_state_init(LodePNGState* state)
embeddedartists 0:b567d56a59d7 4845 {
embeddedartists 0:b567d56a59d7 4846 #ifdef LODEPNG_COMPILE_DECODER
embeddedartists 0:b567d56a59d7 4847 lodepng_decoder_settings_init(&state->decoder);
embeddedartists 0:b567d56a59d7 4848 #endif /*LODEPNG_COMPILE_DECODER*/
embeddedartists 0:b567d56a59d7 4849 #ifdef LODEPNG_COMPILE_ENCODER
embeddedartists 0:b567d56a59d7 4850 lodepng_encoder_settings_init(&state->encoder);
embeddedartists 0:b567d56a59d7 4851 #endif /*LODEPNG_COMPILE_ENCODER*/
embeddedartists 0:b567d56a59d7 4852 lodepng_color_mode_init(&state->info_raw);
embeddedartists 0:b567d56a59d7 4853 lodepng_info_init(&state->info_png);
embeddedartists 0:b567d56a59d7 4854 state->error = 1;
embeddedartists 0:b567d56a59d7 4855 }
embeddedartists 0:b567d56a59d7 4856
embeddedartists 0:b567d56a59d7 4857 void lodepng_state_cleanup(LodePNGState* state)
embeddedartists 0:b567d56a59d7 4858 {
embeddedartists 0:b567d56a59d7 4859 lodepng_color_mode_cleanup(&state->info_raw);
embeddedartists 0:b567d56a59d7 4860 lodepng_info_cleanup(&state->info_png);
embeddedartists 0:b567d56a59d7 4861 }
embeddedartists 0:b567d56a59d7 4862
embeddedartists 0:b567d56a59d7 4863 void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source)
embeddedartists 0:b567d56a59d7 4864 {
embeddedartists 0:b567d56a59d7 4865 lodepng_state_cleanup(dest);
embeddedartists 0:b567d56a59d7 4866 *dest = *source;
embeddedartists 0:b567d56a59d7 4867 lodepng_color_mode_init(&dest->info_raw);
embeddedartists 0:b567d56a59d7 4868 lodepng_info_init(&dest->info_png);
embeddedartists 0:b567d56a59d7 4869 dest->error = lodepng_color_mode_copy(&dest->info_raw, &source->info_raw); if(dest->error) return;
embeddedartists 0:b567d56a59d7 4870 dest->error = lodepng_info_copy(&dest->info_png, &source->info_png); if(dest->error) return;
embeddedartists 0:b567d56a59d7 4871 }
embeddedartists 0:b567d56a59d7 4872
embeddedartists 0:b567d56a59d7 4873 #endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */
embeddedartists 0:b567d56a59d7 4874
embeddedartists 0:b567d56a59d7 4875 #ifdef LODEPNG_COMPILE_ENCODER
embeddedartists 0:b567d56a59d7 4876
embeddedartists 0:b567d56a59d7 4877 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 4878 /* / PNG Encoder / */
embeddedartists 0:b567d56a59d7 4879 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 4880
embeddedartists 0:b567d56a59d7 4881 /*chunkName must be string of 4 characters*/
embeddedartists 0:b567d56a59d7 4882 static unsigned addChunk(ucvector* out, const char* chunkName, const unsigned char* data, size_t length)
embeddedartists 0:b567d56a59d7 4883 {
embeddedartists 0:b567d56a59d7 4884 CERROR_TRY_RETURN(lodepng_chunk_create(&out->data, &out->size, (unsigned)length, chunkName, data));
embeddedartists 0:b567d56a59d7 4885 out->allocsize = out->size; /*fix the allocsize again*/
embeddedartists 0:b567d56a59d7 4886 return 0;
embeddedartists 0:b567d56a59d7 4887 }
embeddedartists 0:b567d56a59d7 4888
embeddedartists 0:b567d56a59d7 4889 static void writeSignature(ucvector* out)
embeddedartists 0:b567d56a59d7 4890 {
embeddedartists 0:b567d56a59d7 4891 /*8 bytes PNG signature, aka the magic bytes*/
embeddedartists 0:b567d56a59d7 4892 ucvector_push_back(out, 137);
embeddedartists 0:b567d56a59d7 4893 ucvector_push_back(out, 80);
embeddedartists 0:b567d56a59d7 4894 ucvector_push_back(out, 78);
embeddedartists 0:b567d56a59d7 4895 ucvector_push_back(out, 71);
embeddedartists 0:b567d56a59d7 4896 ucvector_push_back(out, 13);
embeddedartists 0:b567d56a59d7 4897 ucvector_push_back(out, 10);
embeddedartists 0:b567d56a59d7 4898 ucvector_push_back(out, 26);
embeddedartists 0:b567d56a59d7 4899 ucvector_push_back(out, 10);
embeddedartists 0:b567d56a59d7 4900 }
embeddedartists 0:b567d56a59d7 4901
embeddedartists 0:b567d56a59d7 4902 static unsigned addChunk_IHDR(ucvector* out, unsigned w, unsigned h,
embeddedartists 0:b567d56a59d7 4903 LodePNGColorType colortype, unsigned bitdepth, unsigned interlace_method)
embeddedartists 0:b567d56a59d7 4904 {
embeddedartists 0:b567d56a59d7 4905 unsigned error = 0;
embeddedartists 0:b567d56a59d7 4906 ucvector header;
embeddedartists 0:b567d56a59d7 4907 ucvector_init(&header);
embeddedartists 0:b567d56a59d7 4908
embeddedartists 0:b567d56a59d7 4909 lodepng_add32bitInt(&header, w); /*width*/
embeddedartists 0:b567d56a59d7 4910 lodepng_add32bitInt(&header, h); /*height*/
embeddedartists 0:b567d56a59d7 4911 ucvector_push_back(&header, (unsigned char)bitdepth); /*bit depth*/
embeddedartists 0:b567d56a59d7 4912 ucvector_push_back(&header, (unsigned char)colortype); /*color type*/
embeddedartists 0:b567d56a59d7 4913 ucvector_push_back(&header, 0); /*compression method*/
embeddedartists 0:b567d56a59d7 4914 ucvector_push_back(&header, 0); /*filter method*/
embeddedartists 0:b567d56a59d7 4915 ucvector_push_back(&header, interlace_method); /*interlace method*/
embeddedartists 0:b567d56a59d7 4916
embeddedartists 0:b567d56a59d7 4917 error = addChunk(out, "IHDR", header.data, header.size);
embeddedartists 0:b567d56a59d7 4918 ucvector_cleanup(&header);
embeddedartists 0:b567d56a59d7 4919
embeddedartists 0:b567d56a59d7 4920 return error;
embeddedartists 0:b567d56a59d7 4921 }
embeddedartists 0:b567d56a59d7 4922
embeddedartists 0:b567d56a59d7 4923 static unsigned addChunk_PLTE(ucvector* out, const LodePNGColorMode* info)
embeddedartists 0:b567d56a59d7 4924 {
embeddedartists 0:b567d56a59d7 4925 unsigned error = 0;
embeddedartists 0:b567d56a59d7 4926 size_t i;
embeddedartists 0:b567d56a59d7 4927 ucvector PLTE;
embeddedartists 0:b567d56a59d7 4928 ucvector_init(&PLTE);
embeddedartists 0:b567d56a59d7 4929 for(i = 0; i < info->palettesize * 4; i++)
embeddedartists 0:b567d56a59d7 4930 {
embeddedartists 0:b567d56a59d7 4931 /*add all channels except alpha channel*/
embeddedartists 0:b567d56a59d7 4932 if(i % 4 != 3) ucvector_push_back(&PLTE, info->palette[i]);
embeddedartists 0:b567d56a59d7 4933 }
embeddedartists 0:b567d56a59d7 4934 error = addChunk(out, "PLTE", PLTE.data, PLTE.size);
embeddedartists 0:b567d56a59d7 4935 ucvector_cleanup(&PLTE);
embeddedartists 0:b567d56a59d7 4936
embeddedartists 0:b567d56a59d7 4937 return error;
embeddedartists 0:b567d56a59d7 4938 }
embeddedartists 0:b567d56a59d7 4939
embeddedartists 0:b567d56a59d7 4940 static unsigned addChunk_tRNS(ucvector* out, const LodePNGColorMode* info)
embeddedartists 0:b567d56a59d7 4941 {
embeddedartists 0:b567d56a59d7 4942 unsigned error = 0;
embeddedartists 0:b567d56a59d7 4943 size_t i;
embeddedartists 0:b567d56a59d7 4944 ucvector tRNS;
embeddedartists 0:b567d56a59d7 4945 ucvector_init(&tRNS);
embeddedartists 0:b567d56a59d7 4946 if(info->colortype == LCT_PALETTE)
embeddedartists 0:b567d56a59d7 4947 {
embeddedartists 0:b567d56a59d7 4948 size_t amount = info->palettesize;
embeddedartists 0:b567d56a59d7 4949 /*the tail of palette values that all have 255 as alpha, does not have to be encoded*/
embeddedartists 0:b567d56a59d7 4950 for(i = info->palettesize; i > 0; i--)
embeddedartists 0:b567d56a59d7 4951 {
embeddedartists 0:b567d56a59d7 4952 if(info->palette[4 * (i - 1) + 3] == 255) amount--;
embeddedartists 0:b567d56a59d7 4953 else break;
embeddedartists 0:b567d56a59d7 4954 }
embeddedartists 0:b567d56a59d7 4955 /*add only alpha channel*/
embeddedartists 0:b567d56a59d7 4956 for(i = 0; i < amount; i++) ucvector_push_back(&tRNS, info->palette[4 * i + 3]);
embeddedartists 0:b567d56a59d7 4957 }
embeddedartists 0:b567d56a59d7 4958 else if(info->colortype == LCT_GREY)
embeddedartists 0:b567d56a59d7 4959 {
embeddedartists 0:b567d56a59d7 4960 if(info->key_defined)
embeddedartists 0:b567d56a59d7 4961 {
embeddedartists 0:b567d56a59d7 4962 ucvector_push_back(&tRNS, (unsigned char)(info->key_r / 256));
embeddedartists 0:b567d56a59d7 4963 ucvector_push_back(&tRNS, (unsigned char)(info->key_r % 256));
embeddedartists 0:b567d56a59d7 4964 }
embeddedartists 0:b567d56a59d7 4965 }
embeddedartists 0:b567d56a59d7 4966 else if(info->colortype == LCT_RGB)
embeddedartists 0:b567d56a59d7 4967 {
embeddedartists 0:b567d56a59d7 4968 if(info->key_defined)
embeddedartists 0:b567d56a59d7 4969 {
embeddedartists 0:b567d56a59d7 4970 ucvector_push_back(&tRNS, (unsigned char)(info->key_r / 256));
embeddedartists 0:b567d56a59d7 4971 ucvector_push_back(&tRNS, (unsigned char)(info->key_r % 256));
embeddedartists 0:b567d56a59d7 4972 ucvector_push_back(&tRNS, (unsigned char)(info->key_g / 256));
embeddedartists 0:b567d56a59d7 4973 ucvector_push_back(&tRNS, (unsigned char)(info->key_g % 256));
embeddedartists 0:b567d56a59d7 4974 ucvector_push_back(&tRNS, (unsigned char)(info->key_b / 256));
embeddedartists 0:b567d56a59d7 4975 ucvector_push_back(&tRNS, (unsigned char)(info->key_b % 256));
embeddedartists 0:b567d56a59d7 4976 }
embeddedartists 0:b567d56a59d7 4977 }
embeddedartists 0:b567d56a59d7 4978
embeddedartists 0:b567d56a59d7 4979 error = addChunk(out, "tRNS", tRNS.data, tRNS.size);
embeddedartists 0:b567d56a59d7 4980 ucvector_cleanup(&tRNS);
embeddedartists 0:b567d56a59d7 4981
embeddedartists 0:b567d56a59d7 4982 return error;
embeddedartists 0:b567d56a59d7 4983 }
embeddedartists 0:b567d56a59d7 4984
embeddedartists 0:b567d56a59d7 4985 static unsigned addChunk_IDAT(ucvector* out, const unsigned char* data, size_t datasize,
embeddedartists 0:b567d56a59d7 4986 LodePNGCompressSettings* zlibsettings)
embeddedartists 0:b567d56a59d7 4987 {
embeddedartists 0:b567d56a59d7 4988 ucvector zlibdata;
embeddedartists 0:b567d56a59d7 4989 unsigned error = 0;
embeddedartists 0:b567d56a59d7 4990
embeddedartists 0:b567d56a59d7 4991 /*compress with the Zlib compressor*/
embeddedartists 0:b567d56a59d7 4992 ucvector_init(&zlibdata);
embeddedartists 0:b567d56a59d7 4993 error = zlib_compress(&zlibdata.data, &zlibdata.size, data, datasize, zlibsettings);
embeddedartists 0:b567d56a59d7 4994 if(!error) error = addChunk(out, "IDAT", zlibdata.data, zlibdata.size);
embeddedartists 0:b567d56a59d7 4995 ucvector_cleanup(&zlibdata);
embeddedartists 0:b567d56a59d7 4996
embeddedartists 0:b567d56a59d7 4997 return error;
embeddedartists 0:b567d56a59d7 4998 }
embeddedartists 0:b567d56a59d7 4999
embeddedartists 0:b567d56a59d7 5000 static unsigned addChunk_IEND(ucvector* out)
embeddedartists 0:b567d56a59d7 5001 {
embeddedartists 0:b567d56a59d7 5002 unsigned error = 0;
embeddedartists 0:b567d56a59d7 5003 error = addChunk(out, "IEND", 0, 0);
embeddedartists 0:b567d56a59d7 5004 return error;
embeddedartists 0:b567d56a59d7 5005 }
embeddedartists 0:b567d56a59d7 5006
embeddedartists 0:b567d56a59d7 5007 #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
embeddedartists 0:b567d56a59d7 5008
embeddedartists 0:b567d56a59d7 5009 static unsigned addChunk_tEXt(ucvector* out, const char* keyword, const char* textstring)
embeddedartists 0:b567d56a59d7 5010 {
embeddedartists 0:b567d56a59d7 5011 unsigned error = 0;
embeddedartists 0:b567d56a59d7 5012 size_t i;
embeddedartists 0:b567d56a59d7 5013 ucvector text;
embeddedartists 0:b567d56a59d7 5014 ucvector_init(&text);
embeddedartists 0:b567d56a59d7 5015 for(i = 0; keyword[i] != 0; i++) ucvector_push_back(&text, (unsigned char)keyword[i]);
embeddedartists 0:b567d56a59d7 5016 if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/
embeddedartists 0:b567d56a59d7 5017 ucvector_push_back(&text, 0); /*0 termination char*/
embeddedartists 0:b567d56a59d7 5018 for(i = 0; textstring[i] != 0; i++) ucvector_push_back(&text, (unsigned char)textstring[i]);
embeddedartists 0:b567d56a59d7 5019 error = addChunk(out, "tEXt", text.data, text.size);
embeddedartists 0:b567d56a59d7 5020 ucvector_cleanup(&text);
embeddedartists 0:b567d56a59d7 5021
embeddedartists 0:b567d56a59d7 5022 return error;
embeddedartists 0:b567d56a59d7 5023 }
embeddedartists 0:b567d56a59d7 5024
embeddedartists 0:b567d56a59d7 5025 static unsigned addChunk_zTXt(ucvector* out, const char* keyword, const char* textstring,
embeddedartists 0:b567d56a59d7 5026 LodePNGCompressSettings* zlibsettings)
embeddedartists 0:b567d56a59d7 5027 {
embeddedartists 0:b567d56a59d7 5028 unsigned error = 0;
embeddedartists 0:b567d56a59d7 5029 ucvector data, compressed;
embeddedartists 0:b567d56a59d7 5030 size_t i, textsize = strlen(textstring);
embeddedartists 0:b567d56a59d7 5031
embeddedartists 0:b567d56a59d7 5032 ucvector_init(&data);
embeddedartists 0:b567d56a59d7 5033 ucvector_init(&compressed);
embeddedartists 0:b567d56a59d7 5034 for(i = 0; keyword[i] != 0; i++) ucvector_push_back(&data, (unsigned char)keyword[i]);
embeddedartists 0:b567d56a59d7 5035 if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/
embeddedartists 0:b567d56a59d7 5036 ucvector_push_back(&data, 0); /*0 termination char*/
embeddedartists 0:b567d56a59d7 5037 ucvector_push_back(&data, 0); /*compression method: 0*/
embeddedartists 0:b567d56a59d7 5038
embeddedartists 0:b567d56a59d7 5039 error = zlib_compress(&compressed.data, &compressed.size,
embeddedartists 0:b567d56a59d7 5040 (unsigned char*)textstring, textsize, zlibsettings);
embeddedartists 0:b567d56a59d7 5041 if(!error)
embeddedartists 0:b567d56a59d7 5042 {
embeddedartists 0:b567d56a59d7 5043 for(i = 0; i < compressed.size; i++) ucvector_push_back(&data, compressed.data[i]);
embeddedartists 0:b567d56a59d7 5044 error = addChunk(out, "zTXt", data.data, data.size);
embeddedartists 0:b567d56a59d7 5045 }
embeddedartists 0:b567d56a59d7 5046
embeddedartists 0:b567d56a59d7 5047 ucvector_cleanup(&compressed);
embeddedartists 0:b567d56a59d7 5048 ucvector_cleanup(&data);
embeddedartists 0:b567d56a59d7 5049 return error;
embeddedartists 0:b567d56a59d7 5050 }
embeddedartists 0:b567d56a59d7 5051
embeddedartists 0:b567d56a59d7 5052 static unsigned addChunk_iTXt(ucvector* out, unsigned compressed, const char* keyword, const char* langtag,
embeddedartists 0:b567d56a59d7 5053 const char* transkey, const char* textstring, LodePNGCompressSettings* zlibsettings)
embeddedartists 0:b567d56a59d7 5054 {
embeddedartists 0:b567d56a59d7 5055 unsigned error = 0;
embeddedartists 0:b567d56a59d7 5056 ucvector data;
embeddedartists 0:b567d56a59d7 5057 size_t i, textsize = strlen(textstring);
embeddedartists 0:b567d56a59d7 5058
embeddedartists 0:b567d56a59d7 5059 ucvector_init(&data);
embeddedartists 0:b567d56a59d7 5060
embeddedartists 0:b567d56a59d7 5061 for(i = 0; keyword[i] != 0; i++) ucvector_push_back(&data, (unsigned char)keyword[i]);
embeddedartists 0:b567d56a59d7 5062 if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/
embeddedartists 0:b567d56a59d7 5063 ucvector_push_back(&data, 0); /*null termination char*/
embeddedartists 0:b567d56a59d7 5064 ucvector_push_back(&data, compressed ? 1 : 0); /*compression flag*/
embeddedartists 0:b567d56a59d7 5065 ucvector_push_back(&data, 0); /*compression method*/
embeddedartists 0:b567d56a59d7 5066 for(i = 0; langtag[i] != 0; i++) ucvector_push_back(&data, (unsigned char)langtag[i]);
embeddedartists 0:b567d56a59d7 5067 ucvector_push_back(&data, 0); /*null termination char*/
embeddedartists 0:b567d56a59d7 5068 for(i = 0; transkey[i] != 0; i++) ucvector_push_back(&data, (unsigned char)transkey[i]);
embeddedartists 0:b567d56a59d7 5069 ucvector_push_back(&data, 0); /*null termination char*/
embeddedartists 0:b567d56a59d7 5070
embeddedartists 0:b567d56a59d7 5071 if(compressed)
embeddedartists 0:b567d56a59d7 5072 {
embeddedartists 0:b567d56a59d7 5073 ucvector compressed_data;
embeddedartists 0:b567d56a59d7 5074 ucvector_init(&compressed_data);
embeddedartists 0:b567d56a59d7 5075 error = zlib_compress(&compressed_data.data, &compressed_data.size,
embeddedartists 0:b567d56a59d7 5076 (unsigned char*)textstring, textsize, zlibsettings);
embeddedartists 0:b567d56a59d7 5077 if(!error)
embeddedartists 0:b567d56a59d7 5078 {
embeddedartists 0:b567d56a59d7 5079 for(i = 0; i < compressed_data.size; i++) ucvector_push_back(&data, compressed_data.data[i]);
embeddedartists 0:b567d56a59d7 5080 }
embeddedartists 0:b567d56a59d7 5081 ucvector_cleanup(&compressed_data);
embeddedartists 0:b567d56a59d7 5082 }
embeddedartists 0:b567d56a59d7 5083 else /*not compressed*/
embeddedartists 0:b567d56a59d7 5084 {
embeddedartists 0:b567d56a59d7 5085 for(i = 0; textstring[i] != 0; i++) ucvector_push_back(&data, (unsigned char)textstring[i]);
embeddedartists 0:b567d56a59d7 5086 }
embeddedartists 0:b567d56a59d7 5087
embeddedartists 0:b567d56a59d7 5088 if(!error) error = addChunk(out, "iTXt", data.data, data.size);
embeddedartists 0:b567d56a59d7 5089 ucvector_cleanup(&data);
embeddedartists 0:b567d56a59d7 5090 return error;
embeddedartists 0:b567d56a59d7 5091 }
embeddedartists 0:b567d56a59d7 5092
embeddedartists 0:b567d56a59d7 5093 static unsigned addChunk_bKGD(ucvector* out, const LodePNGInfo* info)
embeddedartists 0:b567d56a59d7 5094 {
embeddedartists 0:b567d56a59d7 5095 unsigned error = 0;
embeddedartists 0:b567d56a59d7 5096 ucvector bKGD;
embeddedartists 0:b567d56a59d7 5097 ucvector_init(&bKGD);
embeddedartists 0:b567d56a59d7 5098 if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA)
embeddedartists 0:b567d56a59d7 5099 {
embeddedartists 0:b567d56a59d7 5100 ucvector_push_back(&bKGD, (unsigned char)(info->background_r / 256));
embeddedartists 0:b567d56a59d7 5101 ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256));
embeddedartists 0:b567d56a59d7 5102 }
embeddedartists 0:b567d56a59d7 5103 else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA)
embeddedartists 0:b567d56a59d7 5104 {
embeddedartists 0:b567d56a59d7 5105 ucvector_push_back(&bKGD, (unsigned char)(info->background_r / 256));
embeddedartists 0:b567d56a59d7 5106 ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256));
embeddedartists 0:b567d56a59d7 5107 ucvector_push_back(&bKGD, (unsigned char)(info->background_g / 256));
embeddedartists 0:b567d56a59d7 5108 ucvector_push_back(&bKGD, (unsigned char)(info->background_g % 256));
embeddedartists 0:b567d56a59d7 5109 ucvector_push_back(&bKGD, (unsigned char)(info->background_b / 256));
embeddedartists 0:b567d56a59d7 5110 ucvector_push_back(&bKGD, (unsigned char)(info->background_b % 256));
embeddedartists 0:b567d56a59d7 5111 }
embeddedartists 0:b567d56a59d7 5112 else if(info->color.colortype == LCT_PALETTE)
embeddedartists 0:b567d56a59d7 5113 {
embeddedartists 0:b567d56a59d7 5114 ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256)); /*palette index*/
embeddedartists 0:b567d56a59d7 5115 }
embeddedartists 0:b567d56a59d7 5116
embeddedartists 0:b567d56a59d7 5117 error = addChunk(out, "bKGD", bKGD.data, bKGD.size);
embeddedartists 0:b567d56a59d7 5118 ucvector_cleanup(&bKGD);
embeddedartists 0:b567d56a59d7 5119
embeddedartists 0:b567d56a59d7 5120 return error;
embeddedartists 0:b567d56a59d7 5121 }
embeddedartists 0:b567d56a59d7 5122
embeddedartists 0:b567d56a59d7 5123 static unsigned addChunk_tIME(ucvector* out, const LodePNGTime* time)
embeddedartists 0:b567d56a59d7 5124 {
embeddedartists 0:b567d56a59d7 5125 unsigned error = 0;
embeddedartists 0:b567d56a59d7 5126 unsigned char* data = (unsigned char*)lodepng_malloc(7);
embeddedartists 0:b567d56a59d7 5127 if(!data) return 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 5128 data[0] = (unsigned char)(time->year / 256);
embeddedartists 0:b567d56a59d7 5129 data[1] = (unsigned char)(time->year % 256);
embeddedartists 0:b567d56a59d7 5130 data[2] = time->month;
embeddedartists 0:b567d56a59d7 5131 data[3] = time->day;
embeddedartists 0:b567d56a59d7 5132 data[4] = time->hour;
embeddedartists 0:b567d56a59d7 5133 data[5] = time->minute;
embeddedartists 0:b567d56a59d7 5134 data[6] = time->second;
embeddedartists 0:b567d56a59d7 5135 error = addChunk(out, "tIME", data, 7);
embeddedartists 0:b567d56a59d7 5136 lodepng_free(data);
embeddedartists 0:b567d56a59d7 5137 return error;
embeddedartists 0:b567d56a59d7 5138 }
embeddedartists 0:b567d56a59d7 5139
embeddedartists 0:b567d56a59d7 5140 static unsigned addChunk_pHYs(ucvector* out, const LodePNGInfo* info)
embeddedartists 0:b567d56a59d7 5141 {
embeddedartists 0:b567d56a59d7 5142 unsigned error = 0;
embeddedartists 0:b567d56a59d7 5143 ucvector data;
embeddedartists 0:b567d56a59d7 5144 ucvector_init(&data);
embeddedartists 0:b567d56a59d7 5145
embeddedartists 0:b567d56a59d7 5146 lodepng_add32bitInt(&data, info->phys_x);
embeddedartists 0:b567d56a59d7 5147 lodepng_add32bitInt(&data, info->phys_y);
embeddedartists 0:b567d56a59d7 5148 ucvector_push_back(&data, info->phys_unit);
embeddedartists 0:b567d56a59d7 5149
embeddedartists 0:b567d56a59d7 5150 error = addChunk(out, "pHYs", data.data, data.size);
embeddedartists 0:b567d56a59d7 5151 ucvector_cleanup(&data);
embeddedartists 0:b567d56a59d7 5152
embeddedartists 0:b567d56a59d7 5153 return error;
embeddedartists 0:b567d56a59d7 5154 }
embeddedartists 0:b567d56a59d7 5155
embeddedartists 0:b567d56a59d7 5156 #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
embeddedartists 0:b567d56a59d7 5157
embeddedartists 0:b567d56a59d7 5158 static void filterScanline(unsigned char* out, const unsigned char* scanline, const unsigned char* prevline,
embeddedartists 0:b567d56a59d7 5159 size_t length, size_t bytewidth, unsigned char filterType)
embeddedartists 0:b567d56a59d7 5160 {
embeddedartists 0:b567d56a59d7 5161 size_t i;
embeddedartists 0:b567d56a59d7 5162 switch(filterType)
embeddedartists 0:b567d56a59d7 5163 {
embeddedartists 0:b567d56a59d7 5164 case 0: /*None*/
embeddedartists 0:b567d56a59d7 5165 for(i = 0; i < length; i++) out[i] = scanline[i];
embeddedartists 0:b567d56a59d7 5166 break;
embeddedartists 0:b567d56a59d7 5167 case 1: /*Sub*/
embeddedartists 0:b567d56a59d7 5168 if(prevline)
embeddedartists 0:b567d56a59d7 5169 {
embeddedartists 0:b567d56a59d7 5170 for(i = 0; i < bytewidth; i++) out[i] = scanline[i];
embeddedartists 0:b567d56a59d7 5171 for(i = bytewidth; i < length; i++) out[i] = scanline[i] - scanline[i - bytewidth];
embeddedartists 0:b567d56a59d7 5172 }
embeddedartists 0:b567d56a59d7 5173 else
embeddedartists 0:b567d56a59d7 5174 {
embeddedartists 0:b567d56a59d7 5175 for(i = 0; i < bytewidth; i++) out[i] = scanline[i];
embeddedartists 0:b567d56a59d7 5176 for(i = bytewidth; i < length; i++) out[i] = scanline[i] - scanline[i - bytewidth];
embeddedartists 0:b567d56a59d7 5177 }
embeddedartists 0:b567d56a59d7 5178 break;
embeddedartists 0:b567d56a59d7 5179 case 2: /*Up*/
embeddedartists 0:b567d56a59d7 5180 if(prevline)
embeddedartists 0:b567d56a59d7 5181 {
embeddedartists 0:b567d56a59d7 5182 for(i = 0; i < length; i++) out[i] = scanline[i] - prevline[i];
embeddedartists 0:b567d56a59d7 5183 }
embeddedartists 0:b567d56a59d7 5184 else
embeddedartists 0:b567d56a59d7 5185 {
embeddedartists 0:b567d56a59d7 5186 for(i = 0; i < length; i++) out[i] = scanline[i];
embeddedartists 0:b567d56a59d7 5187 }
embeddedartists 0:b567d56a59d7 5188 break;
embeddedartists 0:b567d56a59d7 5189 case 3: /*Average*/
embeddedartists 0:b567d56a59d7 5190 if(prevline)
embeddedartists 0:b567d56a59d7 5191 {
embeddedartists 0:b567d56a59d7 5192 for(i = 0; i < bytewidth; i++) out[i] = scanline[i] - prevline[i] / 2;
embeddedartists 0:b567d56a59d7 5193 for(i = bytewidth; i < length; i++) out[i] = scanline[i] - ((scanline[i - bytewidth] + prevline[i]) / 2);
embeddedartists 0:b567d56a59d7 5194 }
embeddedartists 0:b567d56a59d7 5195 else
embeddedartists 0:b567d56a59d7 5196 {
embeddedartists 0:b567d56a59d7 5197 for(i = 0; i < bytewidth; i++) out[i] = scanline[i];
embeddedartists 0:b567d56a59d7 5198 for(i = bytewidth; i < length; i++) out[i] = scanline[i] - scanline[i - bytewidth] / 2;
embeddedartists 0:b567d56a59d7 5199 }
embeddedartists 0:b567d56a59d7 5200 break;
embeddedartists 0:b567d56a59d7 5201 case 4: /*Paeth*/
embeddedartists 0:b567d56a59d7 5202 if(prevline)
embeddedartists 0:b567d56a59d7 5203 {
embeddedartists 0:b567d56a59d7 5204 /*paethPredictor(0, prevline[i], 0) is always prevline[i]*/
embeddedartists 0:b567d56a59d7 5205 for(i = 0; i < bytewidth; i++) out[i] = (scanline[i] - prevline[i]);
embeddedartists 0:b567d56a59d7 5206 for(i = bytewidth; i < length; i++)
embeddedartists 0:b567d56a59d7 5207 {
embeddedartists 0:b567d56a59d7 5208 out[i] = (scanline[i] - paethPredictor(scanline[i - bytewidth], prevline[i], prevline[i - bytewidth]));
embeddedartists 0:b567d56a59d7 5209 }
embeddedartists 0:b567d56a59d7 5210 }
embeddedartists 0:b567d56a59d7 5211 else
embeddedartists 0:b567d56a59d7 5212 {
embeddedartists 0:b567d56a59d7 5213 for(i = 0; i < bytewidth; i++) out[i] = scanline[i];
embeddedartists 0:b567d56a59d7 5214 /*paethPredictor(scanline[i - bytewidth], 0, 0) is always scanline[i - bytewidth]*/
embeddedartists 0:b567d56a59d7 5215 for(i = bytewidth; i < length; i++) out[i] = (scanline[i] - scanline[i - bytewidth]);
embeddedartists 0:b567d56a59d7 5216 }
embeddedartists 0:b567d56a59d7 5217 break;
embeddedartists 0:b567d56a59d7 5218 default: return; /*unexisting filter type given*/
embeddedartists 0:b567d56a59d7 5219 }
embeddedartists 0:b567d56a59d7 5220 }
embeddedartists 0:b567d56a59d7 5221
embeddedartists 0:b567d56a59d7 5222 /* log2 approximation. A slight bit faster than std::log. */
embeddedartists 0:b567d56a59d7 5223 static float flog2(float f)
embeddedartists 0:b567d56a59d7 5224 {
embeddedartists 0:b567d56a59d7 5225 float result = 0;
embeddedartists 0:b567d56a59d7 5226 while(f > 32) { result += 4; f /= 16; }
embeddedartists 0:b567d56a59d7 5227 while(f > 2) { result++; f /= 2; }
embeddedartists 0:b567d56a59d7 5228 return result + 1.442695f * (f * f * f / 3 - 3 * f * f / 2 + 3 * f - 1.83333f);
embeddedartists 0:b567d56a59d7 5229 }
embeddedartists 0:b567d56a59d7 5230
embeddedartists 0:b567d56a59d7 5231 static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h,
embeddedartists 0:b567d56a59d7 5232 const LodePNGColorMode* info, const LodePNGEncoderSettings* settings)
embeddedartists 0:b567d56a59d7 5233 {
embeddedartists 0:b567d56a59d7 5234 /*
embeddedartists 0:b567d56a59d7 5235 For PNG filter method 0
embeddedartists 0:b567d56a59d7 5236 out must be a buffer with as size: h + (w * h * bpp + 7) / 8, because there are
embeddedartists 0:b567d56a59d7 5237 the scanlines with 1 extra byte per scanline
embeddedartists 0:b567d56a59d7 5238 */
embeddedartists 0:b567d56a59d7 5239
embeddedartists 0:b567d56a59d7 5240 unsigned bpp = lodepng_get_bpp(info);
embeddedartists 0:b567d56a59d7 5241 /*the width of a scanline in bytes, not including the filter type*/
embeddedartists 0:b567d56a59d7 5242 size_t linebytes = (w * bpp + 7) / 8;
embeddedartists 0:b567d56a59d7 5243 /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/
embeddedartists 0:b567d56a59d7 5244 size_t bytewidth = (bpp + 7) / 8;
embeddedartists 0:b567d56a59d7 5245 const unsigned char* prevline = 0;
embeddedartists 0:b567d56a59d7 5246 unsigned x, y;
embeddedartists 0:b567d56a59d7 5247 unsigned error = 0;
embeddedartists 0:b567d56a59d7 5248 LodePNGFilterStrategy strategy = settings->filter_strategy;
embeddedartists 0:b567d56a59d7 5249
embeddedartists 0:b567d56a59d7 5250 /*
embeddedartists 0:b567d56a59d7 5251 There is a heuristic called the minimum sum of absolute differences heuristic, suggested by the PNG standard:
embeddedartists 0:b567d56a59d7 5252 * If the image type is Palette, or the bit depth is smaller than 8, then do not filter the image (i.e.
embeddedartists 0:b567d56a59d7 5253 use fixed filtering, with the filter None).
embeddedartists 0:b567d56a59d7 5254 * (The other case) If the image type is Grayscale or RGB (with or without Alpha), and the bit depth is
embeddedartists 0:b567d56a59d7 5255 not smaller than 8, then use adaptive filtering heuristic as follows: independently for each row, apply
embeddedartists 0:b567d56a59d7 5256 all five filters and select the filter that produces the smallest sum of absolute values per row.
embeddedartists 0:b567d56a59d7 5257 This heuristic is used if filter strategy is LFS_MINSUM and filter_palette_zero is true.
embeddedartists 0:b567d56a59d7 5258
embeddedartists 0:b567d56a59d7 5259 If filter_palette_zero is true and filter_strategy is not LFS_MINSUM, the above heuristic is followed,
embeddedartists 0:b567d56a59d7 5260 but for "the other case", whatever strategy filter_strategy is set to instead of the minimum sum
embeddedartists 0:b567d56a59d7 5261 heuristic is used.
embeddedartists 0:b567d56a59d7 5262 */
embeddedartists 0:b567d56a59d7 5263 if(settings->filter_palette_zero &&
embeddedartists 0:b567d56a59d7 5264 (info->colortype == LCT_PALETTE || info->bitdepth < 8)) strategy = LFS_ZERO;
embeddedartists 0:b567d56a59d7 5265
embeddedartists 0:b567d56a59d7 5266 if(bpp == 0) return 31; /*error: invalid color type*/
embeddedartists 0:b567d56a59d7 5267
embeddedartists 0:b567d56a59d7 5268 if(strategy == LFS_ZERO)
embeddedartists 0:b567d56a59d7 5269 {
embeddedartists 0:b567d56a59d7 5270 for(y = 0; y < h; y++)
embeddedartists 0:b567d56a59d7 5271 {
embeddedartists 0:b567d56a59d7 5272 size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/
embeddedartists 0:b567d56a59d7 5273 size_t inindex = linebytes * y;
embeddedartists 0:b567d56a59d7 5274 out[outindex] = 0; /*filter type byte*/
embeddedartists 0:b567d56a59d7 5275 filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, 0);
embeddedartists 0:b567d56a59d7 5276 prevline = &in[inindex];
embeddedartists 0:b567d56a59d7 5277 }
embeddedartists 0:b567d56a59d7 5278 }
embeddedartists 0:b567d56a59d7 5279 else if(strategy == LFS_MINSUM)
embeddedartists 0:b567d56a59d7 5280 {
embeddedartists 0:b567d56a59d7 5281 /*adaptive filtering*/
embeddedartists 0:b567d56a59d7 5282 size_t sum[5];
embeddedartists 0:b567d56a59d7 5283 ucvector attempt[5]; /*five filtering attempts, one for each filter type*/
embeddedartists 0:b567d56a59d7 5284 size_t smallest = 0;
embeddedartists 0:b567d56a59d7 5285 unsigned type, bestType = 0;
embeddedartists 0:b567d56a59d7 5286
embeddedartists 0:b567d56a59d7 5287 for(type = 0; type < 5; type++)
embeddedartists 0:b567d56a59d7 5288 {
embeddedartists 0:b567d56a59d7 5289 ucvector_init(&attempt[type]);
embeddedartists 0:b567d56a59d7 5290 if(!ucvector_resize(&attempt[type], linebytes)) return 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 5291 }
embeddedartists 0:b567d56a59d7 5292
embeddedartists 0:b567d56a59d7 5293 if(!error)
embeddedartists 0:b567d56a59d7 5294 {
embeddedartists 0:b567d56a59d7 5295 for(y = 0; y < h; y++)
embeddedartists 0:b567d56a59d7 5296 {
embeddedartists 0:b567d56a59d7 5297 /*try the 5 filter types*/
embeddedartists 0:b567d56a59d7 5298 for(type = 0; type < 5; type++)
embeddedartists 0:b567d56a59d7 5299 {
embeddedartists 0:b567d56a59d7 5300 filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type);
embeddedartists 0:b567d56a59d7 5301
embeddedartists 0:b567d56a59d7 5302 /*calculate the sum of the result*/
embeddedartists 0:b567d56a59d7 5303 sum[type] = 0;
embeddedartists 0:b567d56a59d7 5304 if(type == 0)
embeddedartists 0:b567d56a59d7 5305 {
embeddedartists 0:b567d56a59d7 5306 for(x = 0; x < linebytes; x++) sum[type] += (unsigned char)(attempt[type].data[x]);
embeddedartists 0:b567d56a59d7 5307 }
embeddedartists 0:b567d56a59d7 5308 else
embeddedartists 0:b567d56a59d7 5309 {
embeddedartists 0:b567d56a59d7 5310 for(x = 0; x < linebytes; x++)
embeddedartists 0:b567d56a59d7 5311 {
embeddedartists 0:b567d56a59d7 5312 /*For differences, each byte should be treated as signed, values above 127 are negative
embeddedartists 0:b567d56a59d7 5313 (converted to signed char). Filtertype 0 isn't a difference though, so use unsigned there.
embeddedartists 0:b567d56a59d7 5314 This means filtertype 0 is almost never chosen, but that is justified.*/
embeddedartists 0:b567d56a59d7 5315 signed char s = (signed char)(attempt[type].data[x]);
embeddedartists 0:b567d56a59d7 5316 sum[type] += s < 0 ? -s : s;
embeddedartists 0:b567d56a59d7 5317 }
embeddedartists 0:b567d56a59d7 5318 }
embeddedartists 0:b567d56a59d7 5319
embeddedartists 0:b567d56a59d7 5320 /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/
embeddedartists 0:b567d56a59d7 5321 if(type == 0 || sum[type] < smallest)
embeddedartists 0:b567d56a59d7 5322 {
embeddedartists 0:b567d56a59d7 5323 bestType = type;
embeddedartists 0:b567d56a59d7 5324 smallest = sum[type];
embeddedartists 0:b567d56a59d7 5325 }
embeddedartists 0:b567d56a59d7 5326 }
embeddedartists 0:b567d56a59d7 5327
embeddedartists 0:b567d56a59d7 5328 prevline = &in[y * linebytes];
embeddedartists 0:b567d56a59d7 5329
embeddedartists 0:b567d56a59d7 5330 /*now fill the out values*/
embeddedartists 0:b567d56a59d7 5331 out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/
embeddedartists 0:b567d56a59d7 5332 for(x = 0; x < linebytes; x++) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x];
embeddedartists 0:b567d56a59d7 5333 }
embeddedartists 0:b567d56a59d7 5334 }
embeddedartists 0:b567d56a59d7 5335
embeddedartists 0:b567d56a59d7 5336 for(type = 0; type < 5; type++) ucvector_cleanup(&attempt[type]);
embeddedartists 0:b567d56a59d7 5337 }
embeddedartists 0:b567d56a59d7 5338 else if(strategy == LFS_ENTROPY)
embeddedartists 0:b567d56a59d7 5339 {
embeddedartists 0:b567d56a59d7 5340 float sum[5];
embeddedartists 0:b567d56a59d7 5341 ucvector attempt[5]; /*five filtering attempts, one for each filter type*/
embeddedartists 0:b567d56a59d7 5342 float smallest = 0;
embeddedartists 0:b567d56a59d7 5343 unsigned type, bestType = 0;
embeddedartists 0:b567d56a59d7 5344 unsigned count[256];
embeddedartists 0:b567d56a59d7 5345
embeddedartists 0:b567d56a59d7 5346 for(type = 0; type < 5; type++)
embeddedartists 0:b567d56a59d7 5347 {
embeddedartists 0:b567d56a59d7 5348 ucvector_init(&attempt[type]);
embeddedartists 0:b567d56a59d7 5349 if(!ucvector_resize(&attempt[type], linebytes)) return 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 5350 }
embeddedartists 0:b567d56a59d7 5351
embeddedartists 0:b567d56a59d7 5352 for(y = 0; y < h; y++)
embeddedartists 0:b567d56a59d7 5353 {
embeddedartists 0:b567d56a59d7 5354 /*try the 5 filter types*/
embeddedartists 0:b567d56a59d7 5355 for(type = 0; type < 5; type++)
embeddedartists 0:b567d56a59d7 5356 {
embeddedartists 0:b567d56a59d7 5357 filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type);
embeddedartists 0:b567d56a59d7 5358 for(x = 0; x < 256; x++) count[x] = 0;
embeddedartists 0:b567d56a59d7 5359 for(x = 0; x < linebytes; x++) count[attempt[type].data[x]]++;
embeddedartists 0:b567d56a59d7 5360 count[type]++; /*the filter type itself is part of the scanline*/
embeddedartists 0:b567d56a59d7 5361 sum[type] = 0;
embeddedartists 0:b567d56a59d7 5362 for(x = 0; x < 256; x++)
embeddedartists 0:b567d56a59d7 5363 {
embeddedartists 0:b567d56a59d7 5364 float p = count[x] / (float)(linebytes + 1);
embeddedartists 0:b567d56a59d7 5365 sum[type] += count[x] == 0 ? 0 : flog2(1 / p) * p;
embeddedartists 0:b567d56a59d7 5366 }
embeddedartists 0:b567d56a59d7 5367 /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/
embeddedartists 0:b567d56a59d7 5368 if(type == 0 || sum[type] < smallest)
embeddedartists 0:b567d56a59d7 5369 {
embeddedartists 0:b567d56a59d7 5370 bestType = type;
embeddedartists 0:b567d56a59d7 5371 smallest = sum[type];
embeddedartists 0:b567d56a59d7 5372 }
embeddedartists 0:b567d56a59d7 5373 }
embeddedartists 0:b567d56a59d7 5374
embeddedartists 0:b567d56a59d7 5375 prevline = &in[y * linebytes];
embeddedartists 0:b567d56a59d7 5376
embeddedartists 0:b567d56a59d7 5377 /*now fill the out values*/
embeddedartists 0:b567d56a59d7 5378 out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/
embeddedartists 0:b567d56a59d7 5379 for(x = 0; x < linebytes; x++) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x];
embeddedartists 0:b567d56a59d7 5380 }
embeddedartists 0:b567d56a59d7 5381
embeddedartists 0:b567d56a59d7 5382 for(type = 0; type < 5; type++) ucvector_cleanup(&attempt[type]);
embeddedartists 0:b567d56a59d7 5383 }
embeddedartists 0:b567d56a59d7 5384 else if(strategy == LFS_PREDEFINED)
embeddedartists 0:b567d56a59d7 5385 {
embeddedartists 0:b567d56a59d7 5386 for(y = 0; y < h; y++)
embeddedartists 0:b567d56a59d7 5387 {
embeddedartists 0:b567d56a59d7 5388 size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/
embeddedartists 0:b567d56a59d7 5389 size_t inindex = linebytes * y;
embeddedartists 0:b567d56a59d7 5390 unsigned type = settings->predefined_filters[y];
embeddedartists 0:b567d56a59d7 5391 out[outindex] = type; /*filter type byte*/
embeddedartists 0:b567d56a59d7 5392 filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, type);
embeddedartists 0:b567d56a59d7 5393 prevline = &in[inindex];
embeddedartists 0:b567d56a59d7 5394 }
embeddedartists 0:b567d56a59d7 5395 }
embeddedartists 0:b567d56a59d7 5396 else if(strategy == LFS_BRUTE_FORCE)
embeddedartists 0:b567d56a59d7 5397 {
embeddedartists 0:b567d56a59d7 5398 /*brute force filter chooser.
embeddedartists 0:b567d56a59d7 5399 deflate the scanline after every filter attempt to see which one deflates best.
embeddedartists 0:b567d56a59d7 5400 This is very slow and gives only slightly smaller, sometimes even larger, result*/
embeddedartists 0:b567d56a59d7 5401 size_t size[5];
embeddedartists 0:b567d56a59d7 5402 ucvector attempt[5]; /*five filtering attempts, one for each filter type*/
embeddedartists 0:b567d56a59d7 5403 size_t smallest = 0;
embeddedartists 0:b567d56a59d7 5404 unsigned type = 0, bestType = 0;
embeddedartists 0:b567d56a59d7 5405 unsigned char* dummy;
embeddedartists 0:b567d56a59d7 5406 LodePNGCompressSettings zlibsettings = settings->zlibsettings;
embeddedartists 0:b567d56a59d7 5407 /*use fixed tree on the attempts so that the tree is not adapted to the filtertype on purpose,
embeddedartists 0:b567d56a59d7 5408 to simulate the true case where the tree is the same for the whole image. Sometimes it gives
embeddedartists 0:b567d56a59d7 5409 better result with dynamic tree anyway. Using the fixed tree sometimes gives worse, but in rare
embeddedartists 0:b567d56a59d7 5410 cases better compression. It does make this a bit less slow, so it's worth doing this.*/
embeddedartists 0:b567d56a59d7 5411 zlibsettings.btype = 1;
embeddedartists 0:b567d56a59d7 5412 /*a custom encoder likely doesn't read the btype setting and is optimized for complete PNG
embeddedartists 0:b567d56a59d7 5413 images only, so disable it*/
embeddedartists 0:b567d56a59d7 5414 zlibsettings.custom_zlib = 0;
embeddedartists 0:b567d56a59d7 5415 zlibsettings.custom_deflate = 0;
embeddedartists 0:b567d56a59d7 5416 for(type = 0; type < 5; type++)
embeddedartists 0:b567d56a59d7 5417 {
embeddedartists 0:b567d56a59d7 5418 ucvector_init(&attempt[type]);
embeddedartists 0:b567d56a59d7 5419 ucvector_resize(&attempt[type], linebytes); /*todo: give error if resize failed*/
embeddedartists 0:b567d56a59d7 5420 }
embeddedartists 0:b567d56a59d7 5421 for(y = 0; y < h; y++) /*try the 5 filter types*/
embeddedartists 0:b567d56a59d7 5422 {
embeddedartists 0:b567d56a59d7 5423 for(type = 0; type < 5; type++)
embeddedartists 0:b567d56a59d7 5424 {
embeddedartists 0:b567d56a59d7 5425 unsigned testsize = attempt[type].size;
embeddedartists 0:b567d56a59d7 5426 /*if(testsize > 8) testsize /= 8;*/ /*it already works good enough by testing a part of the row*/
embeddedartists 0:b567d56a59d7 5427
embeddedartists 0:b567d56a59d7 5428 filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type);
embeddedartists 0:b567d56a59d7 5429 size[type] = 0;
embeddedartists 0:b567d56a59d7 5430 dummy = 0;
embeddedartists 0:b567d56a59d7 5431 zlib_compress(&dummy, &size[type], attempt[type].data, testsize, &zlibsettings);
embeddedartists 0:b567d56a59d7 5432 lodepng_free(dummy);
embeddedartists 0:b567d56a59d7 5433 /*check if this is smallest size (or if type == 0 it's the first case so always store the values)*/
embeddedartists 0:b567d56a59d7 5434 if(type == 0 || size[type] < smallest)
embeddedartists 0:b567d56a59d7 5435 {
embeddedartists 0:b567d56a59d7 5436 bestType = type;
embeddedartists 0:b567d56a59d7 5437 smallest = size[type];
embeddedartists 0:b567d56a59d7 5438 }
embeddedartists 0:b567d56a59d7 5439 }
embeddedartists 0:b567d56a59d7 5440 prevline = &in[y * linebytes];
embeddedartists 0:b567d56a59d7 5441 out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/
embeddedartists 0:b567d56a59d7 5442 for(x = 0; x < linebytes; x++) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x];
embeddedartists 0:b567d56a59d7 5443 }
embeddedartists 0:b567d56a59d7 5444 for(type = 0; type < 5; type++) ucvector_cleanup(&attempt[type]);
embeddedartists 0:b567d56a59d7 5445 }
embeddedartists 0:b567d56a59d7 5446 else return 88; /* unknown filter strategy */
embeddedartists 0:b567d56a59d7 5447
embeddedartists 0:b567d56a59d7 5448 return error;
embeddedartists 0:b567d56a59d7 5449 }
embeddedartists 0:b567d56a59d7 5450
embeddedartists 0:b567d56a59d7 5451 static void addPaddingBits(unsigned char* out, const unsigned char* in,
embeddedartists 0:b567d56a59d7 5452 size_t olinebits, size_t ilinebits, unsigned h)
embeddedartists 0:b567d56a59d7 5453 {
embeddedartists 0:b567d56a59d7 5454 /*The opposite of the removePaddingBits function
embeddedartists 0:b567d56a59d7 5455 olinebits must be >= ilinebits*/
embeddedartists 0:b567d56a59d7 5456 unsigned y;
embeddedartists 0:b567d56a59d7 5457 size_t diff = olinebits - ilinebits;
embeddedartists 0:b567d56a59d7 5458 size_t obp = 0, ibp = 0; /*bit pointers*/
embeddedartists 0:b567d56a59d7 5459 for(y = 0; y < h; y++)
embeddedartists 0:b567d56a59d7 5460 {
embeddedartists 0:b567d56a59d7 5461 size_t x;
embeddedartists 0:b567d56a59d7 5462 for(x = 0; x < ilinebits; x++)
embeddedartists 0:b567d56a59d7 5463 {
embeddedartists 0:b567d56a59d7 5464 unsigned char bit = readBitFromReversedStream(&ibp, in);
embeddedartists 0:b567d56a59d7 5465 setBitOfReversedStream(&obp, out, bit);
embeddedartists 0:b567d56a59d7 5466 }
embeddedartists 0:b567d56a59d7 5467 /*obp += diff; --> no, fill in some value in the padding bits too, to avoid
embeddedartists 0:b567d56a59d7 5468 "Use of uninitialised value of size ###" warning from valgrind*/
embeddedartists 0:b567d56a59d7 5469 for(x = 0; x < diff; x++) setBitOfReversedStream(&obp, out, 0);
embeddedartists 0:b567d56a59d7 5470 }
embeddedartists 0:b567d56a59d7 5471 }
embeddedartists 0:b567d56a59d7 5472
embeddedartists 0:b567d56a59d7 5473 /*
embeddedartists 0:b567d56a59d7 5474 in: non-interlaced image with size w*h
embeddedartists 0:b567d56a59d7 5475 out: the same pixels, but re-ordered according to PNG's Adam7 interlacing, with
embeddedartists 0:b567d56a59d7 5476 no padding bits between scanlines, but between reduced images so that each
embeddedartists 0:b567d56a59d7 5477 reduced image starts at a byte.
embeddedartists 0:b567d56a59d7 5478 bpp: bits per pixel
embeddedartists 0:b567d56a59d7 5479 there are no padding bits, not between scanlines, not between reduced images
embeddedartists 0:b567d56a59d7 5480 in has the following size in bits: w * h * bpp.
embeddedartists 0:b567d56a59d7 5481 out is possibly bigger due to padding bits between reduced images
embeddedartists 0:b567d56a59d7 5482 NOTE: comments about padding bits are only relevant if bpp < 8
embeddedartists 0:b567d56a59d7 5483 */
embeddedartists 0:b567d56a59d7 5484 static void Adam7_interlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp)
embeddedartists 0:b567d56a59d7 5485 {
embeddedartists 0:b567d56a59d7 5486 unsigned passw[7], passh[7];
embeddedartists 0:b567d56a59d7 5487 size_t filter_passstart[8], padded_passstart[8], passstart[8];
embeddedartists 0:b567d56a59d7 5488 unsigned i;
embeddedartists 0:b567d56a59d7 5489
embeddedartists 0:b567d56a59d7 5490 Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp);
embeddedartists 0:b567d56a59d7 5491
embeddedartists 0:b567d56a59d7 5492 if(bpp >= 8)
embeddedartists 0:b567d56a59d7 5493 {
embeddedartists 0:b567d56a59d7 5494 for(i = 0; i < 7; i++)
embeddedartists 0:b567d56a59d7 5495 {
embeddedartists 0:b567d56a59d7 5496 unsigned x, y, b;
embeddedartists 0:b567d56a59d7 5497 size_t bytewidth = bpp / 8;
embeddedartists 0:b567d56a59d7 5498 for(y = 0; y < passh[i]; y++)
embeddedartists 0:b567d56a59d7 5499 for(x = 0; x < passw[i]; x++)
embeddedartists 0:b567d56a59d7 5500 {
embeddedartists 0:b567d56a59d7 5501 size_t pixelinstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth;
embeddedartists 0:b567d56a59d7 5502 size_t pixeloutstart = passstart[i] + (y * passw[i] + x) * bytewidth;
embeddedartists 0:b567d56a59d7 5503 for(b = 0; b < bytewidth; b++)
embeddedartists 0:b567d56a59d7 5504 {
embeddedartists 0:b567d56a59d7 5505 out[pixeloutstart + b] = in[pixelinstart + b];
embeddedartists 0:b567d56a59d7 5506 }
embeddedartists 0:b567d56a59d7 5507 }
embeddedartists 0:b567d56a59d7 5508 }
embeddedartists 0:b567d56a59d7 5509 }
embeddedartists 0:b567d56a59d7 5510 else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/
embeddedartists 0:b567d56a59d7 5511 {
embeddedartists 0:b567d56a59d7 5512 for(i = 0; i < 7; i++)
embeddedartists 0:b567d56a59d7 5513 {
embeddedartists 0:b567d56a59d7 5514 unsigned x, y, b;
embeddedartists 0:b567d56a59d7 5515 unsigned ilinebits = bpp * passw[i];
embeddedartists 0:b567d56a59d7 5516 unsigned olinebits = bpp * w;
embeddedartists 0:b567d56a59d7 5517 size_t obp, ibp; /*bit pointers (for out and in buffer)*/
embeddedartists 0:b567d56a59d7 5518 for(y = 0; y < passh[i]; y++)
embeddedartists 0:b567d56a59d7 5519 for(x = 0; x < passw[i]; x++)
embeddedartists 0:b567d56a59d7 5520 {
embeddedartists 0:b567d56a59d7 5521 ibp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp;
embeddedartists 0:b567d56a59d7 5522 obp = (8 * passstart[i]) + (y * ilinebits + x * bpp);
embeddedartists 0:b567d56a59d7 5523 for(b = 0; b < bpp; b++)
embeddedartists 0:b567d56a59d7 5524 {
embeddedartists 0:b567d56a59d7 5525 unsigned char bit = readBitFromReversedStream(&ibp, in);
embeddedartists 0:b567d56a59d7 5526 setBitOfReversedStream(&obp, out, bit);
embeddedartists 0:b567d56a59d7 5527 }
embeddedartists 0:b567d56a59d7 5528 }
embeddedartists 0:b567d56a59d7 5529 }
embeddedartists 0:b567d56a59d7 5530 }
embeddedartists 0:b567d56a59d7 5531 }
embeddedartists 0:b567d56a59d7 5532
embeddedartists 0:b567d56a59d7 5533 /*out must be buffer big enough to contain uncompressed IDAT chunk data, and in must contain the full image.
embeddedartists 0:b567d56a59d7 5534 return value is error**/
embeddedartists 0:b567d56a59d7 5535 static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const unsigned char* in,
embeddedartists 0:b567d56a59d7 5536 unsigned w, unsigned h,
embeddedartists 0:b567d56a59d7 5537 const LodePNGInfo* info_png, const LodePNGEncoderSettings* settings)
embeddedartists 0:b567d56a59d7 5538 {
embeddedartists 0:b567d56a59d7 5539 /*
embeddedartists 0:b567d56a59d7 5540 This function converts the pure 2D image with the PNG's colortype, into filtered-padded-interlaced data. Steps:
embeddedartists 0:b567d56a59d7 5541 *) if no Adam7: 1) add padding bits (= posible extra bits per scanline if bpp < 8) 2) filter
embeddedartists 0:b567d56a59d7 5542 *) if adam7: 1) Adam7_interlace 2) 7x add padding bits 3) 7x filter
embeddedartists 0:b567d56a59d7 5543 */
embeddedartists 0:b567d56a59d7 5544 unsigned bpp = lodepng_get_bpp(&info_png->color);
embeddedartists 0:b567d56a59d7 5545 unsigned error = 0;
embeddedartists 0:b567d56a59d7 5546
embeddedartists 0:b567d56a59d7 5547 if(info_png->interlace_method == 0)
embeddedartists 0:b567d56a59d7 5548 {
embeddedartists 0:b567d56a59d7 5549 *outsize = h + (h * ((w * bpp + 7) / 8)); /*image size plus an extra byte per scanline + possible padding bits*/
embeddedartists 0:b567d56a59d7 5550 *out = (unsigned char*)lodepng_malloc(*outsize);
embeddedartists 0:b567d56a59d7 5551 if(!(*out) && (*outsize)) error = 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 5552
embeddedartists 0:b567d56a59d7 5553 if(!error)
embeddedartists 0:b567d56a59d7 5554 {
embeddedartists 0:b567d56a59d7 5555 /*non multiple of 8 bits per scanline, padding bits needed per scanline*/
embeddedartists 0:b567d56a59d7 5556 if(bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8)
embeddedartists 0:b567d56a59d7 5557 {
embeddedartists 0:b567d56a59d7 5558 unsigned char* padded = (unsigned char*)lodepng_malloc(h * ((w * bpp + 7) / 8));
embeddedartists 0:b567d56a59d7 5559 if(!padded) error = 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 5560 if(!error)
embeddedartists 0:b567d56a59d7 5561 {
embeddedartists 0:b567d56a59d7 5562 addPaddingBits(padded, in, ((w * bpp + 7) / 8) * 8, w * bpp, h);
embeddedartists 0:b567d56a59d7 5563 error = filter(*out, padded, w, h, &info_png->color, settings);
embeddedartists 0:b567d56a59d7 5564 }
embeddedartists 0:b567d56a59d7 5565 lodepng_free(padded);
embeddedartists 0:b567d56a59d7 5566 }
embeddedartists 0:b567d56a59d7 5567 else
embeddedartists 0:b567d56a59d7 5568 {
embeddedartists 0:b567d56a59d7 5569 /*we can immediatly filter into the out buffer, no other steps needed*/
embeddedartists 0:b567d56a59d7 5570 error = filter(*out, in, w, h, &info_png->color, settings);
embeddedartists 0:b567d56a59d7 5571 }
embeddedartists 0:b567d56a59d7 5572 }
embeddedartists 0:b567d56a59d7 5573 }
embeddedartists 0:b567d56a59d7 5574 else /*interlace_method is 1 (Adam7)*/
embeddedartists 0:b567d56a59d7 5575 {
embeddedartists 0:b567d56a59d7 5576 unsigned passw[7], passh[7];
embeddedartists 0:b567d56a59d7 5577 size_t filter_passstart[8], padded_passstart[8], passstart[8];
embeddedartists 0:b567d56a59d7 5578 unsigned char* adam7;
embeddedartists 0:b567d56a59d7 5579
embeddedartists 0:b567d56a59d7 5580 Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp);
embeddedartists 0:b567d56a59d7 5581
embeddedartists 0:b567d56a59d7 5582 *outsize = filter_passstart[7]; /*image size plus an extra byte per scanline + possible padding bits*/
embeddedartists 0:b567d56a59d7 5583 *out = (unsigned char*)lodepng_malloc(*outsize);
embeddedartists 0:b567d56a59d7 5584 if(!(*out)) error = 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 5585
embeddedartists 0:b567d56a59d7 5586 adam7 = (unsigned char*)lodepng_malloc(passstart[7]);
embeddedartists 0:b567d56a59d7 5587 if(!adam7 && passstart[7]) error = 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 5588
embeddedartists 0:b567d56a59d7 5589 if(!error)
embeddedartists 0:b567d56a59d7 5590 {
embeddedartists 0:b567d56a59d7 5591 unsigned i;
embeddedartists 0:b567d56a59d7 5592
embeddedartists 0:b567d56a59d7 5593 Adam7_interlace(adam7, in, w, h, bpp);
embeddedartists 0:b567d56a59d7 5594 for(i = 0; i < 7; i++)
embeddedartists 0:b567d56a59d7 5595 {
embeddedartists 0:b567d56a59d7 5596 if(bpp < 8)
embeddedartists 0:b567d56a59d7 5597 {
embeddedartists 0:b567d56a59d7 5598 unsigned char* padded = (unsigned char*)lodepng_malloc(padded_passstart[i + 1] - padded_passstart[i]);
embeddedartists 0:b567d56a59d7 5599 if(!padded) ERROR_BREAK(83); /*alloc fail*/
embeddedartists 0:b567d56a59d7 5600 addPaddingBits(padded, &adam7[passstart[i]],
embeddedartists 0:b567d56a59d7 5601 ((passw[i] * bpp + 7) / 8) * 8, passw[i] * bpp, passh[i]);
embeddedartists 0:b567d56a59d7 5602 error = filter(&(*out)[filter_passstart[i]], padded,
embeddedartists 0:b567d56a59d7 5603 passw[i], passh[i], &info_png->color, settings);
embeddedartists 0:b567d56a59d7 5604 lodepng_free(padded);
embeddedartists 0:b567d56a59d7 5605 }
embeddedartists 0:b567d56a59d7 5606 else
embeddedartists 0:b567d56a59d7 5607 {
embeddedartists 0:b567d56a59d7 5608 error = filter(&(*out)[filter_passstart[i]], &adam7[padded_passstart[i]],
embeddedartists 0:b567d56a59d7 5609 passw[i], passh[i], &info_png->color, settings);
embeddedartists 0:b567d56a59d7 5610 }
embeddedartists 0:b567d56a59d7 5611
embeddedartists 0:b567d56a59d7 5612 if(error) break;
embeddedartists 0:b567d56a59d7 5613 }
embeddedartists 0:b567d56a59d7 5614 }
embeddedartists 0:b567d56a59d7 5615
embeddedartists 0:b567d56a59d7 5616 lodepng_free(adam7);
embeddedartists 0:b567d56a59d7 5617 }
embeddedartists 0:b567d56a59d7 5618
embeddedartists 0:b567d56a59d7 5619 return error;
embeddedartists 0:b567d56a59d7 5620 }
embeddedartists 0:b567d56a59d7 5621
embeddedartists 0:b567d56a59d7 5622 /*
embeddedartists 0:b567d56a59d7 5623 palette must have 4 * palettesize bytes allocated, and given in format RGBARGBARGBARGBA...
embeddedartists 0:b567d56a59d7 5624 returns 0 if the palette is opaque,
embeddedartists 0:b567d56a59d7 5625 returns 1 if the palette has a single color with alpha 0 ==> color key
embeddedartists 0:b567d56a59d7 5626 returns 2 if the palette is semi-translucent.
embeddedartists 0:b567d56a59d7 5627 */
embeddedartists 0:b567d56a59d7 5628 static unsigned getPaletteTranslucency(const unsigned char* palette, size_t palettesize)
embeddedartists 0:b567d56a59d7 5629 {
embeddedartists 0:b567d56a59d7 5630 size_t i, key = 0;
embeddedartists 0:b567d56a59d7 5631 unsigned r = 0, g = 0, b = 0; /*the value of the color with alpha 0, so long as color keying is possible*/
embeddedartists 0:b567d56a59d7 5632 for(i = 0; i < palettesize; i++)
embeddedartists 0:b567d56a59d7 5633 {
embeddedartists 0:b567d56a59d7 5634 if(!key && palette[4 * i + 3] == 0)
embeddedartists 0:b567d56a59d7 5635 {
embeddedartists 0:b567d56a59d7 5636 r = palette[4 * i + 0]; g = palette[4 * i + 1]; b = palette[4 * i + 2];
embeddedartists 0:b567d56a59d7 5637 key = 1;
embeddedartists 0:b567d56a59d7 5638 i = (size_t)(-1); /*restart from beginning, to detect earlier opaque colors with key's value*/
embeddedartists 0:b567d56a59d7 5639 }
embeddedartists 0:b567d56a59d7 5640 else if(palette[4 * i + 3] != 255) return 2;
embeddedartists 0:b567d56a59d7 5641 /*when key, no opaque RGB may have key's RGB*/
embeddedartists 0:b567d56a59d7 5642 else if(key && r == palette[i * 4 + 0] && g == palette[i * 4 + 1] && b == palette[i * 4 + 2]) return 2;
embeddedartists 0:b567d56a59d7 5643 }
embeddedartists 0:b567d56a59d7 5644 return key;
embeddedartists 0:b567d56a59d7 5645 }
embeddedartists 0:b567d56a59d7 5646
embeddedartists 0:b567d56a59d7 5647 #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
embeddedartists 0:b567d56a59d7 5648 static unsigned addUnknownChunks(ucvector* out, unsigned char* data, size_t datasize)
embeddedartists 0:b567d56a59d7 5649 {
embeddedartists 0:b567d56a59d7 5650 unsigned char* inchunk = data;
embeddedartists 0:b567d56a59d7 5651 while((size_t)(inchunk - data) < datasize)
embeddedartists 0:b567d56a59d7 5652 {
embeddedartists 0:b567d56a59d7 5653 CERROR_TRY_RETURN(lodepng_chunk_append(&out->data, &out->size, inchunk));
embeddedartists 0:b567d56a59d7 5654 out->allocsize = out->size; /*fix the allocsize again*/
embeddedartists 0:b567d56a59d7 5655 inchunk = lodepng_chunk_next(inchunk);
embeddedartists 0:b567d56a59d7 5656 }
embeddedartists 0:b567d56a59d7 5657 return 0;
embeddedartists 0:b567d56a59d7 5658 }
embeddedartists 0:b567d56a59d7 5659 #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
embeddedartists 0:b567d56a59d7 5660
embeddedartists 0:b567d56a59d7 5661 unsigned lodepng_encode(unsigned char** out, size_t* outsize,
embeddedartists 0:b567d56a59d7 5662 const unsigned char* image, unsigned w, unsigned h,
embeddedartists 0:b567d56a59d7 5663 LodePNGState* state)
embeddedartists 0:b567d56a59d7 5664 {
embeddedartists 0:b567d56a59d7 5665 LodePNGInfo info;
embeddedartists 0:b567d56a59d7 5666 ucvector outv;
embeddedartists 0:b567d56a59d7 5667 unsigned char* data = 0; /*uncompressed version of the IDAT chunk data*/
embeddedartists 0:b567d56a59d7 5668 size_t datasize = 0;
embeddedartists 0:b567d56a59d7 5669
embeddedartists 0:b567d56a59d7 5670 /*provide some proper output values if error will happen*/
embeddedartists 0:b567d56a59d7 5671 *out = 0;
embeddedartists 0:b567d56a59d7 5672 *outsize = 0;
embeddedartists 0:b567d56a59d7 5673 state->error = 0;
embeddedartists 0:b567d56a59d7 5674
embeddedartists 0:b567d56a59d7 5675 lodepng_info_init(&info);
embeddedartists 0:b567d56a59d7 5676 lodepng_info_copy(&info, &state->info_png);
embeddedartists 0:b567d56a59d7 5677
embeddedartists 0:b567d56a59d7 5678 if((info.color.colortype == LCT_PALETTE || state->encoder.force_palette)
embeddedartists 0:b567d56a59d7 5679 && (info.color.palettesize == 0 || info.color.palettesize > 256))
embeddedartists 0:b567d56a59d7 5680 {
embeddedartists 0:b567d56a59d7 5681 state->error = 68; /*invalid palette size, it is only allowed to be 1-256*/
embeddedartists 0:b567d56a59d7 5682 return state->error;
embeddedartists 0:b567d56a59d7 5683 }
embeddedartists 0:b567d56a59d7 5684
embeddedartists 0:b567d56a59d7 5685 if(state->encoder.auto_convert != LAC_NO)
embeddedartists 0:b567d56a59d7 5686 {
embeddedartists 0:b567d56a59d7 5687 state->error = lodepng_auto_choose_color(&info.color, image, w, h, &state->info_raw,
embeddedartists 0:b567d56a59d7 5688 state->encoder.auto_convert);
embeddedartists 0:b567d56a59d7 5689 }
embeddedartists 0:b567d56a59d7 5690 if(state->error) return state->error;
embeddedartists 0:b567d56a59d7 5691
embeddedartists 0:b567d56a59d7 5692 if(state->encoder.zlibsettings.btype > 2)
embeddedartists 0:b567d56a59d7 5693 {
embeddedartists 0:b567d56a59d7 5694 CERROR_RETURN_ERROR(state->error, 61); /*error: unexisting btype*/
embeddedartists 0:b567d56a59d7 5695 }
embeddedartists 0:b567d56a59d7 5696 if(state->info_png.interlace_method > 1)
embeddedartists 0:b567d56a59d7 5697 {
embeddedartists 0:b567d56a59d7 5698 CERROR_RETURN_ERROR(state->error, 71); /*error: unexisting interlace mode*/
embeddedartists 0:b567d56a59d7 5699 }
embeddedartists 0:b567d56a59d7 5700
embeddedartists 0:b567d56a59d7 5701 state->error = checkColorValidity(info.color.colortype, info.color.bitdepth);
embeddedartists 0:b567d56a59d7 5702 if(state->error) return state->error; /*error: unexisting color type given*/
embeddedartists 0:b567d56a59d7 5703 state->error = checkColorValidity(state->info_raw.colortype, state->info_raw.bitdepth);
embeddedartists 0:b567d56a59d7 5704 if(state->error) return state->error; /*error: unexisting color type given*/
embeddedartists 0:b567d56a59d7 5705
embeddedartists 0:b567d56a59d7 5706 if(!lodepng_color_mode_equal(&state->info_raw, &info.color))
embeddedartists 0:b567d56a59d7 5707 {
embeddedartists 0:b567d56a59d7 5708 unsigned char* converted;
embeddedartists 0:b567d56a59d7 5709 size_t size = (w * h * lodepng_get_bpp(&info.color) + 7) / 8;
embeddedartists 0:b567d56a59d7 5710
embeddedartists 0:b567d56a59d7 5711 converted = (unsigned char*)lodepng_malloc(size);
embeddedartists 0:b567d56a59d7 5712 if(!converted && size) state->error = 83; /*alloc fail*/
embeddedartists 0:b567d56a59d7 5713 if(!state->error)
embeddedartists 0:b567d56a59d7 5714 {
embeddedartists 0:b567d56a59d7 5715 state->error = lodepng_convert(converted, image, &info.color, &state->info_raw, w, h, 0 /*fix_png*/);
embeddedartists 0:b567d56a59d7 5716 }
embeddedartists 0:b567d56a59d7 5717 if(!state->error) preProcessScanlines(&data, &datasize, converted, w, h, &info, &state->encoder);
embeddedartists 0:b567d56a59d7 5718 lodepng_free(converted);
embeddedartists 0:b567d56a59d7 5719 }
embeddedartists 0:b567d56a59d7 5720 else preProcessScanlines(&data, &datasize, image, w, h, &info, &state->encoder);
embeddedartists 0:b567d56a59d7 5721
embeddedartists 0:b567d56a59d7 5722 ucvector_init(&outv);
embeddedartists 0:b567d56a59d7 5723 while(!state->error) /*while only executed once, to break on error*/
embeddedartists 0:b567d56a59d7 5724 {
embeddedartists 0:b567d56a59d7 5725 #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
embeddedartists 0:b567d56a59d7 5726 size_t i;
embeddedartists 0:b567d56a59d7 5727 #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
embeddedartists 0:b567d56a59d7 5728 /*write signature and chunks*/
embeddedartists 0:b567d56a59d7 5729 writeSignature(&outv);
embeddedartists 0:b567d56a59d7 5730 /*IHDR*/
embeddedartists 0:b567d56a59d7 5731 addChunk_IHDR(&outv, w, h, info.color.colortype, info.color.bitdepth, info.interlace_method);
embeddedartists 0:b567d56a59d7 5732 #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
embeddedartists 0:b567d56a59d7 5733 /*unknown chunks between IHDR and PLTE*/
embeddedartists 0:b567d56a59d7 5734 if(info.unknown_chunks_data[0])
embeddedartists 0:b567d56a59d7 5735 {
embeddedartists 0:b567d56a59d7 5736 state->error = addUnknownChunks(&outv, info.unknown_chunks_data[0], info.unknown_chunks_size[0]);
embeddedartists 0:b567d56a59d7 5737 if(state->error) break;
embeddedartists 0:b567d56a59d7 5738 }
embeddedartists 0:b567d56a59d7 5739 #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
embeddedartists 0:b567d56a59d7 5740 /*PLTE*/
embeddedartists 0:b567d56a59d7 5741 if(info.color.colortype == LCT_PALETTE)
embeddedartists 0:b567d56a59d7 5742 {
embeddedartists 0:b567d56a59d7 5743 addChunk_PLTE(&outv, &info.color);
embeddedartists 0:b567d56a59d7 5744 }
embeddedartists 0:b567d56a59d7 5745 if(state->encoder.force_palette && (info.color.colortype == LCT_RGB || info.color.colortype == LCT_RGBA))
embeddedartists 0:b567d56a59d7 5746 {
embeddedartists 0:b567d56a59d7 5747 addChunk_PLTE(&outv, &info.color);
embeddedartists 0:b567d56a59d7 5748 }
embeddedartists 0:b567d56a59d7 5749 /*tRNS*/
embeddedartists 0:b567d56a59d7 5750 if(info.color.colortype == LCT_PALETTE && getPaletteTranslucency(info.color.palette, info.color.palettesize) != 0)
embeddedartists 0:b567d56a59d7 5751 {
embeddedartists 0:b567d56a59d7 5752 addChunk_tRNS(&outv, &info.color);
embeddedartists 0:b567d56a59d7 5753 }
embeddedartists 0:b567d56a59d7 5754 if((info.color.colortype == LCT_GREY || info.color.colortype == LCT_RGB) && info.color.key_defined)
embeddedartists 0:b567d56a59d7 5755 {
embeddedartists 0:b567d56a59d7 5756 addChunk_tRNS(&outv, &info.color);
embeddedartists 0:b567d56a59d7 5757 }
embeddedartists 0:b567d56a59d7 5758 #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
embeddedartists 0:b567d56a59d7 5759 /*bKGD (must come between PLTE and the IDAt chunks*/
embeddedartists 0:b567d56a59d7 5760 if(info.background_defined) addChunk_bKGD(&outv, &info);
embeddedartists 0:b567d56a59d7 5761 /*pHYs (must come before the IDAT chunks)*/
embeddedartists 0:b567d56a59d7 5762 if(info.phys_defined) addChunk_pHYs(&outv, &info);
embeddedartists 0:b567d56a59d7 5763
embeddedartists 0:b567d56a59d7 5764 /*unknown chunks between PLTE and IDAT*/
embeddedartists 0:b567d56a59d7 5765 if(info.unknown_chunks_data[1])
embeddedartists 0:b567d56a59d7 5766 {
embeddedartists 0:b567d56a59d7 5767 state->error = addUnknownChunks(&outv, info.unknown_chunks_data[1], info.unknown_chunks_size[1]);
embeddedartists 0:b567d56a59d7 5768 if(state->error) break;
embeddedartists 0:b567d56a59d7 5769 }
embeddedartists 0:b567d56a59d7 5770 #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
embeddedartists 0:b567d56a59d7 5771 /*IDAT (multiple IDAT chunks must be consecutive)*/
embeddedartists 0:b567d56a59d7 5772 state->error = addChunk_IDAT(&outv, data, datasize, &state->encoder.zlibsettings);
embeddedartists 0:b567d56a59d7 5773 if(state->error) break;
embeddedartists 0:b567d56a59d7 5774 #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
embeddedartists 0:b567d56a59d7 5775 /*tIME*/
embeddedartists 0:b567d56a59d7 5776 if(info.time_defined) addChunk_tIME(&outv, &info.time);
embeddedartists 0:b567d56a59d7 5777 /*tEXt and/or zTXt*/
embeddedartists 0:b567d56a59d7 5778 for(i = 0; i < info.text_num; i++)
embeddedartists 0:b567d56a59d7 5779 {
embeddedartists 0:b567d56a59d7 5780 if(strlen(info.text_keys[i]) > 79)
embeddedartists 0:b567d56a59d7 5781 {
embeddedartists 0:b567d56a59d7 5782 state->error = 66; /*text chunk too large*/
embeddedartists 0:b567d56a59d7 5783 break;
embeddedartists 0:b567d56a59d7 5784 }
embeddedartists 0:b567d56a59d7 5785 if(strlen(info.text_keys[i]) < 1)
embeddedartists 0:b567d56a59d7 5786 {
embeddedartists 0:b567d56a59d7 5787 state->error = 67; /*text chunk too small*/
embeddedartists 0:b567d56a59d7 5788 break;
embeddedartists 0:b567d56a59d7 5789 }
embeddedartists 0:b567d56a59d7 5790 if(state->encoder.text_compression)
embeddedartists 0:b567d56a59d7 5791 {
embeddedartists 0:b567d56a59d7 5792 addChunk_zTXt(&outv, info.text_keys[i], info.text_strings[i], &state->encoder.zlibsettings);
embeddedartists 0:b567d56a59d7 5793 }
embeddedartists 0:b567d56a59d7 5794 else
embeddedartists 0:b567d56a59d7 5795 {
embeddedartists 0:b567d56a59d7 5796 addChunk_tEXt(&outv, info.text_keys[i], info.text_strings[i]);
embeddedartists 0:b567d56a59d7 5797 }
embeddedartists 0:b567d56a59d7 5798 }
embeddedartists 0:b567d56a59d7 5799 /*LodePNG version id in text chunk*/
embeddedartists 0:b567d56a59d7 5800 if(state->encoder.add_id)
embeddedartists 0:b567d56a59d7 5801 {
embeddedartists 0:b567d56a59d7 5802 unsigned alread_added_id_text = 0;
embeddedartists 0:b567d56a59d7 5803 for(i = 0; i < info.text_num; i++)
embeddedartists 0:b567d56a59d7 5804 {
embeddedartists 0:b567d56a59d7 5805 if(!strcmp(info.text_keys[i], "LodePNG"))
embeddedartists 0:b567d56a59d7 5806 {
embeddedartists 0:b567d56a59d7 5807 alread_added_id_text = 1;
embeddedartists 0:b567d56a59d7 5808 break;
embeddedartists 0:b567d56a59d7 5809 }
embeddedartists 0:b567d56a59d7 5810 }
embeddedartists 0:b567d56a59d7 5811 if(alread_added_id_text == 0)
embeddedartists 0:b567d56a59d7 5812 {
embeddedartists 0:b567d56a59d7 5813 addChunk_tEXt(&outv, "LodePNG", VERSION_STRING); /*it's shorter as tEXt than as zTXt chunk*/
embeddedartists 0:b567d56a59d7 5814 }
embeddedartists 0:b567d56a59d7 5815 }
embeddedartists 0:b567d56a59d7 5816 /*iTXt*/
embeddedartists 0:b567d56a59d7 5817 for(i = 0; i < info.itext_num; i++)
embeddedartists 0:b567d56a59d7 5818 {
embeddedartists 0:b567d56a59d7 5819 if(strlen(info.itext_keys[i]) > 79)
embeddedartists 0:b567d56a59d7 5820 {
embeddedartists 0:b567d56a59d7 5821 state->error = 66; /*text chunk too large*/
embeddedartists 0:b567d56a59d7 5822 break;
embeddedartists 0:b567d56a59d7 5823 }
embeddedartists 0:b567d56a59d7 5824 if(strlen(info.itext_keys[i]) < 1)
embeddedartists 0:b567d56a59d7 5825 {
embeddedartists 0:b567d56a59d7 5826 state->error = 67; /*text chunk too small*/
embeddedartists 0:b567d56a59d7 5827 break;
embeddedartists 0:b567d56a59d7 5828 }
embeddedartists 0:b567d56a59d7 5829 addChunk_iTXt(&outv, state->encoder.text_compression,
embeddedartists 0:b567d56a59d7 5830 info.itext_keys[i], info.itext_langtags[i], info.itext_transkeys[i], info.itext_strings[i],
embeddedartists 0:b567d56a59d7 5831 &state->encoder.zlibsettings);
embeddedartists 0:b567d56a59d7 5832 }
embeddedartists 0:b567d56a59d7 5833
embeddedartists 0:b567d56a59d7 5834 /*unknown chunks between IDAT and IEND*/
embeddedartists 0:b567d56a59d7 5835 if(info.unknown_chunks_data[2])
embeddedartists 0:b567d56a59d7 5836 {
embeddedartists 0:b567d56a59d7 5837 state->error = addUnknownChunks(&outv, info.unknown_chunks_data[2], info.unknown_chunks_size[2]);
embeddedartists 0:b567d56a59d7 5838 if(state->error) break;
embeddedartists 0:b567d56a59d7 5839 }
embeddedartists 0:b567d56a59d7 5840 #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
embeddedartists 0:b567d56a59d7 5841 addChunk_IEND(&outv);
embeddedartists 0:b567d56a59d7 5842
embeddedartists 0:b567d56a59d7 5843 break; /*this isn't really a while loop; no error happened so break out now!*/
embeddedartists 0:b567d56a59d7 5844 }
embeddedartists 0:b567d56a59d7 5845
embeddedartists 0:b567d56a59d7 5846 lodepng_info_cleanup(&info);
embeddedartists 0:b567d56a59d7 5847 lodepng_free(data);
embeddedartists 0:b567d56a59d7 5848 /*instead of cleaning the vector up, give it to the output*/
embeddedartists 0:b567d56a59d7 5849 *out = outv.data;
embeddedartists 0:b567d56a59d7 5850 *outsize = outv.size;
embeddedartists 0:b567d56a59d7 5851
embeddedartists 0:b567d56a59d7 5852 return state->error;
embeddedartists 0:b567d56a59d7 5853 }
embeddedartists 0:b567d56a59d7 5854
embeddedartists 0:b567d56a59d7 5855 unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, const unsigned char* image,
embeddedartists 0:b567d56a59d7 5856 unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth)
embeddedartists 0:b567d56a59d7 5857 {
embeddedartists 0:b567d56a59d7 5858 unsigned error;
embeddedartists 0:b567d56a59d7 5859 LodePNGState state;
embeddedartists 0:b567d56a59d7 5860 lodepng_state_init(&state);
embeddedartists 0:b567d56a59d7 5861 state.info_raw.colortype = colortype;
embeddedartists 0:b567d56a59d7 5862 state.info_raw.bitdepth = bitdepth;
embeddedartists 0:b567d56a59d7 5863 state.info_png.color.colortype = colortype;
embeddedartists 0:b567d56a59d7 5864 state.info_png.color.bitdepth = bitdepth;
embeddedartists 0:b567d56a59d7 5865 lodepng_encode(out, outsize, image, w, h, &state);
embeddedartists 0:b567d56a59d7 5866 error = state.error;
embeddedartists 0:b567d56a59d7 5867 lodepng_state_cleanup(&state);
embeddedartists 0:b567d56a59d7 5868 return error;
embeddedartists 0:b567d56a59d7 5869 }
embeddedartists 0:b567d56a59d7 5870
embeddedartists 0:b567d56a59d7 5871 unsigned lodepng_encode32(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h)
embeddedartists 0:b567d56a59d7 5872 {
embeddedartists 0:b567d56a59d7 5873 return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGBA, 8);
embeddedartists 0:b567d56a59d7 5874 }
embeddedartists 0:b567d56a59d7 5875
embeddedartists 0:b567d56a59d7 5876 unsigned lodepng_encode24(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h)
embeddedartists 0:b567d56a59d7 5877 {
embeddedartists 0:b567d56a59d7 5878 return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGB, 8);
embeddedartists 0:b567d56a59d7 5879 }
embeddedartists 0:b567d56a59d7 5880
embeddedartists 0:b567d56a59d7 5881 #ifdef LODEPNG_COMPILE_DISK
embeddedartists 0:b567d56a59d7 5882 unsigned lodepng_encode_file(const char* filename, const unsigned char* image, unsigned w, unsigned h,
embeddedartists 0:b567d56a59d7 5883 LodePNGColorType colortype, unsigned bitdepth)
embeddedartists 0:b567d56a59d7 5884 {
embeddedartists 0:b567d56a59d7 5885 unsigned char* buffer;
embeddedartists 0:b567d56a59d7 5886 size_t buffersize;
embeddedartists 0:b567d56a59d7 5887 unsigned error = lodepng_encode_memory(&buffer, &buffersize, image, w, h, colortype, bitdepth);
embeddedartists 0:b567d56a59d7 5888 if(!error) error = lodepng_save_file(buffer, buffersize, filename);
embeddedartists 0:b567d56a59d7 5889 lodepng_free(buffer);
embeddedartists 0:b567d56a59d7 5890 return error;
embeddedartists 0:b567d56a59d7 5891 }
embeddedartists 0:b567d56a59d7 5892
embeddedartists 0:b567d56a59d7 5893 unsigned lodepng_encode32_file(const char* filename, const unsigned char* image, unsigned w, unsigned h)
embeddedartists 0:b567d56a59d7 5894 {
embeddedartists 0:b567d56a59d7 5895 return lodepng_encode_file(filename, image, w, h, LCT_RGBA, 8);
embeddedartists 0:b567d56a59d7 5896 }
embeddedartists 0:b567d56a59d7 5897
embeddedartists 0:b567d56a59d7 5898 unsigned lodepng_encode24_file(const char* filename, const unsigned char* image, unsigned w, unsigned h)
embeddedartists 0:b567d56a59d7 5899 {
embeddedartists 0:b567d56a59d7 5900 return lodepng_encode_file(filename, image, w, h, LCT_RGB, 8);
embeddedartists 0:b567d56a59d7 5901 }
embeddedartists 0:b567d56a59d7 5902 #endif /*LODEPNG_COMPILE_DISK*/
embeddedartists 0:b567d56a59d7 5903
embeddedartists 0:b567d56a59d7 5904 void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings)
embeddedartists 0:b567d56a59d7 5905 {
embeddedartists 0:b567d56a59d7 5906 lodepng_compress_settings_init(&settings->zlibsettings);
embeddedartists 0:b567d56a59d7 5907 settings->filter_palette_zero = 1;
embeddedartists 0:b567d56a59d7 5908 settings->filter_strategy = LFS_MINSUM;
embeddedartists 0:b567d56a59d7 5909 settings->auto_convert = LAC_AUTO;
embeddedartists 0:b567d56a59d7 5910 settings->force_palette = 0;
embeddedartists 0:b567d56a59d7 5911 settings->predefined_filters = 0;
embeddedartists 0:b567d56a59d7 5912 #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
embeddedartists 0:b567d56a59d7 5913 settings->add_id = 0;
embeddedartists 0:b567d56a59d7 5914 settings->text_compression = 1;
embeddedartists 0:b567d56a59d7 5915 #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
embeddedartists 0:b567d56a59d7 5916 }
embeddedartists 0:b567d56a59d7 5917
embeddedartists 0:b567d56a59d7 5918 #endif /*LODEPNG_COMPILE_ENCODER*/
embeddedartists 0:b567d56a59d7 5919 #endif /*LODEPNG_COMPILE_PNG*/
embeddedartists 0:b567d56a59d7 5920
embeddedartists 0:b567d56a59d7 5921 #ifdef LODEPNG_COMPILE_ERROR_TEXT
embeddedartists 0:b567d56a59d7 5922 /*
embeddedartists 0:b567d56a59d7 5923 This returns the description of a numerical error code in English. This is also
embeddedartists 0:b567d56a59d7 5924 the documentation of all the error codes.
embeddedartists 0:b567d56a59d7 5925 */
embeddedartists 0:b567d56a59d7 5926 const char* lodepng_error_text(unsigned code)
embeddedartists 0:b567d56a59d7 5927 {
embeddedartists 0:b567d56a59d7 5928 switch(code)
embeddedartists 0:b567d56a59d7 5929 {
embeddedartists 0:b567d56a59d7 5930 case 0: return "no error, everything went ok";
embeddedartists 0:b567d56a59d7 5931 case 1: return "nothing done yet"; /*the Encoder/Decoder has done nothing yet, error checking makes no sense yet*/
embeddedartists 0:b567d56a59d7 5932 case 10: return "end of input memory reached without huffman end code"; /*while huffman decoding*/
embeddedartists 0:b567d56a59d7 5933 case 11: return "error in code tree made it jump outside of huffman tree"; /*while huffman decoding*/
embeddedartists 0:b567d56a59d7 5934 case 13: return "problem while processing dynamic deflate block";
embeddedartists 0:b567d56a59d7 5935 case 14: return "problem while processing dynamic deflate block";
embeddedartists 0:b567d56a59d7 5936 case 15: return "problem while processing dynamic deflate block";
embeddedartists 0:b567d56a59d7 5937 case 16: return "unexisting code while processing dynamic deflate block";
embeddedartists 0:b567d56a59d7 5938 case 17: return "end of out buffer memory reached while inflating";
embeddedartists 0:b567d56a59d7 5939 case 18: return "invalid distance code while inflating";
embeddedartists 0:b567d56a59d7 5940 case 19: return "end of out buffer memory reached while inflating";
embeddedartists 0:b567d56a59d7 5941 case 20: return "invalid deflate block BTYPE encountered while decoding";
embeddedartists 0:b567d56a59d7 5942 case 21: return "NLEN is not ones complement of LEN in a deflate block";
embeddedartists 0:b567d56a59d7 5943 /*end of out buffer memory reached while inflating:
embeddedartists 0:b567d56a59d7 5944 This can happen if the inflated deflate data is longer than the amount of bytes required to fill up
embeddedartists 0:b567d56a59d7 5945 all the pixels of the image, given the color depth and image dimensions. Something that doesn't
embeddedartists 0:b567d56a59d7 5946 happen in a normal, well encoded, PNG image.*/
embeddedartists 0:b567d56a59d7 5947 case 22: return "end of out buffer memory reached while inflating";
embeddedartists 0:b567d56a59d7 5948 case 23: return "end of in buffer memory reached while inflating";
embeddedartists 0:b567d56a59d7 5949 case 24: return "invalid FCHECK in zlib header";
embeddedartists 0:b567d56a59d7 5950 case 25: return "invalid compression method in zlib header";
embeddedartists 0:b567d56a59d7 5951 case 26: return "FDICT encountered in zlib header while it's not used for PNG";
embeddedartists 0:b567d56a59d7 5952 case 27: return "PNG file is smaller than a PNG header";
embeddedartists 0:b567d56a59d7 5953 /*Checks the magic file header, the first 8 bytes of the PNG file*/
embeddedartists 0:b567d56a59d7 5954 case 28: return "incorrect PNG signature, it's no PNG or corrupted";
embeddedartists 0:b567d56a59d7 5955 case 29: return "first chunk is not the header chunk";
embeddedartists 0:b567d56a59d7 5956 case 30: return "chunk length too large, chunk broken off at end of file";
embeddedartists 0:b567d56a59d7 5957 case 31: return "illegal PNG color type or bpp";
embeddedartists 0:b567d56a59d7 5958 case 32: return "illegal PNG compression method";
embeddedartists 0:b567d56a59d7 5959 case 33: return "illegal PNG filter method";
embeddedartists 0:b567d56a59d7 5960 case 34: return "illegal PNG interlace method";
embeddedartists 0:b567d56a59d7 5961 case 35: return "chunk length of a chunk is too large or the chunk too small";
embeddedartists 0:b567d56a59d7 5962 case 36: return "illegal PNG filter type encountered";
embeddedartists 0:b567d56a59d7 5963 case 37: return "illegal bit depth for this color type given";
embeddedartists 0:b567d56a59d7 5964 case 38: return "the palette is too big"; /*more than 256 colors*/
embeddedartists 0:b567d56a59d7 5965 case 39: return "more palette alpha values given in tRNS chunk than there are colors in the palette";
embeddedartists 0:b567d56a59d7 5966 case 40: return "tRNS chunk has wrong size for greyscale image";
embeddedartists 0:b567d56a59d7 5967 case 41: return "tRNS chunk has wrong size for RGB image";
embeddedartists 0:b567d56a59d7 5968 case 42: return "tRNS chunk appeared while it was not allowed for this color type";
embeddedartists 0:b567d56a59d7 5969 case 43: return "bKGD chunk has wrong size for palette image";
embeddedartists 0:b567d56a59d7 5970 case 44: return "bKGD chunk has wrong size for greyscale image";
embeddedartists 0:b567d56a59d7 5971 case 45: return "bKGD chunk has wrong size for RGB image";
embeddedartists 0:b567d56a59d7 5972 /*Is the palette too small?*/
embeddedartists 0:b567d56a59d7 5973 case 46: return "a value in indexed image is larger than the palette size (bitdepth = 8)";
embeddedartists 0:b567d56a59d7 5974 /*Is the palette too small?*/
embeddedartists 0:b567d56a59d7 5975 case 47: return "a value in indexed image is larger than the palette size (bitdepth < 8)";
embeddedartists 0:b567d56a59d7 5976 /*the input data is empty, maybe a PNG file doesn't exist or is in the wrong path*/
embeddedartists 0:b567d56a59d7 5977 case 48: return "empty input or file doesn't exist";
embeddedartists 0:b567d56a59d7 5978 case 49: return "jumped past memory while generating dynamic huffman tree";
embeddedartists 0:b567d56a59d7 5979 case 50: return "jumped past memory while generating dynamic huffman tree";
embeddedartists 0:b567d56a59d7 5980 case 51: return "jumped past memory while inflating huffman block";
embeddedartists 0:b567d56a59d7 5981 case 52: return "jumped past memory while inflating";
embeddedartists 0:b567d56a59d7 5982 case 53: return "size of zlib data too small";
embeddedartists 0:b567d56a59d7 5983 case 54: return "repeat symbol in tree while there was no value symbol yet";
embeddedartists 0:b567d56a59d7 5984 /*jumped past tree while generating huffman tree, this could be when the
embeddedartists 0:b567d56a59d7 5985 tree will have more leaves than symbols after generating it out of the
embeddedartists 0:b567d56a59d7 5986 given lenghts. They call this an oversubscribed dynamic bit lengths tree in zlib.*/
embeddedartists 0:b567d56a59d7 5987 case 55: return "jumped past tree while generating huffman tree";
embeddedartists 0:b567d56a59d7 5988 case 56: return "given output image colortype or bitdepth not supported for color conversion";
embeddedartists 0:b567d56a59d7 5989 case 57: return "invalid CRC encountered (checking CRC can be disabled)";
embeddedartists 0:b567d56a59d7 5990 case 58: return "invalid ADLER32 encountered (checking ADLER32 can be disabled)";
embeddedartists 0:b567d56a59d7 5991 case 59: return "requested color conversion not supported";
embeddedartists 0:b567d56a59d7 5992 case 60: return "invalid window size given in the settings of the encoder (must be 0-32768)";
embeddedartists 0:b567d56a59d7 5993 case 61: return "invalid BTYPE given in the settings of the encoder (only 0, 1 and 2 are allowed)";
embeddedartists 0:b567d56a59d7 5994 /*LodePNG leaves the choice of RGB to greyscale conversion formula to the user.*/
embeddedartists 0:b567d56a59d7 5995 case 62: return "conversion from color to greyscale not supported";
embeddedartists 0:b567d56a59d7 5996 case 63: return "length of a chunk too long, max allowed for PNG is 2147483647 bytes per chunk"; /*(2^31-1)*/
embeddedartists 0:b567d56a59d7 5997 /*this would result in the inability of a deflated block to ever contain an end code. It must be at least 1.*/
embeddedartists 0:b567d56a59d7 5998 case 64: return "the length of the END symbol 256 in the Huffman tree is 0";
embeddedartists 0:b567d56a59d7 5999 case 66: return "the length of a text chunk keyword given to the encoder is longer than the maximum of 79 bytes";
embeddedartists 0:b567d56a59d7 6000 case 67: return "the length of a text chunk keyword given to the encoder is smaller than the minimum of 1 byte";
embeddedartists 0:b567d56a59d7 6001 case 68: return "tried to encode a PLTE chunk with a palette that has less than 1 or more than 256 colors";
embeddedartists 0:b567d56a59d7 6002 case 69: return "unknown chunk type with 'critical' flag encountered by the decoder";
embeddedartists 0:b567d56a59d7 6003 case 71: return "unexisting interlace mode given to encoder (must be 0 or 1)";
embeddedartists 0:b567d56a59d7 6004 case 72: return "while decoding, unexisting compression method encountering in zTXt or iTXt chunk (it must be 0)";
embeddedartists 0:b567d56a59d7 6005 case 73: return "invalid tIME chunk size";
embeddedartists 0:b567d56a59d7 6006 case 74: return "invalid pHYs chunk size";
embeddedartists 0:b567d56a59d7 6007 /*length could be wrong, or data chopped off*/
embeddedartists 0:b567d56a59d7 6008 case 75: return "no null termination char found while decoding text chunk";
embeddedartists 0:b567d56a59d7 6009 case 76: return "iTXt chunk too short to contain required bytes";
embeddedartists 0:b567d56a59d7 6010 case 77: return "integer overflow in buffer size";
embeddedartists 0:b567d56a59d7 6011 case 78: return "failed to open file for reading"; /*file doesn't exist or couldn't be opened for reading*/
embeddedartists 0:b567d56a59d7 6012 case 79: return "failed to open file for writing";
embeddedartists 0:b567d56a59d7 6013 case 80: return "tried creating a tree of 0 symbols";
embeddedartists 0:b567d56a59d7 6014 case 81: return "lazy matching at pos 0 is impossible";
embeddedartists 0:b567d56a59d7 6015 case 82: return "color conversion to palette requested while a color isn't in palette";
embeddedartists 0:b567d56a59d7 6016 case 83: return "memory allocation failed";
embeddedartists 0:b567d56a59d7 6017 case 84: return "given image too small to contain all pixels to be encoded";
embeddedartists 0:b567d56a59d7 6018 case 85: return "internal color conversion bug";
embeddedartists 0:b567d56a59d7 6019 case 86: return "impossible offset in lz77 encoding (internal bug)";
embeddedartists 0:b567d56a59d7 6020 case 87: return "must provide custom zlib function pointer if LODEPNG_COMPILE_ZLIB is not defined";
embeddedartists 0:b567d56a59d7 6021 case 88: return "invalid filter strategy given for LodePNGEncoderSettings.filter_strategy";
embeddedartists 0:b567d56a59d7 6022 case 89: return "text chunk keyword too short or long: must have size 1-79";
embeddedartists 0:b567d56a59d7 6023 /*the windowsize in the LodePNGCompressSettings. Requiring POT(==> & instead of %) makes encoding 12% faster.*/
embeddedartists 0:b567d56a59d7 6024 case 90: return "windowsize must be a power of two";
embeddedartists 0:b567d56a59d7 6025 }
embeddedartists 0:b567d56a59d7 6026 return "unknown error code";
embeddedartists 0:b567d56a59d7 6027 }
embeddedartists 0:b567d56a59d7 6028 #endif /*LODEPNG_COMPILE_ERROR_TEXT*/
embeddedartists 0:b567d56a59d7 6029
embeddedartists 0:b567d56a59d7 6030 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 6031 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 6032 /* // C++ Wrapper // */
embeddedartists 0:b567d56a59d7 6033 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 6034 /* ////////////////////////////////////////////////////////////////////////// */
embeddedartists 0:b567d56a59d7 6035
embeddedartists 0:b567d56a59d7 6036 #ifdef LODEPNG_COMPILE_CPP
embeddedartists 0:b567d56a59d7 6037 namespace lodepng
embeddedartists 0:b567d56a59d7 6038 {
embeddedartists 0:b567d56a59d7 6039
embeddedartists 0:b567d56a59d7 6040 #ifdef LODEPNG_COMPILE_DISK
embeddedartists 0:b567d56a59d7 6041 void load_file(std::vector<unsigned char>& buffer, const std::string& filename)
embeddedartists 0:b567d56a59d7 6042 {
embeddedartists 0:b567d56a59d7 6043 std::ifstream file(filename.c_str(), std::ios::in|std::ios::binary|std::ios::ate);
embeddedartists 0:b567d56a59d7 6044
embeddedartists 0:b567d56a59d7 6045 /*get filesize*/
embeddedartists 0:b567d56a59d7 6046 std::streamsize size = 0;
embeddedartists 0:b567d56a59d7 6047 if(file.seekg(0, std::ios::end).good()) size = file.tellg();
embeddedartists 0:b567d56a59d7 6048 if(file.seekg(0, std::ios::beg).good()) size -= file.tellg();
embeddedartists 0:b567d56a59d7 6049
embeddedartists 0:b567d56a59d7 6050 /*read contents of the file into the vector*/
embeddedartists 0:b567d56a59d7 6051 buffer.resize(size_t(size));
embeddedartists 0:b567d56a59d7 6052 if(size > 0) file.read((char*)(&buffer[0]), size);
embeddedartists 0:b567d56a59d7 6053 }
embeddedartists 0:b567d56a59d7 6054
embeddedartists 0:b567d56a59d7 6055 /*write given buffer to the file, overwriting the file, it doesn't append to it.*/
embeddedartists 0:b567d56a59d7 6056 void save_file(const std::vector<unsigned char>& buffer, const std::string& filename)
embeddedartists 0:b567d56a59d7 6057 {
embeddedartists 0:b567d56a59d7 6058 std::ofstream file(filename.c_str(), std::ios::out|std::ios::binary);
embeddedartists 0:b567d56a59d7 6059 file.write(buffer.empty() ? 0 : (char*)&buffer[0], std::streamsize(buffer.size()));
embeddedartists 0:b567d56a59d7 6060 }
embeddedartists 0:b567d56a59d7 6061 #endif //LODEPNG_COMPILE_DISK
embeddedartists 0:b567d56a59d7 6062
embeddedartists 0:b567d56a59d7 6063 #ifdef LODEPNG_COMPILE_ZLIB
embeddedartists 0:b567d56a59d7 6064 #ifdef LODEPNG_COMPILE_DECODER
embeddedartists 0:b567d56a59d7 6065 unsigned decompress(std::vector<unsigned char>& out, const unsigned char* in, size_t insize,
embeddedartists 0:b567d56a59d7 6066 const LodePNGDecompressSettings& settings)
embeddedartists 0:b567d56a59d7 6067 {
embeddedartists 0:b567d56a59d7 6068 unsigned char* buffer = 0;
embeddedartists 0:b567d56a59d7 6069 size_t buffersize = 0;
embeddedartists 0:b567d56a59d7 6070 unsigned error = zlib_decompress(&buffer, &buffersize, in, insize, &settings);
embeddedartists 0:b567d56a59d7 6071 if(buffer)
embeddedartists 0:b567d56a59d7 6072 {
embeddedartists 0:b567d56a59d7 6073 out.insert(out.end(), &buffer[0], &buffer[buffersize]);
embeddedartists 0:b567d56a59d7 6074 lodepng_free(buffer);
embeddedartists 0:b567d56a59d7 6075 }
embeddedartists 0:b567d56a59d7 6076 return error;
embeddedartists 0:b567d56a59d7 6077 }
embeddedartists 0:b567d56a59d7 6078
embeddedartists 0:b567d56a59d7 6079 unsigned decompress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in,
embeddedartists 0:b567d56a59d7 6080 const LodePNGDecompressSettings& settings)
embeddedartists 0:b567d56a59d7 6081 {
embeddedartists 0:b567d56a59d7 6082 return decompress(out, in.empty() ? 0 : &in[0], in.size(), settings);
embeddedartists 0:b567d56a59d7 6083 }
embeddedartists 0:b567d56a59d7 6084 #endif //LODEPNG_COMPILE_DECODER
embeddedartists 0:b567d56a59d7 6085
embeddedartists 0:b567d56a59d7 6086 #ifdef LODEPNG_COMPILE_ENCODER
embeddedartists 0:b567d56a59d7 6087 unsigned compress(std::vector<unsigned char>& out, const unsigned char* in, size_t insize,
embeddedartists 0:b567d56a59d7 6088 const LodePNGCompressSettings& settings)
embeddedartists 0:b567d56a59d7 6089 {
embeddedartists 0:b567d56a59d7 6090 unsigned char* buffer = 0;
embeddedartists 0:b567d56a59d7 6091 size_t buffersize = 0;
embeddedartists 0:b567d56a59d7 6092 unsigned error = zlib_compress(&buffer, &buffersize, in, insize, &settings);
embeddedartists 0:b567d56a59d7 6093 if(buffer)
embeddedartists 0:b567d56a59d7 6094 {
embeddedartists 0:b567d56a59d7 6095 out.insert(out.end(), &buffer[0], &buffer[buffersize]);
embeddedartists 0:b567d56a59d7 6096 lodepng_free(buffer);
embeddedartists 0:b567d56a59d7 6097 }
embeddedartists 0:b567d56a59d7 6098 return error;
embeddedartists 0:b567d56a59d7 6099 }
embeddedartists 0:b567d56a59d7 6100
embeddedartists 0:b567d56a59d7 6101 unsigned compress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in,
embeddedartists 0:b567d56a59d7 6102 const LodePNGCompressSettings& settings)
embeddedartists 0:b567d56a59d7 6103 {
embeddedartists 0:b567d56a59d7 6104 return compress(out, in.empty() ? 0 : &in[0], in.size(), settings);
embeddedartists 0:b567d56a59d7 6105 }
embeddedartists 0:b567d56a59d7 6106 #endif //LODEPNG_COMPILE_ENCODER
embeddedartists 0:b567d56a59d7 6107 #endif //LODEPNG_COMPILE_ZLIB
embeddedartists 0:b567d56a59d7 6108
embeddedartists 0:b567d56a59d7 6109
embeddedartists 0:b567d56a59d7 6110 #ifdef LODEPNG_COMPILE_PNG
embeddedartists 0:b567d56a59d7 6111
embeddedartists 0:b567d56a59d7 6112 State::State()
embeddedartists 0:b567d56a59d7 6113 {
embeddedartists 0:b567d56a59d7 6114 lodepng_state_init(this);
embeddedartists 0:b567d56a59d7 6115 }
embeddedartists 0:b567d56a59d7 6116
embeddedartists 0:b567d56a59d7 6117 State::State(const State& other)
embeddedartists 0:b567d56a59d7 6118 {
embeddedartists 0:b567d56a59d7 6119 lodepng_state_init(this);
embeddedartists 0:b567d56a59d7 6120 lodepng_state_copy(this, &other);
embeddedartists 0:b567d56a59d7 6121 }
embeddedartists 0:b567d56a59d7 6122
embeddedartists 0:b567d56a59d7 6123 State::~State()
embeddedartists 0:b567d56a59d7 6124 {
embeddedartists 0:b567d56a59d7 6125 lodepng_state_cleanup(this);
embeddedartists 0:b567d56a59d7 6126 }
embeddedartists 0:b567d56a59d7 6127
embeddedartists 0:b567d56a59d7 6128 State& State::operator=(const State& other)
embeddedartists 0:b567d56a59d7 6129 {
embeddedartists 0:b567d56a59d7 6130 lodepng_state_copy(this, &other);
embeddedartists 0:b567d56a59d7 6131 return *this;
embeddedartists 0:b567d56a59d7 6132 }
embeddedartists 0:b567d56a59d7 6133
embeddedartists 0:b567d56a59d7 6134 #ifdef LODEPNG_COMPILE_DECODER
embeddedartists 0:b567d56a59d7 6135
embeddedartists 0:b567d56a59d7 6136 unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, const unsigned char* in,
embeddedartists 0:b567d56a59d7 6137 size_t insize, LodePNGColorType colortype, unsigned bitdepth)
embeddedartists 0:b567d56a59d7 6138 {
embeddedartists 0:b567d56a59d7 6139 unsigned char* buffer;
embeddedartists 0:b567d56a59d7 6140 unsigned error = lodepng_decode_memory(&buffer, &w, &h, in, insize, colortype, bitdepth);
embeddedartists 0:b567d56a59d7 6141 if(buffer && !error)
embeddedartists 0:b567d56a59d7 6142 {
embeddedartists 0:b567d56a59d7 6143 State state;
embeddedartists 0:b567d56a59d7 6144 state.info_raw.colortype = colortype;
embeddedartists 0:b567d56a59d7 6145 state.info_raw.bitdepth = bitdepth;
embeddedartists 0:b567d56a59d7 6146 size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw);
embeddedartists 0:b567d56a59d7 6147 out.insert(out.end(), &buffer[0], &buffer[buffersize]);
embeddedartists 0:b567d56a59d7 6148 lodepng_free(buffer);
embeddedartists 0:b567d56a59d7 6149 }
embeddedartists 0:b567d56a59d7 6150 return error;
embeddedartists 0:b567d56a59d7 6151 }
embeddedartists 0:b567d56a59d7 6152
embeddedartists 0:b567d56a59d7 6153 unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
embeddedartists 0:b567d56a59d7 6154 const std::vector<unsigned char>& in, LodePNGColorType colortype, unsigned bitdepth)
embeddedartists 0:b567d56a59d7 6155 {
embeddedartists 0:b567d56a59d7 6156 return decode(out, w, h, in.empty() ? 0 : &in[0], (unsigned)in.size(), colortype, bitdepth);
embeddedartists 0:b567d56a59d7 6157 }
embeddedartists 0:b567d56a59d7 6158
embeddedartists 0:b567d56a59d7 6159 unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
embeddedartists 0:b567d56a59d7 6160 State& state,
embeddedartists 0:b567d56a59d7 6161 const unsigned char* in, size_t insize)
embeddedartists 0:b567d56a59d7 6162 {
embeddedartists 0:b567d56a59d7 6163 unsigned char* buffer = NULL;
embeddedartists 0:b567d56a59d7 6164 unsigned error = lodepng_decode(&buffer, &w, &h, &state, in, insize);
embeddedartists 0:b567d56a59d7 6165 if(buffer && !error)
embeddedartists 0:b567d56a59d7 6166 {
embeddedartists 0:b567d56a59d7 6167 size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw);
embeddedartists 0:b567d56a59d7 6168 out.insert(out.end(), &buffer[0], &buffer[buffersize]);
embeddedartists 0:b567d56a59d7 6169 }
embeddedartists 0:b567d56a59d7 6170 lodepng_free(buffer);
embeddedartists 0:b567d56a59d7 6171 return error;
embeddedartists 0:b567d56a59d7 6172 }
embeddedartists 0:b567d56a59d7 6173
embeddedartists 0:b567d56a59d7 6174 unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
embeddedartists 0:b567d56a59d7 6175 State& state,
embeddedartists 0:b567d56a59d7 6176 const std::vector<unsigned char>& in)
embeddedartists 0:b567d56a59d7 6177 {
embeddedartists 0:b567d56a59d7 6178 return decode(out, w, h, state, in.empty() ? 0 : &in[0], in.size());
embeddedartists 0:b567d56a59d7 6179 }
embeddedartists 0:b567d56a59d7 6180
embeddedartists 0:b567d56a59d7 6181 #ifdef LODEPNG_COMPILE_DISK
embeddedartists 0:b567d56a59d7 6182 unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, const std::string& filename,
embeddedartists 0:b567d56a59d7 6183 LodePNGColorType colortype, unsigned bitdepth)
embeddedartists 0:b567d56a59d7 6184 {
embeddedartists 0:b567d56a59d7 6185 std::vector<unsigned char> buffer;
embeddedartists 0:b567d56a59d7 6186 load_file(buffer, filename);
embeddedartists 0:b567d56a59d7 6187 return decode(out, w, h, buffer, colortype, bitdepth);
embeddedartists 0:b567d56a59d7 6188 }
embeddedartists 0:b567d56a59d7 6189 #endif //LODEPNG_COMPILE_DECODER
embeddedartists 0:b567d56a59d7 6190 #endif //LODEPNG_COMPILE_DISK
embeddedartists 0:b567d56a59d7 6191
embeddedartists 0:b567d56a59d7 6192 #ifdef LODEPNG_COMPILE_ENCODER
embeddedartists 0:b567d56a59d7 6193 unsigned encode(std::vector<unsigned char>& out, const unsigned char* in, unsigned w, unsigned h,
embeddedartists 0:b567d56a59d7 6194 LodePNGColorType colortype, unsigned bitdepth)
embeddedartists 0:b567d56a59d7 6195 {
embeddedartists 0:b567d56a59d7 6196 unsigned char* buffer;
embeddedartists 0:b567d56a59d7 6197 size_t buffersize;
embeddedartists 0:b567d56a59d7 6198 unsigned error = lodepng_encode_memory(&buffer, &buffersize, in, w, h, colortype, bitdepth);
embeddedartists 0:b567d56a59d7 6199 if(buffer)
embeddedartists 0:b567d56a59d7 6200 {
embeddedartists 0:b567d56a59d7 6201 out.insert(out.end(), &buffer[0], &buffer[buffersize]);
embeddedartists 0:b567d56a59d7 6202 lodepng_free(buffer);
embeddedartists 0:b567d56a59d7 6203 }
embeddedartists 0:b567d56a59d7 6204 return error;
embeddedartists 0:b567d56a59d7 6205 }
embeddedartists 0:b567d56a59d7 6206
embeddedartists 0:b567d56a59d7 6207 unsigned encode(std::vector<unsigned char>& out,
embeddedartists 0:b567d56a59d7 6208 const std::vector<unsigned char>& in, unsigned w, unsigned h,
embeddedartists 0:b567d56a59d7 6209 LodePNGColorType colortype, unsigned bitdepth)
embeddedartists 0:b567d56a59d7 6210 {
embeddedartists 0:b567d56a59d7 6211 if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84;
embeddedartists 0:b567d56a59d7 6212 return encode(out, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth);
embeddedartists 0:b567d56a59d7 6213 }
embeddedartists 0:b567d56a59d7 6214
embeddedartists 0:b567d56a59d7 6215 unsigned encode(std::vector<unsigned char>& out,
embeddedartists 0:b567d56a59d7 6216 const unsigned char* in, unsigned w, unsigned h,
embeddedartists 0:b567d56a59d7 6217 State& state)
embeddedartists 0:b567d56a59d7 6218 {
embeddedartists 0:b567d56a59d7 6219 unsigned char* buffer;
embeddedartists 0:b567d56a59d7 6220 size_t buffersize;
embeddedartists 0:b567d56a59d7 6221 unsigned error = lodepng_encode(&buffer, &buffersize, in, w, h, &state);
embeddedartists 0:b567d56a59d7 6222 if(buffer)
embeddedartists 0:b567d56a59d7 6223 {
embeddedartists 0:b567d56a59d7 6224 out.insert(out.end(), &buffer[0], &buffer[buffersize]);
embeddedartists 0:b567d56a59d7 6225 lodepng_free(buffer);
embeddedartists 0:b567d56a59d7 6226 }
embeddedartists 0:b567d56a59d7 6227 return error;
embeddedartists 0:b567d56a59d7 6228 }
embeddedartists 0:b567d56a59d7 6229
embeddedartists 0:b567d56a59d7 6230 unsigned encode(std::vector<unsigned char>& out,
embeddedartists 0:b567d56a59d7 6231 const std::vector<unsigned char>& in, unsigned w, unsigned h,
embeddedartists 0:b567d56a59d7 6232 State& state)
embeddedartists 0:b567d56a59d7 6233 {
embeddedartists 0:b567d56a59d7 6234 if(lodepng_get_raw_size(w, h, &state.info_raw) > in.size()) return 84;
embeddedartists 0:b567d56a59d7 6235 return encode(out, in.empty() ? 0 : &in[0], w, h, state);
embeddedartists 0:b567d56a59d7 6236 }
embeddedartists 0:b567d56a59d7 6237
embeddedartists 0:b567d56a59d7 6238 #ifdef LODEPNG_COMPILE_DISK
embeddedartists 0:b567d56a59d7 6239 unsigned encode(const std::string& filename,
embeddedartists 0:b567d56a59d7 6240 const unsigned char* in, unsigned w, unsigned h,
embeddedartists 0:b567d56a59d7 6241 LodePNGColorType colortype, unsigned bitdepth)
embeddedartists 0:b567d56a59d7 6242 {
embeddedartists 0:b567d56a59d7 6243 std::vector<unsigned char> buffer;
embeddedartists 0:b567d56a59d7 6244 unsigned error = encode(buffer, in, w, h, colortype, bitdepth);
embeddedartists 0:b567d56a59d7 6245 if(!error) save_file(buffer, filename);
embeddedartists 0:b567d56a59d7 6246 return error;
embeddedartists 0:b567d56a59d7 6247 }
embeddedartists 0:b567d56a59d7 6248
embeddedartists 0:b567d56a59d7 6249 unsigned encode(const std::string& filename,
embeddedartists 0:b567d56a59d7 6250 const std::vector<unsigned char>& in, unsigned w, unsigned h,
embeddedartists 0:b567d56a59d7 6251 LodePNGColorType colortype, unsigned bitdepth)
embeddedartists 0:b567d56a59d7 6252 {
embeddedartists 0:b567d56a59d7 6253 if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84;
embeddedartists 0:b567d56a59d7 6254 return encode(filename, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth);
embeddedartists 0:b567d56a59d7 6255 }
embeddedartists 0:b567d56a59d7 6256 #endif //LODEPNG_COMPILE_DISK
embeddedartists 0:b567d56a59d7 6257 #endif //LODEPNG_COMPILE_ENCODER
embeddedartists 0:b567d56a59d7 6258 #endif //LODEPNG_COMPILE_PNG
embeddedartists 0:b567d56a59d7 6259 } //namespace lodepng
embeddedartists 0:b567d56a59d7 6260 #endif /*LODEPNG_COMPILE_CPP*/