mirror of
https://github.com/Nexoniarz/YAPF.git
synced 2026-11-03 04:54:26 +00:00
Add files via upload
This commit is contained in:
parent
0a2b234169
commit
b9b8c93a22
3 changed files with 1060 additions and 0 deletions
262
README.md
Normal file
262
README.md
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
# 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
|
||||
```
|
||||
|
||||
```c
|
||||
#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:
|
||||
|
||||
```sh
|
||||
gcc -O2 -std=c99 main.c yapf.c -o myapp
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API Reference
|
||||
|
||||
### Types
|
||||
|
||||
```c
|
||||
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
|
||||
|
||||
```c
|
||||
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()`.
|
||||
|
||||
```c
|
||||
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.
|
||||
|
||||
```c
|
||||
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
|
||||
|
||||
```c
|
||||
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](https://releases.llvm.org/) compiler
|
||||
|
||||
```sh
|
||||
# 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](extensions/gimp/howtocompile.txt) 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](LICENSE).
|
||||
Loading…
Reference in a new issue