// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/.
use jxl::api::{
Endianness, JxlBitstreamInput, JxlColorEncoding, JxlColorProfile, JxlColorType, JxlDataFormat,
JxlDecoderInner, JxlDecoderOptions, JxlOutputBuffer, JxlPixelFormat, ProcessingResult,
VisibleFrameInfo,
}; use jxl::headers::extra_channels::ExtraChannel;
/// Flush partially-decoded pixels into `output_buffer`. Returns true if any new /// pixels were written since the previous call; false if nothing new was /// rendered and the buffer is unchanged. /// `k_buffer` receives the K (Black) channel (1 byte/pixel) for CMYK images. pubfn flush_pixels(
&mutself,
output_buffer: &mut [u8],
k_buffer: Option<&mut [u8]>,
) -> Result<bool, Error> { let (width, height) = self
.inner
.basic_info()
.map(|bi| (bi.size.0, bi.size.1))
.unwrap_or((0, 0)); let bytes_per_row = width
.checked_mul(self.bytes_per_pixel())
.ok_or(Error::Overflow)?;
fn set_pixel_format(&mutself) {
debug_assert!(self.inner.basic_info().is_some()); let basic_info = self.inner.basic_info().unwrap();
let is_hdr = basic_info.bit_depth.bits_per_sample() > 8;
// Detect Black (K) extra channel for CMYK images. let extra_channel_format: Vec<_> = basic_info
.extra_channels
.iter()
.map(|ec| { if ec.ec_type == ExtraChannel::Black {
Some(JxlDataFormat::U8 { bit_depth: 8 })
} else {
None
}
})
.collect(); self.has_black_channel = extra_channel_format.iter().any(|f| f.is_some());
// For SDR grayscale images with CMS, request Gray/GrayAlpha output so the // C++ gray CMS path receives compact pixels. Without CMS, use RGBA so the // data passes through directly. let color_type = if !is_hdr
&& self.has_cms
&& self
.inner
.embedded_color_profile()
.map(is_gray_profile)
.unwrap_or(false)
{ let has_alpha = basic_info
.extra_channels
.iter()
.any(|ec| ec.ec_type == ExtraChannel::Alpha); if has_alpha {
JxlColorType::GrayscaleAlpha
} else {
JxlColorType::Grayscale
}
} else {
JxlColorType::Rgba
};
// Request f16 output only when CMS is available; without CMS, u8 output // lets jxl-rs convert HDR → sRGB u8 so the user sees something. self.use_f16 = is_hdr && self.has_cms; let pixel_format = JxlPixelFormat {
color_type,
color_data_format: Some(ifself.use_f16 {
JxlDataFormat::F16 {
endianness: Endianness::native(),
}
} else {
JxlDataFormat::U8 { bit_depth: 8 }
}),
extra_channel_format,
}; self.inner.set_pixel_format(pixel_format); self.pixel_format_set = true;
}
/// Process JXL data. Pass output_buffer once frame_ready is true. /// k_buffer receives K (Black) channel data (1 byte/pixel) for CMYK images. /// Returns Ok(true) when frame_ready changes state. pubfn process_data<'a>(
&mutself,
data: &mutimpl JxlBitstreamInput,
output_buffer: Option<&'a mut [u8]>,
k_buffer: Option<&'a mut [u8]>,
) -> Result<bool, Error> { let has_output_buffer = output_buffer.is_some();
debug_assert!(!has_output_buffer || self.pixel_format_set);
// Create output buffer wrapper(s) if provided. // When output_buffer is provided, dimensions must already be known. let (width, height) = self
.inner
.basic_info()
.map(|bi| (bi.size.0, bi.size.1))
.unwrap_or((0, 0)); let bytes_per_row = width
.checked_mul(self.bytes_per_pixel())
.ok_or(Error::Overflow)?;
loop { let bufs: Option<&mut [JxlOutputBuffer]> = match &mut buf_mode {
BufMode::Two(arr) => Some(arr.as_mut_slice()),
BufMode::Single(buf) => Some(std::slice::from_mut(buf)),
BufMode::None => None,
}; let result = self.inner.process(data, bufs);
let need_more = match result {
Err(e) => return Err(e.into()),
Ok(ProcessingResult::Complete { .. }) => false,
Ok(ProcessingResult::NeedsMoreInput { .. }) => true,
};
// For metadata-only decode of non-animated images, return once // we have basic_info. For animated images, continue until frame // header is available to get the first frame's duration. ifself.metadata_only { iflet Some(basic_info) = self.inner.basic_info() { if basic_info.animation.is_none() { return Ok(true);
}
}
}
// jxl-rs guarantees that once basic_info() returns Some, the // embedded color profile has also been parsed; set_pixel_format // relies on the latter (update_default_output_color_profile // unwraps it). if !self.pixel_format_set && self.inner.basic_info().is_some() {
debug_assert!(self.inner.embedded_color_profile().is_some()); self.set_pixel_format();
debug_assert!(self.pixel_format_set);
debug_assert!(self.inner.current_pixel_format().is_some()); if !need_more { // Re-enter to let jxl-rs make further progress now that the // pixel format is configured if we don't need more input. continue;
}
}
if need_more { return Ok(false);
}
let frame_header = self.inner.frame_header(); iflet Some(frame_header) = frame_header { self.frame_duration = frame_header.duration.or(Some(0.0)); self.frame_ready = true; return Ok(true);
} elseifself.frame_ready { // Frame was rendered self.frame_ready = false; return Ok(true);
} // No frame yet, need more data return Ok(false);
}
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.1 Sekunden
(vorverarbeitet am 2026-08-25)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.