Skip to content

SovereignSoft/zimage

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

zimage / qoi

Pure-Zig QOI codec. Byte-identical to phoboslab/qoi. C ABI shim for drop-in qoi.h use.

Performance

phoboslab qoibench, full 2848-image corpus, 5 iters. zimage and qoir built for the host CPU.

aarch64 — Apple M4 Pro

decode Mpps encode Mpps
qoi.h 390 306
qoir 522 431
zimage 577 1026

x86_64 — Sapphire Rapids (AWS c7i)

decode Mpps encode Mpps
qoi.h 181 134
qoir 252 210
zimage 291 516

Install

zig fetch --save git+https://github.com/sovereignsoft/zimage
const qoi = b.dependency("qoi", .{}).module("qoi");
exe.root_module.addImport("qoi", qoi);

Zig API

const qoi = @import("qoi");

const img = try qoi.decode(allocator, qoi_bytes);
defer allocator.free(img.pixels);
// img.{width, height, channels, colorspace}
// img.pixels: RGBA8, row-major, top-down, width*height*4 bytes

const encoded = try qoi.encode(allocator, rgba_or_rgb_pixels, .{
    .width = w,
    .height = h,
    .channels = .rgba,     // .rgb (3 B/px) or .rgba (4 B/px)
    .colorspace = .srgb,   // .srgb or .linear
});
defer allocator.free(encoded);

const header = try qoi.decodeHeader(qoi_bytes);

// Caller-owned buffers, no allocation:
_ = try qoi.decodeInto(allocator, qoi_bytes, out_buf);       // RGBA8
_ = try qoi.decodeIntoRgb(allocator, qoi_bytes, rgb_out);    // packed RGB
const written = try qoi.encodeInto(enc_buf, rgba_pixels, header);

// File helpers:
const img2 = try qoi.decodeFile(allocator, init.io, "in.qoi");
try qoi.encodeFile(allocator, init.io, "out.qoi", rgba_pixels, header);
pub const Error = error{
    InvalidQoiSignature,
    InvalidQoiHeader,
    UnexpectedEnd,
    OutputBufferTooSmall,
    InvalidPixelBufferSize,
} || std.mem.Allocator.Error;

C ABI

zig buildzig-out/lib/libqoi.a. Output is libc-malloc'd; free with libc free.

#include "qoi.h"

void *pixels = qoi_read("in.qoi", &desc, 4);
qoi_write("out.qoi", pixels, &desc);
void *encoded = qoi_encode(pixels, &desc, &out_len);
void *decoded = qoi_decode(encoded, out_len, &desc, 4);

Caller-buffer variants (no per-call malloc):

int qoi_decode_into(const void *data, int size, qoi_desc *desc, int channels,
                    void *out_buf, int out_buf_size);
int qoi_encode_into(const void *data, const qoi_desc *desc,
                    void *out_buf, int out_buf_size);

Build

zig build              # libqoi.a
zig build test         # unit tests + fuzz smoke
zig build qoibench     # phoboslab qoibench vs qoi.h + qoir

Default target is cpu_model = .native. -Dcpu=baseline for portable builds.

Bench reproduction

bash <path>/tests/qoi-corpus/fetch.sh --full
RUSTFLAGS="-C target-cpu=native" cargo build --release \
  --manifest-path vendor/qoi_rust_shim/Cargo.toml
zig build qoibench
./zig-out/bin/qoibench 5 <path>/qoi-corpus/images --onlytotals

Status

Platform Decode Encode
aarch64 + ASIMD DotProd (Apple M, Cortex-A75+, Neoverse N1/V1+) hand-asm SIMD (UDOT hash)
Other aarch64 scalar scalar
x86_64 + AVX-VNNI (Sapphire Rapids+, Zen 4+) hand-asm SIMD (VPDPBUSD hash + AVX2 classify)
x86_64 + AVX2 (Haswell..Rocket Lake, Zen 1–3) hand-asm SIMD (VPMADDUBSW hash + AVX2 classify)
Other x86_64 scalar scalar

Gated comptime on dotprod / avxvnni / avx2.

License

MIT.

Credits

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors