YAPF/docs/LANGUAGES.md
Nexoniarz d7f494a0c9 Language bindings, KDE thumbnails, yapf compare, in-memory encoding
- yapf_encode() / yapf_free_buffer(): encode to memory; yapf_save uses it
- yapf.c also compiles as C++
- `yapf compare`: size and decode speed of the original format vs YAPF,
  with a lossless check
- bindings with tested examples: C++ (header-only), C# (P/Invoke),
  Rust (crate, builds the C code), Go (cgo), Java (FFM API, Java 22+),
  Zig (@cImport), LuaJIT (FFI), TypeScript types for the JS port;
  Python now encodes in memory
- docs/LANGUAGES.md and examples/ with measured results
- KDE Dolphin thumbnail plugin (KF6, CMake)
- README: honest status for Photoshop / VS Code / Figma (not run in the
  apps yet) and macOS (cross-compiled only), platform table

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 14:39:56 +02:00

144 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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`](../yapf.h), [`examples/c`](../examples/c) | the library itself | ✅ | 0.26 ms |
| **C++** | [`bindings/cpp`](../bindings/cpp) | header-only RAII wrapper (C++17) | ✅ g++ | 0.25 ms |
| **Python** | [`bindings/python`](../bindings/python) | ctypes; numpy fallback without the library | ✅ CPython 3.13 | 0.23 ms |
| **C# / .NET** | [`bindings/csharp`](../bindings/csharp) | P/Invoke, single file | ✅ .NET 8 | 0.30 ms |
| **Rust** | [`bindings/rust`](../bindings/rust) | crate, builds the C code with `cc` | ✅ Rust 1.95 | 0.28 ms |
| **Go** | [`bindings/go`](../bindings/go) | cgo package | ✅ Go 1.26 | 0.31 ms |
| **Java / Kotlin** | [`bindings/java`](../bindings/java) | Foreign Function & Memory API (Java 22+) | ✅ JDK 25 | 0.42 ms |
| **Zig** | [`bindings/zig`](../bindings/zig) | `@cImport` of `yapf.h` | ✅ Zig 0.16 | 0.28 ms |
| **Lua** | [`bindings/lua`](../bindings/lua) | LuaJIT FFI (also LÖVE) | ✅ LuaJIT 2.1 | 0.28 ms |
| **JavaScript / TypeScript** | [`bindings/js`](../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.
## 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](https://github.com/Nexoniarz/YAPF/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**
```c
yapf_image_t *img = yapf_load("texture.yapf");
/* img->width, img->height, img->channels, img->pixels */
yapf_free(img);
```
**C++**
```cpp
auto img = yapf::Image::load("texture.yapf");
auto bytes = img.encode();
```
**Python**
```python
img = yapf.load("texture.yapf")
yapf.save("copy.yapf", img)
```
**C#**
```csharp
var img = YapfImage.Load("texture.yapf");
File.WriteAllBytes("copy.yapf", img.Encode());
```
**Rust**
```rust
let img = yapf::Image::load("texture.yapf")?;
img.save("copy.yapf")?;
```
**Go**
```go
img, err := yapf.Load("texture.yapf")
data, err := yapf.Encode(img)
```
**Java**
```java
Yapf.Image img = Yapf.load(Path.of("texture.yapf"));
Yapf.save(Path.of("copy.yapf"), img);
```
**Zig**
```zig
const img = c.yapf_load("texture.yapf") orelse return error.CannotLoad;
defer c.yapf_free(img);
```
**Lua**
```lua
local img = yapf.load("texture.yapf")
yapf.save("copy.yapf", img)
```
**JavaScript**
```js
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:
```c
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)`.