1 /// stb_image_write.h translations 2 /// Just the PNG encoder. 3 module gamut.codecs.stb_image_write; 4 5 /* stb_image_write - v1.16 - public domain - http://nothings.org/stb 6 writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015 7 no warranty implied; use at your own risk 8 9 Before #including, 10 11 #define STB_IMAGE_WRITE_IMPLEMENTATION 12 13 in the file that you want to have the implementation. 14 15 Will probably not work correctly with strict-aliasing optimizations. 16 17 ABOUT: 18 19 This header file is a library for writing images to C stdio or a callback. 20 21 The PNG output is not optimal; it is 20-50% larger than the file 22 written by a decent optimizing implementation; though providing a custom 23 zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that. 24 This library is designed for source code compactness and simplicity, 25 not optimal image file size or run-time performance. 26 27 28 USAGE: 29 30 There are one function: 31 32 int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); 33 34 You can configure it with these global variables: 35 int stbi_write_png_compression_level; // defaults to 8; set to higher for more compression 36 int stbi_write_force_png_filter; // defaults to -1; set to 0..5 to force a filter mode 37 38 Each function returns 0 on failure and non-0 on success. 39 40 The functions create an image file defined by the parameters. The image 41 is a rectangle of pixels stored from left-to-right, top-to-bottom. 42 Each pixel contains 'comp' channels of data stored interleaved with 8-bits 43 per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is 44 monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall. 45 The *data pointer points to the first byte of the top-left-most pixel. 46 For PNG, "stride_in_bytes" is the distance in bytes from the first byte of 47 a row of pixels to the first byte of the next row of pixels. 48 49 PNG creates output files with the same number of components as the input. 50 The BMP format expands Y to RGB in the file format and does not 51 output alpha. 52 53 PNG supports writing rectangles of data even when the bytes storing rows of 54 data are not consecutive in memory (e.g. sub-rectangles of a larger image), 55 by supplying the stride between the beginning of adjacent rows. The other 56 formats do not. (Thus you cannot write a native-format BMP through the BMP 57 writer, both because it is in BGR order and because it may have padding 58 at the end of the line.) 59 60 PNG allows you to set the deflate compression level by setting the global 61 variable 'stbi_write_png_compression_level' (it defaults to 8). 62 63 CREDITS: 64 65 66 Sean Barrett - PNG/BMP/TGA 67 Baldur Karlsson - HDR 68 Jean-Sebastien Guay - TGA monochrome 69 Tim Kelsey - misc enhancements 70 Alan Hickman - TGA RLE 71 Emmanuel Julien - initial file IO callback implementation 72 Jon Olick - original jo_jpeg.cpp code 73 Daniel Gibson - integrate JPEG, allow external zlib 74 Aarni Koskela - allow choosing PNG filter 75 76 bugfixes: 77 github:Chribba 78 Guillaume Chereau 79 github:jry2 80 github:romigrou 81 Sergio Gonzalez 82 Jonas Karlsson 83 Filip Wasil 84 Thatcher Ulrich 85 github:poppolopoppo 86 Patrick Boettcher 87 github:xeekworx 88 Cap Petschulat 89 Simon Rodriguez 90 Ivan Tikhonov 91 github:ignotion 92 Adam Schackart 93 Andrew Kensler 94 95 LICENSE 96 97 See end of file for license information. 98 99 */ 100 101 version(encodePNG) 102 version = compileSTBImageWrite; 103 version(encodeJPEG) 104 version = compileSTBImageWrite; 105 106 version(compileSTBImageWrite): 107 108 import std.math: abs; 109 import core.stdc.stdlib: malloc, realloc, free; 110 import core.stdc.string: memcpy, memmove; 111 112 nothrow @nogc: 113 114 private: 115 116 alias STBIW_MALLOC = malloc; 117 alias STBIW_REALLOC = realloc; 118 alias STBIW_FREE = free; 119 alias STBIW_MEMMOVE = memmove; 120 121 void* STBIW_REALLOC_SIZED(void *ptr, size_t oldsz, size_t newsz) 122 { 123 return realloc(ptr, newsz); 124 } 125 126 ubyte STBIW_UCHAR(int x) 127 { 128 return cast(ubyte)(x); 129 } 130 131 enum int stbi_write_png_compression_level = 8; 132 enum int stbi_write_force_png_filter = -1; 133 134 // Useful? 135 enum int stbi__flip_vertically_on_write = 0; 136 137 138 alias stbiw_uint32 = uint; 139 140 ////////////////////////////////////////////////////////////////////////////// 141 // 142 // PNG writer 143 // 144 145 146 // write context 147 148 alias stbi_write_func = void function(void *context, const(void)* data, int size); 149 150 struct stbi__write_context 151 { 152 stbi_write_func func = null; 153 void* context = null; 154 ubyte[64] buffer; 155 int buf_used = 0; 156 } 157 158 // initialize a callback-based context 159 void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func c, void *context) 160 { 161 s.func = c; 162 s.context = context; 163 } 164 165 static void stbiw__putc(stbi__write_context *s, ubyte c) 166 { 167 s.func(s.context, &c, 1); 168 } 169 170 171 // stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() 172 int* stbiw__sbraw(void* a) 173 { 174 return (cast(int *)a) - 2; 175 } 176 177 ref int stbiw__sbm(void* a) 178 { 179 return stbiw__sbraw(a)[0]; // this place stores count of items 180 } 181 182 ref int stbiw__sbn(void* a) 183 { 184 return stbiw__sbraw(a)[1]; // this place stores capacity of items 185 } 186 187 bool stbiw__sbneedgrow(void* a, int n) 188 { 189 return (a == null) || ( stbiw__sbn(a) + n >= stbiw__sbm(a) ); 190 } 191 192 void stbiw__sbmaybegrow(T)(ref T* a, int n) 193 { 194 if (stbiw__sbneedgrow(a,n)) 195 stbiw__sbgrow(a,n); 196 } 197 198 void stbiw__sbgrow(T)(ref T* a, int n) 199 { 200 stbiw__sbgrowf(cast(void **) &a, n, T.sizeof); 201 } 202 203 void stbiw__sbpush(T)(ref T* a, T v) 204 { 205 stbiw__sbmaybegrow!T(a, 1); 206 a[stbiw__sbn(a)++] = v; 207 } 208 209 int stbiw__sbcount(void* a) 210 { 211 if (a) 212 return stbiw__sbn(a); 213 else 214 return 0; 215 } 216 217 void stbiw__sbfree(void* a) 218 { 219 if (a) STBIW_FREE(stbiw__sbraw(a)); 220 } 221 222 223 void *stbiw__sbgrowf(void **arr, int increment, int itemsize) 224 { 225 int m = *arr ? ( 2*stbiw__sbm(*arr)+increment ) : increment+1; 226 void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : null, *arr ? (stbiw__sbm(*arr)*itemsize + int.sizeof*2) : 0, itemsize * m + int.sizeof*2); 227 assert(p); 228 if (!*arr) (cast(int *) p)[1] = 0; 229 *arr = cast(void *) (cast(int *) p + 2); 230 stbiw__sbm(*arr) = m; 231 return *arr; 232 } 233 234 unittest 235 { 236 int* a = null; 237 assert(stbiw__sbcount(a) == 0); 238 stbiw__sbpush(a, 2); 239 assert(a[0] == 2); 240 stbiw__sbfree(a); 241 } 242 243 ubyte *stbiw__zlib_flushf(ubyte *data, uint *bitbuffer, int *bitcount) 244 { 245 while (*bitcount >= 8) { 246 stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer)); 247 *bitbuffer >>= 8; 248 *bitcount -= 8; 249 } 250 return data; 251 } 252 253 int stbiw__zlib_bitrev(int code, int codebits) 254 { 255 int res=0; 256 while (codebits--) { 257 res = (res << 1) | (code & 1); 258 code >>= 1; 259 } 260 return res; 261 } 262 263 uint stbiw__zlib_countm(ubyte* a, ubyte * b, int limit) 264 { 265 int i; 266 for (i=0; i < limit && i < 258; ++i) 267 if (a[i] != b[i]) break; 268 return i; 269 } 270 271 uint stbiw__zhash(ubyte *data) 272 { 273 stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); 274 hash ^= hash << 3; 275 hash += hash >> 5; 276 hash ^= hash << 4; 277 hash += hash >> 17; 278 hash ^= hash << 25; 279 hash += hash >> 6; 280 return hash; 281 } 282 283 284 enum stbiw__ZHASH = 16384; 285 286 287 ubyte * stbi_zlib_compress(ubyte *data, int data_len, int *out_len, int quality) 288 { 289 static immutable ushort[30] lengthc = 290 [ 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 ]; 291 static immutable ubyte[29] lengtheb = 292 [ 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 ]; 293 static immutable ushort[31] distc = 294 [ 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 ]; 295 static immutable ubyte[30] disteb = 296 [ 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 ]; 297 uint bitbuf=0; 298 int i,j, bitcount=0; 299 ubyte *out_ = null; 300 ubyte ***hash_table = cast(ubyte***) STBIW_MALLOC(stbiw__ZHASH * (ubyte**).sizeof); 301 if (hash_table == null) 302 return null; 303 if (quality < 5) quality = 5; 304 305 stbiw__sbpush(out_, 0x78); // DEFLATE 32K window 306 stbiw__sbpush(out_, 0x5e); // FLEVEL = 1 307 308 void stbiw__zlib_flush() nothrow @nogc 309 { 310 out_ = stbiw__zlib_flushf(out_, &bitbuf, &bitcount); 311 } 312 313 void stbiw__zlib_add(int code, int codebits) nothrow @nogc 314 { 315 bitbuf |= code << bitcount; 316 bitcount += codebits; 317 stbiw__zlib_flush(); 318 } 319 320 void stbiw__zlib_huffa(int b, int c) 321 { 322 stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c); 323 } 324 // default huffman tables 325 void stbiw__zlib_huff1(int n) 326 { 327 stbiw__zlib_huffa(0x30 + (n), 8); 328 329 } 330 void stbiw__zlib_huff2(int n) 331 { 332 stbiw__zlib_huffa(0x190 + (n)-144, 9); 333 334 } 335 void stbiw__zlib_huff3(int n) 336 { 337 stbiw__zlib_huffa(0 + (n)-256,7); 338 339 } 340 void stbiw__zlib_huff4(int n) 341 { 342 stbiw__zlib_huffa(0xc0 + (n)-280,8); 343 } 344 345 void stbiw__zlib_huff(int n) 346 { 347 ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n)); 348 } 349 350 void stbiw__zlib_huffb(int n) 351 { 352 ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n)); 353 } 354 355 stbiw__zlib_add(1,1); // BFINAL = 1 356 stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman 357 358 for (i=0; i < stbiw__ZHASH; ++i) 359 hash_table[i] = null; 360 361 i=0; 362 while (i < data_len-3) 363 { 364 // hash next 3 bytes of data to be compressed 365 int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3; 366 ubyte *bestloc = null; 367 ubyte **hlist = hash_table[h]; 368 int n = stbiw__sbcount(hlist); 369 for (j=0; j < n; ++j) { 370 if (hlist[j]-data > i-32768) { // if entry lies within window 371 int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); 372 if (d >= best) { best=d; bestloc=hlist[j]; } 373 } 374 } 375 // when hash table entry is too long, delete half the entries 376 if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) { 377 STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, (hash_table[h][0]).sizeof * quality); 378 stbiw__sbn(hash_table[h]) = quality; 379 } 380 stbiw__sbpush(hash_table[h],data+i); 381 382 if (bestloc) { 383 // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal 384 h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1); 385 hlist = hash_table[h]; 386 n = stbiw__sbcount(hlist); 387 for (j=0; j < n; ++j) { 388 if (hlist[j]-data > i-32767) { 389 int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1); 390 if (e > best) { // if next match is better, bail on current match 391 bestloc = null; 392 break; 393 } 394 } 395 } 396 } 397 398 if (bestloc) { 399 int d = cast(int) (data+i - bestloc); // distance back 400 assert(d <= 32767 && best <= 258); 401 for (j=0; best > lengthc[j+1]-1; ++j) { } 402 stbiw__zlib_huff(j+257); 403 if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]); 404 for (j=0; d > distc[j+1]-1; ++j) { } 405 stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5); 406 if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]); 407 i += best; 408 } else { 409 stbiw__zlib_huffb(data[i]); 410 ++i; 411 } 412 } 413 // write out final bytes 414 for (;i < data_len; ++i) 415 stbiw__zlib_huffb(data[i]); 416 stbiw__zlib_huff(256); // end of block 417 // pad with 0 bits to byte boundary 418 while (bitcount) 419 stbiw__zlib_add(0,1); 420 421 for (i=0; i < stbiw__ZHASH; ++i) 422 { 423 stbiw__sbfree(hash_table[i]); 424 } 425 STBIW_FREE(hash_table); 426 427 // store uncompressed instead if compression was worse 428 if (stbiw__sbn(out_) > data_len + 2 + ((data_len+32766)/32767)*5) { 429 stbiw__sbn(out_) = 2; // truncate to DEFLATE 32K window and FLEVEL = 1 430 for (j = 0; j < data_len;) { 431 int blocklen = data_len - j; 432 if (blocklen > 32767) blocklen = 32767; 433 stbiw__sbpush(out_, data_len - j == blocklen); // BFINAL = ?, BTYPE = 0 -- no compression 434 stbiw__sbpush(out_, STBIW_UCHAR(blocklen)); // LEN 435 stbiw__sbpush(out_, STBIW_UCHAR(blocklen >> 8)); 436 stbiw__sbpush(out_, STBIW_UCHAR(~blocklen)); // NLEN 437 stbiw__sbpush(out_, STBIW_UCHAR(~blocklen >> 8)); 438 memcpy(out_+stbiw__sbn(out_), data+j, blocklen); 439 stbiw__sbn(out_) += blocklen; 440 j += blocklen; 441 } 442 } 443 444 { 445 // compute adler32 on input 446 uint s1=1, s2=0; 447 int blocklen = cast(int) (data_len % 5552); 448 j=0; 449 while (j < data_len) { 450 for (i=0; i < blocklen; ++i) { s1 += data[j+i]; s2 += s1; } 451 s1 %= 65521; s2 %= 65521; 452 j += blocklen; 453 blocklen = 5552; 454 } 455 stbiw__sbpush(out_, STBIW_UCHAR(s2 >> 8)); 456 stbiw__sbpush(out_, STBIW_UCHAR(s2)); 457 stbiw__sbpush(out_, STBIW_UCHAR(s1 >> 8)); 458 stbiw__sbpush(out_, STBIW_UCHAR(s1)); 459 } 460 *out_len = stbiw__sbn(out_); 461 // make returned pointer freeable 462 STBIW_MEMMOVE(stbiw__sbraw(out_), out_, *out_len); 463 return cast(ubyte *) stbiw__sbraw(out_); 464 } 465 466 static uint stbiw__crc32(ubyte *buffer, int len) 467 { 468 static immutable uint[256] crc_table = 469 [ 470 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 471 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 472 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 473 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 474 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 475 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 476 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 477 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 478 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 479 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 480 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 481 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 482 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 483 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 484 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 485 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 486 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 487 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 488 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 489 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 490 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 491 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 492 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 493 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 494 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 495 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 496 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 497 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 498 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 499 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 500 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 501 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D 502 ]; 503 504 uint crc = ~0u; 505 int i; 506 for (i=0; i < len; ++i) 507 crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; 508 return ~crc; 509 } 510 511 void stbiw__wpng4(ref ubyte* o, ubyte a, ubyte b, ubyte c, ubyte d) 512 { 513 o[0] = a; 514 o[1] = b; 515 o[2] = c; 516 o[3] = d; 517 o += 4; 518 } 519 520 void stbiw__wp32(ref ubyte* data, uint v) 521 { 522 stbiw__wpng4(data, v >> 24, (v >> 16) & 0xff, (v >> 8) & 0xff, v & 0xff); 523 } 524 525 void stbiw__wptag(ref ubyte* data, char[4] s) 526 { 527 stbiw__wpng4(data, s[0], s[1], s[2], s[3]); 528 } 529 530 static void stbiw__wpcrc(ubyte **data, int len) 531 { 532 uint crc = stbiw__crc32(*data - len - 4, len+4); 533 stbiw__wp32(*data, crc); 534 } 535 536 ubyte stbiw__paeth(int a, int b, int c) 537 { 538 int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c); 539 if (pa <= pb && pa <= pc) return STBIW_UCHAR(a); 540 if (pb <= pc) return STBIW_UCHAR(b); 541 return STBIW_UCHAR(c); 542 } 543 544 // @OPTIMIZE: provide an option that always forces left-predict or paeth predict 545 static void stbiw__encode_png_line(ubyte *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, byte* line_buffer) 546 { 547 static immutable int[5] mapping = [ 0,1,2,3,4 ]; 548 static immutable int[5] firstmap = [ 0,1,0,5,6 ]; 549 immutable(int)* mymap = (y != 0) ? mapping.ptr : firstmap.ptr; 550 int i; 551 int type = mymap[filter_type]; 552 ubyte *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y); 553 int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes; 554 555 if (type==0) { 556 memcpy(line_buffer, z, width*n); 557 return; 558 } 559 560 // first loop isn't optimized since it's just one pixel 561 for (i = 0; i < n; ++i) { 562 switch (type) { 563 case 1: line_buffer[i] = z[i]; break; 564 case 2: line_buffer[i] = cast(byte)(z[i] - z[i-signed_stride]); break; 565 case 3: line_buffer[i] = cast(byte)(z[i] - (z[i-signed_stride]>>1)); break; 566 case 4: line_buffer[i] = cast(byte) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break; 567 case 5: line_buffer[i] = z[i]; break; 568 case 6: line_buffer[i] = z[i]; break; 569 default: assert(0); 570 } 571 } 572 switch (type) { 573 case 1: for (i=n; i < width*n; ++i) line_buffer[i] = cast(byte)(z[i] - z[i-n]); break; 574 case 2: for (i=n; i < width*n; ++i) line_buffer[i] = cast(byte)(z[i] - z[i-signed_stride]); break; 575 case 3: for (i=n; i < width*n; ++i) line_buffer[i] = cast(byte)(z[i] - ((z[i-n] + z[i-signed_stride])>>1)); break; 576 case 4: for (i=n; i < width*n; ++i) line_buffer[i] = cast(byte)(z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n])); break; 577 case 5: for (i=n; i < width*n; ++i) line_buffer[i] = cast(byte)(z[i] - (z[i-n]>>1)); break; 578 case 6: for (i=n; i < width*n; ++i) line_buffer[i] = cast(byte)(z[i] - stbiw__paeth(z[i-n], 0,0)); break; 579 default: assert(0); 580 } 581 } 582 583 public ubyte *stbi_write_png_to_mem(const(ubyte*) pixels, int stride_bytes, int x, int y, int n, int *out_len) 584 { 585 int force_filter = stbi_write_force_png_filter; 586 static immutable int[5] ctype = [ -1, 0, 4, 2, 6 ]; 587 static immutable ubyte[8] sig = [ 137,80,78,71,13,10,26,10 ]; 588 ubyte *out_, o, filt, zlib; 589 byte* line_buffer; 590 int j, zlen; 591 592 if (stride_bytes == 0) 593 stride_bytes = x * n; 594 595 if (force_filter >= 5) 596 { 597 force_filter = -1; 598 } 599 600 filt = cast(ubyte *) STBIW_MALLOC((x*n+1) * y); 601 if (!filt) 602 return null; 603 line_buffer = cast(byte *) STBIW_MALLOC(x * n); 604 if (!line_buffer) 605 { 606 STBIW_FREE(filt); 607 return null; 608 } 609 610 for (j=0; j < y; ++j) 611 { 612 int filter_type; 613 if (force_filter > -1) { 614 filter_type = force_filter; 615 stbiw__encode_png_line(cast(ubyte*)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer); 616 } else { // Estimate the best filter by running through all of them: 617 int best_filter = 0, best_filter_val = 0x7fffffff, est, i; 618 for (filter_type = 0; filter_type < 5; filter_type++) { 619 stbiw__encode_png_line(cast(ubyte*)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer); 620 621 // Estimate the entropy of the line using this filter; the less, the better. 622 est = 0; 623 for (i = 0; i < x*n; ++i) { 624 est += abs(line_buffer[i]); 625 } 626 if (est < best_filter_val) { 627 best_filter_val = est; 628 best_filter = filter_type; 629 } 630 } 631 if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it 632 stbiw__encode_png_line(cast(ubyte*)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer); 633 filter_type = best_filter; 634 } 635 } 636 // when we get here, filter_type contains the filter type, and line_buffer contains the data 637 filt[j*(x*n+1)] = cast(ubyte) filter_type; 638 STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); 639 } 640 STBIW_FREE(line_buffer); 641 zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level); 642 STBIW_FREE(filt); 643 if (!zlib) 644 return null; 645 646 // each tag requires 12 bytes of overhead 647 out_ = cast(ubyte *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12); 648 if (!out_) return null; 649 *out_len = 8 + 12+13 + 12+zlen + 12; 650 651 o = out_; 652 STBIW_MEMMOVE(o, sig.ptr, 8); 653 o+= 8; 654 stbiw__wp32(o, 13); // header length 655 stbiw__wptag(o, "IHDR"); 656 stbiw__wp32(o, x); 657 stbiw__wp32(o, y); 658 *o++ = 8; 659 *o++ = STBIW_UCHAR(ctype[n]); 660 *o++ = 0; 661 *o++ = 0; 662 *o++ = 0; 663 stbiw__wpcrc(&o,13); 664 665 stbiw__wp32(o, zlen); 666 stbiw__wptag(o, "IDAT"); 667 STBIW_MEMMOVE(o, zlib, zlen); 668 o += zlen; 669 STBIW_FREE(zlib); 670 stbiw__wpcrc(&o, zlen); 671 672 stbiw__wp32(o,0); 673 stbiw__wptag(o, "IEND"); 674 stbiw__wpcrc(&o,0); 675 676 assert(o == out_ + *out_len); 677 678 return out_; 679 } 680 681 682 683 // JPEG encoder 684 685 686 /* *************************************************************************** 687 * 688 * JPEG writer 689 * 690 * This is based on Jon Olick's jo_jpeg.cpp: 691 * public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html 692 */ 693 694 static immutable ubyte[64] stbiw__jpg_ZigZag = 695 [ 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, 696 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 ]; 697 698 void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const(ushort)* bs) 699 { 700 int bitBuf = *bitBufP; 701 int bitCnt = *bitCntP; 702 bitCnt += bs[1]; 703 bitBuf |= bs[0] << (24 - bitCnt); 704 while(bitCnt >= 8) 705 { 706 ubyte c = (bitBuf >> 16) & 255; 707 stbiw__putc(s, c); 708 if(c == 255) { 709 stbiw__putc(s, 0); 710 } 711 bitBuf <<= 8; 712 bitCnt -= 8; 713 } 714 *bitBufP = bitBuf; 715 *bitCntP = bitCnt; 716 } 717 718 void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) 719 { 720 float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p; 721 float z1, z2, z3, z4, z5, z11, z13; 722 723 float tmp0 = d0 + d7; 724 float tmp7 = d0 - d7; 725 float tmp1 = d1 + d6; 726 float tmp6 = d1 - d6; 727 float tmp2 = d2 + d5; 728 float tmp5 = d2 - d5; 729 float tmp3 = d3 + d4; 730 float tmp4 = d3 - d4; 731 732 // Even part 733 float tmp10 = tmp0 + tmp3; // phase 2 734 float tmp13 = tmp0 - tmp3; 735 float tmp11 = tmp1 + tmp2; 736 float tmp12 = tmp1 - tmp2; 737 738 d0 = tmp10 + tmp11; // phase 3 739 d4 = tmp10 - tmp11; 740 741 z1 = (tmp12 + tmp13) * 0.707106781f; // c4 742 d2 = tmp13 + z1; // phase 5 743 d6 = tmp13 - z1; 744 745 // Odd part 746 tmp10 = tmp4 + tmp5; // phase 2 747 tmp11 = tmp5 + tmp6; 748 tmp12 = tmp6 + tmp7; 749 750 // The rotator is modified from fig 4-8 to avoid extra negations. 751 z5 = (tmp10 - tmp12) * 0.382683433f; // c6 752 z2 = tmp10 * 0.541196100f + z5; // c2-c6 753 z4 = tmp12 * 1.306562965f + z5; // c2+c6 754 z3 = tmp11 * 0.707106781f; // c4 755 756 z11 = tmp7 + z3; // phase 5 757 z13 = tmp7 - z3; 758 759 *d5p = z13 + z2; // phase 6 760 *d3p = z13 - z2; 761 *d1p = z11 + z4; 762 *d7p = z11 - z4; 763 764 *d0p = d0; 765 *d2p = d2; 766 *d4p = d4; 767 *d6p = d6; 768 } 769 770 void stbiw__jpg_calcBits(int val, ushort* bits) 771 { 772 int tmp1 = val < 0 ? -val : val; 773 val = val < 0 ? val-1 : val; 774 bits[1] = 1; 775 while(tmp1 >>= 1) 776 { 777 ++bits[1]; 778 } 779 bits[0] = cast(ushort)(val & ((1<<bits[1])-1)); 780 } 781 782 int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt, 783 float *CDU, int du_stride, float *fdtbl, int DC, 784 const(ushort[2])* HTDC, 785 const(ushort[2])* HTAC) 786 { 787 const(ushort[2]) EOB = [ HTAC[0x00][0], HTAC[0x00][1] ]; 788 const(ushort[2]) M16zeroes = [ HTAC[0xF0][0], HTAC[0xF0][1] ]; 789 int dataOff, i, j, n, diff, end0pos, x, y; 790 int[64] DU; 791 792 // DCT rows 793 for(dataOff=0, n=du_stride*8; dataOff<n; dataOff+=du_stride) 794 { 795 stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+1], &CDU[dataOff+2], &CDU[dataOff+3], &CDU[dataOff+4], &CDU[dataOff+5], &CDU[dataOff+6], &CDU[dataOff+7]); 796 } 797 // DCT columns 798 for(dataOff=0; dataOff<8; ++dataOff) 799 { 800 stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+du_stride], &CDU[dataOff+du_stride*2], &CDU[dataOff+du_stride*3], &CDU[dataOff+du_stride*4], 801 &CDU[dataOff+du_stride*5], &CDU[dataOff+du_stride*6], &CDU[dataOff+du_stride*7]); 802 } 803 // Quantize/descale/zigzag the coefficients 804 for(y = 0, j=0; y < 8; ++y) 805 { 806 for(x = 0; x < 8; ++x,++j) 807 { 808 float v; 809 i = y*du_stride+x; 810 v = CDU[i]*fdtbl[j]; 811 // DU[stbiw__jpg_ZigZag[j]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f)); 812 // ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway? 813 DU[stbiw__jpg_ZigZag[j]] = cast(int)(v < 0 ? v - 0.5f : v + 0.5f); 814 } 815 } 816 817 // Encode DC 818 diff = DU[0] - DC; 819 if (diff == 0) { 820 stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[0].ptr); 821 } else { 822 ushort[2] bits; 823 stbiw__jpg_calcBits(diff, bits.ptr); 824 stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[bits[1]].ptr); 825 stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits.ptr); 826 } 827 // Encode ACs 828 end0pos = 63; 829 for(; (end0pos>0)&&(DU[end0pos]==0); --end0pos) { 830 } 831 // end0pos = first element in reverse order !=0 832 if(end0pos == 0) { 833 stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB.ptr); 834 return DU[0]; 835 } 836 for(i = 1; i <= end0pos; ++i) { 837 int startpos = i; 838 int nrzeroes; 839 ushort[2] bits; 840 for (; DU[i]==0 && i<=end0pos; ++i) { 841 } 842 nrzeroes = i-startpos; 843 if ( nrzeroes >= 16 ) { 844 int lng = nrzeroes>>4; 845 int nrmarker; 846 for (nrmarker=1; nrmarker <= lng; ++nrmarker) 847 stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes.ptr); 848 nrzeroes &= 15; 849 } 850 stbiw__jpg_calcBits(DU[i], bits.ptr); 851 stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]].ptr); 852 stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits.ptr); 853 } 854 if(end0pos != 63) { 855 stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB.ptr); 856 } 857 return DU[0]; 858 } 859 860 int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) 861 { 862 // Constants that don't pollute global namespace 863 static immutable ubyte[17] std_dc_luminance_nrcodes = [0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0]; 864 static immutable ubyte[12] std_dc_luminance_values = [0,1,2,3,4,5,6,7,8,9,10,11]; 865 static immutable ubyte[17] std_ac_luminance_nrcodes = [0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d]; 866 static immutable ubyte[162] std_ac_luminance_values = [ 867 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12, 0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07, 868 0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08, 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0, 869 0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16, 0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28, 870 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39, 0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49, 871 0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59, 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69, 872 0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79, 0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89, 873 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98, 0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7, 874 0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6, 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5, 875 0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4, 0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2, 876 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea, 0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8, 877 0xf9,0xfa 878 ]; 879 880 static immutable ubyte[17] std_dc_chrominance_nrcodes = [0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0]; 881 static immutable ubyte[12] std_dc_chrominance_values = [0,1,2,3,4,5,6,7,8,9,10,11]; 882 static immutable ubyte[17] std_ac_chrominance_nrcodes = [0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77]; 883 static immutable ubyte[162] std_ac_chrominance_values = [ 884 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21, 0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71, 885 0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91, 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0, 886 0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34, 0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26, 887 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38, 0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48, 888 0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58, 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68, 889 0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78, 0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87, 890 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96, 0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5, 891 0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4, 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3, 892 0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2, 0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda, 893 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9, 0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8, 894 0xf9,0xfa 895 ]; 896 897 // Huffman tables 898 static immutable ushort[2][256] YDC_HT = 899 [ [0,2],[2,3],[3,3],[4,3],[5,3],[6,3],[14,4],[30,5],[62,6],[126,7],[254,8],[510,9] ]; 900 901 static immutable ushort[2][256] UVDC_HT = 902 [ [0,2],[1,2],[2,2],[6,3],[14,4],[30,5],[62,6],[126,7],[254,8],[510,9],[1022,10],[2046,11]]; 903 904 static immutable ushort[2][256] YAC_HT = 905 [ 906 [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], 907 [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], 908 [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], 909 [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], 910 [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], 911 [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], 912 [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], 913 [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], 914 [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], 915 [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], 916 [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], 917 [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], 918 [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], 919 [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], 920 [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], 921 [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] 922 ]; 923 static immutable ushort[2][256] UVAC_HT = [ 924 [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], 925 [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], 926 [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], 927 [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], 928 [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], 929 [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], 930 [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], 931 [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], 932 [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], 933 [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], 934 [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], 935 [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], 936 [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], 937 [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], 938 [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], 939 [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] 940 ]; 941 static immutable 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, 942 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]; 943 944 static immutable 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, 945 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]; 946 947 static immutable float[] aasf = [ 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f, 948 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f ]; 949 950 int row, col, i, k, subsample; 951 float[64] fdtbl_Y, fdtbl_UV; 952 ubyte[64] YTable, UVTable; 953 954 if(!data || !width || !height || comp > 4 || comp < 1) { 955 return 0; 956 } 957 958 quality = quality ? quality : 90; 959 subsample = quality <= 90 ? 1 : 0; 960 quality = quality < 1 ? 1 : quality > 100 ? 100 : quality; 961 quality = quality < 50 ? 5000 / quality : 200 - quality * 2; 962 963 for(i = 0; i < 64; ++i) { 964 int uvti, yti = (YQT[i]*quality+50)/100; 965 YTable[stbiw__jpg_ZigZag[i]] = cast(ubyte) (yti < 1 ? 1 : yti > 255 ? 255 : yti); 966 uvti = (UVQT[i]*quality+50)/100; 967 UVTable[stbiw__jpg_ZigZag[i]] = cast(ubyte) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti); 968 } 969 970 for(row = 0, k = 0; row < 8; ++row) { 971 for(col = 0; col < 8; ++col, ++k) { 972 fdtbl_Y[k] = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); 973 fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); 974 } 975 } 976 977 // Write Headers 978 { 979 static immutable ubyte[] 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 ]; 980 static immutable ubyte[] head2 = [ 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 ]; 981 immutable ubyte[24] head1 = 982 [ 983 0xFF, 0xC0, 0, 0x11, 8, 984 cast(ubyte)(height>>8), 985 cast(ubyte)(height), 986 cast(ubyte)(width>>8), 987 cast(ubyte)(width), 988 3,1,cast(ubyte)(subsample?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 ]; 989 990 991 s.func(s.context, head0.ptr, cast(int)head0.length); 992 s.func(s.context, YTable.ptr, cast(int)YTable.length); 993 stbiw__putc(s, 1); 994 s.func(s.context, UVTable.ptr, cast(int)UVTable.length); 995 s.func(s.context, head1.ptr, cast(int)head1.sizeof); 996 s.func(s.context, (std_dc_luminance_nrcodes.ptr+1), cast(int)std_dc_luminance_nrcodes.length - 1); 997 s.func(s.context, std_dc_luminance_values.ptr, cast(int)std_dc_luminance_values.length); 998 stbiw__putc(s, 0x10); // HTYACinfo 999 s.func(s.context, (std_ac_luminance_nrcodes.ptr+1), cast(int)std_ac_luminance_nrcodes.length-1); 1000 s.func(s.context, std_ac_luminance_values.ptr, cast(int)std_ac_luminance_values.length); 1001 stbiw__putc(s, 1); // HTUDCinfo 1002 s.func(s.context, (std_dc_chrominance_nrcodes.ptr+1), cast(int)std_dc_chrominance_nrcodes.length-1); 1003 s.func(s.context, std_dc_chrominance_values.ptr, cast(int)std_dc_chrominance_values.length); 1004 stbiw__putc(s, 0x11); // HTUACinfo 1005 s.func(s.context, (std_ac_chrominance_nrcodes.ptr+1), cast(int)std_ac_chrominance_nrcodes.length-1); 1006 s.func(s.context, std_ac_chrominance_values.ptr, cast(int)std_ac_chrominance_values.length); 1007 s.func(s.context, head2.ptr, cast(int) head2.length); 1008 } 1009 1010 // Encode 8x8 macroblocks 1011 { 1012 static immutable ushort[2] fillBits = [0x7F, 7]; 1013 int DCY=0, DCU=0, DCV=0; 1014 int bitBuf=0, bitCnt=0; 1015 // comp == 2 is grey+alpha (alpha is ignored) 1016 int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0; 1017 const(ubyte)* dataR = cast(const(ubyte)*)data; 1018 const(ubyte)* dataG = dataR + ofsG; 1019 const(ubyte)* dataB = dataR + ofsB; 1020 int x, y, pos; 1021 if(subsample) { 1022 for(y = 0; y < height; y += 16) { 1023 for(x = 0; x < width; x += 16) { 1024 float[256] Y = void; 1025 float[256] U = void; 1026 float[256] V = void; 1027 for(row = y, pos = 0; row < y+16; ++row) { 1028 // row >= height => use last input row 1029 int clamped_row = (row < height) ? row : height - 1; 1030 int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; 1031 for(col = x; col < x+16; ++col, ++pos) { 1032 // if col >= width => use pixel from last input column 1033 int p = base_p + ((col < width) ? col : (width-1))*comp; 1034 float r = dataR[p], g = dataG[p], b = dataB[p]; 1035 Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; 1036 U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; 1037 V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; 1038 } 1039 } 1040 DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y.ptr+0, 16, fdtbl_Y.ptr, DCY, YDC_HT.ptr, YAC_HT.ptr); 1041 DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y.ptr+8, 16, fdtbl_Y.ptr, DCY, YDC_HT.ptr, YAC_HT.ptr); 1042 DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y.ptr+128, 16, fdtbl_Y.ptr, DCY, YDC_HT.ptr, YAC_HT.ptr); 1043 DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y.ptr+136, 16, fdtbl_Y.ptr, DCY, YDC_HT.ptr, YAC_HT.ptr); 1044 1045 // subsample U,V 1046 { 1047 float[64] subU = void; 1048 float[64] subV = void; 1049 int yy, xx; 1050 for(yy = 0, pos = 0; yy < 8; ++yy) { 1051 for(xx = 0; xx < 8; ++xx, ++pos) { 1052 int j = yy*32+xx*2; 1053 subU[pos] = (U[j+0] + U[j+1] + U[j+16] + U[j+17]) * 0.25f; 1054 subV[pos] = (V[j+0] + V[j+1] + V[j+16] + V[j+17]) * 0.25f; 1055 } 1056 } 1057 DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU.ptr, 8, fdtbl_UV.ptr, DCU, UVDC_HT.ptr, UVAC_HT.ptr); 1058 DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV.ptr, 8, fdtbl_UV.ptr, DCV, UVDC_HT.ptr, UVAC_HT.ptr); 1059 } 1060 } 1061 } 1062 } else { 1063 for(y = 0; y < height; y += 8) { 1064 for(x = 0; x < width; x += 8) { 1065 float[64] Y = void; 1066 float[64] U = void; 1067 float[64] V = void; 1068 for(row = y, pos = 0; row < y+8; ++row) { 1069 // row >= height => use last input row 1070 int clamped_row = (row < height) ? row : height - 1; 1071 int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; 1072 for(col = x; col < x+8; ++col, ++pos) { 1073 // if col >= width => use pixel from last input column 1074 int p = base_p + ((col < width) ? col : (width-1))*comp; 1075 float r = dataR[p], g = dataG[p], b = dataB[p]; 1076 Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; 1077 U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; 1078 V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; 1079 } 1080 } 1081 1082 DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y.ptr, 8, fdtbl_Y.ptr, DCY, YDC_HT.ptr, YAC_HT.ptr); 1083 DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U.ptr, 8, fdtbl_UV.ptr, DCU, UVDC_HT.ptr, UVAC_HT.ptr); 1084 DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V.ptr, 8, fdtbl_UV.ptr, DCV, UVDC_HT.ptr, UVAC_HT.ptr); 1085 } 1086 } 1087 } 1088 1089 // Do the bit alignment of the EOI marker 1090 stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits.ptr); 1091 } 1092 1093 // EOI 1094 stbiw__putc(s, 0xFF); 1095 stbiw__putc(s, 0xD9); 1096 1097 return 1; 1098 } 1099 1100 public int stbi_write_jpg_to_func(stbi_write_func func, void *context, int x, int y, int comp, const(void) *data, int quality) 1101 { 1102 stbi__write_context s; 1103 stbi__start_write_callbacks(&s, func, context); 1104 return stbi_write_jpg_core(&s, x, y, comp, cast(void *) data, quality); // const_cast here 1105 } 1106 1107 1108 /* Revision history 1109 1.16 (2021-07-11) 1110 make Deflate code emit uncompressed blocks when it would otherwise expand 1111 support writing BMPs with alpha channel 1112 1.15 (2020-07-13) unknown 1113 1.14 (2020-02-02) updated JPEG writer to downsample chroma channels 1114 1.13 1115 1.12 1116 1.11 (2019-08-11) 1117 1118 1.10 (2019-02-07) 1119 support utf8 filenames in Windows; fix warnings and platform ifdefs 1120 1.09 (2018-02-11) 1121 fix typo in zlib quality API, improve STB_I_W_STATIC in C++ 1122 1.08 (2018-01-29) 1123 add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter 1124 1.07 (2017-07-24) 1125 doc fix 1126 1.06 (2017-07-23) 1127 writing JPEG (using Jon Olick's code) 1128 1.05 ??? 1129 1.04 (2017-03-03) 1130 monochrome BMP expansion 1131 1.03 ??? 1132 1.02 (2016-04-02) 1133 avoid allocating large structures on the stack 1134 1.01 (2016-01-16) 1135 STBIW_REALLOC_SIZED: support allocators with no realloc support 1136 avoid race-condition in crc initialization 1137 minor compile issues 1138 1.00 (2015-09-14) 1139 installable file IO function 1140 0.99 (2015-09-13) 1141 warning fixes; TGA rle support 1142 0.98 (2015-04-08) 1143 added STBIW_MALLOC, STBIW_ASSERT etc 1144 0.97 (2015-01-18) 1145 fixed HDR asserts, rewrote HDR rle logic 1146 0.96 (2015-01-17) 1147 add HDR output 1148 fix monochrome BMP 1149 0.95 (2014-08-17) 1150 add monochrome TGA output 1151 0.94 (2014-05-31) 1152 rename private functions to avoid conflicts with stb_image.h 1153 0.93 (2014-05-27) 1154 warning fixes 1155 0.92 (2010-08-01) 1156 casts to unsigned char to fix warnings 1157 0.91 (2010-07-17) 1158 first public release 1159 0.90 first internal release 1160 */ 1161 1162 /* 1163 ------------------------------------------------------------------------------ 1164 This software is available under 2 licenses -- choose whichever you prefer. 1165 ------------------------------------------------------------------------------ 1166 ALTERNATIVE A - MIT License 1167 Copyright (c) 2017 Sean Barrett 1168 Permission is hereby granted, free of charge, to any person obtaining a copy of 1169 this software and associated documentation files (the "Software"), to deal in 1170 the Software without restriction, including without limitation the rights to 1171 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 1172 of the Software, and to permit persons to whom the Software is furnished to do 1173 so, subject to the following conditions: 1174 The above copyright notice and this permission notice shall be included in all 1175 copies or substantial portions of the Software. 1176 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1177 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1178 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1179 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1180 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 1181 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 1182 SOFTWARE. 1183 ------------------------------------------------------------------------------ 1184 ALTERNATIVE B - Public Domain (www.unlicense.org) 1185 This is free and unencumbered software released into the public domain. 1186 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 1187 software, either in source code form or as a compiled binary, for any purpose, 1188 commercial or non-commercial, and by any means. 1189 In jurisdictions that recognize copyright laws, the author or authors of this 1190 software dedicate any and all copyright interest in the software to the public 1191 domain. We make this dedication for the benefit of the public at large and to 1192 the detriment of our heirs and successors. We intend this dedication to be an 1193 overt act of relinquishment in perpetuity of all present and future rights to 1194 this software under copyright law. 1195 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1196 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1197 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1198 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 1199 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 1200 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 1201 ------------------------------------------------------------------------------ 1202 */