6.4 KiB
MetaCrate Skia adapter
This crate implements the pinned SkiaTextureCodec behavior at a bounded,
project-owned image boundary. The core libremetaverse-imaging crate never
exposes a skia-safe type and never discovers or links Skia.
Features and formats
The default feature set enables the pure-Rust rust-skia backend and has no
native Google Skia dependency. SkiaTextureCodec::decode and
RustSkiaTextureCodec::decode return a typed InvalidOperation error when
their respective feature is disabled, while conversion from the checked
project-owned backend::SKBitmap remains available for tests and callers that
already own decoded pixels.
For a fully Rust implementation, enable:
cargo test -p libremetaverse-imaging-skia
rust-skia pins skia-rs-codec 0.3.0
with default features disabled and only
its pure-Rust PNG, JPEG, and GIF codecs selected. Its webp feature is
deliberately disabled because that feature selects libwebp-sys; WebP is
instead decoded by the separately pinned, safe-Rust
image-webp 0.2.4 crate.
BMP, ICO, and WBMP are built into skia-rs-codec. The resulting normal/build
graph has no codec -sys crate, C/C++ compilation, CMake, system-library
lookup, or binary download.
The locked transitive codec lines are png 0.17.16, jpeg-decoder 0.3.2,
jpeg-encoder 0.6.1 (the upstream JPEG feature couples decode and encode), and
gif 0.13.3. skia-rs-codec also brings its ordinary Rust core, paint, and
path crates; their build helpers only select Rust cfgs and compile no native
code. A source audit of the locked skia-rs-* crates found no unsafe blocks,
and image-webp declares forbid(unsafe_code). MetaCrate itself continues to
compile with workspace unsafe_code = "forbid".
RustSkiaTextureCodec implements the same ITextureCodec abstraction and
decodes BMP, GIF, ICO, baseline/progressive JPEG, interlaced PNG, WBMP, and
lossless/lossy/animated WebP. GIF and WebP return frame one composited on the
logical canvas; ICO chooses its largest valid entry. Both Skia features may be
enabled together, and each codec remains independently constructible.
The graph builds with the workspace Rust 1.97.1 toolchain; both selected direct
codecs declare older compatible Rust floors.
Enable native decoding with:
cargo test -p libremetaverse-imaging-skia --features skia
The native skia feature decodes the CPU codec formats supported by the pinned
rust-skia release: BMP, GIF, ICO, JPEG, PNG, WBMP, and WebP. Input is buffered
to at most 64 MiB. Dimensions are rejected before native pixel allocation when
they exceed the core 16,777,216-pixel limit, and decoded storage uses checked
strides and owned Rust buffers.
The mapped C# adapter exposes decoding and SKBitmap-to-ManagedImage
conversion only; it has no encoding or resize method. Encoding selection stays
with the format-specific imaging APIs, and callers use ManagedImage's checked
resize methods after decoding. Premultiplied pixels are converted to straight
alpha at this boundary. RGB565, BGRA8888, RGBA8888, RGBA/BGRA1010102, Gray8,
Alpha8, row padding, and the reference byte-width fallback retain the pinned
C# channel and rounding rules.
Both paths accept any ReadWrite + Send stream and stop buffering after 64
MiB plus one sentinel byte. The pure-Rust path probes encoded dimensions before
codec pixel allocation and enforces the shared 16,777,216-pixel ceiling; WebP
also receives an explicit decoder memory limit. Checked dimensions, strides,
buffer sizes, and fallible project-owned allocations turn malformed,
truncated, oversized, and allocation failures into typed errors. Decoded rows
have a top-left origin and premultiplied native samples are normalized to
straight alpha at the shared ManagedImage boundary.
The pure-Rust graph has identical code on Linux, Windows, macOS, and WASM and
does not call platform APIs. Checked static fixtures cover top-down/bottom-up
BMP, palette/offset GIF, largest-entry ICO, baseline/progressive JPEG,
interlaced palette PNG, multibyte WBMP, lossless-alpha/lossy WebP, malformed and
oversized inputs, and concurrent decode/drop. Gitea runs the rust-skia suite
in a dedicated ubuntu-latest job that installs no native codec prerequisites.
image-webp 0.2's animated-canvas blend fast path rounds fully opaque nonzero
samples one low; the bounded adapter corrects that single upstream edge so the
checked first-frame planes remain byte-identical to native Skia.
Binary cache and source builds
skia-safe 0.99.0 downloads an official prebuilt Skia archive when the target
and Cargo feature set match a published archive. MetaCrate deliberately selects
the published WebP-capable feature sets:
- Linux and Windows: JPEG, PDF, SVG, text layout, Vulkan, and WebP;
- macOS: JPEG, PDF, SVG, text layout, and WebP.
Vulkan is selected on Linux and Windows only to match the published CPU/WebP archive; this adapter does not create a GPU context or call a platform graphics API. The same feature is therefore usable on macOS, Linux, and Windows without leaking platform-specific behavior.
Build prerequisites for the supported desktop targets are:
- Linux: a C++ linker/runtime,
curl,pkg-config, FreeType, and Fontconfig; - macOS: Xcode command-line tools and
curl; - Windows MSVC: the Rust MSVC toolchain, Visual Studio C++ build tools, and
curl.
The build script downloads cache archives from the rust-skia/skia-binaries
GitHub releases. Pin or mirror SKIA_BINARIES_URL in offline/reproducible build
environments. FORCE_SKIA_BINARIES_DOWNLOAD=1 makes a missing archive fail
instead of compiling Skia. If no archive matches and that variable is absent,
rust-skia falls back to a source build, which additionally requires Python 3,
Ninja, and an LLVM/Clang toolchain. FORCE_SKIA_BUILD=1 selects that path
explicitly.
Licensing and redistribution
skia-safe and rust-skia's bindings are MIT licensed; the linked Skia library
is BSD-3-Clause licensed. Official binary-cache archives contain compiled Skia.
Products that redistribute the resulting native artifacts must preserve the
applicable MIT and BSD notices and audit the exact archive they ship.
skia-rs-codec is MIT OR Apache-2.0 and image-webp is MIT OR Apache-2.0.
They are ordinary Rust source dependencies recorded in Cargo.lock; generated
dependency notices and the distribution manifest bind their crates.io checksums
and license texts for source and binary redistribution.