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 */