Skip to content

Commit

Permalink
Replace zune-jpeg with the default image crate
Browse files Browse the repository at this point in the history
  • Loading branch information
emilk committed Feb 26, 2024
1 parent 4e1978d commit 0797fdd
Show file tree
Hide file tree
Showing 7 changed files with 23 additions and 75 deletions.
17 changes: 0 additions & 17 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions Cargo.toml
Expand Up @@ -255,8 +255,6 @@ wgpu = { version = "0.19.1", default-features = false, features = [
wgpu-core = "0.19.0"
xshell = "0.2"
zip = { version = "0.6", default-features = false }
zune-core = "0.4"
zune-jpeg = "0.4"


[profile.dev]
Expand Down
1 change: 1 addition & 0 deletions Cranky.toml
Expand Up @@ -155,6 +155,7 @@ allow = [
"clippy::let_underscore_untyped",
"clippy::missing_assert_message",
"clippy::missing_errors_doc",
"clippy::use_self",
"trivial_casts",
"unused_qualifications",

Expand Down
2 changes: 0 additions & 2 deletions crates/re_log/src/lib.rs
Expand Up @@ -51,8 +51,6 @@ pub mod external {

/// Never log anything less serious than a `ERROR` from these crates.
const CRATES_AT_ERROR_LEVEL: &[&str] = &[
// Waiting for https://github.com/etemesi254/zune-image/issues/131 to be released
"zune_jpeg",
// silence rustls in release mode: https://github.com/rerun-io/rerun/issues/3104
#[cfg(not(debug_assertions))]
"rustls",
Expand Down
8 changes: 4 additions & 4 deletions crates/re_types/Cargo.toml
Expand Up @@ -39,7 +39,7 @@ egui_plot = ["dep:egui_plot"]
glam = ["dep:glam"]

## Integration with the [`image`](https://crates.io/crates/image/) crate, plus JPEG support.
image = ["dep:ecolor", "dep:image", "dep:zune-core", "dep:zune-jpeg"]
image = ["dep:ecolor", "dep:image"]

## Enable (de)serialization using serde.
serde = ["dep:serde"]
Expand Down Expand Up @@ -81,12 +81,12 @@ uuid = { workspace = true, features = ["serde", "v4", "js"] }
ecolor = { workspace = true, optional = true }
egui_plot = { workspace = true, optional = true }
glam = { workspace = true, optional = true }
image = { workspace = true, optional = true, default-features = false }
image = { workspace = true, optional = true, default-features = false, features = [
"jpeg",
] }
mint = { workspace = true, optional = true }
rand = { workspace = true, optional = true, features = ["std", "std_rng"] }
serde = { workspace = true, optional = true, features = ["derive", "rc"] }
zune-core = { workspace = true, optional = true }
zune-jpeg = { workspace = true, optional = true }


[dev-dependencies]
Expand Down
12 changes: 6 additions & 6 deletions crates/re_types/src/datatypes/tensor_data_ext.rs
Expand Up @@ -625,17 +625,17 @@ impl TensorData {
pub fn from_jpeg_bytes(jpeg_bytes: Vec<u8>) -> Result<Self, TensorImageLoadError> {
re_tracing::profile_function!();

use zune_jpeg::JpegDecoder;

let mut decoder = JpegDecoder::new(&jpeg_bytes);
decoder.decode_headers()?;
let (w, h) = decoder.dimensions().unwrap(); // Can't fail after a successful decode_headers
// Parse JPEG header:
use image::ImageDecoder as _;
let jpeg = image::codecs::jpeg::JpegDecoder::new(std::io::Cursor::new(&jpeg_bytes))?;
let (w, h) = jpeg.dimensions();
let depth = jpeg.color_type().channel_count();

Ok(Self {
shape: vec![
TensorDimension::height(h as _),
TensorDimension::width(w as _),
TensorDimension::depth(3),
TensorDimension::depth(depth as _),
],
buffer: TensorBuffer::Jpeg(jpeg_bytes.into()),
})
Expand Down
56 changes: 12 additions & 44 deletions crates/re_types/src/tensor_data.rs
Expand Up @@ -44,9 +44,6 @@ pub enum TensorImageLoadError {

#[error("The encoded tensor shape did not match its metadata {expected:?} != {found:?}")]
InvalidMetaData { expected: Vec<u64>, found: Vec<u64> },

#[error(transparent)]
JpegDecode(#[from] zune_jpeg::errors::DecodeErrors),
}

#[cfg(feature = "image")]
Expand Down Expand Up @@ -549,59 +546,30 @@ impl DecodedTensor {
}

pub fn decode_jpeg_bytes(
jpeg_bytes: &::re_types_core::ArrowBuffer<u8>,
jpeg_bytes: &[u8],
[expected_height, expected_width, expected_channels]: [u64; 3],
) -> Result<DecodedTensor, TensorImageLoadError> {
re_tracing::profile_function!(format!("{expected_width}x{expected_height}"));

use zune_core::colorspace::ColorSpace;
use zune_core::options::DecoderOptions;
use zune_jpeg::JpegDecoder;

let mut options = DecoderOptions::default();

let depth = if expected_channels == 1 {
options = options.jpeg_set_out_colorspace(ColorSpace::Luma);
1
} else {
// We decode to RGBA directly so we don't need to pad to four bytes later when uploading to GPU.
options = options.jpeg_set_out_colorspace(ColorSpace::RGBA);
4
use image::io::Reader as ImageReader;
let mut reader = ImageReader::new(std::io::Cursor::new(jpeg_bytes));
reader.set_format(image::ImageFormat::Jpeg);
let img = {
re_tracing::profile_scope!("decode_jpeg");
reader.decode()?
};

let mut decoder = JpegDecoder::new_with_options(jpeg_bytes.as_slice(), options);
let pixels = decoder.decode()?;
let (w, h) = decoder.dimensions().unwrap(); // Can't fail after a successful decode

let (w, h) = (w as u64, h as u64);
let (w, h) = (img.width() as u64, img.height() as u64);
let channels = img.color().channel_count() as u64;

if w != expected_width || h != expected_height {
if (w, h, channels) != (expected_width, expected_height, expected_channels) {
return Err(TensorImageLoadError::InvalidMetaData {
expected: [expected_height, expected_width, expected_channels].into(),
found: [h, w, depth].into(),
found: [h, w, channels].into(),
});
}

if pixels.len() as u64 != w * h * depth {
return Err(zune_jpeg::errors::DecodeErrors::Format(format!(
"Bug in zune-jpeg: Expected {w}x{h}x{depth}={} bytes, got {}",
w * h * depth,
pixels.len()
))
.into());
}

let tensor = TensorData {
shape: vec![
TensorDimension::height(h),
TensorDimension::width(w),
TensorDimension::depth(depth),
],
buffer: TensorBuffer::U8(pixels.into()),
};
let decoded_tensor = DecodedTensor(tensor);

Ok(decoded_tensor)
Self::from_image(img)
}
}

Expand Down

0 comments on commit 0797fdd

Please sign in to comment.