Example for the LPC4088 QSB Base Board

Dependencies:   EALib mbed

Committer:
embeddedartists
Date:
Wed Jan 08 12:35:11 2014 +0000
Revision:
0:83b8ee8e8d4b
First version (with temporary STACK fix)

Who changed what in which revision?

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