Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
glycin-ng
Drop-in replacement for upstream glycin. One in-process Rust shared library.
- ~9x smaller install. ~4 MiB vs ~37 MiB on Arch.
- No bubblewrap. No D-Bus. No helper binaries.
- Permissive licensing only. No LGPL or MPL transitive code.
- Per-decode sandbox. Landlock + seccomp + rlimit on the worker thread.
+-----------------+
| Caller thread |
+--------+--------+
|
| Loader::load(bytes_or_path)
v
+------------------+------------------+
| glycin-ng-worker thread |
| +-------------------------------+ |
| | rlimit (RLIMIT_AS, _CPU) | |
| +-------------------------------+ |
| | landlock (FS + net + scope) | |
| +-------------------------------+ |
| | seccomp (BPF allowlist) | |
| +-------------------------------+ |
| | Decoder (pure Rust crate) | |
| +-------------------------------+ |
+------------------+------------------+
|
| join, return frames + posture
v
+--------+--------+
| Image, frames |
+-----------------+
Quickstart
Rust
use Loader;
let image = new_path.load?;
let frame = image.first_frame.expect;
let texture = frame.texture;
println!;
if let Enforced =
image.sandbox_posture.landlock
Refuse degraded sandbox:
let image = new_bytes
.require_sandbox
.load?;
require_sandbox() returns Error::SandboxUnavailable("landlock")
(or "seccomp", "rlimit") on any kernel that cannot enforce a
selected layer.
C
GlycinNgLoader *loader = ;
GlycinNgImage *image = ;
if
;
;
Build libglycin_ng.so plus include/glycin_ng.h:
cargo build --release --features c-api
Worked example in examples/c_load.c.
How it differs from upstream
Upstream glycin sits in the same position in the stack: it is the
loader library new versions of gdk-pixbuf and GNOME apps depend on.
It spawns one helper process per format under bwrap, talks to it
over peer-to-peer D-Bus, and inherits LGPL / MPL transitive code from
the codec libraries those helpers link against (librsvg, libjxl,
libheif, libopenraw, ...).
| upstream glycin | glycin-ng | |
|---|---|---|
| Install footprint | ~37 MiB (glycin + librsvg + libjxl + bubblewrap; grows with glycin-loaders, libheif, libopenraw) |
~4 MiB (libglycin_ng.so + shim) |
| Decoder license surface | mixed (LGPL, MPL, BSD) | permissive only (MIT, Apache, BSD, ISC, Zlib) |
| Decode boundary | separate process per format | in-process worker thread |
| Sandbox mechanism | bwrap (mount / PID / user ns) | landlock + seccomp + rlimit |
| IPC | peer-to-peer D-Bus | direct function call |
| Per-decode cost | process spawn + namespace + IPC | thread spawn + prctl |
| Helper binaries shipped | one per format | none |
| Behaves under Flatpak / AppImage / distrobox | needs a sandbox helper to nest | nests cleanly (layers only narrow further) |
If you want every available codec including the LGPL ones, you want upstream glycin. If you want permissive licensing, a small install, or you're packaging into something already sandboxed where bwrap nesting is awkward, you want this.
Supported formats
| Format | Backing crate | Decode | Encode | Notes |
|---|---|---|---|---|
| PNG / APNG | png | yes | yes | animation |
| JPEG | jpeg-decoder | yes | yes | |
| GIF | gif | yes | yes | animation |
| WebP | image-webp | yes | yes | animation |
| TIFF | tiff | yes | yes | |
| BMP | image | yes | yes | |
| ICO / CUR | image | yes | - | picks largest entry |
| TGA | image | yes | - | |
| QOI | qoi | yes | - | |
| OpenEXR | image (exr) | yes | - | 16 / 32-bit float, HDR-aware |
| PNM family | image | yes | - | |
| DDS | image | yes | - | |
| JPEG XL | jxl-oxide | yes | - | |
| SVG | resvg / usvg | yes | - | GTK symbolic-icon wrappers expanded |
Deferred because no permissive decoder exists yet: HEIF, AVIF, RAW.
Sandbox
Each decode runs on a dedicated glycin-ng-worker thread, joined
before the call returns. Three layers stack on that thread:
| Layer | Default | What it does | Failure surface |
|---|---|---|---|
| landlock | on | denies all FS paths to the worker; on V4+ also TCP bind/connect; on V6+ scopes abstract-unix-socket and signals | Unsupported on pre-5.13 kernels |
| seccomp | on | BPF allowlist; everything else returns EPERM |
Unsupported if prctl fails |
| rlimit | off | RLIMIT_AS and RLIMIT_CPU from Limits |
PartiallyApplied per limit |
Toggle layers with Loader::sandbox_selector(SandboxSelector { ... }).
Inspect the result with Image::sandbox_posture() and decide whether
to log, audit, or refuse a degraded posture.
Landlock negotiates up to ABI V6 at runtime and degrades cleanly. The
crate ships built-in regression tests asserting both that an unlisted
syscall (socket) is denied under seccomp, and that the worker
spawns a rayon pool for JPEG / JXL without tripping clone3.
The dominant cost is the seccomp install: the BPF program is
JIT-compiled into the kernel on every prctl(PR_SET_SECCOMP), so its
overhead scales with the size of the allowlist. Landlock adds a
single-digit microsecond cost on top. Run cargo bench --bench sandbox_overhead for the numbers on your specific hardware.
Limits
Every decode is bounded:
| Field | Default |
|---|---|
max_width |
32768 |
max_height |
32768 |
max_pixels |
256 Mpx |
max_frames |
1024 |
max_animation_duration |
60s |
decode_memory_mib |
512 (RLIMIT_AS if rlimit on) |
decode_cpu_seconds |
30 (RLIMIT_CPU if rlimit on) |
Override via Loader::limits(Limits { ... }).
Feature flags
| Group | Default | Notes |
|---|---|---|
| Capability | decode, metadata |
enable encode for PNG, JPEG, GIF, WebP, TIFF, BMP |
| Sandbox | landlock, seccomp (Linux) |
toggling off is supported for portability testing, not as a production posture |
| Per-format | png, jpeg, gif, webp, tiff, bmp, ico, tga, qoi, exr, pnm, dds, jxl, svg |
trim individually |
| ABI | (off) c-api |
enables the cdylib build and cbindgen header |
Minimum build:
cargo build --no-default-features
Trim individual formats:
cargo build --no-default-features --features decode,png,jpeg
Related crates
glycin-ng-libglycin-shim-libglycin-2.so.0drop-in for systems that have hard-linked against upstream's libglycin (Arch's gdk-pixbuf2 is the canonical case).
License
MIT OR Apache-2.0.
CI runs cargo deny check on every push and PR, enforcing that no
transitive dependency carries an MPL, LGPL, GPL, or other copyleft
license. A failing audit is a blocker.