Adds format version 2 alongside version 1 (still written for plain 8-bit images, so existing readers keep working). Full specification in docs/FORMAT.md. - GPU block payloads: BC1-BC7, BC6H, ETC2/EAC, ASTC 4x4-12x12, in tiles of 16x16 blocks. Built-in BC1/BC3/BC4/BC5/BC7/BC6H encoders and BC1-BC7 decoders (BC6H/BC7 bit-exact with a reference decoder). - Lossless 16-bit, half and float pixels as byte planes over the 8-bit coder; order-preserving float mapping, transforms at sample width. - Cubemaps, cube arrays, texture arrays, volumes, animation frames. - Channel meanings, normal convention, linear mask, primaries/transfer, mip filter and coverage-preserving mips (yapf_tex_build_mips). - Small mips stored first, file size in the header, surface/tile tables: decode from a file prefix and single tiles (virtual texturing). - yapf-sum checksums on header, tables and every tile; needs bits so decoders refuse cleanly what they cannot read. - Optional entropy stage: per-surface Huffman code books with a neighbourhood context (~10% smaller photos) and per-lane packing of GPU blocks (~3x smaller on disk); planes decoded interleaved. - Notes: author, licence, source, tool, ICC and application tags. - CLI: --format, --entropy, --coverage, --normal, --map, colour options, 16-bit/HDR input, pack cube/array/volume/anim, info, verify, export. - Tests for all of the above, including fuzzing; v1 API reads 8-bit v2. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DVrVthWN8GsmgHGUhhsCYm
5.7 KiB
Using YAPF from your language
YAPF is a small C library with six functions, so every language that can call C can use it. Ready-made bindings, each with a runnable example:
| Language | Folder | How it works | Tested | Decode¹ |
|---|---|---|---|---|
| C | yapf.h, examples/c |
the library itself | ✅ | 0.26 ms |
| C++ | bindings/cpp |
header-only RAII wrapper (C++17) | ✅ g++ | 0.25 ms |
| Python | bindings/python |
ctypes; numpy fallback without the library | ✅ CPython 3.13 | 0.23 ms |
| C# / .NET | bindings/csharp |
P/Invoke, single file | ✅ .NET 8 | 0.30 ms |
| Rust | bindings/rust |
crate, builds the C code with cc |
✅ Rust 1.95 | 0.28 ms |
| Go | bindings/go |
cgo package | ✅ Go 1.26 | 0.31 ms |
| Java / Kotlin | bindings/java |
Foreign Function & Memory API (Java 22+) | ✅ JDK 25 | 0.42 ms |
| Zig | bindings/zig |
@cImport of yapf.h |
✅ Zig 0.16 | 0.28 ms |
| Lua | bindings/lua |
LuaJIT FFI (also LÖVE) | ✅ LuaJIT 2.1 | 0.28 ms |
| JavaScript / TypeScript | bindings/js |
pure JS port, .d.ts types |
✅ Node 24, Chromium | 5.9 ms |
¹ Decoding the 512×512 RGBA YAPF logo (other/YAPF.YAPF), best of 10 after
a warm-up, on an AMD Ryzen 7 5700G. Every binding except JavaScript runs
the same native code, so they are all about equally fast; the JavaScript
port needs no native library at all. Every example also re-encodes the
image and checks that the result is byte-identical to the original file.
YAPF 2 textures. The bindings wrap the version 1 API (yapf_load,
yapf_save, …). Through it they also read 8-bit version 2 files (2D, or
face 0 / layer 0 of cubes and arrays). GPU blocks, 16-bit / float pixels,
volumes and the other version 2 features are available from C and C++
through the yapf_tex_* functions in yapf.h (see
FORMAT.md); any language with a C FFI can call them the same
way. The JavaScript port reads and writes version 1 only.
Getting the native library
Bindings other than C, C++, Rust, Go, Zig and JavaScript load the shared library at run time:
| System | File | Get it |
|---|---|---|
| Windows | yapf.dll |
Releases or build.bat |
| Linux | libyapf.so |
Releases, make, or sudo make install |
| macOS | libyapf.dylib |
Releases or make |
Put it next to your program, on the library path (PATH,
LD_LIBRARY_PATH, DYLD_LIBRARY_PATH), or pass its path explicitly
(YAPF_LIBRARY for Python and Lua, -Dyapf.library= for Java).
Quick look
C
yapf_image_t *img = yapf_load("texture.yapf");
/* img->width, img->height, img->channels, img->pixels */
yapf_free(img);
C++
auto img = yapf::Image::load("texture.yapf");
auto bytes = img.encode();
Python
img = yapf.load("texture.yapf")
yapf.save("copy.yapf", img)
C#
var img = YapfImage.Load("texture.yapf");
File.WriteAllBytes("copy.yapf", img.Encode());
Rust
let img = yapf::Image::load("texture.yapf")?;
img.save("copy.yapf")?;
Go
img, err := yapf.Load("texture.yapf")
data, err := yapf.Encode(img)
Java
Yapf.Image img = Yapf.load(Path.of("texture.yapf"));
Yapf.save(Path.of("copy.yapf"), img);
Zig
const img = c.yapf_load("texture.yapf") orelse return error.CannotLoad;
defer c.yapf_free(img);
Lua
local img = yapf.load("texture.yapf")
yapf.save("copy.yapf", img)
JavaScript
const img = YAPF.decode(bytes);
const file = YAPF.encode(img);
Any other language
Swift, Kotlin/Native, Dart, PHP, Ruby, Julia, Nim, D, Odin, Haskell, … — anything with a C foreign-function interface can call the library directly. These are the whole API:
typedef struct {
uint32_t width, height;
uint8_t channels; /* 1 gray, 2 gray+alpha, 3 RGB, 4 RGBA */
uint8_t gpu_format; /* hint, see yapf.h */
uint8_t flags; /* 1 premultiplied alpha, 2 sRGB */
uint8_t mip_levels;
uint8_t *pixels; /* width*height*channels bytes, rows top to bottom */
uint8_t **mips; /* mips[0] == pixels */
} yapf_image_t; /* 32 bytes on 64-bit systems: pixels at offset 16, mips at 24 */
yapf_image_t *yapf_load_memory_mt(const void *data, size_t size, int threads); /* threads: 1 or 0 = all cores */
void yapf_free(yapf_image_t *img);
int yapf_encode(const yapf_image_t *img, void **out_data, size_t *out_size);
void yapf_free_buffer(void *data);
yapf_image_t *yapf_load(const char *path);
int yapf_save(const char *path, const yapf_image_t *img);
Returned images and buffers must be released with yapf_free /
yapf_free_buffer from the same library. Ready-made bindings for these
languages are not included yet; the snippets below show the starting point
and are not tested.
Swift — add a module map for yapf.h (or a bridging header) and compile
yapf.c in the target; then let img = yapf_load(path) works as is.
Dart — dart:ffi: DynamicLibrary.open('libyapf.so') and
lookupFunction<Pointer<YapfImage> Function(Pointer<Uint8>, IntPtr, Int32), …>('yapf_load_memory_mt').
PHP 7.4+ — $ffi = FFI::cdef(file_get_contents('yapf_api.h'), 'libyapf.so');
with the declarations above in yapf_api.h.
Ruby — Fiddle::Function.new(lib['yapf_load'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_VOIDP).
Julia — ccall((:yapf_load, "libyapf"), Ptr{Cvoid}, (Cstring,), path).