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 import gamut.codecs.miniz; 112 113 nothrow @nogc: 114 115 private: 116 117 alias STBIW_MALLOC = malloc; 118 alias STBIW_REALLOC = realloc; 119 alias STBIW_FREE = free; 120 alias STBIW_MEMMOVE = memmove; 121 122 void* STBIW_REALLOC_SIZED(void *ptr, size_t oldsz, size_t newsz) 123 { 124 return realloc(ptr, newsz); 125 } 126 127 ubyte STBIW_UCHAR(int x) 128 { 129 return cast(ubyte)(x); 130 } 131 132 enum int stbi_write_png_compression_level = 5; 133 enum int stbi_write_force_png_filter = -1; 134 135 // Useful? 136 enum int stbi__flip_vertically_on_write = 0; 137 138 139 alias stbiw_uint32 = uint; 140 141 ////////////////////////////////////////////////////////////////////////////// 142 // 143 // PNG writer 144 // 145 146 147 // write context 148 149 alias stbi_write_func = void function(void *context, const(void)* data, int size); 150 151 struct stbi__write_context 152 { 153 stbi_write_func func = null; 154 void* context = null; 155 ubyte[64] buffer; 156 int buf_used = 0; 157 } 158 159 // initialize a callback-based context 160 void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func c, void *context) 161 { 162 s.func = c; 163 s.context = context; 164 } 165 166 static void stbiw__putc(stbi__write_context *s, ubyte c) 167 { 168 s.func(s.context, &c, 1); 169 } 170 171 /// Free result with free 172 ubyte * stbi_zlib_compress(ubyte *data, int data_len, int *out_len, int quality) 173 { 174 size_t outLenSize_t; 175 assert(quality >= 1 && quality <= 9); 176 uint comp_flags = TDEFL_COMPUTE_ADLER32 177 | tdefl_create_comp_flags_from_zip_params(quality, MZ_DEFAULT_WINDOW_BITS, MZ_DEFAULT_STRATEGY); 178 179 ubyte* res = cast(ubyte*) tdefl_compress_mem_to_heap(data, data_len, &outLenSize_t, comp_flags); 180 181 if (res) 182 { 183 assert(outLenSize_t <= int.max); // else overflow, fix this library 184 *out_len = cast(int) outLenSize_t; 185 } 186 return res; 187 } 188 189 static uint stbiw__crc32(ubyte *buffer, int len) 190 { 191 static immutable uint[256] crc_table = 192 [ 193 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 194 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 195 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 196 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 197 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 198 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 199 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 200 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 201 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 202 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 203 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 204 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 205 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 206 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 207 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 208 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 209 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 210 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 211 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 212 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 213 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 214 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 215 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 216 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 217 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 218 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 219 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 220 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 221 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 222 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 223 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 224 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D 225 ]; 226 227 uint crc = ~0u; 228 int i; 229 for (i=0; i < len; ++i) 230 crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; 231 return ~crc; 232 } 233 234 void stbiw__wpng4(ref ubyte* o, ubyte a, ubyte b, ubyte c, ubyte d) 235 { 236 o[0] = a; 237 o[1] = b; 238 o[2] = c; 239 o[3] = d; 240 o += 4; 241 } 242 243 void stbiw__wp32(ref ubyte* data, uint v) 244 { 245 stbiw__wpng4(data, v >> 24, (v >> 16) & 0xff, (v >> 8) & 0xff, v & 0xff); 246 } 247 248 void stbiw__wptag(ref ubyte* data, char[4] s) 249 { 250 stbiw__wpng4(data, s[0], s[1], s[2], s[3]); 251 } 252 253 static void stbiw__wpcrc(ubyte **data, int len) 254 { 255 uint crc = stbiw__crc32(*data - len - 4, len+4); 256 stbiw__wp32(*data, crc); 257 } 258 259 ubyte stbiw__paeth(int a, int b, int c) 260 { 261 int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c); 262 if (pa <= pb && pa <= pc) return STBIW_UCHAR(a); 263 if (pb <= pc) return STBIW_UCHAR(b); 264 return STBIW_UCHAR(c); 265 } 266 267 // @OPTIMIZE: provide an option that always forces left-predict or paeth predict 268 static void stbiw__encode_png_line(ubyte *pixels, 269 int stride_bytes, 270 int width, 271 int height, 272 int y, 273 int n, 274 bool is16bit, 275 int filter_type, 276 byte* line_buffer) 277 { 278 static immutable int[5] mapping = [ 0,1,2,3,4 ]; 279 static immutable int[5] firstmap = [ 0,1,0,5,6 ]; 280 immutable(int)* mymap = (y != 0) ? mapping.ptr : firstmap.ptr; 281 int i; 282 int type = mymap[filter_type]; 283 ubyte *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y); 284 int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes; 285 286 int line_bytes = width * n * (is16bit ? 2 : 1); 287 288 if (type==0) { 289 290 if (is16bit) 291 { 292 version(LittleEndian) 293 { 294 // 16-bit PNG samples are actually in Big Endian 295 for (int x = 0; x < width*n; ++x) 296 { 297 line_buffer[x*2 ] = z[x*2+1]; 298 line_buffer[x*2+1] = z[x*2 ]; 299 } 300 } 301 else 302 memcpy(line_buffer, z, line_bytes); 303 } 304 else 305 { 306 memcpy(line_buffer, z, line_bytes); 307 } 308 return; 309 } 310 311 int bytePerSample = n * (is16bit ? 2 : 1); 312 int leftOffset = bytePerSample; 313 314 // first loop isn't optimized since it's just one pixel 315 for (i = 0; i < bytePerSample; ++i) { 316 switch (type) { 317 case 1: line_buffer[i] = z[i]; break; 318 case 2: line_buffer[i] = cast(byte)(z[i] - z[i-signed_stride]); break; 319 case 3: line_buffer[i] = cast(byte)(z[i] - (z[i-signed_stride]>>1)); break; 320 case 4: line_buffer[i] = cast(byte) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break; 321 case 5: line_buffer[i] = z[i]; break; 322 case 6: line_buffer[i] = z[i]; break; 323 default: assert(0); 324 } 325 } 326 switch (type) { 327 case 1: for (i=bytePerSample; i < line_bytes; ++i) line_buffer[i] = cast(byte)(z[i] - z[i-leftOffset]); break; 328 case 2: for (i=bytePerSample; i < line_bytes; ++i) line_buffer[i] = cast(byte)(z[i] - z[i-signed_stride]); break; 329 case 3: for (i=bytePerSample; i < line_bytes; ++i) line_buffer[i] = cast(byte)(z[i] - ((z[i-leftOffset] + z[i-signed_stride])>>1)); break; 330 case 4: for (i=bytePerSample; i < line_bytes; ++i) line_buffer[i] = cast(byte)(z[i] - stbiw__paeth(z[i-leftOffset], z[i-signed_stride], z[i-signed_stride-leftOffset])); break; 331 case 5: for (i=bytePerSample; i < line_bytes; ++i) line_buffer[i] = cast(byte)(z[i] - (z[i-leftOffset]>>1)); break; 332 case 6: for (i=bytePerSample; i < line_bytes; ++i) line_buffer[i] = cast(byte)(z[i] - stbiw__paeth(z[i-leftOffset], 0,0)); break; 333 default: assert(0); 334 } 335 336 version(LittleEndian) 337 { 338 if (is16bit) 339 { 340 // swap bytes 341 // 16-bit PNG samples are actually in Big Endian 342 // Note that the whole prediction is happening in the native endianness. 343 // (Gamut stores 16-bit samples in native endianness). 344 for (int x = 0; x < width*n; ++x) 345 { 346 ubyte b = line_buffer[x*2 ]; 347 line_buffer[x*2 ] = line_buffer[x*2+1]; 348 line_buffer[x*2+1] = b; 349 } 350 } 351 } 352 } 353 354 public ubyte *stbi_write_png_to_mem(const(ubyte*) pixels, int stride_bytes, int x, int y, int n, int *out_len, bool is16bit) 355 { 356 int force_filter = stbi_write_force_png_filter; 357 358 static immutable int[5] ctype = [ -1, 0, 4, 2, 6 ]; 359 static immutable ubyte[8] sig = [ 137,80,78,71,13,10,26,10 ]; 360 ubyte *out_, o, filt, zlib; 361 byte* line_buffer; 362 int j, zlen; 363 364 int lineBytes = x * n * (is16bit ? 2 : 1); 365 366 if (force_filter >= 5) 367 { 368 force_filter = -1; 369 } 370 371 filt = cast(ubyte *) STBIW_MALLOC((lineBytes + 1) * y); // +1 byte for the filter type 372 if (!filt) 373 return null; 374 line_buffer = cast(byte *) STBIW_MALLOC(lineBytes); 375 if (!line_buffer) 376 { 377 STBIW_FREE(filt); 378 return null; 379 } 380 381 for (j=0; j < y; ++j) 382 { 383 int filter_type; 384 if (force_filter > -1) { 385 filter_type = force_filter; 386 stbiw__encode_png_line(cast(ubyte*)(pixels), stride_bytes, x, y, j, n, is16bit, force_filter, line_buffer); 387 388 } else { // Estimate the best filter by running through all of them: 389 int best_filter = 0, best_filter_val = 0x7fffffff, est, i; 390 for (filter_type = 0; filter_type < 5; filter_type++) { 391 stbiw__encode_png_line(cast(ubyte*)(pixels), stride_bytes, x, y, j, n, is16bit, filter_type, line_buffer); 392 393 // Estimate the entropy of the line using this filter; the less, the better. 394 est = 0; 395 for (i = 0; i < x*n; ++i) { // Note: adapting that entropy for 16-bit samples wins nothing. 396 est += abs(line_buffer[i]); 397 } 398 if (est < best_filter_val) { 399 best_filter_val = est; 400 best_filter = filter_type; 401 } 402 } 403 if (filter_type != best_filter) // If the last iteration already got us the best filter, don't redo it 404 { 405 stbiw__encode_png_line(cast(ubyte*)(pixels), stride_bytes, x, y, j, n, is16bit, best_filter, line_buffer); 406 filter_type = best_filter; 407 } 408 } 409 // when we get here, filter_type contains the filter type, and line_buffer contains the data 410 filt[j*(lineBytes+1)] = cast(ubyte) filter_type; 411 STBIW_MEMMOVE(filt+j*(lineBytes+1)+1, line_buffer, lineBytes); 412 } 413 STBIW_FREE(line_buffer); 414 zlib = stbi_zlib_compress(filt, y*(lineBytes+1), &zlen, stbi_write_png_compression_level); 415 STBIW_FREE(filt); 416 if (!zlib) 417 return null; 418 419 // each tag requires 12 bytes of overhead 420 out_ = cast(ubyte *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12); 421 if (!out_) return null; 422 *out_len = 8 + 12+13 + 12+zlen + 12; 423 424 o = out_; 425 STBIW_MEMMOVE(o, sig.ptr, 8); 426 o+= 8; 427 stbiw__wp32(o, 13); // header length 428 stbiw__wptag(o, "IHDR"); 429 stbiw__wp32(o, x); 430 stbiw__wp32(o, y); 431 *o++ = (is16bit ? 16 : 8); 432 *o++ = STBIW_UCHAR(ctype[n]); 433 *o++ = 0; 434 *o++ = 0; 435 *o++ = 0; 436 stbiw__wpcrc(&o,13); 437 438 stbiw__wp32(o, zlen); 439 stbiw__wptag(o, "IDAT"); 440 STBIW_MEMMOVE(o, zlib, zlen); 441 o += zlen; 442 STBIW_FREE(zlib); 443 stbiw__wpcrc(&o, zlen); 444 445 stbiw__wp32(o,0); 446 stbiw__wptag(o, "IEND"); 447 stbiw__wpcrc(&o,0); 448 449 assert(o == out_ + *out_len); 450 451 return out_; 452 } 453 454 455 456 // JPEG encoder 457 458 459 /* *************************************************************************** 460 * 461 * JPEG writer 462 * 463 * This is based on Jon Olick's jo_jpeg.cpp: 464 * public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html 465 */ 466 467 static immutable ubyte[64] stbiw__jpg_ZigZag = 468 [ 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, 469 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 ]; 470 471 void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const(ushort)* bs) 472 { 473 int bitBuf = *bitBufP; 474 int bitCnt = *bitCntP; 475 bitCnt += bs[1]; 476 bitBuf |= bs[0] << (24 - bitCnt); 477 while(bitCnt >= 8) 478 { 479 ubyte c = (bitBuf >> 16) & 255; 480 stbiw__putc(s, c); 481 if(c == 255) { 482 stbiw__putc(s, 0); 483 } 484 bitBuf <<= 8; 485 bitCnt -= 8; 486 } 487 *bitBufP = bitBuf; 488 *bitCntP = bitCnt; 489 } 490 491 void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) 492 { 493 float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p; 494 float z1, z2, z3, z4, z5, z11, z13; 495 496 float tmp0 = d0 + d7; 497 float tmp7 = d0 - d7; 498 float tmp1 = d1 + d6; 499 float tmp6 = d1 - d6; 500 float tmp2 = d2 + d5; 501 float tmp5 = d2 - d5; 502 float tmp3 = d3 + d4; 503 float tmp4 = d3 - d4; 504 505 // Even part 506 float tmp10 = tmp0 + tmp3; // phase 2 507 float tmp13 = tmp0 - tmp3; 508 float tmp11 = tmp1 + tmp2; 509 float tmp12 = tmp1 - tmp2; 510 511 d0 = tmp10 + tmp11; // phase 3 512 d4 = tmp10 - tmp11; 513 514 z1 = (tmp12 + tmp13) * 0.707106781f; // c4 515 d2 = tmp13 + z1; // phase 5 516 d6 = tmp13 - z1; 517 518 // Odd part 519 tmp10 = tmp4 + tmp5; // phase 2 520 tmp11 = tmp5 + tmp6; 521 tmp12 = tmp6 + tmp7; 522 523 // The rotator is modified from fig 4-8 to avoid extra negations. 524 z5 = (tmp10 - tmp12) * 0.382683433f; // c6 525 z2 = tmp10 * 0.541196100f + z5; // c2-c6 526 z4 = tmp12 * 1.306562965f + z5; // c2+c6 527 z3 = tmp11 * 0.707106781f; // c4 528 529 z11 = tmp7 + z3; // phase 5 530 z13 = tmp7 - z3; 531 532 *d5p = z13 + z2; // phase 6 533 *d3p = z13 - z2; 534 *d1p = z11 + z4; 535 *d7p = z11 - z4; 536 537 *d0p = d0; 538 *d2p = d2; 539 *d4p = d4; 540 *d6p = d6; 541 } 542 543 void stbiw__jpg_calcBits(int val, ushort* bits) 544 { 545 int tmp1 = val < 0 ? -val : val; 546 val = val < 0 ? val-1 : val; 547 bits[1] = 1; 548 while(tmp1 >>= 1) 549 { 550 ++bits[1]; 551 } 552 bits[0] = cast(ushort)(val & ((1<<bits[1])-1)); 553 } 554 555 int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt, 556 float *CDU, int du_stride, float *fdtbl, int DC, 557 const(ushort[2])* HTDC, 558 const(ushort[2])* HTAC) 559 { 560 const(ushort[2]) EOB = [ HTAC[0x00][0], HTAC[0x00][1] ]; 561 const(ushort[2]) M16zeroes = [ HTAC[0xF0][0], HTAC[0xF0][1] ]; 562 int dataOff, i, j, n, diff, end0pos, x, y; 563 int[64] DU; 564 565 // DCT rows 566 for(dataOff=0, n=du_stride*8; dataOff<n; dataOff+=du_stride) 567 { 568 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]); 569 } 570 // DCT columns 571 for(dataOff=0; dataOff<8; ++dataOff) 572 { 573 stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+du_stride], &CDU[dataOff+du_stride*2], &CDU[dataOff+du_stride*3], &CDU[dataOff+du_stride*4], 574 &CDU[dataOff+du_stride*5], &CDU[dataOff+du_stride*6], &CDU[dataOff+du_stride*7]); 575 } 576 // Quantize/descale/zigzag the coefficients 577 for(y = 0, j=0; y < 8; ++y) 578 { 579 for(x = 0; x < 8; ++x,++j) 580 { 581 float v; 582 i = y*du_stride+x; 583 v = CDU[i]*fdtbl[j]; 584 // DU[stbiw__jpg_ZigZag[j]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f)); 585 // ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway? 586 DU[stbiw__jpg_ZigZag[j]] = cast(int)(v < 0 ? v - 0.5f : v + 0.5f); 587 } 588 } 589 590 // Encode DC 591 diff = DU[0] - DC; 592 if (diff == 0) { 593 stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[0].ptr); 594 } else { 595 ushort[2] bits; 596 stbiw__jpg_calcBits(diff, bits.ptr); 597 stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[bits[1]].ptr); 598 stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits.ptr); 599 } 600 // Encode ACs 601 end0pos = 63; 602 for(; (end0pos>0)&&(DU[end0pos]==0); --end0pos) { 603 } 604 // end0pos = first element in reverse order !=0 605 if(end0pos == 0) { 606 stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB.ptr); 607 return DU[0]; 608 } 609 for(i = 1; i <= end0pos; ++i) { 610 int startpos = i; 611 int nrzeroes; 612 ushort[2] bits; 613 for (; DU[i]==0 && i<=end0pos; ++i) { 614 } 615 nrzeroes = i-startpos; 616 if ( nrzeroes >= 16 ) { 617 int lng = nrzeroes>>4; 618 int nrmarker; 619 for (nrmarker=1; nrmarker <= lng; ++nrmarker) 620 stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes.ptr); 621 nrzeroes &= 15; 622 } 623 stbiw__jpg_calcBits(DU[i], bits.ptr); 624 stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]].ptr); 625 stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits.ptr); 626 } 627 if(end0pos != 63) { 628 stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB.ptr); 629 } 630 return DU[0]; 631 } 632 633 int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) 634 { 635 // Constants that don't pollute global namespace 636 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]; 637 static immutable ubyte[12] std_dc_luminance_values = [0,1,2,3,4,5,6,7,8,9,10,11]; 638 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]; 639 static immutable ubyte[162] std_ac_luminance_values = [ 640 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12, 0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07, 641 0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08, 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0, 642 0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16, 0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28, 643 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39, 0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49, 644 0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59, 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69, 645 0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79, 0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89, 646 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98, 0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7, 647 0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6, 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5, 648 0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4, 0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2, 649 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea, 0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8, 650 0xf9,0xfa 651 ]; 652 653 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]; 654 static immutable ubyte[12] std_dc_chrominance_values = [0,1,2,3,4,5,6,7,8,9,10,11]; 655 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]; 656 static immutable ubyte[162] std_ac_chrominance_values = [ 657 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21, 0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71, 658 0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91, 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0, 659 0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34, 0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26, 660 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38, 0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48, 661 0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58, 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68, 662 0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78, 0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87, 663 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96, 0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5, 664 0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4, 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3, 665 0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2, 0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda, 666 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9, 0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8, 667 0xf9,0xfa 668 ]; 669 670 // Huffman tables 671 static immutable ushort[2][256] YDC_HT = 672 [ [0,2],[2,3],[3,3],[4,3],[5,3],[6,3],[14,4],[30,5],[62,6],[126,7],[254,8],[510,9] ]; 673 674 static immutable ushort[2][256] UVDC_HT = 675 [ [0,2],[1,2],[2,2],[6,3],[14,4],[30,5],[62,6],[126,7],[254,8],[510,9],[1022,10],[2046,11]]; 676 677 static immutable ushort[2][256] YAC_HT = 678 [ 679 [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], 680 [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], 681 [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], 682 [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], 683 [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], 684 [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], 685 [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], 686 [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], 687 [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], 688 [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], 689 [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], 690 [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], 691 [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], 692 [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], 693 [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], 694 [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] 695 ]; 696 static immutable ushort[2][256] UVAC_HT = [ 697 [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], 698 [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], 699 [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], 700 [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], 701 [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], 702 [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], 703 [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], 704 [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], 705 [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], 706 [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], 707 [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], 708 [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], 709 [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], 710 [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], 711 [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], 712 [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] 713 ]; 714 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, 715 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]; 716 717 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, 718 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]; 719 720 static immutable float[] aasf = [ 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f, 721 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f ]; 722 723 int row, col, i, k, subsample; 724 float[64] fdtbl_Y, fdtbl_UV; 725 ubyte[64] YTable, UVTable; 726 727 if(!data || !width || !height || comp > 4 || comp < 1) { 728 return 0; 729 } 730 731 quality = quality ? quality : 90; 732 subsample = quality <= 90 ? 1 : 0; 733 quality = quality < 1 ? 1 : quality > 100 ? 100 : quality; 734 quality = quality < 50 ? 5000 / quality : 200 - quality * 2; 735 736 for(i = 0; i < 64; ++i) { 737 int uvti, yti = (YQT[i]*quality+50)/100; 738 YTable[stbiw__jpg_ZigZag[i]] = cast(ubyte) (yti < 1 ? 1 : yti > 255 ? 255 : yti); 739 uvti = (UVQT[i]*quality+50)/100; 740 UVTable[stbiw__jpg_ZigZag[i]] = cast(ubyte) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti); 741 } 742 743 for(row = 0, k = 0; row < 8; ++row) { 744 for(col = 0; col < 8; ++col, ++k) { 745 fdtbl_Y[k] = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); 746 fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); 747 } 748 } 749 750 // Write Headers 751 { 752 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 ]; 753 static immutable ubyte[] head2 = [ 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 ]; 754 immutable ubyte[24] head1 = 755 [ 756 0xFF, 0xC0, 0, 0x11, 8, 757 cast(ubyte)(height>>8), 758 cast(ubyte)(height), 759 cast(ubyte)(width>>8), 760 cast(ubyte)(width), 761 3,1,cast(ubyte)(subsample?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 ]; 762 763 764 s.func(s.context, head0.ptr, cast(int)head0.length); 765 s.func(s.context, YTable.ptr, cast(int)YTable.length); 766 stbiw__putc(s, 1); 767 s.func(s.context, UVTable.ptr, cast(int)UVTable.length); 768 s.func(s.context, head1.ptr, cast(int)head1.sizeof); 769 s.func(s.context, (std_dc_luminance_nrcodes.ptr+1), cast(int)std_dc_luminance_nrcodes.length - 1); 770 s.func(s.context, std_dc_luminance_values.ptr, cast(int)std_dc_luminance_values.length); 771 stbiw__putc(s, 0x10); // HTYACinfo 772 s.func(s.context, (std_ac_luminance_nrcodes.ptr+1), cast(int)std_ac_luminance_nrcodes.length-1); 773 s.func(s.context, std_ac_luminance_values.ptr, cast(int)std_ac_luminance_values.length); 774 stbiw__putc(s, 1); // HTUDCinfo 775 s.func(s.context, (std_dc_chrominance_nrcodes.ptr+1), cast(int)std_dc_chrominance_nrcodes.length-1); 776 s.func(s.context, std_dc_chrominance_values.ptr, cast(int)std_dc_chrominance_values.length); 777 stbiw__putc(s, 0x11); // HTUACinfo 778 s.func(s.context, (std_ac_chrominance_nrcodes.ptr+1), cast(int)std_ac_chrominance_nrcodes.length-1); 779 s.func(s.context, std_ac_chrominance_values.ptr, cast(int)std_ac_chrominance_values.length); 780 s.func(s.context, head2.ptr, cast(int) head2.length); 781 } 782 783 // Encode 8x8 macroblocks 784 { 785 static immutable ushort[2] fillBits = [0x7F, 7]; 786 int DCY=0, DCU=0, DCV=0; 787 int bitBuf=0, bitCnt=0; 788 // comp == 2 is grey+alpha (alpha is ignored) 789 int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0; 790 const(ubyte)* dataR = cast(const(ubyte)*)data; 791 const(ubyte)* dataG = dataR + ofsG; 792 const(ubyte)* dataB = dataR + ofsB; 793 int x, y, pos; 794 if(subsample) { 795 for(y = 0; y < height; y += 16) { 796 for(x = 0; x < width; x += 16) { 797 float[256] Y = void; 798 float[256] U = void; 799 float[256] V = void; 800 for(row = y, pos = 0; row < y+16; ++row) { 801 // row >= height => use last input row 802 int clamped_row = (row < height) ? row : height - 1; 803 int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; 804 for(col = x; col < x+16; ++col, ++pos) { 805 // if col >= width => use pixel from last input column 806 int p = base_p + ((col < width) ? col : (width-1))*comp; 807 float r = dataR[p], g = dataG[p], b = dataB[p]; 808 Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; 809 U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; 810 V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; 811 } 812 } 813 DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y.ptr+0, 16, fdtbl_Y.ptr, DCY, YDC_HT.ptr, YAC_HT.ptr); 814 DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y.ptr+8, 16, fdtbl_Y.ptr, DCY, YDC_HT.ptr, YAC_HT.ptr); 815 DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y.ptr+128, 16, fdtbl_Y.ptr, DCY, YDC_HT.ptr, YAC_HT.ptr); 816 DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y.ptr+136, 16, fdtbl_Y.ptr, DCY, YDC_HT.ptr, YAC_HT.ptr); 817 818 // subsample U,V 819 { 820 float[64] subU = void; 821 float[64] subV = void; 822 int yy, xx; 823 for(yy = 0, pos = 0; yy < 8; ++yy) { 824 for(xx = 0; xx < 8; ++xx, ++pos) { 825 int j = yy*32+xx*2; 826 subU[pos] = (U[j+0] + U[j+1] + U[j+16] + U[j+17]) * 0.25f; 827 subV[pos] = (V[j+0] + V[j+1] + V[j+16] + V[j+17]) * 0.25f; 828 } 829 } 830 DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU.ptr, 8, fdtbl_UV.ptr, DCU, UVDC_HT.ptr, UVAC_HT.ptr); 831 DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV.ptr, 8, fdtbl_UV.ptr, DCV, UVDC_HT.ptr, UVAC_HT.ptr); 832 } 833 } 834 } 835 } else { 836 for(y = 0; y < height; y += 8) { 837 for(x = 0; x < width; x += 8) { 838 float[64] Y = void; 839 float[64] U = void; 840 float[64] V = void; 841 for(row = y, pos = 0; row < y+8; ++row) { 842 // row >= height => use last input row 843 int clamped_row = (row < height) ? row : height - 1; 844 int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; 845 for(col = x; col < x+8; ++col, ++pos) { 846 // if col >= width => use pixel from last input column 847 int p = base_p + ((col < width) ? col : (width-1))*comp; 848 float r = dataR[p], g = dataG[p], b = dataB[p]; 849 Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; 850 U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; 851 V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; 852 } 853 } 854 855 DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y.ptr, 8, fdtbl_Y.ptr, DCY, YDC_HT.ptr, YAC_HT.ptr); 856 DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U.ptr, 8, fdtbl_UV.ptr, DCU, UVDC_HT.ptr, UVAC_HT.ptr); 857 DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V.ptr, 8, fdtbl_UV.ptr, DCV, UVDC_HT.ptr, UVAC_HT.ptr); 858 } 859 } 860 } 861 862 // Do the bit alignment of the EOI marker 863 stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits.ptr); 864 } 865 866 // EOI 867 stbiw__putc(s, 0xFF); 868 stbiw__putc(s, 0xD9); 869 870 return 1; 871 } 872 873 public int stbi_write_jpg_to_func(stbi_write_func func, void *context, int x, int y, int comp, const(void) *data, int quality) 874 { 875 stbi__write_context s; 876 stbi__start_write_callbacks(&s, func, context); 877 return stbi_write_jpg_core(&s, x, y, comp, cast(void *) data, quality); // const_cast here 878 } 879 880 881 /* Revision history 882 1.16 (2021-07-11) 883 make Deflate code emit uncompressed blocks when it would otherwise expand 884 support writing BMPs with alpha channel 885 1.15 (2020-07-13) unknown 886 1.14 (2020-02-02) updated JPEG writer to downsample chroma channels 887 1.13 888 1.12 889 1.11 (2019-08-11) 890 891 1.10 (2019-02-07) 892 support utf8 filenames in Windows; fix warnings and platform ifdefs 893 1.09 (2018-02-11) 894 fix typo in zlib quality API, improve STB_I_W_STATIC in C++ 895 1.08 (2018-01-29) 896 add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter 897 1.07 (2017-07-24) 898 doc fix 899 1.06 (2017-07-23) 900 writing JPEG (using Jon Olick's code) 901 1.05 ??? 902 1.04 (2017-03-03) 903 monochrome BMP expansion 904 1.03 ??? 905 1.02 (2016-04-02) 906 avoid allocating large structures on the stack 907 1.01 (2016-01-16) 908 STBIW_REALLOC_SIZED: support allocators with no realloc support 909 avoid race-condition in crc initialization 910 minor compile issues 911 1.00 (2015-09-14) 912 installable file IO function 913 0.99 (2015-09-13) 914 warning fixes; TGA rle support 915 0.98 (2015-04-08) 916 added STBIW_MALLOC, STBIW_ASSERT etc 917 0.97 (2015-01-18) 918 fixed HDR asserts, rewrote HDR rle logic 919 0.96 (2015-01-17) 920 add HDR output 921 fix monochrome BMP 922 0.95 (2014-08-17) 923 add monochrome TGA output 924 0.94 (2014-05-31) 925 rename private functions to avoid conflicts with stb_image.h 926 0.93 (2014-05-27) 927 warning fixes 928 0.92 (2010-08-01) 929 casts to unsigned char to fix warnings 930 0.91 (2010-07-17) 931 first public release 932 0.90 first internal release 933 */ 934 935 /* 936 ------------------------------------------------------------------------------ 937 This software is available under 2 licenses -- choose whichever you prefer. 938 ------------------------------------------------------------------------------ 939 ALTERNATIVE A - MIT License 940 Copyright (c) 2017 Sean Barrett 941 Permission is hereby granted, free of charge, to any person obtaining a copy of 942 this software and associated documentation files (the "Software"), to deal in 943 the Software without restriction, including without limitation the rights to 944 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 945 of the Software, and to permit persons to whom the Software is furnished to do 946 so, subject to the following conditions: 947 The above copyright notice and this permission notice shall be included in all 948 copies or substantial portions of the Software. 949 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 950 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 951 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 952 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 953 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 954 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 955 SOFTWARE. 956 ------------------------------------------------------------------------------ 957 ALTERNATIVE B - Public Domain (www.unlicense.org) 958 This is free and unencumbered software released into the public domain. 959 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 960 software, either in source code form or as a compiled binary, for any purpose, 961 commercial or non-commercial, and by any means. 962 In jurisdictions that recognize copyright laws, the author or authors of this 963 software dedicate any and all copyright interest in the software to the public 964 domain. We make this dedication for the benefit of the public at large and to 965 the detriment of our heirs and successors. We intend this dedication to be an 966 overt act of relinquishment in perpetuity of all present and future rights to 967 this software under copyright law. 968 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 969 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 970 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 971 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 972 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 973 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 974 ------------------------------------------------------------------------------ 975 */