feat(imaging): add pure-Rust Skia backend (#112)
Some checks failed
CI / rust-skia (Rust only) (push) Successful in 2m48s
CI / required (push) Failing after 3m25s

This commit is contained in:
2026-08-13 07:49:37 +00:00
parent e1744f44bb
commit 8c18b2ac8c
46 changed files with 4301 additions and 148 deletions

View File

@@ -6,10 +6,43 @@ exposes a `skia-safe` type and never discovers or links Skia.
## Features and formats
The default feature set has no Skia dependency. `SkiaTextureCodec::decode`
returns a typed `InvalidOperation` error in that configuration, while conversion
from the checked project-owned `backend::SKBitmap` remains available for tests
and callers that already own decoded pixels.
The default feature set has no 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:
```sh
cargo test -p libremetaverse-imaging-skia --no-default-features --features rust-skia
```
`rust-skia` pins [`skia-rs-codec` 0.3.0](https://github.com/rust-skia/skia-rs)
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](https://github.com/image-rs/image-webp) 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 on the workspace Rust 1.96 MSRV; both selected direct codecs
declare older compatible Rust floors.
Enable native decoding with:
@@ -17,7 +50,7 @@ Enable native decoding with:
cargo test -p libremetaverse-imaging-skia --features skia
```
The `skia` feature decodes the CPU codec formats supported by the pinned
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
@@ -31,6 +64,25 @@ 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
@@ -66,3 +118,8 @@ explicitly.
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.