YAPF — Yet Another Picture Format
  • C 56%
  • JavaScript 13.7%
  • HTML 12.3%
  • Python 6%
  • Shell 2.7%
  • Other 9.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-06-20 15:03:21 +02:00
extensions/gimp Update and rename pikture-gimp.c to yapf-gimp.c 2026-06-20 13:02:33 +00:00
other Delete other/Pikture.svg 2026-06-20 13:01:13 +00:00
build.bat Update build.bat 2026-06-20 12:59:11 +00:00
build.sh Update build.sh 2026-06-20 12:59:28 +00:00
LICENSE Update LICENSE 2026-06-06 19:21:41 +00:00
README.md Add files via upload 2026-06-20 15:03:21 +02:00
yapf.c Add files via upload 2026-06-20 15:03:21 +02:00
yapf.h Add files via upload 2026-06-20 15:03:21 +02:00

YAPF — Yet Another Picture Format

Fast. Small. Easy.

YAPF is a lossless image codec built around a single principle: decoding should be as close to a memory copy as possible. Instead of running a general-purpose compressor like DEFLATE over pixel data, YAPF encodes images with five cheap operations — a pixel cache lookup, two flavours of delta encoding, run-length encoding, and verbatim pixel storage — producing files that are smaller than uncompressed formats while decoding nearly as fast as memcpy.


Why YAPF?

Standard lossless formats like PNG compress well, but decompressing DEFLATE streams is CPU-intensive. On large images (4K and above) or in latency-sensitive applications (game engines, real-time pipelines, embedded systems) this is a meaningful bottleneck.

YAPF trades a modest compression ratio advantage for dramatically lower decode complexity. There are no Huffman tables to build, no sliding windows to maintain, and no bit-level unpacking. The decoder is a tight byte-dispatch loop that any modern CPU handles at memory bandwidth.

Performance

Benchmark: loading a 5K professional photograph (5120 × 2880 px).

Format Load time
YAPF 0.111 s
PNG 0.194 s

YAPF decodes approximately 1.7× faster than PNG on the same hardware without SIMD or threading.

When YAPF excels

  • Pixel art, sprites, UI textures — large flat regions of identical colour compress to single RUN bytes; palette-like images benefit heavily from the cache.
  • Screenshots and diagrams — solid backgrounds and repeated gradients hit DIFF/LUMA and the cache constantly.
  • Game asset pipelines — load textures at startup without paying a decompression tax every frame.
  • Embedded / resource-constrained targets — the entire codec fits in ~200 lines of portable C with zero external dependencies.

Integration

The core library is two files. Drop them into your project and compile:

yapf.h    — public API and format documentation
yapf.c    — encoder / decoder implementation
#include "yapf.h"

int main(void) {
    /* Load */
    yapf_image_t *img = yapf_load("photo.yapf");
    if (!img) { /* file not found or not a valid YAPF stream */ }

    printf("%u x %u, %u channel(s)\n",
           img->width, img->height, img->channels);

    /* Save */
    int rc = yapf_save("output.yapf", img);
    if (rc != YAPF_OK) { /* write error */ }

    yapf_free(img);
    return 0;
}

Compile with any C99-capable compiler — no flags required for the baseline:

gcc -O2 -std=c99 main.c yapf.c -o myapp

API Reference

Types

typedef struct {
    uint32_t  width;     /* pixels per row                             */
    uint32_t  height;    /* rows                                       */
    uint8_t   channels;  /* 1 gray / 2 gray+alpha / 3 RGB / 4 RGBA    */
    uint8_t  *pixels;    /* raw pixel buffer, malloc-owned             */
} yapf_image_t;

pixels is a tightly packed, row-major byte array of width × height × channels bytes. The layout per pixel matches the channels value:

channels Layout per pixel
1 Y
2 Y A
3 R G B
4 R G B A

Functions

yapf_image_t *yapf_load(const char *filename);

Decodes a YAPF file from disk. Returns a heap-allocated yapf_image_t on success, NULL on any failure (file not found, invalid magic, unsupported version, out of memory). Free with yapf_free().

int yapf_save(const char *filename, const yapf_image_t *img);

Encodes an image to disk. Returns YAPF_OK (0) on success or a negative YAPF_ERR_* code on failure.

void yapf_free(yapf_image_t *img);

Releases memory returned by yapf_load(). Passing NULL is safe.

Return codes

Constant Value Meaning
YAPF_OK 0 Success
YAPF_ERR_INVALID –1 NULL or logically invalid argument
YAPF_ERR_IO –2 File could not be opened or written

Channel constants

YAPF_CHANNELS_GRAY        1
YAPF_CHANNELS_GRAY_ALPHA  2
YAPF_CHANNELS_RGB         3
YAPF_CHANNELS_RGBA        4

Building the libraries

The build scripts uses the LLVM compiler

# Unix (Linux / macOS)
chmod +x build.sh
./build.sh

# Windows
build.bat

Output goes to dist/ with one subdirectory per platform:

dist/
├── windows-x64/    yapf.dll  yapf.lib
├── windows-arm64/  yapf.dll  yapf.lib
├── macos-x64/      libyapf.dylib
├── macos-arm64/    libyapf.dylib
├── linux-x64/      libyapf.so  libyapf.a
└── linux-arm64/    libyapf.so  libyapf.a

Optional build flags

Flag Effect
-DYAPF_USE_SIMD Reserved for future SIMD acceleration paths

The interactive build script will prompt for these options.


Technical Specification

File header — 14 bytes

Offset Size Type Description
0x00 4 char[4] Magic: "YAPF"
0x04 1 uint8_t Format version (currently 1)
0x05 4 uint32_t Width in pixels, little-endian
0x09 4 uint32_t Height in pixels, little-endian
0x0D 1 uint8_t Channel count: 1 / 2 / 3 / 4

All multi-byte integers are always stored little-endian, regardless of host architecture.

Byte-stream opcodes

The payload begins immediately after the header and is decoded left-to-right. A 64-slot pixel cache (zero-initialised) and a running "previous pixel" state (r=0, g=0, b=0, a=255) are maintained throughout.

Byte range Opcode Size Description
0x00–0x3F INDEX 1 byte Restore pixel from cache slot byte & 0x3F
0x40–0x7F DIFF 1 byte Per-channel deltas: dr = bits[5:4]–2, dg = bits[3:2]–2, db = bits[1:0]–2. Range –2..+1. Alpha unchanged.
0x80–0xBF LUMA 2 bytes Green delta dg = (byte & 0x3F)–32. Second byte: dr = ((b1>>4)&0xF)–8+dg, db = (b1&0xF)–8+dg. Alpha unchanged.
0xC0–0xFD RUN 1 byte Repeat previous pixel (byte&0x3F)+1 times (1–62). Cache not updated.
0xFE RGB 4 bytes Next 3 bytes = R, G, B. Alpha unchanged.
0xFF RGBA 5 bytes Next 4 bytes = R, G, B, A.

After every non-RUN opcode, the cache slot HASH(r,g,b,a) is updated and the pixel becomes the new previous pixel.

HASH(r,g,b,a) = (r×3 + g×5 + b×7 + a×11) mod 64

The stream ends when exactly width × height pixels have been decoded; no end-of-stream marker is required.

Pixel buffer layout

Within the decoded buffer, each pixel occupies channels consecutive bytes in the order shown in the API table above. Grayscale images store a single luminance byte per pixel; the encoder internally promotes gray values to r = g = b = Y for uniform opcode selection.


GIMP Plugin

A plugin for GIMP is located in extensions/gimp/. See the build instructions for details.

Supported colour modes: Gray, Gray+Alpha, RGB, RGBA.
File extension: .yapf. MIME type: image/x-yapf.


Platforms

Platform Architectures Library format
Windows x64, ARM64 .dll + .lib
macOS ARM64 .dylib
Linux (glibc) x64, ARM64 .so
Linux (musl) x64, ARM64 .a (static)

The core library (yapf.c / yapf.h) uses only the C99 standard library (<stdio.h>, <stdlib.h>, <string.h>, <stdint.h>) and compiles cleanly on any conforming C99 or C++ toolchain with no configuration required.


License

Apache License 2.0 — see LICENSE.