├── README.md ├── Makefile ├── src ├── schrift.h ├── Image.h ├── main.cpp ├── Image.cpp ├── schrift.cpp └── stb_image_write.h └── LICENSE /README.md: -------------------------------------------------------------------------------- 1 | # Image-Processing 2 | A c++ project for manipulating image data in fun ways 3 | 4 | ### Check out the YouTube Playlist here 5 | https://www.youtube.com/playlist?list=PLG5M8QIx5lkzdGkdYQeeCK__As6sI2tOY 6 | 7 | # How to Run 8 | If you would like to run this yourself simply type `make` into the command line to compile and `make r` to run your code! This code is only tested on Mac OS but should work on other systems as long as you have the build tools necessary. 9 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC := g++ 2 | TARGET := "ImageProcessing" 3 | BUILDDIR := build 4 | SRCDIR := src 5 | CFLAGS := -std=c++17 -g 6 | SRCEXT := cpp 7 | SOURCES := $(wildcard $(SRCDIR)/*.$(SRCEXT)) 8 | OBJECTS := $(patsubst $(SRCDIR)/%, $(BUILDDIR)/%, $(SOURCES:.$(SRCEXT)=.o)) 9 | 10 | $(BUILDDIR)/%.o: $(SRCDIR)/%.$(SRCEXT) 11 | @printf "\e[33m\e[1mBuilding...\e[0m\n"; 12 | @mkdir -p $(BUILDDIR) 13 | @echo " $(notdir $@) from $(notdir $<)" 14 | @$(CC) $(CFLAGS) -c -o $@ $< 15 | 16 | $(TARGET): $(OBJECTS) 17 | @printf "\e[35m\e[1mLinking...\e[0m\n"; 18 | @echo " $(notdir $(OBJECTS))" 19 | @$(CC) $(CFLAGS) -o $@ $^ 20 | 21 | 22 | PHONY: clean 23 | clean: 24 | @printf "\e[31m\e[1mCleaning...\e[0m\n" 25 | @echo " /$(BUILDDIR)" 26 | @echo " /$(TARGET)" 27 | @$(RM) -r $(BUILDDIR) $(OBJECTS) 28 | @$(RM) "./$(TARGET)" 29 | 30 | PHONY: r 31 | r: 32 | @printf "\e[33m\e[1mRunning $(TARGET)\e[0m\n" 33 | @./$(TARGET) 34 | 35 | PHONY: run 36 | run: 37 | @mkdir -p $(BUILDDIR) 38 | @for source in $(basename $(notdir $(SOURCES))); do\ 39 | printf "\e[33m\e[1mBuilding...\e[0m\n";\ 40 | echo " $$source.o from $$source.$(SRCEXT)";\ 41 | $(CC) $(CFLAGS) -c -o $(BUILDDIR)/$$source.o $(SRCDIR)/$$source.$(SRCEXT);\ 42 | done 43 | @printf "\e[95m\e[1mLinking...\e[0m\n"; 44 | @echo " $(notdir $(OBJECTS))" 45 | @$(CC) $(CFLAGS) -o $(TARGET) $(OBJECTS) 46 | @printf "\e[33m\e[1mRunning $(TARGET)\e[0m\n" 47 | @ ./$(TARGET) 48 | -------------------------------------------------------------------------------- /src/schrift.h: -------------------------------------------------------------------------------- 1 | /* This file is part of libschrift. 2 | * 3 | * © 2019, 2020 Thomas Oltmann 4 | * 5 | * Permission to use, copy, modify, and/or distribute this software for any 6 | * purpose with or without fee is hereby granted, provided that the above 7 | * copyright notice and this permission notice appear in all copies. 8 | * 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ 16 | 17 | #ifndef SCHRIFT_H 18 | #define SCHRIFT_H 1 19 | 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #if defined(_MSC_VER) 33 | # define restrict __restrict 34 | #endif 35 | 36 | #if defined(_WIN32) 37 | # define WIN32_LEAN_AND_MEAN 1 38 | # include 39 | #else 40 | # include 41 | # include 42 | # include 43 | # include 44 | #endif 45 | 46 | #define SFT_DOWNWARD_Y 0x01 47 | #define SFT_RENDER_IMAGE 0x02 48 | #define SFT_CATCH_MISSING 0x04 49 | 50 | /* Deprecated. Use SFT_RENDER_IMAGE instead (Only the name has changed). */ 51 | #define SFT_CHAR_IMAGE 0x02 52 | 53 | struct SFT_Font { 54 | const uint8_t *memory; 55 | unsigned long size; 56 | #if defined(_WIN32) 57 | HANDLE mapping; 58 | #endif 59 | int source; 60 | 61 | uint_least16_t unitsPerEm; 62 | int_least16_t locaFormat; 63 | uint_least16_t numLongHmtx; 64 | }; 65 | typedef struct SFT_Font SFT_Font; 66 | 67 | struct SFT 68 | { 69 | SFT_Font *font; 70 | double xScale; 71 | double yScale; 72 | double x; 73 | double y; 74 | unsigned int flags; 75 | }; 76 | 77 | struct SFT_Char 78 | { 79 | uint8_t* image; 80 | double advance; 81 | int x; 82 | int y; 83 | int width; 84 | int height; 85 | }; 86 | 87 | /* libschrift uses semantic versioning. */ 88 | const char *sft_version(void); 89 | 90 | SFT_Font *sft_loadmem(const void *mem, unsigned long size); 91 | SFT_Font *sft_loadfile(const char *filename); 92 | void sft_freefont(SFT_Font *font); 93 | 94 | int sft_linemetrics(const struct SFT *sft, double *ascent, double *descent, double *gap); 95 | int sft_kerning(const struct SFT *sft, unsigned long leftChar, unsigned long rightChar, double kerning[2]); 96 | int sft_char(const struct SFT *sft, unsigned long charCode, struct SFT_Char *chr); 97 | 98 | #ifdef __cplusplus 99 | } 100 | #endif 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /src/Image.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | //legacy feature of C 6 | #undef __STRICT_ANSI__ 7 | #define _USE_MATH_DEFINES 8 | #include 9 | #ifndef M_PI 10 | #define M_PI (3.14159265358979323846) 11 | #endif 12 | 13 | #include "schrift.h" 14 | 15 | #define STEG_HEADER_SIZE sizeof(uint32_t) * 8 16 | 17 | enum ImageType { 18 | PNG, JPG, BMP, TGA 19 | }; 20 | 21 | struct Font; 22 | 23 | 24 | struct Image { 25 | uint8_t* data = NULL; 26 | size_t size = 0; 27 | int w; 28 | int h; 29 | int channels; 30 | 31 | Image(const char* filename, int channel_force = 0); 32 | Image(int w, int h, int channels = 3); 33 | Image(const Image& img); 34 | ~Image(); 35 | 36 | bool read(const char* filename, int channel_force = 0); 37 | bool write(const char* filename); 38 | 39 | ImageType get_file_type(const char* filename); 40 | 41 | 42 | Image& std_convolve_clamp_to_0(uint8_t channel, uint32_t ker_w, uint32_t ker_h, double ker[], uint32_t cr, uint32_t cc); 43 | Image& std_convolve_clamp_to_border(uint8_t channel, uint32_t ker_w, uint32_t ker_h, double ker[], uint32_t cr, uint32_t cc); 44 | Image& std_convolve_cyclic(uint8_t channel, uint32_t ker_w, uint32_t ker_h, double ker[], uint32_t cr, uint32_t cc); 45 | 46 | static uint32_t rev(uint32_t n, uint32_t a); 47 | static void bit_rev(uint32_t n, std::complex a[], std::complex* A); 48 | 49 | static void fft(uint32_t n, std::complex x[], std::complex* X); 50 | static void ifft(uint32_t n, std::complex X[], std::complex* x); 51 | static void dft_2D(uint32_t m, uint32_t n, std::complex x[], std::complex* X); 52 | static void idft_2D(uint32_t m, uint32_t n, std::complex X[], std::complex* x); 53 | 54 | static void pad_kernel(uint32_t ker_w, uint32_t ker_h, double ker[], uint32_t cr, uint32_t cc, uint32_t pw, uint32_t ph, std::complex* pad_ker); 55 | static inline void pointwise_product(uint64_t l, std::complex a[], std::complex b[], std::complex* p); 56 | 57 | Image& fd_convolve_clamp_to_0(uint8_t channel, uint32_t ker_w, uint32_t ker_h, double ker[], uint32_t cr, uint32_t cc); 58 | Image& fd_convolve_clamp_to_border(uint8_t channel, uint32_t ker_w, uint32_t ker_h, double ker[], uint32_t cr, uint32_t cc); 59 | Image& fd_convolve_cyclic(uint8_t channel, uint32_t ker_w, uint32_t ker_h, double ker[], uint32_t cr, uint32_t cc); 60 | 61 | 62 | Image& convolve_linear(uint8_t channel, uint32_t ker_w, uint32_t ker_h, double ker[], uint32_t cr, uint32_t cc); 63 | Image& convolve_clamp_to_border(uint8_t channel, uint32_t ker_w, uint32_t ker_h, double ker[], uint32_t cr, uint32_t cc); 64 | Image& convolve_cyclic(uint8_t channel, uint32_t ker_w, uint32_t ker_h, double ker[], uint32_t cr, uint32_t cc); 65 | 66 | 67 | Image& diffmap(Image& img); 68 | Image& diffmap_scale(Image& img, uint8_t scl = 0); 69 | 70 | 71 | Image& grayscale_avg(); 72 | Image& grayscale_lum(); 73 | 74 | Image& color_mask(float r, float g, float b); 75 | 76 | 77 | Image& encodeMessage(const char* message); 78 | Image& decodeMessage(char* buffer, size_t* messageLength); 79 | 80 | Image& flipX(); 81 | Image& flipY(); 82 | 83 | Image& overlay(const Image& source, int x, int y); 84 | 85 | Image& overlayText(const char* txt, const Font& font, int x, int y, uint8_t r = 255, uint8_t g = 255, uint8_t b = 255, uint8_t a = 255); 86 | 87 | 88 | Image& crop(uint16_t cx, uint16_t cy, uint16_t cw, uint16_t ch); 89 | 90 | 91 | 92 | Image& resizeNN(uint16_t nw, uint16_t nh); 93 | 94 | 95 | }; 96 | 97 | 98 | struct Font { 99 | SFT sft = {NULL, 12, 12, 0, 0, SFT_DOWNWARD_Y|SFT_RENDER_IMAGE}; 100 | Font(const char* fontfile, uint16_t size) { 101 | if((sft.font = sft_loadfile(fontfile)) == NULL) { 102 | printf("\e[31m[ERROR] Failed to load %s\e[0m\n", fontfile); 103 | return; 104 | } 105 | setSize(size); 106 | } 107 | ~Font() { 108 | sft_freefont(sft.font); 109 | } 110 | void setSize(uint16_t size) { 111 | sft.xScale = size; 112 | sft.yScale = size; 113 | } 114 | }; 115 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | ///* 2 | #include "Image.h" 3 | 4 | 5 | int main(int argc, char** argv) { 6 | Image test("imgs/test1.jpg"); 7 | 8 | /* 9 | 10 | Add your own code here to do some cool stuff with images! 11 | https://www.youtube.com/playlist?list=PLG5M8QIx5lkzdGkdYQeeCK__As6sI2tOY 12 | 13 | */ 14 | 15 | 16 | 17 | 18 | return 0; 19 | } 20 | //*/ 21 | 22 | //Code for edge detector: 23 | /* 24 | #include "Image.h" 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | 31 | int main(int argc, char** argv) { 32 | 33 | Image img("imgs/test6.png"); 34 | 35 | 36 | // grayscale 37 | img.grayscale_avg(); 38 | int img_size = img.w*img.h; 39 | 40 | Image gray_img(img.w, img.h, 1); 41 | for(uint64_t k=0; k threshold ? (g[k]-mn)/(mx-mn) : 0; 139 | } 140 | s = l = v; 141 | 142 | //hsl => rgb 143 | double c = (1-abs(2*l-1))*s; 144 | double x = c*(1-abs(fmod((h/60),2)-1)); 145 | double m = l-c/2; 146 | 147 | double rt, gt, bt; 148 | rt=bt=gt = 0; 149 | if(h < 60) { 150 | rt = c; 151 | gt = x; 152 | } 153 | else if(h < 120) { 154 | rt = x; 155 | gt = c; 156 | } 157 | else if(h < 180) { 158 | gt = c; 159 | bt = x; 160 | } 161 | else if(h < 240) { 162 | gt = x; 163 | bt = c; 164 | } 165 | else if(h < 300) { 166 | bt = c; 167 | rt = x; 168 | } 169 | else { 170 | bt = x; 171 | rt = c; 172 | } 173 | 174 | uint8_t red, green, blue; 175 | red = (uint8_t)(255*(rt+m)); 176 | green = (uint8_t)(255*(gt+m)); 177 | blue = (uint8_t)(255*(bt+m)); 178 | 179 | GT.data[k*3] = red; 180 | GT.data[k*3+1] = green; 181 | GT.data[k*3+2] = blue; 182 | 183 | G.data[k] = (uint8_t)(255*v); 184 | } 185 | G.write("imgs/G.png"); 186 | GT.write("imgs/GT.png"); 187 | 188 | delete[] gx; 189 | delete[] gy; 190 | delete[] g; 191 | delete[] theta; 192 | 193 | 194 | return 0; 195 | } 196 | //*/ 197 | 198 | 199 | 200 | 201 | 202 | -------------------------------------------------------------------------------- /src/Image.cpp: -------------------------------------------------------------------------------- 1 | #define STB_IMAGE_IMPLEMENTATION 2 | #define STB_IMAGE_WRITE_IMPLEMENTATION 3 | #define BYTE_BOUND(value) value < 0 ? 0 : (value > 255 ? 255 : value) 4 | 5 | #include "stb_image.h" 6 | #include "stb_image_write.h" 7 | 8 | #include "Image.h" 9 | 10 | 11 | 12 | Image::Image(const char* filename, int channel_force) { 13 | if(read(filename, channel_force)) { 14 | printf("Read %s\n", filename); 15 | size = w*h*channels; 16 | } 17 | else { 18 | printf("Failed to read %s\n", filename); 19 | } 20 | } 21 | 22 | Image::Image(int w, int h, int channels) : w(w), h(h), channels(channels) { 23 | size = w*h*channels; 24 | data = new uint8_t[size]; 25 | } 26 | 27 | Image::Image(const Image& img) : Image(img.w, img.h, img.channels) { 28 | memcpy(data, img.data, size); 29 | } 30 | 31 | Image::~Image() { 32 | stbi_image_free(data); 33 | } 34 | 35 | bool Image::read(const char* filename, int channel_force) { 36 | data = stbi_load(filename, &w, &h, &channels, channel_force); 37 | channels = channel_force == 0 ? channels : channel_force; 38 | return data != NULL; 39 | } 40 | 41 | bool Image::write(const char* filename) { 42 | ImageType type = get_file_type(filename); 43 | int success; 44 | switch (type) { 45 | case PNG: 46 | success = stbi_write_png(filename, w, h, channels, data, w*channels); 47 | break; 48 | case BMP: 49 | success = stbi_write_bmp(filename, w, h, channels, data); 50 | break; 51 | case JPG: 52 | success = stbi_write_jpg(filename, w, h, channels, data, 100); 53 | break; 54 | case TGA: 55 | success = stbi_write_tga(filename, w, h, channels, data); 56 | break; 57 | } 58 | if(success != 0) { 59 | printf("\e[32mWrote \e[36m%s\e[0m, %d, %d, %d, %zu\n", filename, w, h, channels, size); 60 | return true; 61 | } 62 | else { 63 | printf("\e[31;1m Failed to write \e[36m%s\e[0m, %d, %d, %d, %zu\n", filename, w, h, channels, size); 64 | return false; 65 | } 66 | } 67 | 68 | ImageType Image::get_file_type(const char* filename) { 69 | const char* ext = strrchr(filename, '.'); 70 | if(ext != nullptr) { 71 | if(strcmp(ext, ".png") == 0) { 72 | return PNG; 73 | } 74 | else if(strcmp(ext, ".jpg") == 0) { 75 | return JPG; 76 | } 77 | else if(strcmp(ext, ".bmp") == 0) { 78 | return BMP; 79 | } 80 | else if(strcmp(ext, ".tga") == 0) { 81 | return TGA; 82 | } 83 | } 84 | return PNG; 85 | } 86 | 87 | 88 | Image& Image::std_convolve_clamp_to_0(uint8_t channel, uint32_t ker_w, uint32_t ker_h, double ker[], uint32_t cr, uint32_t cc) { 89 | uint8_t new_data[w*h]; 90 | uint64_t center = cr*ker_w + cc; 91 | for(uint64_t k=channel; k h-1) { 96 | continue; 97 | } 98 | for(long j = -((long)cc); j<(long)ker_w-cc; ++j) { 99 | long col = ((long)k/channels)%w-j; 100 | if(col < 0 || col > w-1) { 101 | continue; 102 | } 103 | c += ker[center+i*(long)ker_w+j]*data[(row*w+col)*channels+channel]; 104 | } 105 | } 106 | new_data[k/channels] = (uint8_t)BYTE_BOUND(round(c)); 107 | } 108 | for(uint64_t k=channel; k h-1) { 126 | row = h-1; 127 | } 128 | for(long j = -((long)cc); j<(long)ker_w-cc; ++j) { 129 | long col = ((long)k/channels)%w-j; 130 | if(col < 0) { 131 | col = 0; 132 | } 133 | else if(col > w-1) { 134 | col = w-1; 135 | } 136 | c += ker[center+i*(long)ker_w+j]*data[(row*w+col)*channels+channel]; 137 | } 138 | } 139 | new_data[k/channels] = (uint8_t)BYTE_BOUND(round(c)); 140 | } 141 | for(uint64_t k=channel; k h-1) { 159 | row %= h; 160 | } 161 | for(long j = -((long)cc); j<(long)ker_w-cc; ++j) { 162 | long col = ((long)k/channels)%w-j; 163 | if(col < 0) { 164 | col = col%w + w; 165 | } 166 | else if(col > w-1) { 167 | col %= w; 168 | } 169 | c += ker[center+i*(long)ker_w+j]*data[(row*w+col)*channels+channel]; 170 | } 171 | } 172 | new_data[k/channels] = (uint8_t)BYTE_BOUND(round(c)); 173 | } 174 | for(uint64_t k=channel; k a[], std::complex* A) { 196 | for(uint32_t i=0; i x[], std::complex* X) { 202 | //x in standard order 203 | if(x != X) { 204 | memcpy(X, x, n*sizeof(std::complex)); 205 | } 206 | 207 | //Gentleman-Sande butterfly 208 | uint32_t sub_probs = 1; 209 | uint32_t sub_prob_size = n; 210 | uint32_t half; 211 | uint32_t i; 212 | uint32_t j_begin; 213 | uint32_t j_end; 214 | uint32_t j; 215 | std::complex w_step; 216 | std::complex w; 217 | std::complex tmp1, tmp2; 218 | while(sub_prob_size>1) { 219 | half = sub_prob_size>>1; 220 | w_step = std::complex(cos(-2*M_PI/sub_prob_size), sin(-2*M_PI/sub_prob_size)); 221 | for(i=0; i(1,0); 225 | for(j=j_begin; j X[], std::complex* x) { 239 | //X in bit reversed order 240 | if(X != x) { 241 | memcpy(x, X, n*sizeof(std::complex)); 242 | } 243 | 244 | //Cooley-Tukey butterfly 245 | uint32_t sub_probs = n>>1; 246 | uint32_t sub_prob_size; 247 | uint32_t half = 1; 248 | uint32_t i; 249 | uint32_t j_begin; 250 | uint32_t j_end; 251 | uint32_t j; 252 | std::complex w_step; 253 | std::complex w; 254 | std::complex tmp1, tmp2; 255 | while(half(cos(2*M_PI/sub_prob_size), sin(2*M_PI/sub_prob_size)); 258 | for(i=0; i(1,0); 262 | for(j=j_begin; j>= 1; 271 | half = sub_prob_size; 272 | } 273 | for(uint32_t i=0; i x[], std::complex* X) { 280 | //x in row-major & standard order 281 | std::complex* intermediate = new std::complex[m*n]; 282 | //rows 283 | for(uint32_t i=0; i col-major 290 | } 291 | fft(m, X+j*m, X+j*m); 292 | } 293 | delete[] intermediate; 294 | //X in column-major & bit-reversed (in rows then columns) 295 | } 296 | void Image::idft_2D(uint32_t m, uint32_t n, std::complex X[], std::complex* x) { 297 | //X in column-major & bit-reversed (in rows then columns) 298 | std::complex* intermediate = new std::complex[m*n]; 299 | //cols 300 | for(uint32_t j=0; j* pad_ker) { 315 | //padded so center of kernel is at top left 316 | for(long i=-((long)cr); i<(long)ker_h-cr; ++i) { 317 | uint32_t r = (i<0) ? i+ph : i; 318 | for(long j=-((long)cc); j<(long)ker_w-cc; ++j) { 319 | uint32_t c = (j<0) ? j+pw : j; 320 | pad_ker[r*pw+c] = std::complex(ker[(i+cr)*ker_w+(j+cc)], 0); 321 | } 322 | } 323 | } 324 | void Image::pointwise_product(uint64_t l, std::complex a[], std::complex b[], std::complex* p) { 325 | for(uint64_t k=0; k* pad_img = new std::complex[psize]; 338 | for(uint32_t i=0; i(data[(i*w+j)*channels+channel],0); 341 | } 342 | } 343 | 344 | //pad kernel 345 | std::complex* pad_ker = new std::complex[psize]; 346 | pad_kernel(ker_w, ker_h, ker, cr, cc, pw, ph, pad_ker); 347 | 348 | //convolution 349 | dft_2D(ph, pw, pad_img, pad_img); 350 | dft_2D(ph, pw, pad_ker, pad_ker); 351 | pointwise_product(psize, pad_img, pad_ker, pad_img); 352 | idft_2D(ph, pw, pad_img, pad_img); 353 | 354 | //update pixel data 355 | for(uint32_t i=0; i* pad_img = new std::complex[psize]; 371 | for(uint32_t i=0; i(data[(r*w+c)*channels+channel],0); 376 | } 377 | } 378 | 379 | //pad kernel 380 | std::complex* pad_ker = new std::complex[psize]; 381 | pad_kernel(ker_w, ker_h, ker, cr, cc, pw, ph, pad_ker); 382 | 383 | //convolution 384 | dft_2D(ph, pw, pad_img, pad_img); 385 | dft_2D(ph, pw, pad_ker, pad_ker); 386 | pointwise_product(psize, pad_img, pad_ker, pad_img); 387 | idft_2D(ph, pw, pad_img, pad_img); 388 | 389 | //update pixel data 390 | for(uint32_t i=0; i* pad_img = new std::complex[psize]; 406 | for(uint32_t i=0; i(data[(r*w+c)*channels+channel],0); 411 | } 412 | } 413 | 414 | //pad kernel 415 | std::complex* pad_ker = new std::complex[psize]; 416 | pad_kernel(ker_w, ker_h, ker, cr, cc, pw, ph, pad_ker); 417 | 418 | //convolution 419 | dft_2D(ph, pw, pad_img, pad_img); 420 | dft_2D(ph, pw, pad_ker, pad_ker); 421 | pointwise_product(psize, pad_img, pad_ker, pad_img); 422 | idft_2D(ph, pw, pad_img, pad_img); 423 | 424 | //update pixel data 425 | for(uint32_t i=0; i 224) { 437 | return fd_convolve_clamp_to_0(channel, ker_w, ker_h, ker, cr, cc); 438 | } 439 | else { 440 | return std_convolve_clamp_to_0(channel, ker_w, ker_h, ker, cr, cc); 441 | } 442 | } 443 | Image& Image::convolve_clamp_to_border(uint8_t channel, uint32_t ker_w, uint32_t ker_h, double ker[], uint32_t cr, uint32_t cc) { 444 | if(ker_w*ker_h > 224) { 445 | return fd_convolve_clamp_to_border(channel, ker_w, ker_h, ker, cr, cc); 446 | } 447 | else { 448 | return std_convolve_clamp_to_border(channel, ker_w, ker_h, ker, cr, cc); 449 | } 450 | } 451 | Image& Image::convolve_cyclic(uint8_t channel, uint32_t ker_w, uint32_t ker_h, double ker[], uint32_t cr, uint32_t cc) { 452 | if(ker_w*ker_h > 224) { 453 | return fd_convolve_cyclic(channel, ker_w, ker_h, ker, cr, cc); 454 | } 455 | else { 456 | return std_convolve_cyclic(channel, ker_w, ker_h, ker, cr, cc); 457 | } 458 | } 459 | 460 | 461 | 462 | 463 | 464 | 465 | Image& Image::diffmap(Image& img) { 466 | int compare_width = fmin(w,img.w); 467 | int compare_height = fmin(h,img.h); 468 | int compare_channels = fmin(channels,img.channels); 469 | for(uint32_t i=0; i size) { 548 | printf("\e[31m[ERROR] This message is too large (%lu bits / %zu bits)\e[0m\n", len+STEG_HEADER_SIZE, size); 549 | return *this; 550 | } 551 | 552 | for(uint8_t i = 0;i < STEG_HEADER_SIZE;++i) { 553 | data[i] &= 0xFE; 554 | data[i] |= (len >> (STEG_HEADER_SIZE - 1 - i)) & 1UL; 555 | } 556 | 557 | for(uint32_t i = 0;i < len;++i) { 558 | data[i+STEG_HEADER_SIZE] &= 0xFE; 559 | data[i+STEG_HEADER_SIZE] |= (message[i/8] >> ((len-1-i)%8)) & 1; 560 | } 561 | 562 | return *this; 563 | } 564 | 565 | Image& Image::decodeMessage(char* buffer, size_t* messageLength) { 566 | uint32_t len = 0; 567 | for(uint8_t i = 0;i < STEG_HEADER_SIZE;++i) { 568 | len = (len << 1) | (data[i] & 1); 569 | } 570 | *messageLength = len / 8; 571 | 572 | for(uint32_t i = 0;i < len;++i) { 573 | buffer[i/8] = (buffer[i/8] << 1) | (data[i+STEG_HEADER_SIZE] & 1); 574 | } 575 | 576 | 577 | return *this; 578 | } 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | Image& Image::flipX() { 592 | uint8_t tmp[4]; 593 | uint8_t* px1; 594 | uint8_t* px2; 595 | for(int y = 0;y < h;++y) { 596 | for(int x = 0;x < w/2;++x) { 597 | px1 = &data[(x + y * w) * channels]; 598 | px2 = &data[((w - 1 - x) + y * w) * channels]; 599 | 600 | memcpy(tmp, px1, channels); 601 | memcpy(px1, px2, channels); 602 | memcpy(px2, tmp, channels); 603 | } 604 | } 605 | return *this; 606 | } 607 | Image& Image::flipY() { 608 | uint8_t tmp[4]; 609 | uint8_t* px1; 610 | uint8_t* px2; 611 | for(int x = 0;x < w;++x) { 612 | for(int y = 0;y < h/2;++y) { 613 | px1 = &data[(x + y * w) * channels]; 614 | px2 = &data[(x + (h - 1 - y) * w) * channels]; 615 | 616 | memcpy(tmp, px1, channels); 617 | memcpy(px1, px2, channels); 618 | memcpy(px2, tmp, channels); 619 | } 620 | } 621 | return *this; 622 | } 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | Image& Image::overlay(const Image& source, int x, int y) { 632 | 633 | uint8_t* srcPx; 634 | uint8_t* dstPx; 635 | 636 | for(int sy = 0;sy < source.h;++sy) { 637 | if(sy + y < 0) {continue;} 638 | else if(sy + y >= h) {break;} 639 | for(int sx = 0;sx < source.w;++sx) { 640 | if(sx + x < 0) {continue;} 641 | else if(sx + x >= w) {break;} 642 | srcPx = &source.data[(sx + sy * source.w) * source.channels]; 643 | dstPx = &data[(sx + x + (sy + y) * w) * channels]; 644 | 645 | float srcAlpha = source.channels < 4 ? 1 : srcPx[3] / 255.f; 646 | float dstAlpha = channels < 4 ? 1 : dstPx[3] / 255.f; 647 | 648 | if(srcAlpha > .99 && dstAlpha > .99) { 649 | if(source.channels >= channels) { 650 | memcpy(dstPx, srcPx, channels); 651 | } 652 | else { 653 | // In case our source image is grayscale and the dest one isnt 654 | memset(dstPx, srcPx[0], channels); 655 | } 656 | } 657 | else { 658 | float outAlpha = srcAlpha + dstAlpha * (1 - srcAlpha); 659 | if(outAlpha < .01) { 660 | memset(dstPx, 0, channels); 661 | } 662 | else { 663 | for(int chnl = 0;chnl < channels;++chnl) { 664 | dstPx[chnl] = (uint8_t)BYTE_BOUND((srcPx[chnl]/255.f * srcAlpha + dstPx[chnl]/255.f * dstAlpha * (1 - srcAlpha)) / outAlpha * 255.f); 665 | } 666 | if(channels > 3) {dstPx[3] = (uint8_t)BYTE_BOUND(outAlpha * 255.f);} 667 | } 668 | } 669 | 670 | } 671 | 672 | } 673 | return *this; 674 | } 675 | 676 | 677 | 678 | 679 | Image& Image::overlayText(const char* txt, const Font& font, int x, int y, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { 680 | size_t len = strlen(txt); 681 | SFT_Char c; 682 | int32_t dx, dy; 683 | uint8_t* dstPx; 684 | uint8_t srcPx; 685 | uint8_t color[4] = {r, g, b, a}; 686 | 687 | for(size_t i = 0;i < len;++i) { 688 | if(sft_char(&font.sft, txt[i], &c) != 0) { 689 | printf("\e[31m[ERROR] Font is missing character '%c'\e[0m\n", txt[i]); 690 | continue; 691 | } 692 | 693 | for(uint16_t sy = 0;sy < c.height;++sy) { 694 | dy = sy + y + c.y; 695 | if(dy < 0) {continue;} 696 | else if(dy >= h) {break;} 697 | for(uint16_t sx = 0;sx < c.width;++sx) { 698 | dx = sx + x + c.x; 699 | if(dx < 0) {continue;} 700 | else if(dx >= w) {break;} 701 | dstPx = &data[(dx + dy * w) * channels]; 702 | srcPx = c.image[sx + sy * c.width]; 703 | 704 | if(srcPx != 0) { 705 | float srcAlpha = (srcPx / 255.f) * (a / 255.f); 706 | float dstAlpha = channels < 4 ? 1 : dstPx[3] / 255.f; 707 | if(srcAlpha > .99 && dstAlpha > .99) { 708 | memcpy(dstPx, color, channels); 709 | } 710 | else { 711 | float outAlpha = srcAlpha + dstAlpha * (1 - srcAlpha); 712 | if(outAlpha < .01) { 713 | memset(dstPx, 0, channels); 714 | } 715 | else { 716 | for(int chnl = 0;chnl < channels;++chnl) { 717 | dstPx[chnl] = (uint8_t)BYTE_BOUND((color[chnl]/255.f * srcAlpha + dstPx[chnl]/255.f * dstAlpha * (1 - srcAlpha)) / outAlpha * 255.f); 718 | } 719 | if(channels > 3) {dstPx[3] = (uint8_t)BYTE_BOUND(outAlpha * 255.f);} 720 | } 721 | } 722 | } 723 | } 724 | } 725 | 726 | x += c.advance; 727 | free(c.image); 728 | } 729 | 730 | return *this; 731 | } 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | Image& Image::crop(uint16_t cx, uint16_t cy, uint16_t cw, uint16_t ch) { 746 | size = cw * ch * channels; 747 | uint8_t* croppedImage = new uint8_t[size]; 748 | memset(croppedImage, 0, size); 749 | 750 | for(uint16_t y = 0;y < ch;++y) { 751 | if(y + cy >= h) {break;} 752 | for(uint16_t x = 0;x < cw;++x) { 753 | if(x + cx >= w) {break;} 754 | memcpy(&croppedImage[(x + y * cw) * channels], &data[(x + cx + (y + cy) * w) * channels], channels); 755 | } 756 | } 757 | 758 | w = cw; 759 | h = ch; 760 | 761 | 762 | delete[] data; 763 | data = croppedImage; 764 | croppedImage = nullptr; 765 | 766 | return *this; 767 | } 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | Image& Image::resizeNN(uint16_t nw, uint16_t nh) { 779 | size = nw * nh * channels; 780 | uint8_t* newImage = new uint8_t[size]; 781 | 782 | float scaleX = (float)nw / (w); 783 | float scaleY = (float)nh / (h); 784 | uint16_t sx, sy; 785 | 786 | for(uint16_t y = 0;y < nh;++y) { 787 | sy = (uint16_t)(y / scaleY); 788 | for(uint16_t x = 0;x < nw;++x) { 789 | sx = (uint16_t)(x / scaleX); 790 | 791 | memcpy(&newImage[(x + y * nw) * channels], &data[(sx + sy * w) * channels], channels); 792 | 793 | } 794 | } 795 | 796 | 797 | w = nw; 798 | h = nh; 799 | delete[] data; 800 | data = newImage; 801 | newImage = nullptr; 802 | 803 | return *this; 804 | } 805 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /src/schrift.cpp: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "schrift.h" 3 | 4 | #define SCHRIFT_VERSION "0.8.0" 5 | 6 | #define FILE_MAGIC_ONE 0x00010000 7 | #define FILE_MAGIC_TWO 0x74727565 8 | 9 | #define HORIZONTAL_KERNING 0x01 10 | #define MINIMUM_KERNING 0x02 11 | #define CROSS_STREAM_KERNING 0x04 12 | #define OVERRIDE_KERNING 0x08 13 | 14 | #define POINT_IS_ON_CURVE 0x01 15 | #define X_CHANGE_IS_SMALL 0x02 16 | #define Y_CHANGE_IS_SMALL 0x04 17 | #define REPEAT_FLAG 0x08 18 | #define X_CHANGE_IS_ZERO 0x10 19 | #define X_CHANGE_IS_POSITIVE 0x10 20 | #define Y_CHANGE_IS_ZERO 0x20 21 | #define Y_CHANGE_IS_POSITIVE 0x20 22 | 23 | #define OFFSETS_ARE_LARGE 0x001 24 | #define ACTUAL_XY_OFFSETS 0x002 25 | #define GOT_A_SINGLE_SCALE 0x008 26 | #define THERE_ARE_MORE_COMPONENTS 0x020 27 | #define GOT_AN_X_AND_Y_SCALE 0x040 28 | #define GOT_A_SCALE_MATRIX 0x080 29 | 30 | /* macros */ 31 | #define MIN(a, b) ((a) < (b) ? (a) : (b)) 32 | #define SIGN(x) ((x) >= 0 ? 1 : -1) 33 | /* Allocate values on the stack if they are small enough, else spill to heap. */ 34 | #define STACK_ALLOC(var, type, thresh, count) \ 35 | type var##_stack_[thresh]; \ 36 | var = (count) <= (thresh) ? var##_stack_ : (type*)calloc(sizeof(type), count); 37 | #define STACK_FREE(var) \ 38 | if (var != var##_stack_) free(var); 39 | 40 | enum { SrcMapping, SrcUser }; 41 | 42 | /* structs */ 43 | struct point { double x, y; }; 44 | struct line { uint_least16_t beg, end; }; 45 | struct curve { uint_least16_t beg, end, ctrl; }; 46 | struct cell { double area, cover; }; 47 | 48 | struct outline 49 | { 50 | struct point *points; 51 | struct curve *curves; 52 | struct line *lines; 53 | unsigned int numPoints, numCurves, numLines; 54 | unsigned int capPoints, capCurves, capLines; 55 | }; 56 | 57 | struct buffer 58 | { 59 | struct cell **rows; 60 | int width, height; 61 | }; 62 | 63 | /* function declarations */ 64 | /* generic utility functions */ 65 | static void *sft_reallocarray(void *optr, size_t nmemb, size_t size); 66 | static inline int fast_floor(double x); 67 | static inline int fast_ceil(double x); 68 | /* file loading */ 69 | static int map_file(SFT_Font *font, const char *filename); 70 | static void unmap_file(SFT_Font *font); 71 | static int init_font(SFT_Font *font); 72 | /* mathematical utilities */ 73 | static struct point midpoint(struct point a, struct point b); 74 | static void transform_points(int numPts, struct point *points, double trf[6]); 75 | static void clip_points(int numPts, struct point *points, int width, int height); 76 | /* 'buffer' data structure management */ 77 | static int init_buffer(struct buffer *buf, int width, int height); 78 | static void free_buffer(struct buffer *buf); 79 | static void flip_buffer(struct buffer *buf); 80 | /* 'outline' data structure management */ 81 | static int init_outline(struct outline *outl); 82 | static void free_outline(struct outline *outl); 83 | static int grow_points(struct outline *outl); 84 | static int grow_curves(struct outline *outl); 85 | static int grow_lines(struct outline *outl); 86 | /* TTF parsing utilities */ 87 | static void *csearch(const void *key, const void *base, 88 | size_t nmemb, size_t size, int (*compar)(const void *, const void *)); 89 | static int cmpu16(const void *a, const void *b); 90 | static int cmpu32(const void *a, const void *b); 91 | static inline uint8_t getu8 (SFT_Font *font, unsigned long offset); 92 | static inline int8_t geti8 (SFT_Font *font, unsigned long offset); 93 | static inline uint16_t getu16(SFT_Font *font, unsigned long offset); 94 | static inline int16_t geti16(SFT_Font *font, unsigned long offset); 95 | static inline uint32_t getu32(SFT_Font *font, unsigned long offset); 96 | static long gettable(SFT_Font *font, const char tag[4]); 97 | /* codepoint -> glyph */ 98 | static long cmap_fmt4(SFT_Font *font, unsigned long table, unsigned long charCode); 99 | static long cmap_fmt6(SFT_Font *font, unsigned long table, unsigned long charCode); 100 | static long glyph_id(SFT_Font *font, unsigned long charCode); 101 | /* glyph -> hmtx */ 102 | static int hor_metrics(SFT_Font *font, long glyph, int *advanceWidth, int *leftSideBearing); 103 | /* glyph -> outline */ 104 | static long outline_offset(SFT_Font *font, long glyph); 105 | /* decoding outlines */ 106 | static long simple_flags(SFT_Font *font, unsigned long offset, int numPts, uint8_t *flags); 107 | static int simple_points(SFT_Font *font, unsigned long offset, int numPts, uint8_t *flags, struct point *points); 108 | static int decode_contour(uint8_t *flags, unsigned int basePoint, unsigned int count, struct outline *outl); 109 | static int simple_outline(SFT_Font *font, unsigned long offset, int numContours, struct outline *outl); 110 | static int compound_outline(SFT_Font *font, unsigned long offset, int recDepth, struct outline *outl); 111 | static int decode_outline(SFT_Font *font, unsigned long offset, int recDepth, struct outline *outl); 112 | /* tesselation */ 113 | static int is_flat(struct outline *outl, struct curve curve, double flatness); 114 | static int tesselate_curve(struct curve curve, struct outline *outl); 115 | static int tesselate_curves(struct outline *outl); 116 | /* silhouette rasterization */ 117 | static void draw_dot(struct buffer buf, int px, int py, double xAvg, double yDiff); 118 | static void draw_line(struct buffer buf, struct point origin, struct point goal); 119 | static void draw_lines(struct outline *outl, struct buffer buf); 120 | /* post-processing */ 121 | static void post_process(struct buffer buf, uint8_t *image); 122 | /* glyph rendering */ 123 | static int render_image(const struct SFT *sft, unsigned long offset, double transform[6], struct SFT_Char *chr); 124 | 125 | /* function implementations */ 126 | 127 | const char * 128 | sft_version(void) 129 | { 130 | return SCHRIFT_VERSION; 131 | } 132 | 133 | /* Loads a font from a user-supplied memory range. */ 134 | SFT_Font * 135 | sft_loadmem(const void *mem, unsigned long size) 136 | { 137 | SFT_Font *font; 138 | if ((font = (SFT_Font*)calloc(1, sizeof(SFT_Font))) == NULL) { 139 | return NULL; 140 | } 141 | font->memory = (const uint8_t *)mem; 142 | font->size = size; 143 | font->source = SrcUser; 144 | if (init_font(font) < 0) { 145 | sft_freefont(font); 146 | return NULL; 147 | } 148 | return font; 149 | } 150 | 151 | /* Loads a font from the file system. To do so, it has to map the entire font into memory. */ 152 | SFT_Font * 153 | sft_loadfile(char const *filename) 154 | { 155 | SFT_Font *font; 156 | if ((font = (SFT_Font*)calloc(1, sizeof(SFT_Font))) == NULL) { 157 | return NULL; 158 | } 159 | if (map_file(font, filename) < 0) { 160 | free(font); 161 | return NULL; 162 | } 163 | if (init_font(font) < 0) { 164 | sft_freefont(font); 165 | return NULL; 166 | } 167 | return font; 168 | } 169 | 170 | void 171 | sft_freefont(SFT_Font *font) 172 | { 173 | if (font == NULL) return; 174 | /* Only unmap if we mapped it ourselves. */ 175 | if (font->source == SrcMapping) 176 | unmap_file(font); 177 | free(font); 178 | } 179 | 180 | static int 181 | init_font(SFT_Font *font) 182 | { 183 | unsigned long scalerType; 184 | long head, hhea; 185 | 186 | /* Check for a compatible scalerType (magic number). */ 187 | scalerType = getu32(font, 0); 188 | if (scalerType != FILE_MAGIC_ONE && scalerType != FILE_MAGIC_TWO) 189 | return -1; 190 | 191 | if ((head = gettable(font, "head")) < 0) 192 | return -1; 193 | if (font->size < (unsigned long) head + 54) 194 | return -1; 195 | font->unitsPerEm = getu16(font, head + 18); 196 | font->locaFormat = geti16(font, head + 50); 197 | 198 | if ((hhea = gettable(font, "hhea")) < 0) 199 | return -1; 200 | if (font->size < (unsigned long) hhea + 36) 201 | return -1; 202 | font->numLongHmtx = getu16(font, hhea + 34); 203 | 204 | return 0; 205 | } 206 | 207 | int 208 | sft_linemetrics(const struct SFT *sft, double *ascent, double *descent, double *gap) 209 | { 210 | double factor; 211 | long hhea; 212 | if ((hhea = gettable(sft->font, "hhea")) < 0) 213 | return -1; 214 | if (sft->font->size < (unsigned long) hhea + 36) return -1; 215 | factor = sft->yScale / sft->font->unitsPerEm; 216 | *ascent = geti16(sft->font, hhea + 4) * factor; 217 | *descent = geti16(sft->font, hhea + 6) * factor; 218 | *gap = geti16(sft->font, hhea + 8) * factor; 219 | return 0; 220 | } 221 | 222 | int 223 | sft_kerning(const struct SFT *sft, unsigned long leftChar, unsigned long rightChar, double kerning[2]) 224 | { 225 | void *match; 226 | unsigned long offset; 227 | long kern; 228 | unsigned int numTables, numPairs, length, format, flags, value; 229 | uint8_t key[4]; 230 | 231 | kerning[0] = 0.0; 232 | kerning[1] = 0.0; 233 | 234 | if ((kern = gettable(sft->font, "kern")) < 0) 235 | return 0; 236 | offset = kern; 237 | 238 | /* Read kern table header. */ 239 | if (sft->font->size < offset + 4) 240 | return -1; 241 | if (getu16(sft->font, offset) != 0) 242 | return 0; 243 | numTables = getu16(sft->font, offset + 2); 244 | offset += 4; 245 | 246 | while (numTables > 0) { 247 | /* Read subtable header. */ 248 | if (sft->font->size < offset + 6) 249 | return -1; 250 | length = getu16(sft->font, offset + 2); 251 | format = getu8 (sft->font, offset + 4); 252 | flags = getu8 (sft->font, offset + 5); 253 | offset += 6; 254 | 255 | if (format == 0 && (flags & HORIZONTAL_KERNING) && !(flags & MINIMUM_KERNING)) { 256 | /* Read format 0 header. */ 257 | if (sft->font->size < offset + 8) 258 | return -1; 259 | numPairs = getu16(sft->font, offset); 260 | offset += 8; 261 | /* Look up character code pair via binary search. */ 262 | key[0] = (leftChar >> 8) & 0xFF; 263 | key[1] = leftChar & 0xFF; 264 | key[2] = (rightChar >> 8) & 0xFF; 265 | key[3] = rightChar & 0xFF; 266 | if ((match = bsearch(key, sft->font->memory + offset, 267 | numPairs, 6, cmpu32)) != NULL) { 268 | 269 | value = geti16(sft->font, (uint8_t *) match - sft->font->memory + 4); 270 | if (flags & CROSS_STREAM_KERNING) { 271 | kerning[1] += value; 272 | } else { 273 | kerning[0] += value; 274 | } 275 | } 276 | 277 | } 278 | 279 | offset += length; 280 | --numTables; 281 | } 282 | 283 | kerning[0] = kerning[0] / sft->font->unitsPerEm * sft->xScale; 284 | kerning[1] = kerning[1] / sft->font->unitsPerEm * sft->yScale; 285 | 286 | return 0; 287 | } 288 | 289 | int 290 | sft_char(const struct SFT *sft, unsigned long charCode, struct SFT_Char *chr) 291 | { 292 | 293 | double transform[6]; 294 | double xScale, yScale, xOff, yOff; 295 | long glyph, outline; 296 | int advance, leftSideBearing; 297 | int x1, y1, x2, y2; 298 | 299 | memset(chr, 0, sizeof(*chr)); 300 | if ((glyph = glyph_id(sft->font, charCode)) < 0) 301 | return -1; 302 | if (glyph == 0 && (sft->flags & SFT_CATCH_MISSING)) 303 | return 1; 304 | 305 | 306 | /* Set up the initial transformation from 307 | * glyph coordinate space to SFT coordinate space. */ 308 | xScale = sft->xScale / sft->font->unitsPerEm; 309 | yScale = sft->yScale / sft->font->unitsPerEm; 310 | xOff = sft->x; 311 | yOff = sft->y; 312 | if (hor_metrics(sft->font, glyph, &advance, &leftSideBearing) < 0) 313 | return -1; 314 | 315 | 316 | /* We can compute the advance width early because the scaling factors 317 | * won't be changed. This is neccessary for glyphs with completely 318 | * empty outlines. */ 319 | chr->advance = (int) round(advance * xScale); 320 | 321 | if ((outline = outline_offset(sft->font, glyph)) < 0) 322 | return -1; 323 | /* A glyph may have a completely empty outline. */ 324 | if (!outline) 325 | return 0; 326 | 327 | 328 | 329 | /* Read the bounding box from the font file verbatim. */ 330 | if (sft->font->size < (unsigned long) outline + 10) 331 | return -1; 332 | x1 = geti16(sft->font, outline + 2); 333 | y1 = geti16(sft->font, outline + 4); 334 | x2 = geti16(sft->font, outline + 6); 335 | y2 = geti16(sft->font, outline + 8); 336 | if (x2 <= x1 || y2 <= y1) 337 | return -1; 338 | 339 | 340 | /* Shift the transformation along the X axis such that 341 | * x1 and leftSideBearing line up. Derivation: 342 | * lsb * xScale + xOff_1 = x1 * xScale + xOff_2 343 | * <=> lsb * xScale + xOff_1 - x1 * xScale = xOff_2 344 | * <=> (lsb - x1) * xScale + xOff_1 = xOff_2 */ 345 | xOff += (leftSideBearing - x1) * xScale; 346 | 347 | /* Transform the bounding box into SFT coordinate space. */ 348 | x1 = (int) floor(x1 * xScale + xOff); 349 | y1 = (int) floor(y1 * yScale + yOff); 350 | x2 = (int) ceil(x2 * xScale + xOff) + 1; 351 | y2 = (int) ceil(y2 * yScale + yOff) + 1; 352 | 353 | /* Compute the user-facing bounding box, respecting Y direction etc. */ 354 | chr->x = x1; 355 | chr->y = sft->flags & SFT_DOWNWARD_Y ? -y2 : y1; 356 | chr->width = x2 - x1; 357 | chr->height = y2 - y1; 358 | 359 | /* Render the outline (if requested). */ 360 | if (sft->flags & SFT_RENDER_IMAGE) { 361 | /* Set up the transformation matrix such that 362 | * the transformed bounding boxes min corner lines 363 | * up with the (0, 0) point. */ 364 | transform[0] = xScale; 365 | transform[1] = 0.0; 366 | transform[2] = 0.0; 367 | transform[3] = yScale; 368 | transform[4] = xOff - x1; 369 | transform[5] = yOff - y1; 370 | 371 | if (render_image(sft, outline, transform, chr) < 0) 372 | return -1; 373 | 374 | } 375 | 376 | return glyph == 0; 377 | } 378 | 379 | /* This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX 380 | * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW */ 381 | #define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) 382 | 383 | /* OpenBSD's reallocarray() standard libary function. 384 | * A wrapper for realloc() that takes two size args like calloc(). 385 | * Useful because it eliminates common integer overflow bugs. */ 386 | static void * 387 | sft_reallocarray(void *optr, size_t nmemb, size_t size) 388 | { 389 | if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && 390 | nmemb > 0 && SIZE_MAX / nmemb < size) { 391 | errno = ENOMEM; 392 | return NULL; 393 | } 394 | return realloc(optr, size * nmemb); 395 | } 396 | 397 | /* TODO maybe we should use long here instead of int. */ 398 | static inline int 399 | fast_floor(double x) 400 | { 401 | int i = (int) x; 402 | return i - (i > x); 403 | } 404 | 405 | static inline int 406 | fast_ceil(double x) 407 | { 408 | int i = (int) x; 409 | return i + (i < x); 410 | } 411 | 412 | #if defined(_WIN32) 413 | 414 | static int 415 | map_file(SFT_Font *font, const char *filename) 416 | { 417 | HANDLE file; 418 | DWORD high, low; 419 | 420 | font->mapping = NULL; 421 | font->memory = NULL; 422 | 423 | file = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); 424 | if (file == INVALID_HANDLE_VALUE) { 425 | return -1; 426 | } 427 | 428 | low = GetFileSize(file, &high); 429 | if (low == INVALID_FILE_SIZE) { 430 | CloseHandle(file); 431 | return -1; 432 | } 433 | 434 | font->size = (size_t)high << (8 * sizeof(DWORD)) | low; 435 | 436 | font->mapping = CreateFileMapping(file, NULL, PAGE_READONLY, high, low, NULL); 437 | if (font->mapping == NULL) { 438 | CloseHandle(file); 439 | return -1; 440 | } 441 | 442 | CloseHandle(file); 443 | 444 | font->memory = MapViewOfFile(font->mapping, FILE_MAP_READ, 0, 0, 0); 445 | if (font->memory == NULL) { 446 | CloseHandle(font->mapping); 447 | font->mapping = NULL; 448 | return -1; 449 | } 450 | 451 | return 0; 452 | } 453 | 454 | static void 455 | unmap_file(SFT_Font *font) 456 | { 457 | if (font->memory != NULL) { 458 | UnmapViewOfFile(font->memory); 459 | font->memory = NULL; 460 | } 461 | if (font->mapping != NULL) { 462 | CloseHandle(font->mapping); 463 | font->mapping = NULL; 464 | } 465 | } 466 | 467 | #else 468 | 469 | static int 470 | map_file(SFT_Font *font, const char *filename) 471 | { 472 | struct stat info; 473 | int fd; 474 | font->memory = (const uint8_t*)MAP_FAILED; 475 | font->size = 0; 476 | font->source = SrcMapping; 477 | if ((fd = open(filename, O_RDONLY)) < 0) { 478 | return -1; 479 | } 480 | if (fstat(fd, &info) < 0) { 481 | close(fd); 482 | return -1; 483 | } 484 | font->memory = (const uint8_t*) mmap(NULL, info.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 485 | font->size = info.st_size; 486 | close(fd); 487 | return font->memory == MAP_FAILED ? -1 : 0; 488 | } 489 | 490 | static void 491 | unmap_file(SFT_Font *font) 492 | { 493 | assert(font->memory != MAP_FAILED); 494 | munmap((void *) font->memory, font->size); 495 | } 496 | 497 | #endif 498 | 499 | static struct point 500 | midpoint(struct point a, struct point b) 501 | { 502 | return (struct point) { 503 | 0.5 * a.x + 0.5 * b.x, 504 | 0.5 * a.y + 0.5 * b.y 505 | }; 506 | } 507 | 508 | /* Applies an affine linear transformation matrix to a set of points. */ 509 | static void 510 | transform_points(int numPts, struct point *points, double trf[6]) 511 | { 512 | struct point* pt; 513 | int i; 514 | for (i = 0; i < numPts; ++i) { 515 | pt = &points[i]; 516 | *pt = (struct point) { 517 | pt->x * trf[0] + pt->y * trf[2] + trf[4], 518 | pt->x * trf[1] + pt->y * trf[3] + trf[5] 519 | }; 520 | } 521 | } 522 | 523 | static void 524 | clip_points(int numPts, struct point *points, int width, int height) 525 | { 526 | struct point pt; 527 | int i; 528 | 529 | for (i = 0; i < numPts; ++i) { 530 | pt = points[i]; 531 | 532 | if (pt.x < 0.0) { 533 | points[i].x = 0.0; 534 | } 535 | if (pt.x >= width) { 536 | points[i].x = nextafter(width, 0.0); 537 | } 538 | if (pt.y < 0.0) { 539 | points[i].y = 0.0; 540 | } 541 | if (pt.y >= height) { 542 | points[i].y = nextafter(height, 0.0); 543 | } 544 | } 545 | } 546 | 547 | static int 548 | init_buffer(struct buffer *buf, int width, int height) 549 | { 550 | struct cell *ptr; 551 | size_t rowsSize, cellsSize; 552 | int i; 553 | 554 | buf->rows = NULL; 555 | buf->width = width; 556 | buf->height = height; 557 | 558 | rowsSize = (size_t) height * sizeof(buf->rows[0]); 559 | cellsSize = (size_t) width * height * sizeof(struct cell); 560 | if ((buf->rows = (struct cell**) calloc(rowsSize + cellsSize, 1)) == NULL) 561 | return -1; 562 | 563 | ptr = (struct cell*) (buf->rows + height); 564 | for (i = 0; i < height; ++i) { 565 | buf->rows[i] = ptr; 566 | ptr += width; 567 | } 568 | 569 | return 0; 570 | } 571 | 572 | static void 573 | free_buffer(struct buffer *buf) 574 | { 575 | free(buf->rows); 576 | } 577 | 578 | static void 579 | flip_buffer(struct buffer *buf) 580 | { 581 | struct cell *row; 582 | int front = 0, back = buf->height - 1; 583 | while (front < back) { 584 | row = buf->rows[front]; 585 | buf->rows[front] = buf->rows[back]; 586 | buf->rows[back] = row; 587 | ++front, --back; 588 | } 589 | } 590 | 591 | static int 592 | init_outline(struct outline *outl) 593 | { 594 | outl->numPoints = 0; 595 | outl->capPoints = 64; 596 | if ((outl->points = (struct point*)malloc(outl->capPoints * sizeof(outl->points[0]))) == NULL) 597 | return -1; 598 | outl->numCurves = 0; 599 | outl->capCurves = 64; 600 | if ((outl->curves = (struct curve*)malloc(outl->capCurves * sizeof(outl->curves[0]))) == NULL) 601 | return -1; 602 | outl->numLines = 0; 603 | outl->capLines = 64; 604 | if ((outl->lines = (struct line*)malloc(outl->capLines * sizeof(outl->lines[0]))) == NULL) 605 | return -1; 606 | return 0; 607 | } 608 | 609 | static void 610 | free_outline(struct outline *outl) 611 | { 612 | free(outl->points); 613 | free(outl->curves); 614 | free(outl->lines); 615 | } 616 | 617 | static int 618 | grow_points(struct outline *outl) 619 | { 620 | void *mem; 621 | int cap = outl->capPoints * 2; 622 | /* This precondition is relatively important. Otherwise, if cap 623 | * were 0, reallocarray() may return NULL as an allocated pointer, which 624 | * we would misinterpret as an out-of-memory situation. */ 625 | assert(cap > 0); 626 | if ((mem = sft_reallocarray(outl->points, cap, sizeof(outl->points[0]))) == NULL) 627 | return -1; 628 | outl->capPoints = cap; 629 | outl->points = (struct point*)mem; 630 | return 0; 631 | } 632 | 633 | static int 634 | grow_curves(struct outline *outl) 635 | { 636 | void *mem; 637 | int cap = outl->capCurves * 2; 638 | assert(cap > 0); 639 | if ((mem = sft_reallocarray(outl->curves, cap, sizeof(outl->curves[0]))) == NULL) 640 | return -1; 641 | outl->capCurves = cap; 642 | outl->curves = (struct curve*)mem; 643 | return 0; 644 | } 645 | 646 | static int 647 | grow_lines(struct outline *outl) 648 | { 649 | void *mem; 650 | int cap = outl->capLines * 2; 651 | assert(cap > 0); 652 | if ((mem = sft_reallocarray(outl->lines, cap, sizeof(outl->lines[0]))) == NULL) 653 | return -1; 654 | outl->capLines = cap; 655 | outl->lines = (struct line*)mem; 656 | return 0; 657 | } 658 | 659 | /* Like bsearch(), but returns the next highest element if key could not be found. */ 660 | static void * 661 | csearch(const void *key, const void *base, 662 | size_t nmemb, size_t size, 663 | int (*compar)(const void *, const void *)) 664 | { 665 | const uint8_t *bytes = (const uint8_t*)base, *sample; 666 | size_t low = 0, high = nmemb - 1, mid; 667 | if (nmemb == 0) 668 | return NULL; 669 | while (low != high) { 670 | mid = low + (high - low) / 2; 671 | sample = bytes + mid * size; 672 | if (compar(key, sample) > 0) { 673 | low = mid + 1; 674 | } else { 675 | high = mid; 676 | } 677 | } 678 | return (uint8_t *) bytes + low * size; 679 | } 680 | 681 | /* Used as a comparison function for [bc]search(). */ 682 | static int 683 | cmpu16(const void *a, const void *b) 684 | { 685 | return memcmp(a, b, 2); 686 | } 687 | 688 | /* Used as a comparison function for [bc]search(). */ 689 | static int 690 | cmpu32(const void *a, const void *b) 691 | { 692 | return memcmp(a, b, 4); 693 | } 694 | 695 | static inline uint8_t 696 | getu8(SFT_Font *font, unsigned long offset) 697 | { 698 | assert(offset + 1 <= font->size); 699 | return *(font->memory + offset); 700 | } 701 | 702 | static inline int8_t 703 | geti8(SFT_Font *font, unsigned long offset) 704 | { 705 | return (int8_t) getu8(font, offset); 706 | } 707 | 708 | static inline uint16_t 709 | getu16(SFT_Font *font, unsigned long offset) 710 | { 711 | assert(offset + 2 <= font->size); 712 | const uint8_t *base = font->memory + offset; 713 | uint16_t b1 = base[0], b0 = base[1]; 714 | return (uint16_t) (b1 << 8 | b0); 715 | } 716 | 717 | static inline int16_t 718 | geti16(SFT_Font *font, unsigned long offset) 719 | { 720 | return (int16_t) getu16(font, offset); 721 | } 722 | 723 | static inline uint32_t 724 | getu32(SFT_Font *font, unsigned long offset) 725 | { 726 | assert(offset + 4 <= font->size); 727 | const uint8_t *base = font->memory + offset; 728 | uint32_t b3 = base[0], b2 = base[1], b1 = base[2], b0 = base[3]; 729 | return (uint32_t) (b3 << 24 | b2 << 16 | b1 << 8 | b0); 730 | } 731 | 732 | static long 733 | gettable(SFT_Font *font, const char tag[4]) 734 | { 735 | void *match; 736 | unsigned int numTables; 737 | if (font->size < 12) 738 | return -1; 739 | numTables = getu16(font, 4); 740 | if (font->size < 12 + (size_t) numTables * 16) 741 | return -1; 742 | 743 | if ((match = bsearch(tag, font->memory + 12, numTables, 16, cmpu32)) == NULL) 744 | return -1; 745 | 746 | return getu32(font, (uint8_t *) match - font->memory + 8); 747 | } 748 | 749 | static long 750 | cmap_fmt4(SFT_Font *font, unsigned long table, unsigned long charCode) 751 | { 752 | unsigned long endCodes, startCodes, idDeltas, idRangeOffsets, idOffset; 753 | unsigned int segCountX2, segIdxX2, startCode, idRangeOffset, id; 754 | int idDelta; 755 | uint8_t key[2] = { (uint8_t) (charCode >> 8), (uint8_t) charCode }; 756 | /* cmap format 4 only supports the Unicode BMP. */ 757 | if (charCode > 0xFFFF) 758 | return 0; 759 | if (font->size < table + 8) 760 | return -1; 761 | segCountX2 = getu16(font, table); 762 | if ((segCountX2 & 1) || !segCountX2) 763 | return -1; 764 | /* Find starting positions of the relevant arrays. */ 765 | endCodes = table + 8; 766 | startCodes = endCodes + segCountX2 + 2; 767 | idDeltas = startCodes + segCountX2; 768 | idRangeOffsets = idDeltas + segCountX2; 769 | if (font->size < idRangeOffsets + segCountX2) 770 | return -1; 771 | /* Find the segment that contains charCode by binary searching over the highest codes in the segments. */ 772 | segIdxX2 = (uintptr_t) csearch(key, font->memory + endCodes, 773 | segCountX2 / 2, 2, cmpu16) - (uintptr_t) (font->memory + endCodes); 774 | /* Look up segment info from the arrays & short circuit if the spec requires. */ 775 | if ((startCode = getu16(font, startCodes + segIdxX2)) > charCode) 776 | return 0; 777 | idDelta = geti16(font, idDeltas + segIdxX2); 778 | if (!(idRangeOffset = getu16(font, idRangeOffsets + segIdxX2))) 779 | return (charCode + idDelta) & 0xFFFF; 780 | /* Calculate offset into glyph array and determine ultimate value. */ 781 | idOffset = idRangeOffsets + segIdxX2 + idRangeOffset + 2 * (charCode - startCode); 782 | if (font->size < idOffset + 2) 783 | return -1; 784 | id = getu16(font, idOffset); 785 | return id ? (id + idDelta) & 0xFFFF : 0L; 786 | } 787 | 788 | static long 789 | cmap_fmt6(SFT_Font *font, unsigned long table, unsigned long charCode) 790 | { 791 | unsigned int firstCode, entryCount; 792 | /* cmap format 6 only supports the Unicode BMP. */ 793 | if (charCode > 0xFFFF) 794 | return 0; 795 | if (font->size < table + 4) 796 | return -1; 797 | firstCode = getu16(font, table); 798 | entryCount = getu16(font, table + 2); 799 | if (font->size < table + 4 + 2 * entryCount) 800 | return -1; 801 | if (charCode < firstCode) 802 | return -1; 803 | charCode -= firstCode; 804 | if (!(charCode < entryCount)) 805 | return -1; 806 | return getu16(font, table + 4 + 2 * charCode); 807 | } 808 | 809 | /* Maps Unicode code points to glyph indices. */ 810 | static long 811 | glyph_id(SFT_Font *font, unsigned long charCode) 812 | { 813 | unsigned long entry, table; 814 | long cmap; 815 | unsigned int idx, numEntries; 816 | int type; 817 | if ((cmap = gettable(font, "cmap")) < 0) 818 | return -1; 819 | if (font->size < (unsigned long) cmap + 4) 820 | return -1; 821 | numEntries = getu16(font, cmap + 2); 822 | 823 | if (font->size < (unsigned long) cmap + 4 + numEntries * 8) 824 | return -1; 825 | /* Search for the first Unicode BMP entry. */ 826 | for (idx = 0; idx < numEntries; ++idx) { 827 | entry = cmap + 4 + idx * 8; 828 | type = getu16(font, entry) * 0100 + getu16(font, entry + 2); 829 | if (type == 0003 || type == 0301) { 830 | table = cmap + getu32(font, entry + 4); 831 | if (font->size < table + 6) 832 | return -1; 833 | /* Dispatch based on cmap format. */ 834 | switch (getu16(font, table)) { 835 | case 4: 836 | return cmap_fmt4(font, table + 6, charCode); 837 | case 6: 838 | return cmap_fmt6(font, table + 6, charCode); 839 | default: 840 | return -1; 841 | } 842 | } 843 | } 844 | 845 | return -1; 846 | } 847 | 848 | static int 849 | hor_metrics(SFT_Font *font, long glyph, int *advanceWidth, int *leftSideBearing) 850 | { 851 | unsigned long offset, boundary; 852 | long hmtx; 853 | if ((hmtx = gettable(font, "hmtx")) < 0) 854 | return -1; 855 | if (glyph < font->numLongHmtx) { 856 | /* glyph is inside long metrics segment. */ 857 | offset = hmtx + 4 * glyph; 858 | if (font->size < offset + 4) 859 | return -1; 860 | *advanceWidth = getu16(font, offset); 861 | *leftSideBearing = geti16(font, offset + 2); 862 | return 0; 863 | } else { 864 | /* glyph is inside short metrics segment. */ 865 | boundary = hmtx + 4 * font->numLongHmtx; 866 | if (boundary < 4) 867 | return -1; 868 | 869 | offset = boundary - 4; 870 | if (font->size < offset + 4) 871 | return -1; 872 | *advanceWidth = getu16(font, offset); 873 | 874 | offset = boundary + 2 * (glyph - font->numLongHmtx); 875 | if (font->size < offset + 2) 876 | return -1; 877 | *leftSideBearing = geti16(font, offset); 878 | return 0; 879 | } 880 | } 881 | 882 | /* Returns the offset into the font that the glyph's outline is stored at. */ 883 | static long 884 | outline_offset(SFT_Font *font, long glyph) 885 | { 886 | unsigned long base, t, next; 887 | long loca, glyf; 888 | 889 | if ((loca = gettable(font, "loca")) < 0) 890 | return -1; 891 | if ((glyf = gettable(font, "glyf")) < 0) 892 | return -1; 893 | 894 | if (font->locaFormat == 0) { 895 | base = loca + 2 * glyph; 896 | 897 | if (font->size < base + 4) 898 | return -1; 899 | 900 | t = 2L * getu16(font, base); 901 | next = 2L * getu16(font, base + 2); 902 | } else { 903 | base = loca + 4 * glyph; 904 | 905 | if (font->size < base + 8) 906 | return -1; 907 | 908 | t = getu32(font, base); 909 | next = getu32(font, base + 4); 910 | } 911 | 912 | return t == next ? 0 : glyf + t; 913 | } 914 | 915 | /* For a 'simple' outline, determines each point of the outline with a set of flags. */ 916 | static long 917 | simple_flags(SFT_Font *font, unsigned long offset, int numPts, uint8_t *flags) 918 | { 919 | int value = 0, repeat = 0, i; 920 | for (i = 0; i < numPts; ++i) { 921 | if (repeat) { 922 | --repeat; 923 | } else { 924 | if (font->size < offset + 1) 925 | return -1; 926 | value = getu8(font, offset++); 927 | if (value & REPEAT_FLAG) { 928 | if (font->size < offset + 1) 929 | return -1; 930 | repeat = getu8(font, offset++); 931 | } 932 | } 933 | flags[i] = value; 934 | } 935 | return offset; 936 | } 937 | 938 | /* For a 'simple' outline, decodes both X and Y coordinates for each point of the outline. */ 939 | static int 940 | simple_points(SFT_Font *font, unsigned long offset, int numPts, uint8_t *flags, struct point *points) 941 | { 942 | long accum, value, bit; 943 | int i; 944 | 945 | assert(numPts > 0); 946 | 947 | accum = 0L; 948 | for (i = 0; i < numPts; ++i) { 949 | if (flags[i] & X_CHANGE_IS_SMALL) { 950 | if (font->size < offset + 1) 951 | return -1; 952 | value = (long) getu8(font, offset++); 953 | bit = !!(flags[i] & X_CHANGE_IS_POSITIVE); 954 | accum -= (value ^ -bit) + bit; 955 | } else if (!(flags[i] & X_CHANGE_IS_ZERO)) { 956 | if (font->size < offset + 2) 957 | return -1; 958 | accum += geti16(font, offset); 959 | offset += 2; 960 | } 961 | points[i].x = accum; 962 | } 963 | 964 | accum = 0L; 965 | for (i = 0; i < numPts; ++i) { 966 | if (flags[i] & Y_CHANGE_IS_SMALL) { 967 | if (font->size < offset + 1) 968 | return -1; 969 | value = (long) getu8(font, offset++); 970 | bit = !!(flags[i] & Y_CHANGE_IS_POSITIVE); 971 | accum -= (value ^ -bit) + bit; 972 | } else if (!(flags[i] & Y_CHANGE_IS_ZERO)) { 973 | if (font->size < offset + 2) 974 | return -1; 975 | accum += geti16(font, offset); 976 | offset += 2; 977 | } 978 | points[i].y = accum; 979 | } 980 | 981 | return 0; 982 | } 983 | 984 | static int 985 | decode_contour(uint8_t *flags, unsigned int basePoint, unsigned int count, struct outline *outl) 986 | { 987 | unsigned int looseEnd, beg, ctrl, center; 988 | unsigned int gotCtrl, i; 989 | 990 | /* Skip contours with less than two points, since the following algorithm can't handle them and 991 | * they should appear invisible either way (because they don't have any area). */ 992 | if (count < 2) return 0; 993 | if (flags[0] & POINT_IS_ON_CURVE) { 994 | looseEnd = basePoint++; 995 | ++flags; 996 | --count; 997 | 998 | } else if (flags[count - 1] & POINT_IS_ON_CURVE) { 999 | looseEnd = basePoint + --count; 1000 | } else { 1001 | if (outl->numPoints >= outl->capPoints && grow_points(outl) < 0) 1002 | return -1; 1003 | 1004 | looseEnd = outl->numPoints; 1005 | outl->points[outl->numPoints++] = midpoint( 1006 | outl->points[basePoint], 1007 | outl->points[basePoint + count - 1]); 1008 | } 1009 | beg = looseEnd; 1010 | gotCtrl = 0; 1011 | 1012 | for (i = 0; i < count; ++i) { 1013 | if (flags[i] & POINT_IS_ON_CURVE) { 1014 | if (gotCtrl) { 1015 | if (outl->numCurves >= outl->capCurves && grow_curves(outl) < 0) 1016 | return -1; 1017 | outl->curves[outl->numCurves++] = (struct curve) { static_cast(beg), static_cast(basePoint + i), static_cast(ctrl) }; 1018 | } else { 1019 | if (outl->numLines >= outl->capLines && grow_lines(outl) < 0) 1020 | return -1; 1021 | outl->lines[outl->numLines++] = (struct line) { static_cast(beg), static_cast(basePoint + i) }; 1022 | } 1023 | beg = basePoint + i; 1024 | gotCtrl = 0; 1025 | } else { 1026 | if (gotCtrl) { 1027 | center = outl->numPoints; 1028 | if (outl->numPoints >= outl->capPoints && grow_points(outl) < 0) 1029 | return -1; 1030 | outl->points[center] = midpoint(outl->points[ctrl], outl->points[basePoint + i]); 1031 | ++outl->numPoints; 1032 | 1033 | if (outl->numCurves >= outl->capCurves && grow_curves(outl) < 0) 1034 | return -1; 1035 | outl->curves[outl->numCurves++] = (struct curve) { static_cast(beg), static_cast(center), static_cast(ctrl) }; 1036 | 1037 | beg = center; 1038 | } 1039 | ctrl = basePoint + i; 1040 | gotCtrl = 1; 1041 | } 1042 | } 1043 | if (gotCtrl) { 1044 | if (outl->numCurves >= outl->capCurves && grow_curves(outl) < 0) 1045 | return -1; 1046 | outl->curves[outl->numCurves++] = (struct curve) { static_cast(beg), static_cast(looseEnd), static_cast(ctrl) }; 1047 | } else { 1048 | if (outl->numLines >= outl->capLines && grow_lines(outl) < 0) 1049 | return -1; 1050 | outl->lines[outl->numLines++] = (struct line) { static_cast(beg), static_cast(looseEnd) }; 1051 | } 1052 | 1053 | return 0; 1054 | } 1055 | 1056 | static int 1057 | simple_outline(SFT_Font *font, unsigned long offset, int numContours, struct outline *outl) 1058 | { 1059 | unsigned int *endPts = NULL; 1060 | uint8_t *flags = NULL; 1061 | long sgnOffset; 1062 | unsigned int numPts; 1063 | int i; 1064 | uint8_t *flagsPtr = flags; 1065 | unsigned int contourBase = 0; 1066 | 1067 | unsigned int basePoint = outl->numPoints; 1068 | 1069 | if (font->size < offset + numContours * 2 + 2) 1070 | goto failure; 1071 | numPts = getu16(font, offset + (numContours - 1) * 2) + 1; 1072 | 1073 | while (outl->capPoints < basePoint + numPts) { 1074 | if (grow_points(outl) < 0) 1075 | return -1; 1076 | } 1077 | STACK_ALLOC(endPts, unsigned int, 16, numContours); 1078 | if (endPts == NULL) 1079 | goto failure; 1080 | 1081 | STACK_ALLOC(flags, uint8_t, 128, numPts); 1082 | flagsPtr = flags; 1083 | 1084 | if (flags == NULL) 1085 | goto failure; 1086 | 1087 | for (i = 0; i < numContours; ++i) { 1088 | endPts[i] = getu16(font, offset); 1089 | offset += 2; 1090 | } 1091 | /* Ensure that endPts are never falling. 1092 | * Falling endPts have no sensible interpretation and most likely only occur in malicious input. 1093 | * Therefore, we bail, should we ever encounter such input. */ 1094 | for (i = 0; i < numContours - 1; ++i) { 1095 | if (endPts[i + 1] < endPts[i] + 1) 1096 | goto failure; 1097 | } 1098 | offset += 2 + getu16(font, offset); 1099 | 1100 | if ((sgnOffset = simple_flags(font, offset, numPts, flags)) < 0) 1101 | goto failure; 1102 | offset = sgnOffset; 1103 | if (simple_points(font, offset, numPts, flags, outl->points + basePoint) < 0) 1104 | goto failure; 1105 | outl->numPoints += numPts; 1106 | 1107 | for (int c = 0; c < numContours; ++c) { 1108 | unsigned int count = endPts[c] - contourBase + 1; 1109 | if (decode_contour(flagsPtr, basePoint, count, outl) < 0) 1110 | goto failure; 1111 | flagsPtr += count; 1112 | basePoint += count; 1113 | contourBase += count; 1114 | } 1115 | 1116 | STACK_FREE(endPts); 1117 | STACK_FREE(flags); 1118 | return 0; 1119 | failure: 1120 | STACK_FREE(endPts); 1121 | STACK_FREE(flags); 1122 | return -1; 1123 | } 1124 | 1125 | static int 1126 | compound_outline(SFT_Font *font, unsigned long offset, int recDepth, struct outline *outl) 1127 | { 1128 | double local[6]; 1129 | long outline; 1130 | unsigned int flags, glyph; 1131 | /* Guard against infinite recursion (compound glyphs that have themselves as component). */ 1132 | if (recDepth >= 4) 1133 | return -1; 1134 | do { 1135 | memset(local, 0, sizeof(local)); 1136 | if (font->size < offset + 4) 1137 | return -1; 1138 | flags = getu16(font, offset); 1139 | glyph = getu16(font, offset + 2); 1140 | offset += 4; 1141 | /* We don't implement point matching, and neither does stb_truetype for that matter. */ 1142 | if (!(flags & ACTUAL_XY_OFFSETS)) 1143 | return -1; 1144 | /* Read additional X and Y offsets (in FUnits) of this component. */ 1145 | if (flags & OFFSETS_ARE_LARGE) { 1146 | if (font->size < offset + 4) 1147 | return -1; 1148 | local[4] = geti16(font, offset); 1149 | local[5] = geti16(font, offset + 2); 1150 | offset += 4; 1151 | } else { 1152 | if (font->size < offset + 2) 1153 | return -1; 1154 | local[4] = geti8(font, offset); 1155 | local[5] = geti8(font, offset + 1); 1156 | offset += 2; 1157 | } 1158 | if (flags & GOT_A_SINGLE_SCALE) { 1159 | if (font->size < offset + 2) 1160 | return -1; 1161 | local[0] = geti16(font, offset) / 16384.0; 1162 | local[3] = local[0]; 1163 | offset += 2; 1164 | } else if (flags & GOT_AN_X_AND_Y_SCALE) { 1165 | if (font->size < offset + 4) 1166 | return -1; 1167 | local[0] = geti16(font, offset + 0) / 16384.0; 1168 | local[3] = geti16(font, offset + 2) / 16384.0; 1169 | offset += 4; 1170 | } else if (flags & GOT_A_SCALE_MATRIX) { 1171 | if (font->size < offset + 8) 1172 | return -1; 1173 | local[0] = geti16(font, offset + 0) / 16384.0; 1174 | local[1] = geti16(font, offset + 2) / 16384.0; 1175 | local[2] = geti16(font, offset + 4) / 16384.0; 1176 | local[3] = geti16(font, offset + 6) / 16384.0; 1177 | offset += 8; 1178 | } else { 1179 | local[0] = 1.0; 1180 | local[3] = 1.0; 1181 | } 1182 | /* At this point, Apple's spec more or less tells you to scale the matrix by its own L1 norm. 1183 | * But stb_truetype scales by the L2 norm. And FreeType2 doesn't scale at all. 1184 | * Furthermore, Microsoft's spec doesn't even mention anything like this. 1185 | * It's almost as if nobody ever uses this feature anyway. */ 1186 | if ((outline = outline_offset(font, glyph)) < 0) 1187 | return -1; 1188 | if (outline) { 1189 | unsigned int basePoint = outl->numPoints; 1190 | if (decode_outline(font, outline, recDepth + 1, outl) < 0) 1191 | return -1; 1192 | transform_points(outl->numPoints - basePoint, outl->points + basePoint, local); 1193 | } 1194 | } while (flags & THERE_ARE_MORE_COMPONENTS); 1195 | 1196 | return 0; 1197 | } 1198 | 1199 | static int 1200 | decode_outline(SFT_Font *font, unsigned long offset, int recDepth, struct outline *outl) 1201 | { 1202 | int numContours; 1203 | if (font->size < offset + 10) 1204 | return -1; 1205 | numContours = geti16(font, offset); 1206 | if (numContours >= 0) { 1207 | /* Glyph has a 'simple' outline consisting of a number of contours. */ 1208 | return simple_outline(font, offset + 10, numContours, outl); 1209 | } else { 1210 | /* Glyph has a compound outline combined from mutiple other outlines. */ 1211 | return compound_outline(font, offset + 10, recDepth, outl); 1212 | } 1213 | } 1214 | 1215 | /* A heuristic to tell whether a given curve can be approximated closely enough by a line. */ 1216 | static int 1217 | is_flat(struct outline *outl, struct curve curve, double flatness) 1218 | { 1219 | struct point beg = outl->points[curve.beg]; 1220 | struct point end = outl->points[curve.end]; 1221 | struct point ctrl = outl->points[curve.ctrl]; 1222 | struct point mid = midpoint(beg, end); 1223 | double x = ctrl.x - mid.x; 1224 | double y = ctrl.y - mid.y; 1225 | return x * x + y * y <= flatness * flatness; 1226 | } 1227 | 1228 | static int 1229 | tesselate_curve(struct curve curve, struct outline *outl) 1230 | { 1231 | /* From my tests I can conclude that this stack barely reaches a top height 1232 | * of 4 elements even for the largest font sizes I'm willing to support. And 1233 | * as space requirements should only grow logarithmically, I think 10 is 1234 | * more than enough. */ 1235 | #define STACK_SIZE 10 1236 | struct curve stack[STACK_SIZE]; 1237 | unsigned int top = 0; 1238 | for (;;) { 1239 | if (is_flat(outl, curve, 0.5) || top >= STACK_SIZE) { 1240 | if (outl->numLines >= outl->capLines && grow_lines(outl) < 0) 1241 | return -1; 1242 | outl->lines[outl->numLines++] = (struct line) { curve.beg, curve.end }; 1243 | if (top == 0) break; 1244 | curve = stack[--top]; 1245 | } else { 1246 | unsigned int ctrl0 = outl->numPoints; 1247 | if (outl->numPoints >= outl->capPoints && grow_points(outl) < 0) 1248 | return -1; 1249 | outl->points[ctrl0] = midpoint(outl->points[curve.beg], outl->points[curve.ctrl]); 1250 | ++outl->numPoints; 1251 | 1252 | unsigned int ctrl1 = outl->numPoints; 1253 | if (outl->numPoints >= outl->capPoints && grow_points(outl) < 0) 1254 | return -1; 1255 | outl->points[ctrl1] = midpoint(outl->points[curve.ctrl], outl->points[curve.end]); 1256 | ++outl->numPoints; 1257 | 1258 | unsigned int pivot = outl->numPoints; 1259 | if (outl->numPoints >= outl->capPoints && grow_points(outl) < 0) 1260 | return -1; 1261 | outl->points[pivot] = midpoint(outl->points[ctrl0], outl->points[ctrl1]); 1262 | ++outl->numPoints; 1263 | 1264 | stack[top++] = (struct curve) { curve.beg, static_cast(pivot), static_cast(ctrl0) }; 1265 | curve = (struct curve) { static_cast(pivot), curve.end, static_cast(ctrl1) }; 1266 | } 1267 | } 1268 | return 0; 1269 | #undef STACK_SIZE 1270 | } 1271 | 1272 | static int 1273 | tesselate_curves(struct outline *outl) 1274 | { 1275 | unsigned int i; 1276 | for (i = 0; i < outl->numCurves; ++i) { 1277 | if (tesselate_curve(outl->curves[i], outl) < 0) 1278 | return -1; 1279 | } 1280 | return 0; 1281 | } 1282 | 1283 | static void 1284 | draw_dot(struct buffer buf, int px, int py, double xAvg, double yDiff) 1285 | { 1286 | struct cell* ptr = &buf.rows[py][px]; 1287 | struct cell cell = *ptr; 1288 | cell.cover += yDiff; 1289 | cell.area += (1.0 - xAvg) * yDiff; 1290 | *ptr = cell; 1291 | } 1292 | 1293 | /* Draws a line into the buffer. Uses a custom 2D raycasting algorithm to do so. */ 1294 | static void 1295 | draw_line(struct buffer buf, struct point origin, struct point goal) 1296 | { 1297 | double originX, originY; 1298 | double goalX, goalY; 1299 | double deltaX, deltaY; 1300 | double nextCrossingX, nextCrossingY; 1301 | double crossingGapX, crossingGapY; 1302 | double prevDistance = 0.0; 1303 | int pixelX, pixelY; 1304 | int iter, numIters = 0; 1305 | 1306 | originX = origin.x; 1307 | goalX = goal.x; 1308 | deltaX = goalX - originX; 1309 | if (deltaX > 0.0) { 1310 | crossingGapX = 1.0 / deltaX; 1311 | pixelX = fast_floor(originX); 1312 | nextCrossingX = (1.0 - (originX - pixelX)) * crossingGapX; 1313 | numIters += fast_ceil(goalX) - fast_floor(originX) - 1; 1314 | } else if (deltaX < 0.0) { 1315 | crossingGapX = -(1.0 / deltaX); 1316 | pixelX = fast_ceil(originX) - 1; 1317 | nextCrossingX = (originX - pixelX) * crossingGapX; 1318 | numIters += fast_ceil(originX) - fast_floor(goalX) - 1; 1319 | } else { 1320 | crossingGapX = 0.0; 1321 | pixelX = fast_floor(originX); 1322 | nextCrossingX = 100.0; 1323 | } 1324 | 1325 | originY = origin.y; 1326 | goalY = goal.y; 1327 | deltaY = goalY - originY; 1328 | if (deltaY > 0.0) { 1329 | crossingGapY = 1.0 / deltaY; 1330 | pixelY = fast_floor(originY); 1331 | nextCrossingY = (1.0 - (originY - pixelY)) * crossingGapY; 1332 | numIters += fast_ceil(goalY) - fast_floor(originY) - 1; 1333 | } else if (deltaY < 0.0) { 1334 | crossingGapY = -(1.0 / deltaY); 1335 | pixelY = fast_ceil(originY) - 1; 1336 | nextCrossingY = (originY - pixelY) * crossingGapY; 1337 | numIters += fast_ceil(originY) - fast_floor(goalY) - 1; 1338 | } else { 1339 | return; 1340 | } 1341 | 1342 | for (iter = 0; iter < numIters; ++iter) { 1343 | if (nextCrossingX < nextCrossingY) { 1344 | double deltaDistance = nextCrossingX - prevDistance; 1345 | double averageX = (deltaX > 0) - 0.5 * deltaX * deltaDistance; 1346 | draw_dot(buf, pixelX, pixelY, averageX, deltaY * deltaDistance); 1347 | pixelX += SIGN(deltaX); 1348 | prevDistance = nextCrossingX; 1349 | nextCrossingX += crossingGapX; 1350 | } else { 1351 | double deltaDistance = nextCrossingY - prevDistance; 1352 | double x = originX - pixelX + nextCrossingY * deltaX; 1353 | double averageX = x - 0.5 * deltaX * deltaDistance; 1354 | draw_dot(buf, pixelX, pixelY, averageX, deltaY * deltaDistance); 1355 | pixelY += SIGN(deltaY); 1356 | prevDistance = nextCrossingY; 1357 | nextCrossingY += crossingGapY; 1358 | } 1359 | } 1360 | 1361 | double deltaDistance = 1.0 - prevDistance; 1362 | double averageX = (goalX - pixelX) - 0.5 * deltaX * deltaDistance; 1363 | draw_dot(buf, pixelX, pixelY, averageX, deltaY * deltaDistance); 1364 | } 1365 | 1366 | static void 1367 | draw_lines(struct outline *outl, struct buffer buf) 1368 | { 1369 | unsigned int i; 1370 | for (i = 0; i < outl->numLines; ++i) { 1371 | struct line line = outl->lines[i]; 1372 | struct point origin = outl->points[line.beg]; 1373 | struct point goal = outl->points[line.end]; 1374 | if (origin.y != goal.y) { 1375 | draw_line(buf, origin, goal); 1376 | } 1377 | } 1378 | } 1379 | 1380 | /* Integrate the values in the buffer to arrive at the final grayscale image. */ 1381 | static void 1382 | post_process(struct buffer buf, uint8_t *image) 1383 | { 1384 | struct cell* in, cell; 1385 | uint8_t* out; 1386 | double accum, value; 1387 | int x, y; 1388 | out = image; 1389 | for (y = 0; y < buf.height; ++y) { 1390 | accum = 0.0; 1391 | in = buf.rows[y]; 1392 | for (x = 0; x < buf.width; ++x) { 1393 | cell = *in++; 1394 | value = fabs(accum + cell.area); 1395 | value = MIN(value, 1.0); 1396 | value = value * 255.0 + 0.5; 1397 | *out++ = (uint8_t) value; 1398 | accum += cell.cover; 1399 | } 1400 | } 1401 | } 1402 | 1403 | static int 1404 | render_image(const struct SFT *sft, unsigned long offset, double transform[6], struct SFT_Char *chr) 1405 | { 1406 | struct outline outl; 1407 | struct buffer buf; 1408 | int err = 0; 1409 | 1410 | memset(&outl, 0, sizeof(outl)); 1411 | memset(&buf, 0, sizeof(buf)); 1412 | 1413 | err = err || init_outline(&outl) < 0; 1414 | err = err || decode_outline(sft->font, offset, 0, &outl) < 0; 1415 | if (!err) transform_points(outl.numPoints, outl.points, transform); 1416 | if (!err) clip_points(outl.numPoints, outl.points, chr->width, chr->height); 1417 | err = err || tesselate_curves(&outl) < 0; 1418 | 1419 | err = err || init_buffer(&buf, chr->width, chr->height) < 0; 1420 | if (!err) draw_lines(&outl, buf); 1421 | free_outline(&outl); 1422 | if (!err && sft->flags & SFT_DOWNWARD_Y) 1423 | flip_buffer(&buf); 1424 | 1425 | err = err || (chr->image = (uint8_t*)calloc(chr->width * chr->height, 1)) == NULL; 1426 | if (!err) post_process(buf, (uint8_t*)chr->image); 1427 | 1428 | free_buffer(&buf); 1429 | 1430 | return err ? -1 : 0; 1431 | } 1432 | -------------------------------------------------------------------------------- /src/stb_image_write.h: -------------------------------------------------------------------------------- 1 | /* stb_image_write - v1.14 - public domain - http://nothings.org/stb 2 | writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015 3 | no warranty implied; use at your own risk 4 | Before #including, 5 | #define STB_IMAGE_WRITE_IMPLEMENTATION 6 | in the file that you want to have the implementation. 7 | Will probably not work correctly with strict-aliasing optimizations. 8 | ABOUT: 9 | This header file is a library for writing images to C stdio or a callback. 10 | The PNG output is not optimal; it is 20-50% larger than the file 11 | written by a decent optimizing implementation; though providing a custom 12 | zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that. 13 | This library is designed for source code compactness and simplicity, 14 | not optimal image file size or run-time performance. 15 | BUILDING: 16 | You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h. 17 | You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace 18 | malloc,realloc,free. 19 | You can #define STBIW_MEMMOVE() to replace memmove() 20 | You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function 21 | for PNG compression (instead of the builtin one), it must have the following signature: 22 | unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality); 23 | The returned data will be freed with STBIW_FREE() (free() by default), 24 | so it must be heap allocated with STBIW_MALLOC() (malloc() by default), 25 | UNICODE: 26 | If compiling for Windows and you wish to use Unicode filenames, compile 27 | with 28 | #define STBIW_WINDOWS_UTF8 29 | and pass utf8-encoded filenames. Call stbiw_convert_wchar_to_utf8 to convert 30 | Windows wchar_t filenames to utf8. 31 | USAGE: 32 | There are five functions, one for each image file format: 33 | int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); 34 | int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); 35 | int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); 36 | int stbi_write_jpg(char const *filename, int w, int h, int comp, const void *data, int quality); 37 | int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); 38 | void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically 39 | There are also five equivalent functions that use an arbitrary write function. You are 40 | expected to open/close your file-equivalent before and after calling these: 41 | int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); 42 | int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); 43 | int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); 44 | int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); 45 | int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); 46 | where the callback is: 47 | void stbi_write_func(void *context, void *data, int size); 48 | You can configure it with these global variables: 49 | int stbi_write_tga_with_rle; // defaults to true; set to 0 to disable RLE 50 | int stbi_write_png_compression_level; // defaults to 8; set to higher for more compression 51 | int stbi_write_force_png_filter; // defaults to -1; set to 0..5 to force a filter mode 52 | You can define STBI_WRITE_NO_STDIO to disable the file variant of these 53 | functions, so the library will not use stdio.h at all. However, this will 54 | also disable HDR writing, because it requires stdio for formatted output. 55 | Each function returns 0 on failure and non-0 on success. 56 | The functions create an image file defined by the parameters. The image 57 | is a rectangle of pixels stored from left-to-right, top-to-bottom. 58 | Each pixel contains 'comp' channels of data stored interleaved with 8-bits 59 | per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is 60 | monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall. 61 | The *data pointer points to the first byte of the top-left-most pixel. 62 | For PNG, "stride_in_bytes" is the distance in bytes from the first byte of 63 | a row of pixels to the first byte of the next row of pixels. 64 | PNG creates output files with the same number of components as the input. 65 | The BMP format expands Y to RGB in the file format and does not 66 | output alpha. 67 | PNG supports writing rectangles of data even when the bytes storing rows of 68 | data are not consecutive in memory (e.g. sub-rectangles of a larger image), 69 | by supplying the stride between the beginning of adjacent rows. The other 70 | formats do not. (Thus you cannot write a native-format BMP through the BMP 71 | writer, both because it is in BGR order and because it may have padding 72 | at the end of the line.) 73 | PNG allows you to set the deflate compression level by setting the global 74 | variable 'stbi_write_png_compression_level' (it defaults to 8). 75 | HDR expects linear float data. Since the format is always 32-bit rgb(e) 76 | data, alpha (if provided) is discarded, and for monochrome data it is 77 | replicated across all three channels. 78 | TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed 79 | data, set the global variable 'stbi_write_tga_with_rle' to 0. 80 | JPEG does ignore alpha channels in input data; quality is between 1 and 100. 81 | Higher quality looks better but results in a bigger image. 82 | JPEG baseline (no JPEG progressive). 83 | CREDITS: 84 | Sean Barrett - PNG/BMP/TGA 85 | Baldur Karlsson - HDR 86 | Jean-Sebastien Guay - TGA monochrome 87 | Tim Kelsey - misc enhancements 88 | Alan Hickman - TGA RLE 89 | Emmanuel Julien - initial file IO callback implementation 90 | Jon Olick - original jo_jpeg.cpp code 91 | Daniel Gibson - integrate JPEG, allow external zlib 92 | Aarni Koskela - allow choosing PNG filter 93 | bugfixes: 94 | github:Chribba 95 | Guillaume Chereau 96 | github:jry2 97 | github:romigrou 98 | Sergio Gonzalez 99 | Jonas Karlsson 100 | Filip Wasil 101 | Thatcher Ulrich 102 | github:poppolopoppo 103 | Patrick Boettcher 104 | github:xeekworx 105 | Cap Petschulat 106 | Simon Rodriguez 107 | Ivan Tikhonov 108 | github:ignotion 109 | Adam Schackart 110 | LICENSE 111 | See end of file for license information. 112 | */ 113 | 114 | #ifndef INCLUDE_STB_IMAGE_WRITE_H 115 | #define INCLUDE_STB_IMAGE_WRITE_H 116 | 117 | #include 118 | 119 | // if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline' 120 | #ifndef STBIWDEF 121 | #ifdef STB_IMAGE_WRITE_STATIC 122 | #define STBIWDEF static 123 | #else 124 | #ifdef __cplusplus 125 | #define STBIWDEF extern "C" 126 | #else 127 | #define STBIWDEF extern 128 | #endif 129 | #endif 130 | #endif 131 | 132 | #ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations 133 | extern int stbi_write_tga_with_rle; 134 | extern int stbi_write_png_compression_level; 135 | extern int stbi_write_force_png_filter; 136 | #endif 137 | 138 | #ifndef STBI_WRITE_NO_STDIO 139 | STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); 140 | STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); 141 | STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); 142 | STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); 143 | STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality); 144 | 145 | #ifdef STBI_WINDOWS_UTF8 146 | STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); 147 | #endif 148 | #endif 149 | 150 | typedef void stbi_write_func(void *context, void *data, int size); 151 | 152 | STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); 153 | STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); 154 | STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); 155 | STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); 156 | STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); 157 | 158 | STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean); 159 | 160 | #endif//INCLUDE_STB_IMAGE_WRITE_H 161 | 162 | #ifdef STB_IMAGE_WRITE_IMPLEMENTATION 163 | 164 | #ifdef _WIN32 165 | #ifndef _CRT_SECURE_NO_WARNINGS 166 | #define _CRT_SECURE_NO_WARNINGS 167 | #endif 168 | #ifndef _CRT_NONSTDC_NO_DEPRECATE 169 | #define _CRT_NONSTDC_NO_DEPRECATE 170 | #endif 171 | #endif 172 | 173 | #ifndef STBI_WRITE_NO_STDIO 174 | #include 175 | #endif // STBI_WRITE_NO_STDIO 176 | 177 | #include 178 | #include 179 | #include 180 | #include 181 | 182 | #if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED)) 183 | // ok 184 | #elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED) 185 | // ok 186 | #else 187 | #error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)." 188 | #endif 189 | 190 | #ifndef STBIW_MALLOC 191 | #define STBIW_MALLOC(sz) malloc(sz) 192 | #define STBIW_REALLOC(p,newsz) realloc(p,newsz) 193 | #define STBIW_FREE(p) free(p) 194 | #endif 195 | 196 | #ifndef STBIW_REALLOC_SIZED 197 | #define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz) 198 | #endif 199 | 200 | 201 | #ifndef STBIW_MEMMOVE 202 | #define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz) 203 | #endif 204 | 205 | 206 | #ifndef STBIW_ASSERT 207 | #include 208 | #define STBIW_ASSERT(x) assert(x) 209 | #endif 210 | 211 | #define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) 212 | 213 | #ifdef STB_IMAGE_WRITE_STATIC 214 | static int stbi_write_png_compression_level = 8; 215 | static int stbi_write_tga_with_rle = 1; 216 | static int stbi_write_force_png_filter = -1; 217 | #else 218 | int stbi_write_png_compression_level = 8; 219 | int stbi_write_tga_with_rle = 1; 220 | int stbi_write_force_png_filter = -1; 221 | #endif 222 | 223 | static int stbi__flip_vertically_on_write = 0; 224 | 225 | STBIWDEF void stbi_flip_vertically_on_write(int flag) 226 | { 227 | stbi__flip_vertically_on_write = flag; 228 | } 229 | 230 | typedef struct 231 | { 232 | stbi_write_func *func; 233 | void *context; 234 | } stbi__write_context; 235 | 236 | // initialize a callback-based context 237 | static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context) 238 | { 239 | s->func = c; 240 | s->context = context; 241 | } 242 | 243 | #ifndef STBI_WRITE_NO_STDIO 244 | 245 | static void stbi__stdio_write(void *context, void *data, int size) 246 | { 247 | fwrite(data,1,size,(FILE*) context); 248 | } 249 | 250 | #if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) 251 | #ifdef __cplusplus 252 | #define STBIW_EXTERN extern "C" 253 | #else 254 | #define STBIW_EXTERN extern 255 | #endif 256 | STBIW_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); 257 | STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); 258 | 259 | STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) 260 | { 261 | return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); 262 | } 263 | #endif 264 | 265 | static FILE *stbiw__fopen(char const *filename, char const *mode) 266 | { 267 | FILE *f; 268 | #if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) 269 | wchar_t wMode[64]; 270 | wchar_t wFilename[1024]; 271 | if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) 272 | return 0; 273 | 274 | if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) 275 | return 0; 276 | 277 | #if _MSC_VER >= 1400 278 | if (0 != _wfopen_s(&f, wFilename, wMode)) 279 | f = 0; 280 | #else 281 | f = _wfopen(wFilename, wMode); 282 | #endif 283 | 284 | #elif defined(_MSC_VER) && _MSC_VER >= 1400 285 | if (0 != fopen_s(&f, filename, mode)) 286 | f=0; 287 | #else 288 | f = fopen(filename, mode); 289 | #endif 290 | return f; 291 | } 292 | 293 | static int stbi__start_write_file(stbi__write_context *s, const char *filename) 294 | { 295 | FILE *f = stbiw__fopen(filename, "wb"); 296 | stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f); 297 | return f != NULL; 298 | } 299 | 300 | static void stbi__end_write_file(stbi__write_context *s) 301 | { 302 | fclose((FILE *)s->context); 303 | } 304 | 305 | #endif // !STBI_WRITE_NO_STDIO 306 | 307 | typedef unsigned int stbiw_uint32; 308 | typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1]; 309 | 310 | static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) 311 | { 312 | while (*fmt) { 313 | switch (*fmt++) { 314 | case ' ': break; 315 | case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int)); 316 | s->func(s->context,&x,1); 317 | break; } 318 | case '2': { int x = va_arg(v,int); 319 | unsigned char b[2]; 320 | b[0] = STBIW_UCHAR(x); 321 | b[1] = STBIW_UCHAR(x>>8); 322 | s->func(s->context,b,2); 323 | break; } 324 | case '4': { stbiw_uint32 x = va_arg(v,int); 325 | unsigned char b[4]; 326 | b[0]=STBIW_UCHAR(x); 327 | b[1]=STBIW_UCHAR(x>>8); 328 | b[2]=STBIW_UCHAR(x>>16); 329 | b[3]=STBIW_UCHAR(x>>24); 330 | s->func(s->context,b,4); 331 | break; } 332 | default: 333 | STBIW_ASSERT(0); 334 | return; 335 | } 336 | } 337 | } 338 | 339 | static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) 340 | { 341 | va_list v; 342 | va_start(v, fmt); 343 | stbiw__writefv(s, fmt, v); 344 | va_end(v); 345 | } 346 | 347 | static void stbiw__putc(stbi__write_context *s, unsigned char c) 348 | { 349 | s->func(s->context, &c, 1); 350 | } 351 | 352 | static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) 353 | { 354 | unsigned char arr[3]; 355 | arr[0] = a; arr[1] = b; arr[2] = c; 356 | s->func(s->context, arr, 3); 357 | } 358 | 359 | static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d) 360 | { 361 | unsigned char bg[3] = { 255, 0, 255}, px[3]; 362 | int k; 363 | 364 | if (write_alpha < 0) 365 | s->func(s->context, &d[comp - 1], 1); 366 | 367 | switch (comp) { 368 | case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case 369 | case 1: 370 | if (expand_mono) 371 | stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp 372 | else 373 | s->func(s->context, d, 1); // monochrome TGA 374 | break; 375 | case 4: 376 | if (!write_alpha) { 377 | // composite against pink background 378 | for (k = 0; k < 3; ++k) 379 | px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255; 380 | stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]); 381 | break; 382 | } 383 | /* FALLTHROUGH */ 384 | case 3: 385 | stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]); 386 | break; 387 | } 388 | if (write_alpha > 0) 389 | s->func(s->context, &d[comp - 1], 1); 390 | } 391 | 392 | static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono) 393 | { 394 | stbiw_uint32 zero = 0; 395 | int i,j, j_end; 396 | 397 | if (y <= 0) 398 | return; 399 | 400 | if (stbi__flip_vertically_on_write) 401 | vdir *= -1; 402 | 403 | if (vdir < 0) { 404 | j_end = -1; j = y-1; 405 | } else { 406 | j_end = y; j = 0; 407 | } 408 | 409 | for (; j != j_end; j += vdir) { 410 | for (i=0; i < x; ++i) { 411 | unsigned char *d = (unsigned char *) data + (j*x+i)*comp; 412 | stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); 413 | } 414 | s->func(s->context, &zero, scanline_pad); 415 | } 416 | } 417 | 418 | static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...) 419 | { 420 | if (y < 0 || x < 0) { 421 | return 0; 422 | } else { 423 | va_list v; 424 | va_start(v, fmt); 425 | stbiw__writefv(s, fmt, v); 426 | va_end(v); 427 | stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono); 428 | return 1; 429 | } 430 | } 431 | 432 | static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) 433 | { 434 | int pad = (-x*3) & 3; 435 | return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, 436 | "11 4 22 4" "4 44 22 444444", 437 | 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header 438 | 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header 439 | } 440 | 441 | STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) 442 | { 443 | stbi__write_context s; 444 | stbi__start_write_callbacks(&s, func, context); 445 | return stbi_write_bmp_core(&s, x, y, comp, data); 446 | } 447 | 448 | #ifndef STBI_WRITE_NO_STDIO 449 | STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) 450 | { 451 | stbi__write_context s; 452 | if (stbi__start_write_file(&s,filename)) { 453 | int r = stbi_write_bmp_core(&s, x, y, comp, data); 454 | stbi__end_write_file(&s); 455 | return r; 456 | } else 457 | return 0; 458 | } 459 | #endif //!STBI_WRITE_NO_STDIO 460 | 461 | static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data) 462 | { 463 | int has_alpha = (comp == 2 || comp == 4); 464 | int colorbytes = has_alpha ? comp-1 : comp; 465 | int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3 466 | 467 | if (y < 0 || x < 0) 468 | return 0; 469 | 470 | if (!stbi_write_tga_with_rle) { 471 | return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0, 472 | "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); 473 | } else { 474 | int i,j,k; 475 | int jend, jdir; 476 | 477 | stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8); 478 | 479 | if (stbi__flip_vertically_on_write) { 480 | j = 0; 481 | jend = y; 482 | jdir = 1; 483 | } else { 484 | j = y-1; 485 | jend = -1; 486 | jdir = -1; 487 | } 488 | for (; j != jend; j += jdir) { 489 | unsigned char *row = (unsigned char *) data + j * x * comp; 490 | int len; 491 | 492 | for (i = 0; i < x; i += len) { 493 | unsigned char *begin = row + i * comp; 494 | int diff = 1; 495 | len = 1; 496 | 497 | if (i < x - 1) { 498 | ++len; 499 | diff = memcmp(begin, row + (i + 1) * comp, comp); 500 | if (diff) { 501 | const unsigned char *prev = begin; 502 | for (k = i + 2; k < x && len < 128; ++k) { 503 | if (memcmp(prev, row + k * comp, comp)) { 504 | prev += comp; 505 | ++len; 506 | } else { 507 | --len; 508 | break; 509 | } 510 | } 511 | } else { 512 | for (k = i + 2; k < x && len < 128; ++k) { 513 | if (!memcmp(begin, row + k * comp, comp)) { 514 | ++len; 515 | } else { 516 | break; 517 | } 518 | } 519 | } 520 | } 521 | 522 | if (diff) { 523 | unsigned char header = STBIW_UCHAR(len - 1); 524 | s->func(s->context, &header, 1); 525 | for (k = 0; k < len; ++k) { 526 | stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); 527 | } 528 | } else { 529 | unsigned char header = STBIW_UCHAR(len - 129); 530 | s->func(s->context, &header, 1); 531 | stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); 532 | } 533 | } 534 | } 535 | } 536 | return 1; 537 | } 538 | 539 | STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) 540 | { 541 | stbi__write_context s; 542 | stbi__start_write_callbacks(&s, func, context); 543 | return stbi_write_tga_core(&s, x, y, comp, (void *) data); 544 | } 545 | 546 | #ifndef STBI_WRITE_NO_STDIO 547 | STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) 548 | { 549 | stbi__write_context s; 550 | if (stbi__start_write_file(&s,filename)) { 551 | int r = stbi_write_tga_core(&s, x, y, comp, (void *) data); 552 | stbi__end_write_file(&s); 553 | return r; 554 | } else 555 | return 0; 556 | } 557 | #endif 558 | 559 | // ************************************************************************************************* 560 | // Radiance RGBE HDR writer 561 | // by Baldur Karlsson 562 | 563 | #define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) 564 | 565 | static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) 566 | { 567 | int exponent; 568 | float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); 569 | 570 | if (maxcomp < 1e-32f) { 571 | rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; 572 | } else { 573 | float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp; 574 | 575 | rgbe[0] = (unsigned char)(linear[0] * normalize); 576 | rgbe[1] = (unsigned char)(linear[1] * normalize); 577 | rgbe[2] = (unsigned char)(linear[2] * normalize); 578 | rgbe[3] = (unsigned char)(exponent + 128); 579 | } 580 | } 581 | 582 | static void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) 583 | { 584 | unsigned char lengthbyte = STBIW_UCHAR(length+128); 585 | STBIW_ASSERT(length+128 <= 255); 586 | s->func(s->context, &lengthbyte, 1); 587 | s->func(s->context, &databyte, 1); 588 | } 589 | 590 | static void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) 591 | { 592 | unsigned char lengthbyte = STBIW_UCHAR(length); 593 | STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code 594 | s->func(s->context, &lengthbyte, 1); 595 | s->func(s->context, data, length); 596 | } 597 | 598 | static void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline) 599 | { 600 | unsigned char scanlineheader[4] = { 2, 2, 0, 0 }; 601 | unsigned char rgbe[4]; 602 | float linear[3]; 603 | int x; 604 | 605 | scanlineheader[2] = (width&0xff00)>>8; 606 | scanlineheader[3] = (width&0x00ff); 607 | 608 | /* skip RLE for images too small or large */ 609 | if (width < 8 || width >= 32768) { 610 | for (x=0; x < width; x++) { 611 | switch (ncomp) { 612 | case 4: /* fallthrough */ 613 | case 3: linear[2] = scanline[x*ncomp + 2]; 614 | linear[1] = scanline[x*ncomp + 1]; 615 | linear[0] = scanline[x*ncomp + 0]; 616 | break; 617 | default: 618 | linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; 619 | break; 620 | } 621 | stbiw__linear_to_rgbe(rgbe, linear); 622 | s->func(s->context, rgbe, 4); 623 | } 624 | } else { 625 | int c,r; 626 | /* encode into scratch buffer */ 627 | for (x=0; x < width; x++) { 628 | switch(ncomp) { 629 | case 4: /* fallthrough */ 630 | case 3: linear[2] = scanline[x*ncomp + 2]; 631 | linear[1] = scanline[x*ncomp + 1]; 632 | linear[0] = scanline[x*ncomp + 0]; 633 | break; 634 | default: 635 | linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; 636 | break; 637 | } 638 | stbiw__linear_to_rgbe(rgbe, linear); 639 | scratch[x + width*0] = rgbe[0]; 640 | scratch[x + width*1] = rgbe[1]; 641 | scratch[x + width*2] = rgbe[2]; 642 | scratch[x + width*3] = rgbe[3]; 643 | } 644 | 645 | s->func(s->context, scanlineheader, 4); 646 | 647 | /* RLE each component separately */ 648 | for (c=0; c < 4; c++) { 649 | unsigned char *comp = &scratch[width*c]; 650 | 651 | x = 0; 652 | while (x < width) { 653 | // find first run 654 | r = x; 655 | while (r+2 < width) { 656 | if (comp[r] == comp[r+1] && comp[r] == comp[r+2]) 657 | break; 658 | ++r; 659 | } 660 | if (r+2 >= width) 661 | r = width; 662 | // dump up to first run 663 | while (x < r) { 664 | int len = r-x; 665 | if (len > 128) len = 128; 666 | stbiw__write_dump_data(s, len, &comp[x]); 667 | x += len; 668 | } 669 | // if there's a run, output it 670 | if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd 671 | // find next byte after run 672 | while (r < width && comp[r] == comp[x]) 673 | ++r; 674 | // output run up to r 675 | while (x < r) { 676 | int len = r-x; 677 | if (len > 127) len = 127; 678 | stbiw__write_run_data(s, len, comp[x]); 679 | x += len; 680 | } 681 | } 682 | } 683 | } 684 | } 685 | } 686 | 687 | static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data) 688 | { 689 | if (y <= 0 || x <= 0 || data == NULL) 690 | return 0; 691 | else { 692 | // Each component is stored separately. Allocate scratch space for full output scanline. 693 | unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4); 694 | int i, len; 695 | char buffer[128]; 696 | char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; 697 | s->func(s->context, header, sizeof(header)-1); 698 | 699 | #ifdef __STDC_WANT_SECURE_LIB__ 700 | len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); 701 | #else 702 | len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); 703 | #endif 704 | s->func(s->context, buffer, len); 705 | 706 | for(i=0; i < y; i++) 707 | stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i)); 708 | STBIW_FREE(scratch); 709 | return 1; 710 | } 711 | } 712 | 713 | STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) 714 | { 715 | stbi__write_context s; 716 | stbi__start_write_callbacks(&s, func, context); 717 | return stbi_write_hdr_core(&s, x, y, comp, (float *) data); 718 | } 719 | 720 | #ifndef STBI_WRITE_NO_STDIO 721 | STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) 722 | { 723 | stbi__write_context s; 724 | if (stbi__start_write_file(&s,filename)) { 725 | int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data); 726 | stbi__end_write_file(&s); 727 | return r; 728 | } else 729 | return 0; 730 | } 731 | #endif // STBI_WRITE_NO_STDIO 732 | 733 | 734 | ////////////////////////////////////////////////////////////////////////////// 735 | // 736 | // PNG writer 737 | // 738 | 739 | #ifndef STBIW_ZLIB_COMPRESS 740 | // stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() 741 | #define stbiw__sbraw(a) ((int *) (void *) (a) - 2) 742 | #define stbiw__sbm(a) stbiw__sbraw(a)[0] 743 | #define stbiw__sbn(a) stbiw__sbraw(a)[1] 744 | 745 | #define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a)) 746 | #define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0) 747 | #define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a))) 748 | 749 | #define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v)) 750 | #define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0) 751 | #define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0) 752 | 753 | static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) 754 | { 755 | int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1; 756 | void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2); 757 | STBIW_ASSERT(p); 758 | if (p) { 759 | if (!*arr) ((int *) p)[1] = 0; 760 | *arr = (void *) ((int *) p + 2); 761 | stbiw__sbm(*arr) = m; 762 | } 763 | return *arr; 764 | } 765 | 766 | static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) 767 | { 768 | while (*bitcount >= 8) { 769 | stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer)); 770 | *bitbuffer >>= 8; 771 | *bitcount -= 8; 772 | } 773 | return data; 774 | } 775 | 776 | static int stbiw__zlib_bitrev(int code, int codebits) 777 | { 778 | int res=0; 779 | while (codebits--) { 780 | res = (res << 1) | (code & 1); 781 | code >>= 1; 782 | } 783 | return res; 784 | } 785 | 786 | static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit) 787 | { 788 | int i; 789 | for (i=0; i < limit && i < 258; ++i) 790 | if (a[i] != b[i]) break; 791 | return i; 792 | } 793 | 794 | static unsigned int stbiw__zhash(unsigned char *data) 795 | { 796 | stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); 797 | hash ^= hash << 3; 798 | hash += hash >> 5; 799 | hash ^= hash << 4; 800 | hash += hash >> 17; 801 | hash ^= hash << 25; 802 | hash += hash >> 6; 803 | return hash; 804 | } 805 | 806 | #define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount)) 807 | #define stbiw__zlib_add(code,codebits) \ 808 | (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush()) 809 | #define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c) 810 | // default huffman tables 811 | #define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8) 812 | #define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9) 813 | #define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7) 814 | #define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8) 815 | #define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n)) 816 | #define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n)) 817 | 818 | #define stbiw__ZHASH 16384 819 | 820 | #endif // STBIW_ZLIB_COMPRESS 821 | 822 | STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) 823 | { 824 | #ifdef STBIW_ZLIB_COMPRESS 825 | // user provided a zlib compress implementation, use that 826 | return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality); 827 | #else // use builtin 828 | static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; 829 | static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; 830 | static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; 831 | static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 }; 832 | unsigned int bitbuf=0; 833 | int i,j, bitcount=0; 834 | unsigned char *out = NULL; 835 | unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char**)); 836 | if (hash_table == NULL) 837 | return NULL; 838 | if (quality < 5) quality = 5; 839 | 840 | stbiw__sbpush(out, 0x78); // DEFLATE 32K window 841 | stbiw__sbpush(out, 0x5e); // FLEVEL = 1 842 | stbiw__zlib_add(1,1); // BFINAL = 1 843 | stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman 844 | 845 | for (i=0; i < stbiw__ZHASH; ++i) 846 | hash_table[i] = NULL; 847 | 848 | i=0; 849 | while (i < data_len-3) { 850 | // hash next 3 bytes of data to be compressed 851 | int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3; 852 | unsigned char *bestloc = 0; 853 | unsigned char **hlist = hash_table[h]; 854 | int n = stbiw__sbcount(hlist); 855 | for (j=0; j < n; ++j) { 856 | if (hlist[j]-data > i-32768) { // if entry lies within window 857 | int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); 858 | if (d >= best) { best=d; bestloc=hlist[j]; } 859 | } 860 | } 861 | // when hash table entry is too long, delete half the entries 862 | if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) { 863 | STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality); 864 | stbiw__sbn(hash_table[h]) = quality; 865 | } 866 | stbiw__sbpush(hash_table[h],data+i); 867 | 868 | if (bestloc) { 869 | // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal 870 | h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1); 871 | hlist = hash_table[h]; 872 | n = stbiw__sbcount(hlist); 873 | for (j=0; j < n; ++j) { 874 | if (hlist[j]-data > i-32767) { 875 | int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1); 876 | if (e > best) { // if next match is better, bail on current match 877 | bestloc = NULL; 878 | break; 879 | } 880 | } 881 | } 882 | } 883 | 884 | if (bestloc) { 885 | int d = (int) (data+i - bestloc); // distance back 886 | STBIW_ASSERT(d <= 32767 && best <= 258); 887 | for (j=0; best > lengthc[j+1]-1; ++j); 888 | stbiw__zlib_huff(j+257); 889 | if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]); 890 | for (j=0; d > distc[j+1]-1; ++j); 891 | stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5); 892 | if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]); 893 | i += best; 894 | } else { 895 | stbiw__zlib_huffb(data[i]); 896 | ++i; 897 | } 898 | } 899 | // write out final bytes 900 | for (;i < data_len; ++i) 901 | stbiw__zlib_huffb(data[i]); 902 | stbiw__zlib_huff(256); // end of block 903 | // pad with 0 bits to byte boundary 904 | while (bitcount) 905 | stbiw__zlib_add(0,1); 906 | 907 | for (i=0; i < stbiw__ZHASH; ++i) 908 | (void) stbiw__sbfree(hash_table[i]); 909 | STBIW_FREE(hash_table); 910 | 911 | { 912 | // compute adler32 on input 913 | unsigned int s1=1, s2=0; 914 | int blocklen = (int) (data_len % 5552); 915 | j=0; 916 | while (j < data_len) { 917 | for (i=0; i < blocklen; ++i) { s1 += data[j+i]; s2 += s1; } 918 | s1 %= 65521; s2 %= 65521; 919 | j += blocklen; 920 | blocklen = 5552; 921 | } 922 | stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8)); 923 | stbiw__sbpush(out, STBIW_UCHAR(s2)); 924 | stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8)); 925 | stbiw__sbpush(out, STBIW_UCHAR(s1)); 926 | } 927 | *out_len = stbiw__sbn(out); 928 | // make returned pointer freeable 929 | STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); 930 | return (unsigned char *) stbiw__sbraw(out); 931 | #endif // STBIW_ZLIB_COMPRESS 932 | } 933 | 934 | static unsigned int stbiw__crc32(unsigned char *buffer, int len) 935 | { 936 | #ifdef STBIW_CRC32 937 | return STBIW_CRC32(buffer, len); 938 | #else 939 | static unsigned int crc_table[256] = 940 | { 941 | 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 942 | 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 943 | 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 944 | 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 945 | 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 946 | 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 947 | 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 948 | 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 949 | 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 950 | 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 951 | 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 952 | 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 953 | 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 954 | 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 955 | 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 956 | 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 957 | 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 958 | 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 959 | 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 960 | 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 961 | 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 962 | 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 963 | 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 964 | 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 965 | 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 966 | 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 967 | 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 968 | 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 969 | 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 970 | 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 971 | 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 972 | 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D 973 | }; 974 | 975 | unsigned int crc = ~0u; 976 | int i; 977 | for (i=0; i < len; ++i) 978 | crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; 979 | return ~crc; 980 | #endif 981 | } 982 | 983 | #define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4) 984 | #define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v)); 985 | #define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3]) 986 | 987 | static void stbiw__wpcrc(unsigned char **data, int len) 988 | { 989 | unsigned int crc = stbiw__crc32(*data - len - 4, len+4); 990 | stbiw__wp32(*data, crc); 991 | } 992 | 993 | static unsigned char stbiw__paeth(int a, int b, int c) 994 | { 995 | int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c); 996 | if (pa <= pb && pa <= pc) return STBIW_UCHAR(a); 997 | if (pb <= pc) return STBIW_UCHAR(b); 998 | return STBIW_UCHAR(c); 999 | } 1000 | 1001 | // @OPTIMIZE: provide an option that always forces left-predict or paeth predict 1002 | static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, signed char *line_buffer) 1003 | { 1004 | static int mapping[] = { 0,1,2,3,4 }; 1005 | static int firstmap[] = { 0,1,0,5,6 }; 1006 | int *mymap = (y != 0) ? mapping : firstmap; 1007 | int i; 1008 | int type = mymap[filter_type]; 1009 | unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y); 1010 | int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes; 1011 | 1012 | if (type==0) { 1013 | memcpy(line_buffer, z, width*n); 1014 | return; 1015 | } 1016 | 1017 | // first loop isn't optimized since it's just one pixel 1018 | for (i = 0; i < n; ++i) { 1019 | switch (type) { 1020 | case 1: line_buffer[i] = z[i]; break; 1021 | case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break; 1022 | case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break; 1023 | case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break; 1024 | case 5: line_buffer[i] = z[i]; break; 1025 | case 6: line_buffer[i] = z[i]; break; 1026 | } 1027 | } 1028 | switch (type) { 1029 | case 1: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-n]; break; 1030 | case 2: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-signed_stride]; break; 1031 | case 3: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break; 1032 | case 4: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break; 1033 | case 5: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - (z[i-n]>>1); break; 1034 | case 6: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; 1035 | } 1036 | } 1037 | 1038 | STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) 1039 | { 1040 | int force_filter = stbi_write_force_png_filter; 1041 | int ctype[5] = { -1, 0, 4, 2, 6 }; 1042 | unsigned char sig[8] = { 137,80,78,71,13,10,26,10 }; 1043 | unsigned char *out,*o, *filt, *zlib; 1044 | signed char *line_buffer; 1045 | int j,zlen; 1046 | 1047 | if (stride_bytes == 0) 1048 | stride_bytes = x * n; 1049 | 1050 | if (force_filter >= 5) { 1051 | force_filter = -1; 1052 | } 1053 | 1054 | filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0; 1055 | line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; } 1056 | for (j=0; j < y; ++j) { 1057 | int filter_type; 1058 | if (force_filter > -1) { 1059 | filter_type = force_filter; 1060 | stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer); 1061 | } else { // Estimate the best filter by running through all of them: 1062 | int best_filter = 0, best_filter_val = 0x7fffffff, est, i; 1063 | for (filter_type = 0; filter_type < 5; filter_type++) { 1064 | stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer); 1065 | 1066 | // Estimate the entropy of the line using this filter; the less, the better. 1067 | est = 0; 1068 | for (i = 0; i < x*n; ++i) { 1069 | est += abs((signed char) line_buffer[i]); 1070 | } 1071 | if (est < best_filter_val) { 1072 | best_filter_val = est; 1073 | best_filter = filter_type; 1074 | } 1075 | } 1076 | if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it 1077 | stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer); 1078 | filter_type = best_filter; 1079 | } 1080 | } 1081 | // when we get here, filter_type contains the filter type, and line_buffer contains the data 1082 | filt[j*(x*n+1)] = (unsigned char) filter_type; 1083 | STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); 1084 | } 1085 | STBIW_FREE(line_buffer); 1086 | zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level); 1087 | STBIW_FREE(filt); 1088 | if (!zlib) return 0; 1089 | 1090 | // each tag requires 12 bytes of overhead 1091 | out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12); 1092 | if (!out) return 0; 1093 | *out_len = 8 + 12+13 + 12+zlen + 12; 1094 | 1095 | o=out; 1096 | STBIW_MEMMOVE(o,sig,8); o+= 8; 1097 | stbiw__wp32(o, 13); // header length 1098 | stbiw__wptag(o, "IHDR"); 1099 | stbiw__wp32(o, x); 1100 | stbiw__wp32(o, y); 1101 | *o++ = 8; 1102 | *o++ = STBIW_UCHAR(ctype[n]); 1103 | *o++ = 0; 1104 | *o++ = 0; 1105 | *o++ = 0; 1106 | stbiw__wpcrc(&o,13); 1107 | 1108 | stbiw__wp32(o, zlen); 1109 | stbiw__wptag(o, "IDAT"); 1110 | STBIW_MEMMOVE(o, zlib, zlen); 1111 | o += zlen; 1112 | STBIW_FREE(zlib); 1113 | stbiw__wpcrc(&o, zlen); 1114 | 1115 | stbiw__wp32(o,0); 1116 | stbiw__wptag(o, "IEND"); 1117 | stbiw__wpcrc(&o,0); 1118 | 1119 | STBIW_ASSERT(o == out + *out_len); 1120 | 1121 | return out; 1122 | } 1123 | 1124 | #ifndef STBI_WRITE_NO_STDIO 1125 | STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) 1126 | { 1127 | FILE *f; 1128 | int len; 1129 | unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); 1130 | if (png == NULL) return 0; 1131 | 1132 | f = stbiw__fopen(filename, "wb"); 1133 | if (!f) { STBIW_FREE(png); return 0; } 1134 | fwrite(png, 1, len, f); 1135 | fclose(f); 1136 | STBIW_FREE(png); 1137 | return 1; 1138 | } 1139 | #endif 1140 | 1141 | STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes) 1142 | { 1143 | int len; 1144 | unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); 1145 | if (png == NULL) return 0; 1146 | func(context, png, len); 1147 | STBIW_FREE(png); 1148 | return 1; 1149 | } 1150 | 1151 | 1152 | /* *************************************************************************** 1153 | * 1154 | * JPEG writer 1155 | * 1156 | * This is based on Jon Olick's jo_jpeg.cpp: 1157 | * public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html 1158 | */ 1159 | 1160 | static const unsigned char stbiw__jpg_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18, 1161 | 24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 }; 1162 | 1163 | static void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) { 1164 | int bitBuf = *bitBufP, bitCnt = *bitCntP; 1165 | bitCnt += bs[1]; 1166 | bitBuf |= bs[0] << (24 - bitCnt); 1167 | while(bitCnt >= 8) { 1168 | unsigned char c = (bitBuf >> 16) & 255; 1169 | stbiw__putc(s, c); 1170 | if(c == 255) { 1171 | stbiw__putc(s, 0); 1172 | } 1173 | bitBuf <<= 8; 1174 | bitCnt -= 8; 1175 | } 1176 | *bitBufP = bitBuf; 1177 | *bitCntP = bitCnt; 1178 | } 1179 | 1180 | static void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) { 1181 | float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p; 1182 | float z1, z2, z3, z4, z5, z11, z13; 1183 | 1184 | float tmp0 = d0 + d7; 1185 | float tmp7 = d0 - d7; 1186 | float tmp1 = d1 + d6; 1187 | float tmp6 = d1 - d6; 1188 | float tmp2 = d2 + d5; 1189 | float tmp5 = d2 - d5; 1190 | float tmp3 = d3 + d4; 1191 | float tmp4 = d3 - d4; 1192 | 1193 | // Even part 1194 | float tmp10 = tmp0 + tmp3; // phase 2 1195 | float tmp13 = tmp0 - tmp3; 1196 | float tmp11 = tmp1 + tmp2; 1197 | float tmp12 = tmp1 - tmp2; 1198 | 1199 | d0 = tmp10 + tmp11; // phase 3 1200 | d4 = tmp10 - tmp11; 1201 | 1202 | z1 = (tmp12 + tmp13) * 0.707106781f; // c4 1203 | d2 = tmp13 + z1; // phase 5 1204 | d6 = tmp13 - z1; 1205 | 1206 | // Odd part 1207 | tmp10 = tmp4 + tmp5; // phase 2 1208 | tmp11 = tmp5 + tmp6; 1209 | tmp12 = tmp6 + tmp7; 1210 | 1211 | // The rotator is modified from fig 4-8 to avoid extra negations. 1212 | z5 = (tmp10 - tmp12) * 0.382683433f; // c6 1213 | z2 = tmp10 * 0.541196100f + z5; // c2-c6 1214 | z4 = tmp12 * 1.306562965f + z5; // c2+c6 1215 | z3 = tmp11 * 0.707106781f; // c4 1216 | 1217 | z11 = tmp7 + z3; // phase 5 1218 | z13 = tmp7 - z3; 1219 | 1220 | *d5p = z13 + z2; // phase 6 1221 | *d3p = z13 - z2; 1222 | *d1p = z11 + z4; 1223 | *d7p = z11 - z4; 1224 | 1225 | *d0p = d0; *d2p = d2; *d4p = d4; *d6p = d6; 1226 | } 1227 | 1228 | static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) { 1229 | int tmp1 = val < 0 ? -val : val; 1230 | val = val < 0 ? val-1 : val; 1231 | bits[1] = 1; 1232 | while(tmp1 >>= 1) { 1233 | ++bits[1]; 1234 | } 1235 | bits[0] = val & ((1<0)&&(DU[end0pos]==0); --end0pos) { 1278 | } 1279 | // end0pos = first element in reverse order !=0 1280 | if(end0pos == 0) { 1281 | stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); 1282 | return DU[0]; 1283 | } 1284 | for(i = 1; i <= end0pos; ++i) { 1285 | int startpos = i; 1286 | int nrzeroes; 1287 | unsigned short bits[2]; 1288 | for (; DU[i]==0 && i<=end0pos; ++i) { 1289 | } 1290 | nrzeroes = i-startpos; 1291 | if ( nrzeroes >= 16 ) { 1292 | int lng = nrzeroes>>4; 1293 | int nrmarker; 1294 | for (nrmarker=1; nrmarker <= lng; ++nrmarker) 1295 | stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes); 1296 | nrzeroes &= 15; 1297 | } 1298 | stbiw__jpg_calcBits(DU[i], bits); 1299 | stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]]); 1300 | stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits); 1301 | } 1302 | if(end0pos != 63) { 1303 | stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); 1304 | } 1305 | return DU[0]; 1306 | } 1307 | 1308 | static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) { 1309 | // Constants that don't pollute global namespace 1310 | static const unsigned char std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0}; 1311 | static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; 1312 | static const unsigned char std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d}; 1313 | static const unsigned char std_ac_luminance_values[] = { 1314 | 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08, 1315 | 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28, 1316 | 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59, 1317 | 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89, 1318 | 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6, 1319 | 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2, 1320 | 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa 1321 | }; 1322 | static const unsigned char std_dc_chrominance_nrcodes[] = {0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0}; 1323 | static const unsigned char std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; 1324 | static const unsigned char std_ac_chrominance_nrcodes[] = {0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77}; 1325 | static const unsigned char std_ac_chrominance_values[] = { 1326 | 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91, 1327 | 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26, 1328 | 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58, 1329 | 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87, 1330 | 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4, 1331 | 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda, 1332 | 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa 1333 | }; 1334 | // Huffman tables 1335 | static const unsigned short YDC_HT[256][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}}; 1336 | static const unsigned short UVDC_HT[256][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}}; 1337 | static const unsigned short YAC_HT[256][2] = { 1338 | {10,4},{0,2},{1,2},{4,3},{11,4},{26,5},{120,7},{248,8},{1014,10},{65410,16},{65411,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1339 | {12,4},{27,5},{121,7},{502,9},{2038,11},{65412,16},{65413,16},{65414,16},{65415,16},{65416,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1340 | {28,5},{249,8},{1015,10},{4084,12},{65417,16},{65418,16},{65419,16},{65420,16},{65421,16},{65422,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1341 | {58,6},{503,9},{4085,12},{65423,16},{65424,16},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1342 | {59,6},{1016,10},{65430,16},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1343 | {122,7},{2039,11},{65438,16},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1344 | {123,7},{4086,12},{65446,16},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1345 | {250,8},{4087,12},{65454,16},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1346 | {504,9},{32704,15},{65462,16},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1347 | {505,9},{65470,16},{65471,16},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1348 | {506,9},{65479,16},{65480,16},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1349 | {1017,10},{65488,16},{65489,16},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1350 | {1018,10},{65497,16},{65498,16},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1351 | {2040,11},{65506,16},{65507,16},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1352 | {65515,16},{65516,16},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{0,0},{0,0},{0,0},{0,0},{0,0}, 1353 | {2041,11},{65525,16},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} 1354 | }; 1355 | static const unsigned short UVAC_HT[256][2] = { 1356 | {0,2},{1,2},{4,3},{10,4},{24,5},{25,5},{56,6},{120,7},{500,9},{1014,10},{4084,12},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1357 | {11,4},{57,6},{246,8},{501,9},{2038,11},{4085,12},{65416,16},{65417,16},{65418,16},{65419,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1358 | {26,5},{247,8},{1015,10},{4086,12},{32706,15},{65420,16},{65421,16},{65422,16},{65423,16},{65424,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1359 | {27,5},{248,8},{1016,10},{4087,12},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{65430,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1360 | {58,6},{502,9},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{65438,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1361 | {59,6},{1017,10},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{65446,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1362 | {121,7},{2039,11},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{65454,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1363 | {122,7},{2040,11},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{65462,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1364 | {249,8},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{65470,16},{65471,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1365 | {503,9},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{65479,16},{65480,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1366 | {504,9},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{65488,16},{65489,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1367 | {505,9},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{65497,16},{65498,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1368 | {506,9},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{65506,16},{65507,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1369 | {2041,11},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{65515,16},{65516,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1370 | {16352,14},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{65525,16},{0,0},{0,0},{0,0},{0,0},{0,0}, 1371 | {1018,10},{32707,15},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} 1372 | }; 1373 | static const int YQT[] = {16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22, 1374 | 37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99}; 1375 | static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99, 1376 | 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99}; 1377 | static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f, 1378 | 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f }; 1379 | 1380 | int row, col, i, k, subsample; 1381 | float fdtbl_Y[64], fdtbl_UV[64]; 1382 | unsigned char YTable[64], UVTable[64]; 1383 | 1384 | if(!data || !width || !height || comp > 4 || comp < 1) { 1385 | return 0; 1386 | } 1387 | 1388 | quality = quality ? quality : 90; 1389 | subsample = quality <= 90 ? 1 : 0; 1390 | quality = quality < 1 ? 1 : quality > 100 ? 100 : quality; 1391 | quality = quality < 50 ? 5000 / quality : 200 - quality * 2; 1392 | 1393 | for(i = 0; i < 64; ++i) { 1394 | int uvti, yti = (YQT[i]*quality+50)/100; 1395 | YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti); 1396 | uvti = (UVQT[i]*quality+50)/100; 1397 | UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti); 1398 | } 1399 | 1400 | for(row = 0, k = 0; row < 8; ++row) { 1401 | for(col = 0; col < 8; ++col, ++k) { 1402 | fdtbl_Y[k] = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); 1403 | fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); 1404 | } 1405 | } 1406 | 1407 | // Write Headers 1408 | { 1409 | static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 }; 1410 | static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 }; 1411 | const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width), 1412 | 3,1,(unsigned char)(subsample?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 }; 1413 | s->func(s->context, (void*)head0, sizeof(head0)); 1414 | s->func(s->context, (void*)YTable, sizeof(YTable)); 1415 | stbiw__putc(s, 1); 1416 | s->func(s->context, UVTable, sizeof(UVTable)); 1417 | s->func(s->context, (void*)head1, sizeof(head1)); 1418 | s->func(s->context, (void*)(std_dc_luminance_nrcodes+1), sizeof(std_dc_luminance_nrcodes)-1); 1419 | s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values)); 1420 | stbiw__putc(s, 0x10); // HTYACinfo 1421 | s->func(s->context, (void*)(std_ac_luminance_nrcodes+1), sizeof(std_ac_luminance_nrcodes)-1); 1422 | s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values)); 1423 | stbiw__putc(s, 1); // HTUDCinfo 1424 | s->func(s->context, (void*)(std_dc_chrominance_nrcodes+1), sizeof(std_dc_chrominance_nrcodes)-1); 1425 | s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values)); 1426 | stbiw__putc(s, 0x11); // HTUACinfo 1427 | s->func(s->context, (void*)(std_ac_chrominance_nrcodes+1), sizeof(std_ac_chrominance_nrcodes)-1); 1428 | s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values)); 1429 | s->func(s->context, (void*)head2, sizeof(head2)); 1430 | } 1431 | 1432 | // Encode 8x8 macroblocks 1433 | { 1434 | static const unsigned short fillBits[] = {0x7F, 7}; 1435 | int DCY=0, DCU=0, DCV=0; 1436 | int bitBuf=0, bitCnt=0; 1437 | // comp == 2 is grey+alpha (alpha is ignored) 1438 | int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0; 1439 | const unsigned char *dataR = (const unsigned char *)data; 1440 | const unsigned char *dataG = dataR + ofsG; 1441 | const unsigned char *dataB = dataR + ofsB; 1442 | int x, y, pos; 1443 | if(subsample) { 1444 | for(y = 0; y < height; y += 16) { 1445 | for(x = 0; x < width; x += 16) { 1446 | float Y[256], U[256], V[256]; 1447 | for(row = y, pos = 0; row < y+16; ++row) { 1448 | // row >= height => use last input row 1449 | int clamped_row = (row < height) ? row : height - 1; 1450 | int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; 1451 | for(col = x; col < x+16; ++col, ++pos) { 1452 | // if col >= width => use pixel from last input column 1453 | int p = base_p + ((col < width) ? col : (width-1))*comp; 1454 | float r = dataR[p], g = dataG[p], b = dataB[p]; 1455 | Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; 1456 | U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; 1457 | V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; 1458 | } 1459 | } 1460 | DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+0, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); 1461 | DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+8, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); 1462 | DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); 1463 | DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); 1464 | 1465 | // subsample U,V 1466 | { 1467 | float subU[64], subV[64]; 1468 | int yy, xx; 1469 | for(yy = 0, pos = 0; yy < 8; ++yy) { 1470 | for(xx = 0; xx < 8; ++xx, ++pos) { 1471 | int j = yy*32+xx*2; 1472 | subU[pos] = (U[j+0] + U[j+1] + U[j+16] + U[j+17]) * 0.25f; 1473 | subV[pos] = (V[j+0] + V[j+1] + V[j+16] + V[j+17]) * 0.25f; 1474 | } 1475 | } 1476 | DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); 1477 | DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); 1478 | } 1479 | } 1480 | } 1481 | } else { 1482 | for(y = 0; y < height; y += 8) { 1483 | for(x = 0; x < width; x += 8) { 1484 | float Y[64], U[64], V[64]; 1485 | for(row = y, pos = 0; row < y+8; ++row) { 1486 | // row >= height => use last input row 1487 | int clamped_row = (row < height) ? row : height - 1; 1488 | int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; 1489 | for(col = x; col < x+8; ++col, ++pos) { 1490 | // if col >= width => use pixel from last input column 1491 | int p = base_p + ((col < width) ? col : (width-1))*comp; 1492 | float r = dataR[p], g = dataG[p], b = dataB[p]; 1493 | Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; 1494 | U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; 1495 | V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; 1496 | } 1497 | } 1498 | 1499 | DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y, DCY, YDC_HT, YAC_HT); 1500 | DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); 1501 | DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); 1502 | } 1503 | } 1504 | } 1505 | 1506 | // Do the bit alignment of the EOI marker 1507 | stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits); 1508 | } 1509 | 1510 | // EOI 1511 | stbiw__putc(s, 0xFF); 1512 | stbiw__putc(s, 0xD9); 1513 | 1514 | return 1; 1515 | } 1516 | 1517 | STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality) 1518 | { 1519 | stbi__write_context s; 1520 | stbi__start_write_callbacks(&s, func, context); 1521 | return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality); 1522 | } 1523 | 1524 | 1525 | #ifndef STBI_WRITE_NO_STDIO 1526 | STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality) 1527 | { 1528 | stbi__write_context s; 1529 | if (stbi__start_write_file(&s,filename)) { 1530 | int r = stbi_write_jpg_core(&s, x, y, comp, data, quality); 1531 | stbi__end_write_file(&s); 1532 | return r; 1533 | } else 1534 | return 0; 1535 | } 1536 | #endif 1537 | 1538 | #endif // STB_IMAGE_WRITE_IMPLEMENTATION 1539 | 1540 | /* Revision history 1541 | 1.14 (2020-02-02) updated JPEG writer to downsample chroma channels 1542 | 1.13 1543 | 1.12 1544 | 1.11 (2019-08-11) 1545 | 1.10 (2019-02-07) 1546 | support utf8 filenames in Windows; fix warnings and platform ifdefs 1547 | 1.09 (2018-02-11) 1548 | fix typo in zlib quality API, improve STB_I_W_STATIC in C++ 1549 | 1.08 (2018-01-29) 1550 | add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter 1551 | 1.07 (2017-07-24) 1552 | doc fix 1553 | 1.06 (2017-07-23) 1554 | writing JPEG (using Jon Olick's code) 1555 | 1.05 ??? 1556 | 1.04 (2017-03-03) 1557 | monochrome BMP expansion 1558 | 1.03 ??? 1559 | 1.02 (2016-04-02) 1560 | avoid allocating large structures on the stack 1561 | 1.01 (2016-01-16) 1562 | STBIW_REALLOC_SIZED: support allocators with no realloc support 1563 | avoid race-condition in crc initialization 1564 | minor compile issues 1565 | 1.00 (2015-09-14) 1566 | installable file IO function 1567 | 0.99 (2015-09-13) 1568 | warning fixes; TGA rle support 1569 | 0.98 (2015-04-08) 1570 | added STBIW_MALLOC, STBIW_ASSERT etc 1571 | 0.97 (2015-01-18) 1572 | fixed HDR asserts, rewrote HDR rle logic 1573 | 0.96 (2015-01-17) 1574 | add HDR output 1575 | fix monochrome BMP 1576 | 0.95 (2014-08-17) 1577 | add monochrome TGA output 1578 | 0.94 (2014-05-31) 1579 | rename private functions to avoid conflicts with stb_image.h 1580 | 0.93 (2014-05-27) 1581 | warning fixes 1582 | 0.92 (2010-08-01) 1583 | casts to unsigned char to fix warnings 1584 | 0.91 (2010-07-17) 1585 | first public release 1586 | 0.90 first internal release 1587 | */ 1588 | 1589 | /* 1590 | ------------------------------------------------------------------------------ 1591 | This software is available under 2 licenses -- choose whichever you prefer. 1592 | ------------------------------------------------------------------------------ 1593 | ALTERNATIVE A - MIT License 1594 | Copyright (c) 2017 Sean Barrett 1595 | Permission is hereby granted, free of charge, to any person obtaining a copy of 1596 | this software and associated documentation files (the "Software"), to deal in 1597 | the Software without restriction, including without limitation the rights to 1598 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 1599 | of the Software, and to permit persons to whom the Software is furnished to do 1600 | so, subject to the following conditions: 1601 | The above copyright notice and this permission notice shall be included in all 1602 | copies or substantial portions of the Software. 1603 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1604 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1605 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1606 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1607 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 1608 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 1609 | SOFTWARE. 1610 | ------------------------------------------------------------------------------ 1611 | ALTERNATIVE B - Public Domain (www.unlicense.org) 1612 | This is free and unencumbered software released into the public domain. 1613 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 1614 | software, either in source code form or as a compiled binary, for any purpose, 1615 | commercial or non-commercial, and by any means. 1616 | In jurisdictions that recognize copyright laws, the author or authors of this 1617 | software dedicate any and all copyright interest in the software to the public 1618 | domain. We make this dedication for the benefit of the public at large and to 1619 | the detriment of our heirs and successors. We intend this dedication to be an 1620 | overt act of relinquishment in perpetuity of all present and future rights to 1621 | this software under copyright law. 1622 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1623 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1624 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1625 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 1626 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 1627 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 1628 | ------------------------------------------------------------------------------ 1629 | */ --------------------------------------------------------------------------------