feat(imaging): add pure-Rust JPEG 2000 backend (#109)
Some checks failed
CI / required (push) Failing after 3m18s
Some checks failed
CI / required (push) Failing after 3m18s
This commit is contained in:
@@ -11,6 +11,7 @@ description = "Rust rewrite shell for the LibreMetaverse client library"
|
||||
default = ["dds-bc67"]
|
||||
dds-bc67 = ["dep:bcdec_rs"]
|
||||
jpeg2000 = ["libremetaverse-imaging/jpeg2000"]
|
||||
rust-j2k = ["libremetaverse-imaging/rust-j2k"]
|
||||
vorbis = ["dep:vorbis_rs"]
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -15,10 +15,10 @@ they use those APIs directly.
|
||||
|
||||
| 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` and `vorbis` |
|
||||
| `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-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-imaging` | Managed images, TGA/DDS, codec traits | Optional `jpeg2000` |
|
||||
| `libremetaverse-imaging` | Managed images, TGA/DDS, codec traits | Optional `jpeg2000` or pure-Rust `rust-j2k` |
|
||||
| `libremetaverse-imaging-skia` | Common raster formats through Skia | Optional `skia`; native Skia build/cache |
|
||||
| `libremetaverse-prim-mesher` | Legacy prim and sculpt geometry | Pure Rust |
|
||||
| `libremetaverse-rendering-simple` | Deterministic reference geometry | Pure Rust |
|
||||
@@ -190,6 +190,7 @@ The default client build needs no image-codec system library. Optional native
|
||||
features require:
|
||||
|
||||
- `OpenJPEG` 2.5.4 or newer for `jpeg2000`;
|
||||
- no native prerequisite for the pure-Rust `rust-j2k` feature;
|
||||
- the rust-skia prerequisites/cache for `skia`;
|
||||
- system libopus for WebRTC voice and the `libremetaverse-opus` adapter;
|
||||
- ALSA development headers on Linux, `CoreAudio` on macOS, or WASAPI on Windows
|
||||
|
||||
@@ -150,7 +150,7 @@ impl Baker {
|
||||
let texture = crate::assets::AssetTexture::new_with_managed_image(output)?;
|
||||
// JPEG2000 is the protocol representation. Keep the decoded image even
|
||||
// when a build intentionally excludes that optional codec.
|
||||
#[cfg(feature = "jpeg2000")]
|
||||
#[cfg(any(feature = "jpeg2000", feature = "rust-j2k"))]
|
||||
texture.encode()?;
|
||||
self.baked_texture = Some(texture);
|
||||
Ok(())
|
||||
|
||||
@@ -9,7 +9,11 @@
|
||||
)]
|
||||
|
||||
use crate::{Error, Permissions};
|
||||
#[cfg(feature = "jpeg2000")]
|
||||
use libremetaverse_imaging::J2kCodec as TextureJ2kCodec;
|
||||
use libremetaverse_imaging::ManagedImage;
|
||||
#[cfg(all(not(feature = "jpeg2000"), feature = "rust-j2k"))]
|
||||
use libremetaverse_imaging::RustJ2kCodec as TextureJ2kCodec;
|
||||
use libremetaverse_structured_data::{OSD, OSDMap, OSDParser};
|
||||
use libremetaverse_types::{AssetType, SaleType, UUID, Vector3, WearableType};
|
||||
use std::collections::HashMap;
|
||||
@@ -526,9 +530,9 @@ impl AssetTexture {
|
||||
if self.image.is_some() {
|
||||
return Ok(true);
|
||||
}
|
||||
#[cfg(feature = "jpeg2000")]
|
||||
#[cfg(any(feature = "jpeg2000", feature = "rust-j2k"))]
|
||||
{
|
||||
self.image = Some(libremetaverse_imaging::J2kCodec::decode_bytes(
|
||||
self.image = Some(TextureJ2kCodec::decode_bytes(
|
||||
&self.raw.bytes(),
|
||||
libremetaverse_imaging::J2kDecodeOptions::default(),
|
||||
)?);
|
||||
@@ -543,7 +547,7 @@ impl AssetTexture {
|
||||
};
|
||||
Ok(true)
|
||||
}
|
||||
#[cfg(not(feature = "jpeg2000"))]
|
||||
#[cfg(not(any(feature = "jpeg2000", feature = "rust-j2k")))]
|
||||
{
|
||||
Err(Error::InvalidOperation)
|
||||
}
|
||||
@@ -570,15 +574,15 @@ impl AssetTexture {
|
||||
})
|
||||
}
|
||||
pub fn decode(&self) -> Result<bool, Error> {
|
||||
#[cfg(feature = "jpeg2000")]
|
||||
#[cfg(any(feature = "jpeg2000", feature = "rust-j2k"))]
|
||||
{
|
||||
Ok(libremetaverse_imaging::J2kCodec::decode_bytes(
|
||||
Ok(TextureJ2kCodec::decode_bytes(
|
||||
&self.raw.bytes(),
|
||||
libremetaverse_imaging::J2kDecodeOptions::default(),
|
||||
)
|
||||
.is_ok())
|
||||
}
|
||||
#[cfg(not(feature = "jpeg2000"))]
|
||||
#[cfg(not(any(feature = "jpeg2000", feature = "rust-j2k")))]
|
||||
{
|
||||
validate_bytes(&self.raw.bytes())?;
|
||||
Err(Error::InvalidOperation)
|
||||
@@ -586,15 +590,15 @@ impl AssetTexture {
|
||||
}
|
||||
pub fn encode(&self) -> Result<(), Error> {
|
||||
let image = self.image.as_ref().ok_or(Error::InvalidOperation)?;
|
||||
#[cfg(feature = "jpeg2000")]
|
||||
#[cfg(any(feature = "jpeg2000", feature = "rust-j2k"))]
|
||||
{
|
||||
let encoded = libremetaverse_imaging::J2kCodec::encode(
|
||||
let encoded = TextureJ2kCodec::encode(
|
||||
image,
|
||||
libremetaverse_imaging::J2kEncodeOptions::default(),
|
||||
)?;
|
||||
self.raw.replace(encoded)
|
||||
}
|
||||
#[cfg(not(feature = "jpeg2000"))]
|
||||
#[cfg(not(any(feature = "jpeg2000", feature = "rust-j2k")))]
|
||||
{
|
||||
let _ = image;
|
||||
Err(Error::InvalidOperation)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#[cfg(feature = "jpeg2000")]
|
||||
#[cfg(any(feature = "jpeg2000", feature = "rust-j2k"))]
|
||||
use crate::assets::AssetTexture;
|
||||
use crate::assets::{AssetMesh, AssetMutable, AssetSound};
|
||||
use crate::{
|
||||
AssetCache, AssetCacheComputeAssetCacheFilenameDelegate, Error, GridClient, ImageCodec,
|
||||
};
|
||||
#[cfg(feature = "jpeg2000")]
|
||||
#[cfg(any(feature = "jpeg2000", feature = "rust-j2k"))]
|
||||
use libremetaverse_imaging::{ManagedImage, ManagedImageImageChannels};
|
||||
use libremetaverse_types::{AssetType, UUID};
|
||||
use std::fs;
|
||||
@@ -58,7 +58,7 @@ fn sound_codec_is_explicitly_feature_gated() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "jpeg2000")]
|
||||
#[cfg(any(feature = "jpeg2000", feature = "rust-j2k"))]
|
||||
fn texture_codec_produces_real_valid_payload() {
|
||||
let mut image = ManagedImage::new(2, 2, ManagedImageImageChannels::COLOR).unwrap();
|
||||
image.red.fill(255);
|
||||
|
||||
@@ -11,6 +11,10 @@ use std::path::{Component, Path, PathBuf};
|
||||
|
||||
use flate2::{Compression, write::ZlibEncoder};
|
||||
use libremetaverse_imaging::ITextureCodec;
|
||||
#[cfg(feature = "jpeg2000")]
|
||||
use libremetaverse_imaging::J2kCodec as TextureJ2kCodec;
|
||||
#[cfg(all(not(feature = "jpeg2000"), feature = "rust-j2k"))]
|
||||
use libremetaverse_imaging::RustJ2kCodec as TextureJ2kCodec;
|
||||
use libremetaverse_structured_data::{OSD, OSDFormat, OSDParser};
|
||||
use libremetaverse_types::compat::{CancellationToken, Uri};
|
||||
use libremetaverse_types::{AssetType, Color4, Error, Quaternion, UUID, Vector2, Vector3};
|
||||
@@ -956,14 +960,14 @@ fn load_texture(
|
||||
return Err(Error::InvalidOperation);
|
||||
};
|
||||
let image = codec.decode(Box::new(std::io::Cursor::new(bytes)))?;
|
||||
#[cfg(feature = "jpeg2000")]
|
||||
#[cfg(any(feature = "jpeg2000", feature = "rust-j2k"))]
|
||||
{
|
||||
return libremetaverse_imaging::J2kCodec::encode(
|
||||
return TextureJ2kCodec::encode(
|
||||
&image,
|
||||
libremetaverse_imaging::J2kEncodeOptions::default(),
|
||||
);
|
||||
}
|
||||
#[cfg(not(feature = "jpeg2000"))]
|
||||
#[cfg(not(any(feature = "jpeg2000", feature = "rust-j2k")))]
|
||||
{
|
||||
let _ = image;
|
||||
return Err(Error::InvalidOperation);
|
||||
|
||||
Reference in New Issue
Block a user