Lossless image codec.
Fox is a tiny lossless image codec aiming to provide a satisfying compression ratio.
Fox only encodes a stream of 32bit rgba pixels (8-bit per channel), includes no additional metadata like width/height.
This makes fox a good choice for embedding into a custom container format.
Both encoder and decoder are currenty written in under 48 LOC.
No dependencies, not event libc. Just plain C99.
Fox usually provides similar compression ratio to a PNG (libpng encoded).
Fox might outperform PNG on photos, smaller images, some textures or screenshots.
PNG works better for repeating patterns and can be usually brute force optimized to further reduce the image size.
Both formats are outperformed by lossless versions of modern image formats such as WebP or JpegXL.
See the benchmark for size comparison on few image sets.
Each pixel is encoded/decoded in O(1) time. Therefore the whole image is encoded in O(n) time.
The actual speed is not as impressive, mainly because each symbol (color, hash index or run length) is encoded bit by bit.
No build system is currently included as it is not necessary.
Simply add include
folder to your header paths and compile/link src/enc.c
and/or src/dec.c
with your sources. Boom. Done.
Colors are represented by 32 bit integer as 0xAARRGGBB.
Both encoder and decoder share the same data structure.
The structure has to be zero initialized except for user-provided callback and a user pointer.
In this example we pass a standard stdio FILE through the user pointer.
// fields except callback and user are initialized to zero
struct fox example = { .callback = my_callback, .user = file };
Define your callback.
If used as an encoder, the callback will be called by the encoder to write a byte to the output stream, return value is ignored.
If used as a decoder, the callback will be called by the decoder to read a byte from the input stream, arg argument is ignored.
In any case the byte read/written is always expected to be 8-bits.
static unsigned char my_callback(unsigned char arg, void *user) {
// return fputc(arg, (FILE*) user); // for encoder mode
// return fgetc((FILE*) user); // for decoder mode
}
Now that the structure is initialized we can start encoding/decoding.
Initialize the fox structure as shown above.
Do not use fox_open
- it is only used by the decoder.
For each pixel call:
// void fox_write(struct fox *encoder, unsigned long color);
fox_write(&example, color);
Close the stream by calling:
// void fox_close(struct fox *encoder);
fox_close(&example);
Initialize the fox structure as shown above.
Open the stream by calling:
// void fox_open(struct fox *decoder);
fox_open(&example);
For each pixel call:
// unsigned long fox_read(struct fox *decoder);
unsigned long color = fox_read(&example);
Do not use fox_close
- it is only used by the encoder.
Example is provided to show encoding and decoding.
It converts TGA image to Fox and Fox to TGA.
Only supported TGA formats are uncompressed 24 bit RGB, 32 bit RGBA and 8 bit grayscale.
The fox image is saved with a minimal header.
To build the example there are two scripts build.sh
and build.bat
to build the example using cc and cl respectively.
Usage:
fox encode image.tga image.fox
fox decode image.fox image.tga