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"
// ...
clang says:
error: non-constant-expression cannot be narrowed from type 'int'
to 'unsigned char' in initializer list [-Wc++11-narrowing]
so I explicitly cast affected stuff to unsigned char.
Some functions were missing that in the definition, others weren't,
all had it in the declarations.
Added mention of JPG and HDR formats at the top of the file
jo_jpeg.cpp is a Public Domain JPEG writer written by Jon Olick in 2012
http://www.jonolick.com/code.html
My changes to jo_jpeg:
* port to plain C89 (+ // comments, as supported by MSVC6)
* support for 2 comp input (Greyscale+Alpha, Alpha is ignored)
* use stbi__write_context abstraction instead of stdio for writing
* adjust names to stbiw-style