feat(imaging): default to pure-Rust codecs
Some checks failed
CI / rust-skia (Rust only) (push) Successful in 2m51s
CI / required (push) Failing after 3m23s

This commit is contained in:
2026-08-13 11:24:38 +00:00
parent e16ad04dbd
commit 25fdffbd3b
25 changed files with 124 additions and 103 deletions

View File

@@ -49,20 +49,22 @@ python3 tools/check_test_parity.py
python3 tools/audit_red_suite.py python3 tools/audit_red_suite.py
``` ```
### Optional codec features ### Image codec features
The default build needs no system image-codec library. It includes the The default build needs no system image-codec library. It includes the
project-owned TGA and DDS implementations; the default `dds-bc67` feature uses project-owned TGA and DDS implementations, pure-Rust J2K/JP2 through
the pure-Rust `bcdec_rs` dependency for BC6H and BC7. Build without BC6H/BC7 `rust-j2k`, and pure-Rust common-raster decoding through the default
support with `cargo build -p libremetaverse --no-default-features`. `libremetaverse-imaging-skia` `rust-skia` feature. The default `dds-bc67`
feature uses the pure-Rust `bcdec_rs` dependency for BC6H and BC7. Use
`--no-default-features` only for a deliberately minimal codec-free build.
The currently available opt-in codec backends are: The available default and optional codec backends are:
| Capability | Feature | Build command | External prerequisite | | Capability | Feature | Build command | External prerequisite |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| Raw J2K and JP2 decoding/encoding through OpenJPEG | `libremetaverse/jpeg2000` | `cargo build -p libremetaverse --features jpeg2000` | OpenJPEG 2.5.4 or newer | | Raw J2K and JP2 decoding/encoding in pure Rust (default) | `libremetaverse/rust-j2k` | `cargo build -p libremetaverse` | none |
| Raw J2K and JP2 decoding/encoding in pure Rust | `libremetaverse/rust-j2k` | `cargo build -p libremetaverse --no-default-features --features rust-j2k` | none | | BMP, GIF, ICO, JPEG, PNG, WBMP, and WebP decoding in pure Rust (default) | `libremetaverse-imaging-skia/rust-skia` | `cargo build -p libremetaverse-imaging-skia` | none |
| BMP, GIF, ICO, JPEG, PNG, WBMP, and WebP decoding in pure Rust | `libremetaverse-imaging-skia/rust-skia` | `cargo build -p libremetaverse-imaging-skia --features rust-skia` | None | | Raw J2K and JP2 decoding/encoding through OpenJPEG (optional) | `libremetaverse/jpeg2000` | `cargo build -p libremetaverse --features jpeg2000` | OpenJPEG 2.5.4 or newer |
| BMP, GIF, ICO, JPEG, PNG, WBMP, and WebP decoding through native Skia | `libremetaverse-imaging-skia/skia` | `cargo build -p libremetaverse-imaging-skia --features skia` | A matching rust-skia binary cache, or the documented native source-build tools | | BMP, GIF, ICO, JPEG, PNG, WBMP, and WebP decoding through native Skia | `libremetaverse-imaging-skia/skia` | `cargo build -p libremetaverse-imaging-skia --features skia` | A matching rust-skia binary cache, or the documented native source-build tools |
| PCM to Ogg Vorbis encoding | `libremetaverse/vorbis` | `cargo build -p libremetaverse --features vorbis` | `vorbis_rs` 0.5.6 and its native encoder build prerequisites | | PCM to Ogg Vorbis encoding | `libremetaverse/vorbis` | `cargo build -p libremetaverse --features vorbis` | `vorbis_rs` 0.5.6 and its native encoder build prerequisites |
@@ -70,9 +72,9 @@ Run their focused test suites with:
```sh ```sh
cargo test -p libremetaverse-imaging --features jpeg2000 cargo test -p libremetaverse-imaging --features jpeg2000
cargo test -p libremetaverse-imaging --no-default-features --features rust-j2k cargo test -p libremetaverse-imaging
cargo test -p libremetaverse-imaging-skia --features skia cargo test -p libremetaverse-imaging-skia --features skia
cargo test -p libremetaverse-imaging-skia --features rust-skia cargo test -p libremetaverse-imaging-skia
cargo test -p libremetaverse --no-default-features --features vorbis cargo test -p libremetaverse --no-default-features --features vorbis
``` ```
@@ -95,10 +97,11 @@ Deterministic task, socket, file, subscription, cancellation, and allocation
baselines are documented in the baselines are documented in the
[concurrency hardening guide](docs/concurrency-hardening.md). [concurrency hardening guide](docs/concurrency-hardening.md).
The independent `rust-j2k` backend is off by default and never enables the The default `rust-j2k` backend never enables the native OpenJPEG adapter. Its
native OpenJPEG adapter. Its explicit `RustJ2kCodec` preserves the existing explicit `RustJ2kCodec` preserves the existing `J2kCodec` meaning when both
`J2kCodec` meaning when both features are enabled. Use the combined feature set features are enabled. Likewise, default `RustSkiaTextureCodec` selection does
to run backend-interoperability tests without changing application selection. not rename or enable native `SkiaTextureCodec`. The native features remain
available for backend-interoperability testing or explicit application use.
`tests/upstream-tests.json` is the machine-readable NUnit parity catalog. `tests/upstream-tests.json` is the machine-readable NUnit parity catalog.
Translated tests live in hand-written Rust files with the `parity-case` marker Translated tests live in hand-written Rust files with the `parity-case` marker
@@ -208,8 +211,14 @@ Legacy and DX10 BC1 through BC5 decoding is built in. The default `dds-bc67`
feature adds BC6H/BC7 decoding through the safe, pure-Rust `bcdec_rs` crate; feature adds BC6H/BC7 decoding through the safe, pure-Rust `bcdec_rs` crate;
disabling default features removes that optional dependency and makes those disabling default features removes that optional dependency and makes those
two formats return a typed unsupported-format error. two formats return a typed unsupported-format error.
JPEG 2000 is available through the opt-in `jpeg2000` feature. It provides raw The default `rust-j2k` feature provides raw J2K and JP2 lossless/lossy encoding
J2K and JP2 lossless/lossy encoding and decoding, preserves one through five and decoding through `RustJ2kCodec`, backed by the exact pure-Rust `j2k` 0.8.1
release. It supports native component precision/signedness/order,
reduced-resolution and progressive quality-layer decoding, and strict or
explicitly permissive truncation handling. It has no C/C++ codec, CMake,
pkg-config, vcpkg, CLR, or platform-specific API.
The optional `jpeg2000` feature provides the native OpenJPEG alternative. It
provides raw J2K and JP2 lossless/lossy encoding and decoding, preserves one through five
component order, precision, signedness, and alpha metadata until explicit byte component order, precision, signedness, and alpha metadata until explicit byte
conversion, and bounds encoded input, output, dimensions, and decoded samples. conversion, and bounds encoded input, output, dimensions, and decoded samples.
The compatibility encoder reproduces CoreJ2K's four-plane RGB/alpha view, The compatibility encoder reproduces CoreJ2K's four-plane RGB/alpha view,
@@ -217,20 +226,15 @@ including its alpha-only and opaque-alpha substitutions. See
[`crates/libremetaverse-openjpeg/README.md`](crates/libremetaverse-openjpeg/README.md) [`crates/libremetaverse-openjpeg/README.md`](crates/libremetaverse-openjpeg/README.md)
for OpenJPEG prerequisites, licensing, and deployment details. Default builds for OpenJPEG prerequisites, licensing, and deployment details. Default builds
do not discover or link OpenJPEG. do not discover or link OpenJPEG.
The independent opt-in `rust-j2k` feature provides the same bounded public The default pure-Rust raster adapter decodes BMP, GIF, ICO, JPEG, PNG, WBMP,
options through `RustJ2kCodec`, backed by the exact pure-Rust `j2k` 0.8.1 and WebP into the same checked planar representation through
release. It supports J2K and JP2, reversible and irreversible encoding, `RustSkiaTextureCodec`. Its optional native `skia` feature uses pinned
native component precision/signedness/order, reduced-resolution and progressive
quality-layer decoding, and strict or explicitly permissive truncation handling.
It has no C/C++ codec, CMake, pkg-config, vcpkg, CLR, or platform-specific API.
The optional Skia adapter decodes BMP, GIF, ICO, JPEG, PNG, WBMP, and WebP into
the same checked planar representation. Its `skia` feature uses pinned
rust-skia binary-cache configurations on macOS, Linux, and Windows, normalizes rust-skia binary-cache configurations on macOS, Linux, and Windows, normalizes
premultiplied color at the imaging boundary, and keeps encoded input, decoded premultiplied color at the imaging boundary, and keeps encoded input, decoded
dimensions, strides, and allocations bounded. See dimensions, strides, and allocations bounded. See
[`crates/libremetaverse-imaging-skia/README.md`](crates/libremetaverse-imaging-skia/README.md) [`crates/libremetaverse-imaging-skia/README.md`](crates/libremetaverse-imaging-skia/README.md)
for native prerequisites, cache/source-build controls, licenses, and packaging for native prerequisites, cache/source-build controls, licenses, and packaging
details. Default workspace builds do not compile or link Skia. details. Default workspace builds compile neither OpenJPEG nor native Skia.
Primitive profile and path meshing is implemented in native Rust from the Primitive profile and path meshing is implemented in native Rust from the
pinned `PrimMesher.cs` reference. It covers checked linear, flexible, and pinned `PrimMesher.cs` reference. It covers checked linear, flexible, and
circular extrusion; profile cuts and hollows; twist, taper, shear, skew, circular extrusion; profile cuts and hollows; twist, taper, shear, skew,

View File

@@ -46,7 +46,7 @@ The exact mapping, exported-marker, feature, and normalized Rust declaration has
- .NET events become `subscribe_*` calls returning an owned `Subscription`; callbacks are `Send + Sync` and dispatch outside internal locks. - .NET events become `subscribe_*` calls returning an owned `Subscription`; callbacks are `Send + Sync` and dispatch outside internal locks.
- `IDisposable` becomes explicit idempotent shutdown plus `Drop`; cancellation remains a typed `Error::Cancelled`. - `IDisposable` becomes explicit idempotent shutdown plus `Drop`; cancellation remains a typed `Error::Cancelled`.
- Closed C# enums retain fixed discriminants and are SemVer-breaking to extend; flags retain unknown bits, while public Rust error enums are `non_exhaustive`. - Closed C# enums retain fixed discriminants and are SemVer-breaking to extend; flags retain unknown bits, while public Rust error enums are `non_exhaustive`.
- Optional native and pure-Rust backends remain feature-gated (`jpeg2000`, `rust-j2k`, `skia`, `rust-skia`, `vorbis`, `real-audio`); default and empty-default sets are part of the baseline. - Pure-Rust image backends are enabled by default (`rust-j2k`, `rust-skia`); native alternatives remain feature-gated (`jpeg2000`, `skia`, `vorbis`, `real-audio`), and empty-default sets remain part of the baseline.
- Capability HTTP injection uses project-owned `HttpMessageHandler`, `CapsHttpLimits`, and `with_native_transport`; the internal `reqwest` client is not part of the public surface. - Capability HTTP injection uses project-owned `HttpMessageHandler`, `CapsHttpLimits`, and `with_native_transport`; the internal `reqwest` client is not part of the public surface.
- External C# signature types map to core/std, adopted cross-platform crates, or project-owned boundary types; no third-party crate path leaks through mapped signatures or public Rust declarations. - External C# signature types map to core/std, adopted cross-platform crates, or project-owned boundary types; no third-party crate path leaks through mapped signatures or public Rust declarations.

View File

@@ -30,7 +30,8 @@
"dep:bcdec_rs" "dep:bcdec_rs"
], ],
"default": [ "default": [
"dds-bc67" "dds-bc67",
"rust-j2k"
], ],
"jpeg2000": [ "jpeg2000": [
"libremetaverse-imaging/jpeg2000" "libremetaverse-imaging/jpeg2000"
@@ -69,7 +70,9 @@
"name": "libremetaverse-imaging", "name": "libremetaverse-imaging",
"version": "0.0.1", "version": "0.0.1",
"features": { "features": {
"default": [], "default": [
"rust-j2k"
],
"jpeg2000": [ "jpeg2000": [
"dep:libremetaverse-openjpeg" "dep:libremetaverse-openjpeg"
], ],
@@ -86,7 +89,9 @@
"name": "libremetaverse-imaging-skia", "name": "libremetaverse-imaging-skia",
"version": "0.0.1", "version": "0.0.1",
"features": { "features": {
"default": [], "default": [
"rust-skia"
],
"rust-skia": [ "rust-skia": [
"dep:image-webp", "dep:image-webp",
"dep:skia-rs-codec", "dep:skia-rs-codec",

View File

@@ -15,8 +15,8 @@
{ "name": "getrandom", "versions": ["0.4.3"], "purpose": "Operating-system entropy for protocol identifiers", "maintenance": "active", "transitive_cost": "low", "native": false, "rewrite_anchor": "`getrandom`" }, { "name": "getrandom", "versions": ["0.4.3"], "purpose": "Operating-system entropy for protocol identifiers", "maintenance": "active", "transitive_cost": "low", "native": false, "rewrite_anchor": "`getrandom`" },
{ "name": "goblin", "versions": ["0.10.5"], "purpose": "Cross-platform ELF, PE, and Mach-O release artifact inspection", "maintenance": "active", "transitive_cost": "low", "native": false, "rewrite_anchor": "`goblin`" }, { "name": "goblin", "versions": ["0.10.5"], "purpose": "Cross-platform ELF, PE, and Mach-O release artifact inspection", "maintenance": "active", "transitive_cost": "low", "native": false, "rewrite_anchor": "`goblin`" },
{ "name": "hound", "versions": ["3.5.1"], "purpose": "Bounded PCM WAV parsing for WebRTC playback", "maintenance": "stable", "transitive_cost": "low", "native": false, "rewrite_anchor": "`hound`" }, { "name": "hound", "versions": ["3.5.1"], "purpose": "Bounded PCM WAV parsing for WebRTC playback", "maintenance": "stable", "transitive_cost": "low", "native": false, "rewrite_anchor": "`hound`" },
{ "name": "image-webp", "versions": ["0.2.4"], "purpose": "Opt-in pure-Rust bounded WebP image decoding", "maintenance": "active", "transitive_cost": "low", "native": false, "rewrite_anchor": "`image-webp`" }, { "name": "image-webp", "versions": ["0.2.4"], "purpose": "Default pure-Rust bounded WebP image decoding", "maintenance": "active", "transitive_cost": "low", "native": false, "rewrite_anchor": "`image-webp`" },
{ "name": "j2k", "versions": ["0.8.1"], "purpose": "Opt-in pure-Rust bounded JPEG 2000 and JP2 encoding and decoding", "maintenance": "active", "transitive_cost": "medium", "native": false, "rewrite_anchor": "`j2k`" }, { "name": "j2k", "versions": ["0.8.1"], "purpose": "Default pure-Rust bounded JPEG 2000 and JP2 encoding and decoding", "maintenance": "active", "transitive_cost": "medium", "native": false, "rewrite_anchor": "`j2k`" },
{ "name": "mac_address2", "versions": ["2.0.2"], "purpose": "Cross-platform machine identity compatibility input", "maintenance": "active", "transitive_cost": "low", "native": false, "rewrite_anchor": "`mac_address2`" }, { "name": "mac_address2", "versions": ["2.0.2"], "purpose": "Cross-platform machine identity compatibility input", "maintenance": "active", "transitive_cost": "low", "native": false, "rewrite_anchor": "`mac_address2`" },
{ "name": "md-5", "versions": ["0.10.6"], "purpose": "Legacy protocol checksum compatibility", "maintenance": "active", "transitive_cost": "low", "native": false, "rewrite_anchor": "`md-5`" }, { "name": "md-5", "versions": ["0.10.6"], "purpose": "Legacy protocol checksum compatibility", "maintenance": "active", "transitive_cost": "low", "native": false, "rewrite_anchor": "`md-5`" },
{ "name": "os_info", "versions": ["3.15.0"], "purpose": "Cross-platform login platform reporting", "maintenance": "active", "transitive_cost": "low", "native": false, "rewrite_anchor": "`os_info`" }, { "name": "os_info", "versions": ["3.15.0"], "purpose": "Cross-platform login platform reporting", "maintenance": "active", "transitive_cost": "low", "native": false, "rewrite_anchor": "`os_info`" },
@@ -30,7 +30,7 @@
{ "name": "sha1", "versions": ["0.10.7"], "purpose": "Legacy protocol hash compatibility", "maintenance": "active", "transitive_cost": "low", "native": false, "rewrite_anchor": "`sha1`" }, { "name": "sha1", "versions": ["0.10.7"], "purpose": "Legacy protocol hash compatibility", "maintenance": "active", "transitive_cost": "low", "native": false, "rewrite_anchor": "`sha1`" },
{ "name": "sha2", "versions": ["0.11.0"], "purpose": "Manifest integrity and protocol hashing", "maintenance": "active", "transitive_cost": "low", "native": false, "rewrite_anchor": "`sha2`" }, { "name": "sha2", "versions": ["0.11.0"], "purpose": "Manifest integrity and protocol hashing", "maintenance": "active", "transitive_cost": "low", "native": false, "rewrite_anchor": "`sha2`" },
{ "name": "skia-safe", "versions": ["0.99.0"], "purpose": "Opt-in cross-platform Skia image decoding", "maintenance": "monitored-native", "transitive_cost": "high", "native": true, "rewrite_anchor": "`skia-safe`" }, { "name": "skia-safe", "versions": ["0.99.0"], "purpose": "Opt-in cross-platform Skia image decoding", "maintenance": "monitored-native", "transitive_cost": "high", "native": true, "rewrite_anchor": "`skia-safe`" },
{ "name": "skia-rs-codec", "versions": ["0.3.0"], "purpose": "Opt-in pure-Rust BMP, GIF, ICO, JPEG, PNG, and WBMP image decoding", "maintenance": "active", "transitive_cost": "high", "native": false, "rewrite_anchor": "`skia-rs-codec`" }, { "name": "skia-rs-codec", "versions": ["0.3.0"], "purpose": "Default pure-Rust BMP, GIF, ICO, JPEG, PNG, and WBMP image decoding", "maintenance": "active", "transitive_cost": "high", "native": false, "rewrite_anchor": "`skia-rs-codec`" },
{ "name": "stats_alloc", "versions": ["0.1.10"], "purpose": "Allocation-budget compatibility tests, concurrency leak audits, and reproducible performance evidence", "maintenance": "stable", "transitive_cost": "low", "native": false, "rewrite_anchor": "`stats_alloc`" }, { "name": "stats_alloc", "versions": ["0.1.10"], "purpose": "Allocation-budget compatibility tests, concurrency leak audits, and reproducible performance evidence", "maintenance": "stable", "transitive_cost": "low", "native": false, "rewrite_anchor": "`stats_alloc`" },
{ "name": "str0m", "versions": ["0.22.0"], "purpose": "Native Rust ICE, DTLS, SRTP, RTP, and SCTP WebRTC transport", "maintenance": "active", "transitive_cost": "high", "native": false, "rewrite_anchor": "`str0m`" }, { "name": "str0m", "versions": ["0.22.0"], "purpose": "Native Rust ICE, DTLS, SRTP, RTP, and SCTP WebRTC transport", "maintenance": "active", "transitive_cost": "high", "native": false, "rewrite_anchor": "`str0m`" },
{ "name": "syn", "versions": ["2.0.119"], "purpose": "Syntax validation for generated Rust sources", "maintenance": "active", "transitive_cost": "medium", "native": false, "rewrite_anchor": "`syn`" }, { "name": "syn", "versions": ["2.0.119"], "purpose": "Syntax validation for generated Rust sources", "maintenance": "active", "transitive_cost": "medium", "native": false, "rewrite_anchor": "`syn`" },

View File

@@ -8,12 +8,12 @@ repository.workspace = true
description = "Optional Skia image decoder for the MetaCrate LibreMetaverse rewrite" description = "Optional Skia image decoder for the MetaCrate LibreMetaverse rewrite"
[features] [features]
default = [] default = ["rust-skia"]
skia = ["dep:skia-safe"] skia = ["dep:skia-safe"]
rust-skia = ["dep:image-webp", "dep:skia-rs-codec", "skia-rs-codec/gif", "skia-rs-codec/jpeg", "skia-rs-codec/png"] rust-skia = ["dep:image-webp", "dep:skia-rs-codec", "skia-rs-codec/gif", "skia-rs-codec/jpeg", "skia-rs-codec/png"]
[dependencies] [dependencies]
libremetaverse-imaging = { version = "0.0.1", path = "../libremetaverse-imaging" } libremetaverse-imaging = { version = "0.0.1", path = "../libremetaverse-imaging", default-features = false }
libremetaverse-types = { version = "0.0.1", path = "../libremetaverse-types" } libremetaverse-types = { version = "0.0.1", path = "../libremetaverse-types" }
image-webp = { version = "=0.2.4", optional = true } image-webp = { version = "=0.2.4", optional = true }
skia-rs-codec = { version = "=0.3.0", default-features = false, optional = true } skia-rs-codec = { version = "=0.3.0", default-features = false, optional = true }

View File

@@ -6,7 +6,8 @@ exposes a `skia-safe` type and never discovers or links Skia.
## Features and formats ## Features and formats
The default feature set has no Skia dependency. `SkiaTextureCodec::decode` and 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 `RustSkiaTextureCodec::decode` return a typed `InvalidOperation` error when
their respective feature is disabled, while conversion from the checked their respective feature is disabled, while conversion from the checked
project-owned `backend::SKBitmap` remains available for tests and callers that project-owned `backend::SKBitmap` remains available for tests and callers that
@@ -15,7 +16,7 @@ already own decoded pixels.
For a fully Rust implementation, enable: For a fully Rust implementation, enable:
```sh ```sh
cargo test -p libremetaverse-imaging-skia --no-default-features --features rust-skia cargo test -p libremetaverse-imaging-skia
``` ```
`rust-skia` pins [`skia-rs-codec` 0.3.0](https://github.com/rust-skia/skia-rs) `rust-skia` pins [`skia-rs-codec` 0.3.0](https://github.com/rust-skia/skia-rs)

View File

@@ -1,9 +1,9 @@
//! Optional Skia imaging adapter corresponding to `LibreMetaverse.Imaging.Skia`. //! Optional Skia imaging adapter corresponding to `LibreMetaverse.Imaging.Skia`.
//! //!
//! Enable `skia` or the fully native-Rust `rust-skia` alternative for bounded //! The default `rust-skia` backend provides bounded pure-Rust `BMP`, `GIF`,
//! `BMP`, `GIF`, `ICO`, `JPEG`, `PNG`, `WBMP`, and `WebP` decoding. //! `ICO`, `JPEG`, `PNG`, `WBMP`, and `WebP` decoding. Enable the optional
//! The default build remains inert. See the crate README for native cache, //! `skia` feature when native Google Skia is specifically required. See the
//! source-build, licensing, and cross-platform prerequisite details. //! crate README for native cache, source-build, licensing, and deployment details.
extern crate self as libremetaverse_imaging_skia; extern crate self as libremetaverse_imaging_skia;

View File

@@ -8,7 +8,7 @@ repository.workspace = true
description = "Texture codec abstractions for the MetaCrate LibreMetaverse rewrite" description = "Texture codec abstractions for the MetaCrate LibreMetaverse rewrite"
[features] [features]
default = [] default = ["rust-j2k"]
jpeg2000 = ["dep:libremetaverse-openjpeg"] jpeg2000 = ["dep:libremetaverse-openjpeg"]
rust-j2k = ["dep:j2k"] rust-j2k = ["dep:j2k"]

View File

@@ -1,9 +1,9 @@
//! Image and texture abstractions corresponding to `LibreMetaverse.Imaging`. //! Image and texture abstractions corresponding to `LibreMetaverse.Imaging`.
//! //!
//! The default surface provides managed images plus native `TGA`/`DDS` handling. //! The default surface provides managed images, native `TGA`/`DDS` handling,
//! Enable `jpeg2000` for the audited system `OpenJPEG` adapter or `rust-j2k` //! and the pure-Rust `rust-j2k` JPEG 2000 backend. Enable `jpeg2000` for the
//! for the independently selectable pure-Rust JPEG 2000 backend. Ordinary //! optional audited system `OpenJPEG` adapter. Consumers that only need the
//! users can consume the traits without either codec dependency. //! format-neutral image types can disable default features.
extern crate self as libremetaverse_imaging; extern crate self as libremetaverse_imaging;

View File

@@ -8,7 +8,7 @@ repository.workspace = true
description = "Primitive meshing shims for the MetaCrate LibreMetaverse rewrite" description = "Primitive meshing shims for the MetaCrate LibreMetaverse rewrite"
[dependencies] [dependencies]
libremetaverse-imaging = { version = "0.0.1", path = "../libremetaverse-imaging" } libremetaverse-imaging = { version = "0.0.1", path = "../libremetaverse-imaging", default-features = false }
libremetaverse-types = { version = "0.0.1", path = "../libremetaverse-types" } libremetaverse-types = { version = "0.0.1", path = "../libremetaverse-types" }
[dev-dependencies] [dev-dependencies]

View File

@@ -8,7 +8,7 @@ repository.workspace = true
description = "Rust rewrite shell for the LibreMetaverse client library" description = "Rust rewrite shell for the LibreMetaverse client library"
[features] [features]
default = ["dds-bc67"] default = ["dds-bc67", "rust-j2k"]
dds-bc67 = ["dep:bcdec_rs"] dds-bc67 = ["dep:bcdec_rs"]
jpeg2000 = ["libremetaverse-imaging/jpeg2000"] jpeg2000 = ["libremetaverse-imaging/jpeg2000"]
rust-j2k = ["libremetaverse-imaging/rust-j2k"] rust-j2k = ["libremetaverse-imaging/rust-j2k"]
@@ -20,7 +20,7 @@ bcdec_rs = { version = "0.2.0", optional = true }
flate2 = "1.1.2" flate2 = "1.1.2"
futures-channel = "0.3.31" futures-channel = "0.3.31"
futures-util = "0.3.31" futures-util = "0.3.31"
libremetaverse-imaging = { version = "0.0.1", path = "../libremetaverse-imaging" } libremetaverse-imaging = { version = "0.0.1", path = "../libremetaverse-imaging", default-features = false }
libremetaverse-prim-mesher = { version = "0.0.1", path = "../libremetaverse-prim-mesher" } libremetaverse-prim-mesher = { version = "0.0.1", path = "../libremetaverse-prim-mesher" }
libremetaverse-structured-data = { version = "0.0.1", path = "../libremetaverse-structured-data" } libremetaverse-structured-data = { version = "0.0.1", path = "../libremetaverse-structured-data" }
libremetaverse-types = { version = "0.0.1", path = "../libremetaverse-types" } libremetaverse-types = { version = "0.0.1", path = "../libremetaverse-types" }

View File

@@ -15,11 +15,11 @@ they use those APIs directly.
| Crate | Choose it for | Features or system boundary | | Crate | Choose it for | Features or system boundary |
| --- | --- | --- | | --- | --- | --- |
| `libremetaverse` | Grid client, login, network, agents, inventory, assets, appearance, world, and social APIs | Default pure-Rust BC6H/BC7; optional `jpeg2000`, `rust-j2k`, and `vorbis` | | `libremetaverse` | Grid client, login, network, agents, inventory, assets, appearance, world, and social APIs | Default pure-Rust BC6H/BC7 and J2K/JP2; optional native `jpeg2000` and `vorbis` |
| `libremetaverse-types` | UUIDs, vectors, matrices, colors, cancellation, compatibility collections, and boundary types | Pure Rust | | `libremetaverse-types` | UUIDs, vectors, matrices, colors, cancellation, compatibility collections, and boundary types | Pure Rust |
| `libremetaverse-structured-data` | LLSD/OSD XML, JSON, binary, and notation | Pure Rust | | `libremetaverse-structured-data` | LLSD/OSD XML, JSON, binary, and notation | Pure Rust |
| `libremetaverse-imaging` | Managed images, TGA/DDS, codec traits | Optional `jpeg2000` or pure-Rust `rust-j2k` | | `libremetaverse-imaging` | Managed images, TGA/DDS, codec traits | Default pure-Rust `rust-j2k`; optional native `jpeg2000` |
| `libremetaverse-imaging-skia` | Common raster formats through native Skia or pure Rust | Optional `skia` native build/cache; optional `rust-skia` has no native prerequisites | | `libremetaverse-imaging-skia` | Common raster formats through native Skia or pure Rust | Default pure-Rust `rust-skia`; optional `skia` native build/cache |
| `libremetaverse-prim-mesher` | Legacy prim and sculpt geometry | Pure Rust | | `libremetaverse-prim-mesher` | Legacy prim and sculpt geometry | Pure Rust |
| `libremetaverse-rendering-simple` | Deterministic reference geometry | Pure Rust | | `libremetaverse-rendering-simple` | Deterministic reference geometry | Pure Rust |
| `libremetaverse-rendering-mesh-foundry` | Prim, terrain, sculpt, and mesh-asset rendering | Pure Rust | | `libremetaverse-rendering-mesh-foundry` | Prim, terrain, sculpt, and mesh-asset rendering | Pure Rust |
@@ -31,8 +31,8 @@ they use those APIs directly.
| `libremetaverse-openjpeg` | Audited `OpenJPEG` adapter | System `OpenJPEG` 2.5.4 or newer | | `libremetaverse-openjpeg` | Audited `OpenJPEG` adapter | System `OpenJPEG` 2.5.4 or newer |
| `libremetaverse-opus` | Audited Opus encoder/decoder adapter | System libopus | | `libremetaverse-opus` | Audited Opus encoder/decoder adapter | System libopus |
Features are additive. Keep defaults unless you need a codec, and enable one Features are additive. Keep the pure-Rust defaults for normal applications,
native adapter at a time while diagnosing installation problems. The and enable a native adapter only when it is specifically needed. The
[release CI matrix](https://git.rfc1437.de/hugo/MetaCrate/src/branch/main/docs/release-ci-matrix.md) records every validated combination. [release CI matrix](https://git.rfc1437.de/hugo/MetaCrate/src/branch/main/docs/release-ci-matrix.md) records every validated combination.
## Naming and overload migration ## Naming and overload migration
@@ -190,7 +190,7 @@ The default client build needs no image-codec system library. Optional native
features require: features require:
- `OpenJPEG` 2.5.4 or newer for `jpeg2000`; - `OpenJPEG` 2.5.4 or newer for `jpeg2000`;
- no native prerequisite for the pure-Rust `rust-j2k` feature; - no native prerequisite for the default pure-Rust `rust-j2k` and `rust-skia` features;
- the rust-skia prerequisites/cache for `skia`; - the rust-skia prerequisites/cache for `skia`;
- system libopus for WebRTC voice and the `libremetaverse-opus` adapter; - system libopus for WebRTC voice and the `libremetaverse-opus` adapter;
- ALSA development headers on Linux, `CoreAudio` on macOS, or WASAPI on Windows - ALSA development headers on Linux, `CoreAudio` on macOS, or WASAPI on Windows

View File

@@ -6,11 +6,11 @@ and mutable raw payload. Concrete animation, sound, script, calling-card,
landmark, settings, mesh, texture, wearable, and notecard models enforce a 64 MiB landmark, settings, mesh, texture, wearable, and notecard models enforce a 64 MiB
input ceiling and reject malformed structured formats with typed errors. Mesh and input ceiling and reject malformed structured formats with typed errors. Mesh and
settings parsing use StructuredData. Texture encode/decode uses the imaging settings parsing use StructuredData. Texture encode/decode uses the imaging
crate's bounded `jpeg2000` adapter, while the opt-in `vorbis` feature streams crate's default bounded pure-Rust JPEG 2000 adapter, while the opt-in `vorbis`
PCM conversion through bounded planar Ogg Vorbis blocks; neither API exposes feature streams PCM conversion through bounded planar Ogg Vorbis blocks;
codec implementation types. With either native codec feature disabled, its neither API exposes codec implementation types. The optional native OpenJPEG
public API remains present and returns a typed `InvalidOperation` for otherwise path is selected only by its explicit feature and never discovered or linked
valid input instead of discovering or linking a system codec implicitly. by a default build.
`AssetManager` is client-owned and shares one `DownloadManager` and `AssetCache`. `AssetManager` is client-owned and shares one `DownloadManager` and `AssetCache`.
ViewerAsset, GetMesh, GetTexture, and server-bake requests check the cache before ViewerAsset, GetMesh, GetTexture, and server-bake requests check the cache before

View File

@@ -49,7 +49,8 @@ All native boundaries have Linux, Windows, and macOS strategies:
|---|---|---|---| |---|---|---|---|
| libopus 1.3+ | `pkg-config` package `opus` | vcpkg `opus` for MSVC; `pkg-config` for GNU | WebRTC voice crate | | libopus 1.3+ | `pkg-config` package `opus` | vcpkg `opus` for MSVC; `pkg-config` for GNU | WebRTC voice crate |
| OpenJPEG 2.5.4+ | `pkg-config` package `libopenjp2` | vcpkg `openjpeg` for MSVC; `pkg-config` for GNU | opt-in `jpeg2000` | | OpenJPEG 2.5.4+ | `pkg-config` package `libopenjp2` | vcpkg `openjpeg` for MSVC; `pkg-config` for GNU | opt-in `jpeg2000` |
| j2k 0.8.1 | pure Rust, no platform prerequisite | same pure-Rust graph | opt-in `rust-j2k` | | j2k 0.8.1 | pure Rust, no platform prerequisite | same pure-Rust graph | default `rust-j2k` |
| skia-rs-codec 0.3.0 and image-webp 0.2.4 | pure Rust, no platform prerequisite | same pure-Rust graph | default `rust-skia` |
| Skia 0.99.0 | target-specific official binary cache or source build | same target-specific strategy | opt-in `skia` | | Skia 0.99.0 | target-specific official binary cache or source build | same target-specific strategy | opt-in `skia` |
| Vorbis 0.5.6 stack | `vorbis_rs` builds its reviewed C codec stack | same crate strategy | opt-in `vorbis` | | Vorbis 0.5.6 stack | `vorbis_rs` builds its reviewed C codec stack | same crate strategy | opt-in `vorbis` |
| Physical audio | ALSA development files on Linux; CoreAudio is system-provided on macOS | WASAPI is system-provided | opt-in `real-audio` | | Physical audio | ALSA development files on Linux; CoreAudio is system-provided on macOS | WASAPI is system-provided | opt-in `real-audio` |

View File

@@ -17,18 +17,19 @@ and [`MeshFoundry` guide](../crates/libremetaverse-rendering-mesh-foundry/README
| --- | --- | --- | --- | | --- | --- | --- | --- |
| Managed images and TGA | enabled | n/a | none | | Managed images and TGA | enabled | n/a | none |
| JPEG 2000 | disabled | `libremetaverse-imaging/jpeg2000` | OpenJPEG 2.5.x | | JPEG 2000 | disabled | `libremetaverse-imaging/jpeg2000` | OpenJPEG 2.5.x |
| JPEG 2000 (pure Rust) | disabled | `libremetaverse-imaging/rust-j2k` | none (`j2k` 0.8.1) | | JPEG 2000 (pure Rust) | enabled | `libremetaverse-imaging/rust-j2k` | none (`j2k` 0.8.1) |
| BMP/GIF/ICO/JPEG/PNG/WBMP/WebP (pure Rust) | disabled | `libremetaverse-imaging-skia/rust-skia` | none (`skia-rs-codec` 0.3.0 plus `image-webp` 0.2.4) | | BMP/GIF/ICO/JPEG/PNG/WBMP/WebP (pure Rust) | enabled | `libremetaverse-imaging-skia/rust-skia` | none (`skia-rs-codec` 0.3.0 plus `image-webp` 0.2.4) |
| BMP/GIF/ICO/JPEG/PNG/WBMP/WebP (native) | disabled | `libremetaverse-imaging-skia/skia` | Skia | | BMP/GIF/ICO/JPEG/PNG/WBMP/WebP (native) | disabled | `libremetaverse-imaging-skia/skia` | Skia |
| Prim and sculpt meshing, OBJ ingestion | enabled | n/a | none | | Prim and sculpt meshing, OBJ ingestion | enabled | n/a | none |
OpenJPEG is a non-default workspace member so release tooling can package the OpenJPEG is a non-default workspace member so release tooling can package the
adapter explicitly, and imaging reaches it only through the optional adapter explicitly, and imaging reaches it only through the optional
dependency. The independent `rust-j2k` feature reaches only the audited dependency. The default `rust-j2k` feature reaches only the audited pure-Rust
pure-Rust `j2k` graph; enabling both features keeps both explicit codec types `j2k` graph; enabling both features keeps both explicit codec types available
available for interoperability testing. Skia is likewise an optional, for interoperability testing. Native Skia is likewise an optional,
target-specific dependency. The consolidated required Gitea gate exercises the target-specific dependency, while `rust-skia` is the raster crate default. The
native feature, while a dedicated `ubuntu-latest` job tests `rust-skia`, audits consolidated required Gitea gate exercises the native feature, while a dedicated
`ubuntu-latest` job tests `rust-skia`, audits
its normal/build graph without installing native codec tools, and compiles the its normal/build graph without installing native codec tools, and compiles the
same code for WASM. Minimal-feature checks still prove no codec is needed for same code for WASM. Minimal-feature checks still prove no codec is needed for
the owned Rust and translated compatibility tests. the owned Rust and translated compatibility tests.

View File

@@ -17,14 +17,14 @@ is evidence of remaining work, never permission to waive it.
## Features and prerequisites ## Features and prerequisites
The default `libremetaverse` build uses the pure-Rust `dds-bc67` image path. The default MetaCrate build uses the pure-Rust `dds-bc67`, `rust-j2k`, and
Optional boundaries are explicit: `rust-skia` image paths. Native alternatives remain explicit opt-ins:
| Feature | Capability | Native/build prerequisite | | Feature | Capability | Native/build prerequisite |
| --- | --- | --- | | --- | --- | --- |
| `jpeg2000` | J2K/JP2 through the safe OpenJPEG adapter | OpenJPEG 2.5.4 or newer | | `jpeg2000` | J2K/JP2 through the safe OpenJPEG adapter | OpenJPEG 2.5.4 or newer |
| `rust-j2k` | J2K/JP2 through `RustJ2kCodec` | none; exact pure-Rust `j2k` 0.8.1 | | `rust-j2k` (default) | J2K/JP2 through `RustJ2kCodec` | none; exact pure-Rust `j2k` 0.8.1 |
| `rust-skia` | BMP/GIF/ICO/JPEG/PNG/WBMP/WebP through `RustSkiaTextureCodec` | none; exact pure-Rust `skia-rs-codec` 0.3.0 and `image-webp` 0.2.4 | | `rust-skia` (default) | BMP/GIF/ICO/JPEG/PNG/WBMP/WebP through `RustSkiaTextureCodec` | none; exact pure-Rust `skia-rs-codec` 0.3.0 and `image-webp` 0.2.4 |
| `skia` | PNG/JPEG/WebP and other Skia formats | Skia 0.99 target cache or documented source tools | | `skia` | PNG/JPEG/WebP and other Skia formats | Skia 0.99 target cache or documented source tools |
| `vorbis` | PCM to Ogg Vorbis | the locked `vorbis_rs` native build stack | | `vorbis` | PCM to Ogg Vorbis | the locked `vorbis_rs` native build stack |
| default WebRTC | native ICE/DTLS/SRTP/RTP/SCTP and Opus | system libopus 1.3 or newer | | default WebRTC | native ICE/DTLS/SRTP/RTP/SCTP and Opus | system libopus 1.3 or newer |

View File

@@ -15,11 +15,11 @@ they use those APIs directly.
| Crate | Choose it for | Features or system boundary | | Crate | Choose it for | Features or system boundary |
| --- | --- | --- | | --- | --- | --- |
| `libremetaverse` | Grid client, login, network, agents, inventory, assets, appearance, world, and social APIs | Default pure-Rust BC6H/BC7; optional `jpeg2000`, `rust-j2k`, and `vorbis` | | `libremetaverse` | Grid client, login, network, agents, inventory, assets, appearance, world, and social APIs | Default pure-Rust BC6H/BC7 and J2K/JP2; optional native `jpeg2000` and `vorbis` |
| `libremetaverse-types` | UUIDs, vectors, matrices, colors, cancellation, compatibility collections, and boundary types | Pure Rust | | `libremetaverse-types` | UUIDs, vectors, matrices, colors, cancellation, compatibility collections, and boundary types | Pure Rust |
| `libremetaverse-structured-data` | LLSD/OSD XML, JSON, binary, and notation | Pure Rust | | `libremetaverse-structured-data` | LLSD/OSD XML, JSON, binary, and notation | Pure Rust |
| `libremetaverse-imaging` | Managed images, TGA/DDS, codec traits | Optional `jpeg2000` or pure-Rust `rust-j2k` | | `libremetaverse-imaging` | Managed images, TGA/DDS, codec traits | Default pure-Rust `rust-j2k`; optional native `jpeg2000` |
| `libremetaverse-imaging-skia` | Common raster formats through native Skia or pure Rust | Optional `skia` native build/cache; optional `rust-skia` has no native prerequisites | | `libremetaverse-imaging-skia` | Common raster formats through native Skia or pure Rust | Default pure-Rust `rust-skia`; optional `skia` native build/cache |
| `libremetaverse-prim-mesher` | Legacy prim and sculpt geometry | Pure Rust | | `libremetaverse-prim-mesher` | Legacy prim and sculpt geometry | Pure Rust |
| `libremetaverse-rendering-simple` | Deterministic reference geometry | Pure Rust | | `libremetaverse-rendering-simple` | Deterministic reference geometry | Pure Rust |
| `libremetaverse-rendering-mesh-foundry` | Prim, terrain, sculpt, and mesh-asset rendering | Pure Rust | | `libremetaverse-rendering-mesh-foundry` | Prim, terrain, sculpt, and mesh-asset rendering | Pure Rust |
@@ -31,8 +31,8 @@ they use those APIs directly.
| `libremetaverse-openjpeg` | Audited `OpenJPEG` adapter | System `OpenJPEG` 2.5.4 or newer | | `libremetaverse-openjpeg` | Audited `OpenJPEG` adapter | System `OpenJPEG` 2.5.4 or newer |
| `libremetaverse-opus` | Audited Opus encoder/decoder adapter | System libopus | | `libremetaverse-opus` | Audited Opus encoder/decoder adapter | System libopus |
Features are additive. Keep defaults unless you need a codec, and enable one Features are additive. Keep the pure-Rust defaults for normal applications,
native adapter at a time while diagnosing installation problems. The and enable a native adapter only when it is specifically needed. The
[release CI matrix](release-ci-matrix.md) records every validated combination. [release CI matrix](release-ci-matrix.md) records every validated combination.
## Naming and overload migration ## Naming and overload migration
@@ -190,7 +190,7 @@ The default client build needs no image-codec system library. Optional native
features require: features require:
- `OpenJPEG` 2.5.4 or newer for `jpeg2000`; - `OpenJPEG` 2.5.4 or newer for `jpeg2000`;
- no native prerequisite for the pure-Rust `rust-j2k` feature; - no native prerequisite for the default pure-Rust `rust-j2k` and `rust-skia` features;
- the rust-skia prerequisites/cache for `skia`; - the rust-skia prerequisites/cache for `skia`;
- system libopus for WebRTC voice and the `libremetaverse-opus` adapter; - system libopus for WebRTC voice and the `libremetaverse-opus` adapter;
- ALSA development headers on Linux, `CoreAudio` on macOS, or WASAPI on Windows - ALSA development headers on Linux, `CoreAudio` on macOS, or WASAPI on Windows

View File

@@ -10,9 +10,9 @@ publish = false
[dependencies] [dependencies]
clap = { version = "4.5", features = ["derive"] } clap = { version = "4.5", features = ["derive"] }
libremetaverse = { version = "0.0.1", path = "../crates/libremetaverse", default-features = false } libremetaverse = { version = "0.0.1", path = "../crates/libremetaverse" }
libremetaverse-imaging = { version = "0.0.1", path = "../crates/libremetaverse-imaging", features = ["jpeg2000"] } libremetaverse-imaging = { version = "0.0.1", path = "../crates/libremetaverse-imaging" }
libremetaverse-imaging-skia = { version = "0.0.1", path = "../crates/libremetaverse-imaging-skia", features = ["skia"] } libremetaverse-imaging-skia = { version = "0.0.1", path = "../crates/libremetaverse-imaging-skia" }
libremetaverse-structured-data = { version = "0.0.1", path = "../crates/libremetaverse-structured-data" } libremetaverse-structured-data = { version = "0.0.1", path = "../crates/libremetaverse-structured-data" }
libremetaverse-voice-vivox = { version = "0.0.1", path = "../crates/libremetaverse-voice-vivox" } libremetaverse-voice-vivox = { version = "0.0.1", path = "../crates/libremetaverse-voice-vivox" }
libremetaverse-voice-webrtc = { version = "0.0.1", path = "../crates/libremetaverse-voice-webrtc" } libremetaverse-voice-webrtc = { version = "0.0.1", path = "../crates/libremetaverse-voice-webrtc" }

View File

@@ -14,10 +14,10 @@ use libremetaverse::types::compat::CancellationToken;
use libremetaverse::types::{AssetType, FolderType, InventoryType, UUID}; use libremetaverse::types::{AssetType, FolderType, InventoryType, UUID};
use libremetaverse::{PermissionMask, Permissions}; use libremetaverse::{PermissionMask, Permissions};
use libremetaverse_imaging::{ use libremetaverse_imaging::{
J2kCodec, J2kCompression, J2kDecodeOptions, J2kEncodeOptions, ManagedImage, J2kCompression, J2kDecodeOptions, J2kEncodeOptions, ManagedImage, ManagedImageImageChannels,
ManagedImageImageChannels, RustJ2kCodec,
}; };
use libremetaverse_imaging_skia::SkiaTextureCodec; use libremetaverse_imaging_skia::RustSkiaTextureCodec;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::fs::{self, File}; use std::fs::{self, File};
use std::io::{Cursor, Read, Write}; use std::io::{Cursor, Read, Write};
@@ -1465,14 +1465,14 @@ fn image_to_j2k(path: &Path) -> Result<Vec<u8>, String> {
.unwrap_or("") .unwrap_or("")
.to_ascii_lowercase(); .to_ascii_lowercase();
if matches!(extension.as_str(), "jp2" | "j2c" | "j2k") { if matches!(extension.as_str(), "jp2" | "j2c" | "j2k") {
J2kCodec::decode_bytes(&bytes, J2kDecodeOptions::default()) RustJ2kCodec::decode_bytes(&bytes, J2kDecodeOptions::default())
.map_err(|_| "Invalid JPEG 2000 image".to_owned())?; .map_err(|_| "Invalid JPEG 2000 image".to_owned())?;
return Ok(bytes); return Ok(bytes);
} }
let mut image = if matches!(extension.as_str(), "tga" | "targa") { let mut image = if matches!(extension.as_str(), "tga" | "targa") {
decode_tga(&bytes)? decode_tga(&bytes)?
} else { } else {
SkiaTextureCodec::new() RustSkiaTextureCodec::new()
.map_err(|_| "Could not initialize the image decoder".to_owned())? .map_err(|_| "Could not initialize the image decoder".to_owned())?
.decode(Box::new(Cursor::new(bytes))) .decode(Box::new(Cursor::new(bytes)))
.map_err(|_| "Failed to decode image".to_owned())? .map_err(|_| "Failed to decode image".to_owned())?
@@ -1491,7 +1491,7 @@ fn image_to_j2k(path: &Path) -> Result<Vec<u8>, String> {
.resize_bilinear(width.min(1024), height.min(1024)) .resize_bilinear(width.min(1024), height.min(1024))
.map_err(|_| "Failed to limit image dimensions".to_owned())?; .map_err(|_| "Failed to limit image dimensions".to_owned())?;
} }
J2kCodec::encode( RustJ2kCodec::encode(
&image, &image,
J2kEncodeOptions::default().with_compression(J2kCompression::Lossy { J2kEncodeOptions::default().with_compression(J2kCompression::Lossy {
compression_ratio: 10.0, compression_ratio: 10.0,
@@ -1583,7 +1583,7 @@ async fn dump_outfit<B: Backend + ?Sized>(
.await?; .await?;
let jp2 = directory.join(format!("{texture_id}.jp2")); let jp2 = directory.join(format!("{texture_id}.jp2"));
write_bounded(&jp2, &bytes)?; write_bounded(&jp2, &bytes)?;
let image = J2kCodec::decode_bytes(&bytes, J2kDecodeOptions::default()) let image = RustJ2kCodec::decode_bytes(&bytes, J2kDecodeOptions::default())
.map_err(|_| format!("Failed to decode outfit texture {texture_id}"))?; .map_err(|_| format!("Failed to decode outfit texture {texture_id}"))?;
let tga = directory.join(format!("{texture_id}.tga")); let tga = directory.join(format!("{texture_id}.tga"));
write_bounded(&tga, &encode_tga(&image)?)?; write_bounded(&tga, &encode_tga(&image)?)?;

View File

@@ -1466,7 +1466,7 @@ async fn download_texture<B: Backend + ?Sized>(
.as_str(), .as_str(),
)?; )?;
write_bounded(&path, &data)?; write_bounded(&path, &data)?;
let dimensions = libremetaverse_imaging::J2kCodec::decode_bytes( let dimensions = libremetaverse_imaging::RustJ2kCodec::decode_bytes(
&data, &data,
libremetaverse_imaging::J2kDecodeOptions::default(), libremetaverse_imaging::J2kDecodeOptions::default(),
) )
@@ -1574,7 +1574,7 @@ async fn export<B: Backend + ?Sized>(
.await?; .await?;
let path = texture_directory.join(format!("{texture}.jp2")); let path = texture_directory.join(format!("{texture}.jp2"));
write_bounded(&path, &data)?; write_bounded(&path, &data)?;
let image = libremetaverse_imaging::J2kCodec::decode_bytes( let image = libremetaverse_imaging::RustJ2kCodec::decode_bytes(
&data, &data,
libremetaverse_imaging::J2kDecodeOptions::default(), libremetaverse_imaging::J2kDecodeOptions::default(),
) )

View File

@@ -1,4 +1,6 @@
use libremetaverse_imaging::{J2kCodec, J2kEncodeOptions, ManagedImage, ManagedImageImageChannels}; use libremetaverse_imaging::{
J2kEncodeOptions, ManagedImage, ManagedImageImageChannels, RustJ2kCodec,
};
use std::fs; use std::fs;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::{Command, Output, Stdio}; use std::process::{Command, Output, Stdio};
@@ -111,7 +113,7 @@ fn one_pixel_jp2() -> Vec<u8> {
image.red[0] = 10; image.red[0] = 10;
image.green[0] = 20; image.green[0] = 20;
image.blue[0] = 30; image.blue[0] = 30;
J2kCodec::encode(&image, J2kEncodeOptions::default()).expect("encode JPEG2000 fixture") RustJ2kCodec::encode(&image, J2kEncodeOptions::default()).expect("encode JPEG2000 fixture")
} }
fn one_pixel_tga() -> Vec<u8> { fn one_pixel_tga() -> Vec<u8> {
@@ -277,7 +279,7 @@ fn fake_grid_exercises_every_owned_inventory_appearance_and_asset_command() {
b"default { state_entry() {} }" b"default { state_entry() {} }"
); );
assert_eq!( assert_eq!(
J2kCodec::decode_bytes( RustJ2kCodec::decode_bytes(
&fs::read(outfit.join(format!("{UPLOADED_TEXTURE_ASSET}.jp2"))) &fs::read(outfit.join(format!("{UPLOADED_TEXTURE_ASSET}.jp2")))
.expect("uploaded outfit jp2"), .expect("uploaded outfit jp2"),
libremetaverse_imaging::J2kDecodeOptions::default(), libremetaverse_imaging::J2kDecodeOptions::default(),

View File

@@ -1,4 +1,6 @@
use libremetaverse_imaging::{J2kCodec, J2kEncodeOptions, ManagedImage, ManagedImageImageChannels}; use libremetaverse_imaging::{
J2kEncodeOptions, ManagedImage, ManagedImageImageChannels, RustJ2kCodec,
};
use std::fs; use std::fs;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::{Command, Output, Stdio}; use std::process::{Command, Output, Stdio};
@@ -85,7 +87,7 @@ fn one_pixel_jp2() -> Vec<u8> {
image.red[0] = 10; image.red[0] = 10;
image.green[0] = 20; image.green[0] = 20;
image.blue[0] = 30; image.blue[0] = 30;
J2kCodec::encode(&image, J2kEncodeOptions::default()).expect("encode JPEG2000") RustJ2kCodec::encode(&image, J2kEncodeOptions::default()).expect("encode JPEG2000")
} }
#[test] #[test]

View File

@@ -40,8 +40,8 @@ def check_owned_rust() -> None:
def check_features() -> None: def check_features() -> None:
imaging = load_toml(OWNED_CRATES[0] / "Cargo.toml") imaging = load_toml(OWNED_CRATES[0] / "Cargo.toml")
if imaging["features"].get("default") != []: if imaging["features"].get("default") != ["rust-j2k"]:
raise SystemExit("imaging default features must stay empty") raise SystemExit("imaging defaults must select only pure-Rust JPEG 2000")
if imaging["features"].get("jpeg2000") != ["dep:libremetaverse-openjpeg"]: if imaging["features"].get("jpeg2000") != ["dep:libremetaverse-openjpeg"]:
raise SystemExit("JPEG 2000 must stay isolated behind its optional feature") raise SystemExit("JPEG 2000 must stay isolated behind its optional feature")
if imaging["features"].get("rust-j2k") != ["dep:j2k"]: if imaging["features"].get("rust-j2k") != ["dep:j2k"]:
@@ -50,8 +50,8 @@ def check_features() -> None:
raise SystemExit("the OpenJPEG adapter dependency must stay optional") raise SystemExit("the OpenJPEG adapter dependency must stay optional")
skia = load_toml(OWNED_CRATES[1] / "Cargo.toml") skia = load_toml(OWNED_CRATES[1] / "Cargo.toml")
if skia["features"].get("default") != []: if skia["features"].get("default") != ["rust-skia"]:
raise SystemExit("Skia adapter default features must stay empty") raise SystemExit("raster adapter defaults must select only pure-Rust codecs")
if skia["features"].get("skia") != ["dep:skia-safe"]: if skia["features"].get("skia") != ["dep:skia-safe"]:
raise SystemExit("Skia must stay isolated behind its optional feature") raise SystemExit("Skia must stay isolated behind its optional feature")
targets = skia.get("target", {}).values() targets = skia.get("target", {}).values()

View File

@@ -911,7 +911,10 @@ fn validate_features(name: &str, actual: &BTreeMap<String, Vec<String>>) -> Resu
let expected = match name { let expected = match name {
"libremetaverse" => BTreeMap::from([ "libremetaverse" => BTreeMap::from([
("dds-bc67".to_owned(), vec!["dep:bcdec_rs".to_owned()]), ("dds-bc67".to_owned(), vec!["dep:bcdec_rs".to_owned()]),
("default".to_owned(), vec!["dds-bc67".to_owned()]), (
"default".to_owned(),
vec!["dds-bc67".to_owned(), "rust-j2k".to_owned()],
),
( (
"jpeg2000".to_owned(), "jpeg2000".to_owned(),
vec!["libremetaverse-imaging/jpeg2000".to_owned()], vec!["libremetaverse-imaging/jpeg2000".to_owned()],
@@ -923,7 +926,7 @@ fn validate_features(name: &str, actual: &BTreeMap<String, Vec<String>>) -> Resu
("vorbis".to_owned(), vec!["dep:vorbis_rs".to_owned()]), ("vorbis".to_owned(), vec!["dep:vorbis_rs".to_owned()]),
]), ]),
"libremetaverse-imaging" => BTreeMap::from([ "libremetaverse-imaging" => BTreeMap::from([
("default".to_owned(), Vec::new()), ("default".to_owned(), vec!["rust-j2k".to_owned()]),
( (
"jpeg2000".to_owned(), "jpeg2000".to_owned(),
vec!["dep:libremetaverse-openjpeg".to_owned()], vec!["dep:libremetaverse-openjpeg".to_owned()],
@@ -931,7 +934,7 @@ fn validate_features(name: &str, actual: &BTreeMap<String, Vec<String>>) -> Resu
("rust-j2k".to_owned(), vec!["dep:j2k".to_owned()]), ("rust-j2k".to_owned(), vec!["dep:j2k".to_owned()]),
]), ]),
"libremetaverse-imaging-skia" => BTreeMap::from([ "libremetaverse-imaging-skia" => BTreeMap::from([
("default".to_owned(), Vec::new()), ("default".to_owned(), vec!["rust-skia".to_owned()]),
( (
"rust-skia".to_owned(), "rust-skia".to_owned(),
vec![ vec![
@@ -1242,7 +1245,7 @@ The exact mapping, exported-marker, feature, and normalized Rust declaration has
- .NET events become `subscribe_*` calls returning an owned `Subscription`; callbacks are `Send + Sync` and dispatch outside internal locks.\n\ - .NET events become `subscribe_*` calls returning an owned `Subscription`; callbacks are `Send + Sync` and dispatch outside internal locks.\n\
- `IDisposable` becomes explicit idempotent shutdown plus `Drop`; cancellation remains a typed `Error::Cancelled`.\n\ - `IDisposable` becomes explicit idempotent shutdown plus `Drop`; cancellation remains a typed `Error::Cancelled`.\n\
- Closed C# enums retain fixed discriminants and are SemVer-breaking to extend; flags retain unknown bits, while public Rust error enums are `non_exhaustive`.\n\ - Closed C# enums retain fixed discriminants and are SemVer-breaking to extend; flags retain unknown bits, while public Rust error enums are `non_exhaustive`.\n\
- Optional native and pure-Rust backends remain feature-gated (`jpeg2000`, `rust-j2k`, `skia`, `rust-skia`, `vorbis`, `real-audio`); default and empty-default sets are part of the baseline.\n\ - Pure-Rust image backends are enabled by default (`rust-j2k`, `rust-skia`); native alternatives remain feature-gated (`jpeg2000`, `skia`, `vorbis`, `real-audio`), and empty-default sets remain part of the baseline.\n\
- Capability HTTP injection uses project-owned `HttpMessageHandler`, `CapsHttpLimits`, and `with_native_transport`; the internal `reqwest` client is not part of the public surface.\n\ - Capability HTTP injection uses project-owned `HttpMessageHandler`, `CapsHttpLimits`, and `with_native_transport`; the internal `reqwest` client is not part of the public surface.\n\
- External C# signature types map to core/std, adopted cross-platform crates, or project-owned boundary types; no third-party crate path leaks through mapped signatures or public Rust declarations.\n\n\ - External C# signature types map to core/std, adopted cross-platform crates, or project-owned boundary types; no third-party crate path leaks through mapped signatures or public Rust declarations.\n\n\
## Compile consumers\n\n\ ## Compile consumers\n\n\

View File

@@ -422,7 +422,7 @@ fn audit_cargo_features(root: &Path) -> Result<()> {
if defaults.iter().any(|feature| { if defaults.iter().any(|feature| {
matches!( matches!(
feature.as_str(), feature.as_str(),
Some("jpeg2000" | "vorbis" | "dep:vorbis_rs") Some("jpeg2000" | "skia" | "vorbis" | "dep:vorbis_rs")
) )
}) { }) {
return Err(MatrixError::new( return Err(MatrixError::new(
@@ -450,6 +450,8 @@ fn audit_cargo_features(root: &Path) -> Result<()> {
let default_tree = String::from_utf8_lossy(&default_tree.stdout); let default_tree = String::from_utf8_lossy(&default_tree.stdout);
for forbidden in [ for forbidden in [
"libremetaverse-openjpeg ", "libremetaverse-openjpeg ",
"skia-safe ",
"skia-bindings ",
"vorbis_rs ", "vorbis_rs ",
"ogg_next_sys ", "ogg_next_sys ",
"aotuv_lancer_vorbis_sys ", "aotuv_lancer_vorbis_sys ",