Example for the LPC4088 QSB Base Board

Dependencies:   EALib mbed

Committer:
embeddedartists
Date:
Wed Apr 09 09:44:58 2014 +0000
Revision:
3:15f457b3bdbd
Parent:
0:a771927a62fd
Updated to latest version of EALib

Who changed what in which revision?

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