JPG always encodes 8x8 pixel blocks. If the input image does not have
a width or height that's a multiple of 8, the last column or row is just
used multiple times for the remaining pixels of the block.
The original code first calculated p (the index into the pixel data)
with the "imaginary" row/colum (that might be up to 7 pixels too far
into each direction) and then subtracted the necessary amount of bytes
it if row >= height or col >= width.
That was a bit cryptic (IMHO), and didn't get more readable/obvious when
vertical flipping was added - which introduced a bug, by not taking
stbi__flip_vertically_on_write into account when adjusting p for
row >= height...
The code should be more obvious (and less buggy) now.
This fixes bug #592
The PNG filters of the pixels row N are computed using row N-1 of the final image. If the image should be flipped when saving, this corresponds to row N+1 of the initial image.
* `force_filter` being < 0 means the original behavior (i.e. figure out
the best-performing filter per scanline); any other values 0 <= x <= 4 correspond
to PNG filters (0 = none, 1 = sub, 2 = up, 3 = average, 4 = Paeth).
* `compression_level` being < 0 equals `compression_level` 8 (the previous value).
The higher this is, the better the compression should be (though it will use
more memory).
These new parameters are not (yet) exposed for the higher-level API functions.
The builtin stbi_zlib_compress does not compress as well as zlib or
miniz (which is not too surprising as it's <200 LOC), thus PNGs created
by stb_image_write are about 20-50% bigger than PNGs compressed with
libpng.
This change lets the user supply a custom deflate/zlib-style compress
function, which improves compression a lot. This was requested in #113.
Example for zlib:
#include <zlib.h>
unsigned char* compress_for_stbiw(unsigned char *data, int data_len,
int *out_len, int quality)
{
uLongf bufSize = compressBound(data_len);
// note that buf will be free'd by stb_image_write.h
// with STBIW_FREE() (plain free() by default)
unsigned char* buf = malloc(bufSize);
if(buf == NULL) return NULL;
if(compress2(buf, &bufSize, data, data_len, quality) != Z_OK)
{
free(buf);
return NULL;
}
*out_len = bufSize;
return buf;
}
#define STBIW_ZLIB_COMPRESS compress_for_stbiw
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
// ...