From b9487901105dbaafd12f7c2df555d046eb959ffb Mon Sep 17 00:00:00 2001 From: Inflation <2375962+inflation@users.noreply.github.com> Date: Thu, 19 Sep 2024 14:52:17 +0800 Subject: [PATCH] doc: Convert `libjxl` doc to rustdoc format with help from @copilot --- jpegxl-rs/src/memory.rs | 94 +- jpegxl-rs/src/tests/encode.rs | 5 +- jpegxl-sys/Cargo.toml | 2 +- jpegxl-sys/src/color.rs | 22 + jpegxl-sys/src/color/cms_interface.rs | 86 + jpegxl-sys/src/color/color_encoding.rs | 159 ++ jpegxl-sys/src/common.rs | 21 + jpegxl-sys/src/common/memory_manager.rs | 64 + jpegxl-sys/src/common/types.rs | 148 ++ jpegxl-sys/src/decode.rs | 1212 ++++++++++++- jpegxl-sys/src/encoder.rs | 21 + jpegxl-sys/src/encoder/encode.rs | 1598 +++++++++++++++++ jpegxl-sys/src/encoder/stats.rs | 96 + jpegxl-sys/src/metadata.rs | 22 + jpegxl-sys/src/metadata/codestream_header.rs | 388 ++++ jpegxl-sys/src/threads.rs | 22 + jpegxl-sys/src/threads/parallel_runner.rs | 122 ++ .../src/threads/resizable_parallel_runner.rs | 68 + .../src/threads/thread_parallel_runner.rs | 66 + 19 files changed, 4144 insertions(+), 72 deletions(-) create mode 100644 jpegxl-sys/src/color.rs create mode 100644 jpegxl-sys/src/color/cms_interface.rs create mode 100644 jpegxl-sys/src/color/color_encoding.rs create mode 100644 jpegxl-sys/src/common.rs create mode 100644 jpegxl-sys/src/common/memory_manager.rs create mode 100644 jpegxl-sys/src/common/types.rs create mode 100644 jpegxl-sys/src/encoder.rs create mode 100644 jpegxl-sys/src/encoder/encode.rs create mode 100644 jpegxl-sys/src/encoder/stats.rs create mode 100644 jpegxl-sys/src/metadata.rs create mode 100644 jpegxl-sys/src/metadata/codestream_header.rs create mode 100644 jpegxl-sys/src/threads.rs create mode 100644 jpegxl-sys/src/threads/parallel_runner.rs create mode 100644 jpegxl-sys/src/threads/resizable_parallel_runner.rs create mode 100644 jpegxl-sys/src/threads/thread_parallel_runner.rs diff --git a/jpegxl-rs/src/memory.rs b/jpegxl-rs/src/memory.rs index 619d1cc..e442599 100644 --- a/jpegxl-rs/src/memory.rs +++ b/jpegxl-rs/src/memory.rs @@ -17,31 +17,24 @@ //! Memory manager interface -use std::ffi::c_void; - -use jpegxl_sys::memory_manager::JxlMemoryManager; - -/// Allocating function type -pub type AllocFn = unsafe extern "C-unwind" fn(opaque: *mut c_void, size: usize) -> *mut c_void; -/// Deallocating function type -pub type FreeFn = unsafe extern "C-unwind" fn(opaque: *mut c_void, address: *mut c_void); +use jpegxl_sys::common::memory_manager::{JpegxlAllocFunc, JpegxlFreeFunc, JxlMemoryManager}; /// General trait for a memory manager #[allow(clippy::module_name_repetitions)] pub trait MemoryManager { /// Return a custom allocating function - fn alloc(&self) -> AllocFn; + fn alloc(&self) -> JpegxlAllocFunc; /// Return a custom deallocating function - fn free(&self) -> FreeFn; + fn free(&self) -> JpegxlFreeFunc; /// Helper conversion function for C API #[must_use] fn manager(&self) -> JxlMemoryManager { JxlMemoryManager { opaque: (self as *const Self).cast_mut().cast(), - alloc: self.alloc(), - free: self.free(), + alloc: Some(self.alloc()), + free: Some(self.free()), } } } @@ -49,65 +42,43 @@ pub trait MemoryManager { #[cfg(test)] pub(crate) mod tests { use std::{ + ffi::c_void, ptr::null_mut, sync::atomic::{AtomicUsize, Ordering}, }; + use testresult::TestResult; + use crate::{decoder_builder, encoder_builder}; use super::*; - - pub struct NoManager {} - - impl MemoryManager for NoManager { - fn alloc(&self) -> AllocFn { - #[cfg_attr(coverage_nightly, coverage(off))] - unsafe extern "C-unwind" fn alloc(_opaque: *mut c_void, _size: usize) -> *mut c_void { - null_mut() - } - - alloc - } - - fn free(&self) -> FreeFn { - #[cfg_attr(coverage_nightly, coverage(off))] - unsafe extern "C-unwind" fn free(_opaque: *mut c_void, _address: *mut c_void) { - debug_assert!(false, "Should not be called"); - } - - free - } - } - /// Example implementation of [`MemoryManager`] of a fixed size allocator - pub struct BumpManager { - arena: Box<[u8; N]>, + pub struct BumpManager { + arena: Vec, footer: AtomicUsize, } - impl Default for BumpManager { - fn default() -> Self { + impl BumpManager { + pub(crate) fn new(n: usize) -> Self { Self { - arena: Box::new([0_u8; N]), + arena: vec![0; n], footer: AtomicUsize::new(0), } } } - impl MemoryManager for BumpManager { - fn alloc(&self) -> AllocFn { + impl MemoryManager for BumpManager { + fn alloc(&self) -> JpegxlAllocFunc { #[cfg_attr(coverage_nightly, coverage(off))] - unsafe extern "C-unwind" fn alloc( - opaque: *mut c_void, - size: usize, - ) -> *mut c_void { - let mm = &mut *opaque.cast::>(); + unsafe extern "C-unwind" fn alloc(opaque: *mut c_void, size: usize) -> *mut c_void { + let mm = &mut *opaque.cast::(); let footer = mm.footer.load(Ordering::Acquire); let mut new = footer + size; loop { - if new > N { + if new > mm.arena.len() { + println!("Out of memory"); break null_mut(); } else if let Err(s) = mm.footer.compare_exchange_weak( footer, @@ -123,10 +94,10 @@ pub(crate) mod tests { } } - alloc:: + alloc } - fn free(&self) -> FreeFn { + fn free(&self) -> JpegxlFreeFunc { #[cfg_attr(coverage_nightly, coverage(off))] unsafe extern "C-unwind" fn free(_opaque: *mut c_void, _address: *mut c_void) {} @@ -136,7 +107,7 @@ pub(crate) mod tests { pub struct PanicManager {} impl MemoryManager for PanicManager { - fn alloc(&self) -> AllocFn { + fn alloc(&self) -> JpegxlAllocFunc { #[cfg_attr(coverage_nightly, coverage(off))] unsafe extern "C-unwind" fn alloc(_opaque: *mut c_void, _size: usize) -> *mut c_void { panic!("Stack unwind test") @@ -145,7 +116,7 @@ pub(crate) mod tests { alloc } - fn free(&self) -> FreeFn { + fn free(&self) -> JpegxlFreeFunc { #[cfg_attr(coverage_nightly, coverage(off))] unsafe extern "C-unwind" fn free(_opaque: *mut c_void, _address: *mut c_void) { debug_assert!(false, "Should not be called"); @@ -156,20 +127,21 @@ pub(crate) mod tests { } #[test] - fn test_mm() { - let mm = NoManager {}; - assert!(decoder_builder().memory_manager(&mm).build().is_err()); - assert!(encoder_builder().memory_manager(&mm).build().is_err()); - - let mm = BumpManager::<{ 1024 * 10 }>::default(); - assert!(decoder_builder().memory_manager(&mm).build().is_ok()); - assert!(encoder_builder().memory_manager(&mm).build().is_ok()); + fn test_mm() -> TestResult { + let mm = BumpManager::new(1024 * 1024 * 50); + let dec = decoder_builder().memory_manager(&mm).build()?; + let (meta, img) = dec.decode_with::(crate::tests::SAMPLE_JXL)?; + + let mut enc = encoder_builder().memory_manager(&mm).build()?; + let _ = enc.encode::(&img, meta.width, meta.height)?; + + Ok(()) } #[test] #[should_panic = "Stack unwind test"] fn test_unwind() { let mm = PanicManager {}; - let _ = decoder_builder().memory_manager(&mm).build(); + let _ = decoder_builder().memory_manager(&mm).build().unwrap(); } } diff --git a/jpegxl-rs/src/tests/encode.rs b/jpegxl-rs/src/tests/encode.rs index 7eb7442..a32e1b7 100644 --- a/jpegxl-rs/src/tests/encode.rs +++ b/jpegxl-rs/src/tests/encode.rs @@ -211,7 +211,10 @@ fn gray() -> TestResult { )?; _ = decoder.decode(&result)?; - encoder.set_frame_option(jpegxl_sys::encoder::encode::FrameSetting::BrotliEffort, 1)?; + encoder.set_frame_option( + jpegxl_sys::encoder::encode::JxlEncoderFrameSettingId::BrotliEffort, + 1, + )?; Ok(()) } diff --git a/jpegxl-sys/Cargo.toml b/jpegxl-sys/Cargo.toml index 9721e1e..746f208 100644 --- a/jpegxl-sys/Cargo.toml +++ b/jpegxl-sys/Cargo.toml @@ -31,7 +31,7 @@ features = ["docs"] pkg-config = "0.3.31" [build-dependencies.jpegxl-src] -version = "0.10.4" +version = "0.11.0" path = "../jpegxl-src" optional = true diff --git a/jpegxl-sys/src/color.rs b/jpegxl-sys/src/color.rs new file mode 100644 index 0000000..edeafff --- /dev/null +++ b/jpegxl-sys/src/color.rs @@ -0,0 +1,22 @@ +/* +This file is part of jpegxl-sys. + +jpegxl-sys is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +jpegxl-sys is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with jpegxl-sys. If not, see . +*/ + +//! `jxl_color`: ICC profiles and color space conversions. + +pub mod cms; +pub mod cms_interface; +pub mod color_encoding; diff --git a/jpegxl-sys/src/color/cms_interface.rs b/jpegxl-sys/src/color/cms_interface.rs new file mode 100644 index 0000000..36c4fbc --- /dev/null +++ b/jpegxl-sys/src/color/cms_interface.rs @@ -0,0 +1,86 @@ +/* +This file is part of jpegxl-sys. + +jpegxl-sys is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +jpegxl-sys is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with jpegxl-sys. If not, see . +*/ + +//! Interface to allow the injection of different color management systems +//! (CMSes, also called color management modules, or CMMs) in JPEG XL. +//! +//! A CMS is needed by the JPEG XL encoder and decoder to perform colorspace +//! conversions. This defines an interface that can be implemented for different +//! CMSes and then passed to the library. + +use std::ffi::c_void; + +use crate::common::types::JxlBool; + +use super::color_encoding::JxlColorEncoding; + +pub type JpegXlCmsSetFieldsFromIccFunc = extern "C" fn( + user_data: *mut c_void, + icc_data: *const u8, + icc_size: usize, + c: *mut JxlColorEncoding, + cmyk: *mut JxlBool, +) -> JxlBool; + +#[repr(C)] +#[derive(Debug, Clone)] +pub struct JxlColorProfileIcc { + data: *const u8, + size: usize, +} + +#[repr(C)] +#[derive(Debug, Clone)] +pub struct JxlColorProfile { + pub icc: JxlColorProfileIcc, + pub color_encoding: JxlColorEncoding, + pub num_channels: usize, +} + +pub type JpegXlCmsInitFunc = extern "C" fn( + init_data: *mut c_void, + num_threads: usize, + pixels_per_thread: usize, + input_profile: *const JxlColorProfile, + output_profile: *const JxlColorProfile, + intensity_target: f32, +) -> *mut c_void; + +pub type JpegXlCmsGetBufferFunc = extern "C" fn(user_data: *mut c_void, thread: usize) -> *mut f32; + +pub type JpegXlCmsRunFunc = extern "C" fn( + user_data: *mut c_void, + thread: usize, + input_buffer: *const f32, + output_buffer: *mut f32, + num_pixels: usize, +) -> JxlBool; + +pub type JpegXlCmsDestroyFun = extern "C" fn(user_data: *mut c_void); + +#[repr(C)] +#[derive(Debug, Clone)] +pub struct JxlCmsInterface { + pub set_fields_data: *mut c_void, + pub set_fields_from_icc: JpegXlCmsSetFieldsFromIccFunc, + pub init_data: *mut c_void, + pub init: JpegXlCmsInitFunc, + pub get_src_buf: JpegXlCmsGetBufferFunc, + pub get_dst_buf: JpegXlCmsGetBufferFunc, + pub run: JpegXlCmsRunFunc, + pub destroy: JpegXlCmsDestroyFun, +} diff --git a/jpegxl-sys/src/color/color_encoding.rs b/jpegxl-sys/src/color/color_encoding.rs new file mode 100644 index 0000000..2e18dde --- /dev/null +++ b/jpegxl-sys/src/color/color_encoding.rs @@ -0,0 +1,159 @@ +/* +This file is part of jpegxl-sys. + +jpegxl-sys is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +jpegxl-sys is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with jpegxl-sys. If not, see . +*/ + +//! Color Encoding definitions used by JPEG XL. +//! All CIE units are for the standard 1931 2 degree observer. + +#[cfg(doc)] +use crate::metadata::codestream_header::JxlBasicInfo; + +/// Color space of the image data. +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum JxlColorSpace { + /// Tristimulus RGB + Rgb = 0, + /// Luminance based, the primaries in [`JxlColorEncoding`] must be ignored. + /// This value implies that [`JxlBasicInfo::num_color_channels`] is `1`, any + /// other value implies `num_color_channels` is `3`. + Gray, + /// XYB (opsin) color space + Xyb, + /// None of the other table entries describe the color space appropriately + Unknown, +} + +/// Built-in white points for color encoding. When decoding, the numerical xy +/// white point value can be read from the [`JxlColorEncoding::white_point`] +/// field regardless of the enum value. When encoding, enum values except +/// [`JxlWhitePoint::Custom`] override the numerical fields. Some enum values +/// match a subset of CICP (Rec. ITU-T H.273 | ISO/IEC 23091-2:2019(E)), however +/// the white point and RGB primaries are separate enums here. +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum JxlWhitePoint { + /// CIE Standard Illuminant D65: 0.3127, 0.3290 + D65 = 1, + /// White point must be read from the [`JxlColorEncoding::white_point`] field, + /// or as ICC profile. This enum value is not an exact match of the + /// corresponding CICP value. + Custom = 2, + /// CIE Standard Illuminant E (equal-energy): 1/3, 1/3 + E = 10, + /// DCI-P3 from SMPTE RP 431-2: 0.314, 0.351 + Dci = 11, +} + +/// Built-in primaries for color encoding. When decoding, the primaries can be +/// read from the [`JxlColorEncoding::primaries_red_xy`], [`JxlColorEncoding::primaries_green_xy`], +/// and [`JxlColorEncoding::primaries_blue_xy`] fields regardless of the enum value. When encoding, +/// the enum values except [`JxlPrimaries::Custom`] override the numerical fields. Some enum values +/// match a subset of CICP (Rec. ITU-T H.273 | ISO/IEC 23091-2:2019(E)), however the white point +/// and RGB primaries are separate enums here. +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum JxlPrimaries { + /// The CIE xy values of the red, green and blue primaries are: 0.639998686, + /// 0.330010138; 0.300003784, 0.600003357; 0.150002046, 0.059997204 + SRgb = 1, + /// Primaries must be read from the [`JxlColorEncoding::primaries_red_xy`], + /// [`JxlColorEncoding::primaries_green_xy`] and [`JxlColorEncoding::primaries_blue_xy`] fields, + /// or as ICC profile. This enum value is not an exact match of the corresponding CICP value. + Custom = 2, + /// As specified in Rec. ITU-R BT.2100-1 + Rec2100 = 9, + /// As specified in SMPTE RP 431-2 + P3 = 11, +} + +/// Built-in transfer functions for color encoding. Enum values match a subset +/// of CICP (Rec. ITU-T H.273 | ISO/IEC 23091-2:2019(E)) unless specified +/// otherwise. +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum JxlTransferFunction { + /// As specified in ITU-R BT.709-6 + BT709 = 1, + /// None of the other table entries describe the transfer function. + Unknown = 2, + /// The gamma exponent is 1 + Linear = 8, + /// As specified in IEC 61966-2-1 sRGB + SRGB = 13, + /// As specified in SMPTE ST 2084 + PQ = 16, + /// As specified in SMPTE ST 428-1 + DCI = 17, + /// As specified in Rec. ITU-R BT.2100-1 + HLG = 18, + /// Transfer function follows power law given by the gamma value in [`JxlColorEncoding`]. + /// Not a CICP value. + Gamma = 65535, +} + +/// Rendering intent for color encoding, as specified in ISO 15076-1:2010 +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum JxlRenderingIntent { + /// vendor-specific + Perceptual = 0, + /// media-relative + Relative, + /// vendor-specific + Saturation, + /// ICC-absolute + Absolute, +} + +/// Color encoding of the image as structured information. +#[repr(C)] +#[derive(Clone, Debug)] +pub struct JxlColorEncoding { + /// Color space of the image data. + pub color_space: JxlColorSpace, + + /// Built-in white point. If this value is [`JxlWhitePoint::Custom`], must + /// use the numerical white point values from [`Self::white_point_xy`]. + pub white_point: JxlWhitePoint, + + /// Numerical whitepoint values in CIE xy space. + pub white_point_xy: [f64; 2], + + /// Built-in RGB primaries. If this value is [`JxlPrimaries::Custom`], must + /// use the numerical primaries values below. This field and the custom values + /// below are unused and must be ignored if the color space is + /// [`JxlColorSpace::Gray`] or [`JxlColorSpace::Xyb`]. + pub primaries: JxlPrimaries, + + /// Numerical red primary values in CIE xy space. + pub primaries_red_xy: [f64; 2], + + /// Numerical green primary values in CIE xy space. + pub primaries_green_xy: [f64; 2], + + /// Numerical blue primary values in CIE xy space. + pub primaries_blue_xy: [f64; 2], + + /// Transfer function if `have_gamma` is 0. + pub transfer_function: JxlTransferFunction, + + /// Gamma value used when [`Self::transfer_function`] is [`JxlTransferFunction::Gamma`]. + pub gamma: f64, + + /// Rendering intent defined for the color profile. + pub rendering_intent: JxlRenderingIntent, +} diff --git a/jpegxl-sys/src/common.rs b/jpegxl-sys/src/common.rs new file mode 100644 index 0000000..477d505 --- /dev/null +++ b/jpegxl-sys/src/common.rs @@ -0,0 +1,21 @@ +/* +This file is part of jpegxl-sys. + +jpegxl-sys is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +jpegxl-sys is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with jpegxl-sys. If not, see . +*/ + +//! `jxl_common`: Common utilities for the JPEG XL library. + +pub mod memory_manager; +pub mod types; diff --git a/jpegxl-sys/src/common/memory_manager.rs b/jpegxl-sys/src/common/memory_manager.rs new file mode 100644 index 0000000..139f825 --- /dev/null +++ b/jpegxl-sys/src/common/memory_manager.rs @@ -0,0 +1,64 @@ +/* +This file is part of jpegxl-sys. + +jpegxl-sys is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +jpegxl-sys is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with jpegxl-sys. If not, see . +*/ + +//! Abstraction functions used by JPEG XL to allocate memory. + +use std::ffi::c_void; + +/// Allocating function for a memory region of a given size. +/// +/// Allocates a contiguous memory region of size `size` bytes. The returned +/// memory may not be aligned to a specific size or initialized at all. +/// +/// # Parameters +/// - `opaque`: custom memory manager handle provided by the caller. +/// - `size`: size in bytes of the requested memory region. +/// +/// # Returns +/// - `NULL` if the memory cannot be allocated. +/// - Pointer to the memory otherwise. +pub type JpegxlAllocFunc = + unsafe extern "C-unwind" fn(opaque: *mut c_void, size: usize) -> *mut c_void; + +/// Deallocating function pointer type. +/// +/// This function **MUST** do nothing if `address` is `NULL`. +/// +/// # Parameters +/// - `opaque`: custom memory manager handle provided by the caller. +/// - `address`: memory region pointer returned by [`JpegxlAllocFunc`], or `NULL`. +pub type JpegxlFreeFunc = unsafe extern "C-unwind" fn(opaque: *mut c_void, address: *mut c_void); + +/// Memory Manager struct. +/// These functions, when provided by the caller, will be used to handle memory +/// allocations. +#[repr(C)] +#[derive(Debug, Clone)] +pub struct JxlMemoryManager { + /// The opaque pointer that will be passed as the first parameter to all the + /// functions in this struct. + pub opaque: *mut c_void, + + /// Memory allocation function. This can be NULL if and only if also the + /// [`Self::free`] member in this class is NULL. All dynamic memory will be allocated + /// and freed with these functions if they are not NULL, otherwise with the + /// standard malloc/free. + pub alloc: Option, + + /// Free function matching the [`Self::alloc`] member. + pub free: Option, +} diff --git a/jpegxl-sys/src/common/types.rs b/jpegxl-sys/src/common/types.rs new file mode 100644 index 0000000..cb090bc --- /dev/null +++ b/jpegxl-sys/src/common/types.rs @@ -0,0 +1,148 @@ +/* +This file is part of jpegxl-sys. + +jpegxl-sys is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +jpegxl-sys is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with jpegxl-sys. If not, see . +*/ + +//! Data types for the JPEG XL API, for both encoding and decoding. + +use std::ffi::c_char; + +#[cfg(doc)] +use crate::metadata::codestream_header::JxlBasicInfo; + +#[repr(i32)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum JxlBool { + True = 1, + False = 0, +} + +impl From for JxlBool { + fn from(b: bool) -> Self { + if b { + JxlBool::True + } else { + JxlBool::False + } + } +} + +/// Data type for the sample values per channel per pixel. +#[repr(C)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum JxlDataType { + /// Use 32-bit single-precision floating point values, with range 0.0-1.0 + /// (within gamut, may go outside this range for wide color gamut). Floating + /// point output, either [`JxlDataType::Float`] or [`JxlDataType::Float16`], is recommended + /// for HDR and wide gamut images when color profile conversion is required. + Float = 0, + + /// Use type `u8`. May clip wide color gamut data. + Uint8 = 2, + + /// Use type `u16`. May clip wide color gamut data. + Uint16 = 3, + + /// Use 16-bit IEEE 754 half-precision floating point values. + Float16 = 5, +} + +/// Ordering of multi-byte data. +#[repr(C)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum JxlEndianness { + /// Use the endianness of the system, either little endian or big endian, + /// without forcing either specific endianness. Do not use if pixel data + /// should be exported to a well defined format. + Native = 0, + /// Force little endian + Little = 1, + /// Force big endian + Big = 2, +} + +/// Data type for the sample values per channel per pixel for the output buffer +/// for pixels. This is not necessarily the same as the data type encoded in the +/// codestream. The channels are interleaved per pixel. The pixels are +/// organized row by row, left to right, top to bottom. +/// TODO: support different channel orders if needed (RGB, BGR, ...) +#[repr(C)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct JxlPixelFormat { + /// Amount of channels available in a pixel buffer. + /// 1: single-channel data, e.g. grayscale or a single extra channel + /// 2: single-channel + alpha + /// 3: trichromatic, e.g. RGB + /// 4: trichromatic + alpha + /// TODO: this needs finetuning. It is not yet defined how the user + /// chooses output color space. CMYK+alpha needs 5 channels. + pub num_channels: u32, + + /// Data type of each channel. + pub data_type: JxlDataType, + + /// Whether multi-byte data types are represented in big endian or little + /// endian format. This applies to [`JxlDataType::Uint16`] and [`JxlDataType::Float`]. + pub endianness: JxlEndianness, + + /// Align scanlines to a multiple of align bytes, or 0 to require no + /// alignment at all (which has the same effect as value 1) + pub align: usize, +} + +/// Settings for the interpretation of UINT input and output buffers. +/// (buffers using a FLOAT data type are not affected by this) +#[repr(i32)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum JxlBitDepthType { + /// This is the default setting, where the encoder expects the input pixels + /// to use the full range of the pixel format data type (e.g. for UINT16, the + /// input range is 0 .. 65535 and the value 65535 is mapped to 1.0 when + /// converting to float), and the decoder uses the full range to output + /// pixels. If the bit depth in the basic info is different from this, the + /// encoder expects the values to be rescaled accordingly (e.g. multiplied by + /// 65535/4095 for a 12-bit image using UINT16 input data type). + FromPixelFormat = 0, + + /// If this setting is selected, the encoder expects the input pixels to be + /// in the range defined by the [`JxlBasicInfo::bits_per_sample`] value (e.g. + /// for 12-bit images using UINT16 input data types, the allowed range is + /// 0 .. 4095 and the value 4095 is mapped to 1.0 when converting to float), + /// and the decoder outputs pixels in this range. + FromCodestream = 1, + + /// This setting can only be used in the decoder to select a custom range for + /// pixel output. + Custom = 2, +} + +/// Data type for describing the interpretation of the input and output buffers +/// in terms of the range of allowed input and output pixel values. +#[repr(C)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct JxlBitDepth { + /// Bit depth setting, see comment on [`JxlBitDepthType`] + pub r#type: JxlBitDepthType, + + /// Custom bits per sample + pub bits_per_sample: u32, + + /// Custom exponent bits per sample + pub exponent_bits_per_sample: u32, +} + +/// Data type holding the 4-character type name of an ISOBMFF box. +#[repr(transparent)] +pub struct JxlBoxType(pub [c_char; 4]); diff --git a/jpegxl-sys/src/decode.rs b/jpegxl-sys/src/decode.rs index 8627671..31d031c 100644 --- a/jpegxl-sys/src/decode.rs +++ b/jpegxl-sys/src/decode.rs @@ -15,67 +15,270 @@ You should have received a copy of the GNU General Public License along with jpegxl-sys. If not, see . */ +//! Decoding API for JPEG XL. + use std::{ ffi::c_void, os::raw::{c_char, c_int}, }; use crate::{ - cms::JxlCmsInterface, - codestream_header::{JxlBasicInfo, JxlBlendInfo, JxlExtraChannelInfo, JxlFrameHeader}, - color_encoding::JxlColorEncoding, - memory_manager::JxlMemoryManager, - parallel_runner::JxlParallelRunner, - types::{JxlBitDepth, JxlBool, JxlBoxType, JxlPixelFormat}, + color::{cms_interface::JxlCmsInterface, color_encoding::JxlColorEncoding}, + common::memory_manager::JxlMemoryManager, + common::types::{JxlBitDepth, JxlBool, JxlBoxType, JxlPixelFormat}, + metadata::codestream_header::{ + JxlBasicInfo, JxlBlendInfo, JxlExtraChannelInfo, JxlFrameHeader, + }, + threads::parallel_runner::JxlParallelRunner, +}; +#[cfg(doc)] +use crate::{ + common::types::JxlBitDepthType, + metadata::codestream_header::{JxlOrientation, JxlPreviewHeader}, }; +/// The result of [`JxlSignatureCheck`]. #[repr(C)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum JxlSignature { + /// Not enough bytes were passed to determine if a valid signature was found. NotEnoughBytes = 0, + /// No valid JPEG XL header was found. Invalid = 1, + /// A valid JPEG XL codestream signature was found, that is a JPEG XL image + /// without container. Codestream = 2, + /// A valid container signature was found, that is a JPEG XL image embedded + /// in a box format container. Container = 3, } -// Opaque type +/// Opaque structure that holds the JPEG XL decoder. +/// +/// Allocated and initialized with [`JxlDecoderCreate`]. +/// Cleaned up and deallocated with [`JxlDecoderDestroy`]. #[repr(C)] pub struct JxlDecoder { _unused: [u8; 0], } +/// Return value for [`JxlDecoderProcessInput`]. +/// The values from [`JxlDecoderStatus::BasicInfo`] onwards are optional informative +/// events that can be subscribed to, they are never returned if they +/// have not been registered with [`JxlDecoderSubscribeEvents`]. #[repr(C)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum JxlDecoderStatus { + /// Function call finished successfully, or decoding is finished and there is + /// nothing more to be done. + /// + /// Note that [`JxlDecoderProcessInput`] will return [`JxlDecoderStatus::Success`] if + /// all events that were registered with [`JxlDecoderSubscribeEvents`] were + /// processed, even before the end of the JPEG XL codestream. + /// + /// In this case, the return value [`JxlDecoderReleaseInput`] will be the same + /// as it was at the last signaled event. E.g. if [`JxlDecoderStatus::FullImage`] was + /// subscribed to, then all bytes from the end of the JPEG XL codestream + /// (including possible boxes needed for jpeg reconstruction) will be returned + /// as unprocessed. Success = 0, + + /// An error occurred, for example invalid input file or out of memory. + /// TODO: add function to get error information from decoder. Error = 1, + + /// The decoder needs more input bytes to continue. Before the next [`JxlDecoderProcessInput`] + /// call, more input data must be set, by calling [`JxlDecoderReleaseInput`] (if input was set previously) + /// and then calling [`JxlDecoderSetInput`]. [`JxlDecoderReleaseInput`] returns how many bytes + /// are not yet processed, before a next call to [`JxlDecoderProcessInput`] + /// all unprocessed bytes must be provided again (the address need not match, + /// but the contents must), and more bytes must be concatenated after the + /// unprocessed bytes. + /// In most cases, [`JxlDecoderReleaseInput`] will return no unprocessed bytes + /// at this event, the only exceptions are if the previously set input ended + /// within (a) the raw codestream signature, (b) the signature box, (c) a box + /// header, or (d) the first 4 bytes of a `brob`, `ftyp`, or `jxlp` box. In any + /// of these cases the number of unprocessed bytes is less than 20. NeedMoreInput = 2, + + /// The decoder is able to decode a preview image and requests setting a + /// preview output buffer using [`JxlDecoderSetPreviewOutBuffer`]. This occurs + /// if [`JxlDecoderStatus::PreviewImage`] is requested and it is possible to decode a + /// preview image from the codestream and the preview out buffer was not yet + /// set. There is maximum one preview image in a codestream. + /// In this case, [`JxlDecoderReleaseInput`] will return all bytes from the + /// end of the frame header (including `ToC`) of the preview frame as + /// unprocessed. NeedPreviewOutBuffer = 3, + + /// The decoder requests an output buffer to store the full resolution image, + /// which can be set with [`JxlDecoderSetImageOutBuffer`] or with [`JxlDecoderSetImageOutCallback`]. + /// This event re-occurs for new frames if there are multiple animation frames and requires setting an output again. + /// In this case, [`JxlDecoderReleaseInput`] will return all bytes from the + /// end of the frame header (including `ToC`) as unprocessed. NeedImageOutBuffer = 5, - JpegNeedMoreOutput = 6, + + /// The JPEG reconstruction buffer is too small for reconstructed JPEG + /// codestream to fit. [`JxlDecoderSetJPEGBuffer`] must be called again to + /// make room for remaining bytes. This event may occur multiple times + /// after [`JxlDecoderStatus::JPEGReconstruction`]. + JPEGNeedMoreOutput = 6, + + /// The box contents output buffer is too small. [`JxlDecoderSetBoxBuffer`] + /// must be called again to make room for remaining bytes. This event may occur + /// multiple times after [`JxlDecoderStatus::Box`]. BoxNeedMoreOutput = 7, + + /// Informative event by [`JxlDecoderProcessInput`]: Basic information such as image dimensions and + /// extra channels. This event occurs max once per image. + /// In this case, [`JxlDecoderReleaseInput`] will return all bytes from the + /// end of the basic info as unprocessed (including the last byte of basic info + /// if it did not end on a byte boundary). BasicInfo = 0x40, + + /// Informative event by [`JxlDecoderProcessInput`]: Color encoding or ICC profile from the + /// codestream header. This event occurs max once per image and always later + /// than [`JxlDecoderStatus::BasicInfo`] and earlier than any pixel data. + /// In this case, [`JxlDecoderReleaseInput`] will return all bytes from the + /// end of the image header (which is the start of the first frame) as + /// unprocessed. ColorEncoding = 0x100, + + /// Informative event by [`JxlDecoderProcessInput`]: Preview image, a small frame, decoded. This + /// event can only happen if the image has a preview frame encoded. This event + /// occurs max once for the codestream and always later than [`JxlDecoderStatus::ColorEncoding`] + /// and before [`JxlDecoderStatus::Frame`]. In this case, [`JxlDecoderReleaseInput`] will return all bytes + /// from the end of the preview frame as unprocessed. PreviewImage = 0x200, + + /// Informative event by [`JxlDecoderProcessInput`]: Beginning of a frame. [`JxlDecoderGetFrameHeader`] can be + /// used at this point. + /// + /// ## Note: + /// + /// a JPEG XL image can have internal frames that are not intended to be + /// displayed (e.g. used for compositing a final frame), but this only returns + /// displayed frames, unless [`JxlDecoderSetCoalescing`] was set to [`JxlBool::False`]: + /// in that case, the individual layers are returned, without blending. + /// Note that even when coalescing is disabled, only frames of type `kRegularFrame` are returned; + /// frames of type `kReferenceOnly` and `kLfFrame` are always for internal purposes only and cannot be accessed. + /// A displayed frame either has an animation duration or is the only or last + /// frame in the image. This event occurs max once per displayed frame, always + /// later than [`JxlDecoderStatus::ColorEncoding`], and always earlier than any pixel + /// data. While JPEG XL supports encoding a single frame as the composition of + /// multiple internal sub-frames also called frames, this event is not + /// indicated for the internal frames. In this case, [`JxlDecoderReleaseInput`] will return all bytes + /// from the end of the frame header (including `ToC`) as unprocessed. Frame = 0x400, + + /// Informative event by [`JxlDecoderProcessInput`]: full frame (or layer, in case coalescing is + /// disabled) is decoded. [`JxlDecoderSetImageOutBuffer`] must be used after + /// getting the basic image information to be able to get the image pixels, if + /// not this return status only indicates we're past this point in the + /// codestream. This event occurs max once per frame. + /// In this case, [`JxlDecoderReleaseInput`] will return all bytes from the + /// end of the frame (or if [`JxlDecoderStatus::JPEGReconstruction`] is subscribed to, + /// from the end of the last box that is needed for jpeg reconstruction) as + /// unprocessed. FullImage = 0x1000, - JpegReconstruction = 0x2000, + + /// Informative event by [`JxlDecoderProcessInput`]: JPEG reconstruction data decoded. + /// [`JxlDecoderSetJPEGBuffer`] may be used to set a JPEG reconstruction buffer + /// after getting the JPEG reconstruction data. If a JPEG reconstruction buffer + /// is set a byte stream identical to the JPEG codestream used to encode the + /// image will be written to the JPEG reconstruction buffer instead of pixels + /// to the image out buffer. This event occurs max once per image and always + /// before [`JxlDecoderStatus::FullImage`]. + /// In this case, [`JxlDecoderReleaseInput`] will return all bytes from the + /// end of the `jbrd` box as unprocessed. + JPEGReconstruction = 0x2000, + + /// Informative event by [`JxlDecoderProcessInput`]: The header of a box of the container format + /// (BMFF) is decoded. The following API functions related to boxes can be used + /// after this event: + /// - [`JxlDecoderSetBoxBuffer`] and [`JxlDecoderReleaseBoxBuffer`]: set and release a buffer to get the box + /// data. + /// - [`JxlDecoderGetBoxType`] get the 4-character box typename. + /// - [`JxlDecoderGetBoxSizeRaw`] get the size of the box as it appears in + /// the container file, not decompressed. + /// - [`JxlDecoderSetDecompressBoxes`] to configure whether to get the box + /// data decompressed, or possibly compressed. + /// + /// Boxes can be compressed. This is so when their box type is + /// "brob". In that case, they have an underlying decompressed box + /// type and decompressed data. [`JxlDecoderSetDecompressBoxes`] allows + /// configuring which data to get. Decompressing requires + /// Brotli. [`JxlDecoderGetBoxType`] has a flag to get the compressed box + /// type, which can be "brob", or the decompressed box type. If a box + /// is not compressed (its compressed type is not "brob"), then + /// the output decompressed box type and data is independent of what + /// setting is configured. + /// + /// The buffer set with [`JxlDecoderSetBoxBuffer`] must be set again for each + /// next box to be obtained, or can be left unset to skip outputting this box. + /// The output buffer contains the full box data when the + /// [`JxlDecoderStatus::BoxComplete`] (if subscribed to) or subsequent [`JxlDecoderStatus::Success`] + /// or subsequent [`JxlDecoderStatus::Box`] event occurs. [`JxlDecoderStatus::Box`] occurs for all boxes, + /// including non-metadata boxes such as the signature box or codestream boxes. + /// To check whether the box is a metadata type for respectively EXIF, XMP or + /// JUMBF, use [`JxlDecoderGetBoxType`] and check for types "Exif", "xml " and + /// "jumb" respectively. + /// + /// In this case, [`JxlDecoderReleaseInput`] will return all bytes from the + /// start of the box header as unprocessed. Box = 0x4000, + + /// Informative event by [`JxlDecoderProcessInput`]: a progressive step in decoding the frame is + /// reached. When calling [`JxlDecoderFlushImage`] at this point, the flushed + /// image will correspond exactly to this point in decoding, and not yet + /// contain partial results (such as partially more fine detail) of a next + /// step. By default, this event will trigger maximum once per frame, when a + /// 8x8th resolution (DC) image is ready (the image data is still returned at + /// full resolution, giving upscaled DC). Use [`JxlDecoderSetProgressiveDetail`] to configure more fine-grainedness. + /// The event is not guaranteed to trigger, not all images have progressive steps + /// or DC encoded. + /// In this case, [`JxlDecoderReleaseInput`] will return all bytes from the + /// end of the section that was needed to produce this progressive event as + /// unprocessed. FrameProgression = 0x8000, + + /// The box being decoded is now complete. This is only emitted if a buffer + /// was set for the box. + BoxComplete = 0x10000, } +/// Types of progressive detail. +/// Setting a progressive detail with value N implies all progressive details +/// with smaller or equal value. Currently only the following level of +/// progressive detail is implemented: +/// - [`JxlProgressiveDetail::DC`] (which implies [`JxlProgressiveDetail::Frames`]) +/// - [`JxlProgressiveDetail::LastPasses`] (which implies [`JxlProgressiveDetail::DC`] +/// and [`JxlProgressiveDetail::Frames`]) +/// - [`JxlProgressiveDetail::Passes`] (which implies [`JxlProgressiveDetail::LastPasses`], +/// [`JxlProgressiveDetail::DC`] and [`JxlProgressiveDetail::Frames`]) #[repr(C)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum JxlProgressiveDetail { + /// After completed kRegularFrames Frames = 0, + /// After completed DC (1:8) DC = 1, + /// After completed AC passes that are the last pass for their resolution target. LastPasses = 2, + /// After completed AC passes that are not the last pass for their resolution target. Passes = 3, + /// During DC frame when lower resolutions are completed (1:32, 1:16) DCProgressive = 4, + /// After completed groups DCGroups = 5, + /// After completed groups Groups = 6, } +/// Defines which color profile to get: the profile from the codestream +/// metadata header, which represents the color profile of the original image, +/// or the color profile from the pixel data produced by the decoder. Both are +/// the same if the [`JxlBasicInfo`] has `uses_original_profile` set. #[repr(C)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum JxlColorProfileTarget { @@ -83,6 +286,20 @@ pub enum JxlColorProfileTarget { Data = 1, } +/// Function type for [`JxlDecoderSetImageOutCallback`]. +/// +/// The callback may be called simultaneously by different threads when using a +/// threaded parallel runner, on different pixels. +/// +/// # Parameters +/// - `opaque`: optional user data, as given to [`JxlDecoderSetImageOutCallback`]. +/// - `x`: horizontal position of leftmost pixel of the pixel data. +/// - `y`: vertical position of the pixel data. +/// - `num_pixels`: amount of pixels included in the pixel data, horizontally. +/// This is not the same as xsize of the full image, it may be smaller. +/// - `pixels`: pixel data as a horizontal stripe, in the format passed to +/// [`JxlDecoderSetImageOutCallback`]. The memory is not owned by the user, and +/// is only valid during the time the callback is running. pub type JxlImageOutCallback = extern "C" fn( opaque: *mut c_void, x: usize, @@ -91,12 +308,40 @@ pub type JxlImageOutCallback = extern "C" fn( pixels: *const c_void, ); +/// Initialization callback for [`JxlDecoderSetMultithreadedImageOutCallback`]. +/// +/// # Parameters +/// - `init_opaque`: optional user data, as given to +/// [`JxlDecoderSetMultithreadedImageOutCallback`]. +/// - `num_threads`: maximum number of threads that will call the [`run`](JxlImageOutRunCallback) +/// callback concurrently. +/// - `num_pixels_per_thread`: maximum number of pixels that will be passed in +/// one call to [`run`](JxlImageOutRunCallback). +/// +/// # Returns +/// - a pointer to data that will be passed to the [`run`](JxlImageOutRunCallback) callback, or +/// `NULL` if initialization failed. pub type JxlImageOutInitCallback = extern "C" fn( init_opaque: *mut c_void, num_threads: usize, num_pixels_per_thread: usize, ) -> *mut c_void; +/// Worker callback for [`JxlDecoderSetMultithreadedImageOutCallback`] +/// +/// # Parameters +/// - `run_opaque`: user data returned by the [`init`](JxlImageOutInitCallback) callback. +/// - `thread_id`: number in `[0, num_threads)` identifying the thread of the +/// current invocation of the callback. +/// - `x`: horizontal position of the first (leftmost) pixel of the pixel data. +/// - `y`: vertical position of the pixel data. +/// - `num_pixels`: number of pixels in the pixel data. May be less than the +/// full `xsize` of the image, and will be at most equal to the `num_pixels_per_thread` +/// that was passed to [`init`](JxlImageOutInitCallback). +/// - `pixels`: pixel data as a horizontal stripe, in the format passed to +/// [`JxlDecoderSetMultithreadedImageOutCallback`]. The data pointed to +/// remains owned by the caller and is only guaranteed to outlive the current +/// callback invocation. pub type JxlImageOutRunCallback = extern "C" fn( run_opaque: *mut c_void, thread_id: usize, @@ -106,72 +351,429 @@ pub type JxlImageOutRunCallback = extern "C" fn( pixels: *const c_void, ); +/// +/// Destruction callback for [`JxlDecoderSetMultithreadedImageOutCallback`], +/// called after all invocations of the [`run`](JxlImageOutCallback) callback to perform any +/// appropriate clean-up of the `run_opaque` data returned by [`init`](JxlImageOutInitCallback). +/// +/// # Parameters +/// - `run_opaque`: user data returned by the [`init`](JxlImageOutInitCallback) callback. pub type JxlImageOutDestroyCallback = extern "C" fn(run_opaque: *mut c_void); extern "C" { + /// Decoder library version. + /// + /// # Returns + /// The decoder library version as an integer: + /// `MAJOR_VERSION * 1000000 + MINOR_VERSION * 1000 + PATCH_VERSION`. For example, + /// version 1.2.3 would return 1002003. pub fn JxlDecoderVersion() -> u32; + + /// JPEG XL signature identification. + /// + /// Checks if the passed buffer contains a valid JPEG XL signature. The passed `buf` of size + /// `size` doesn't need to be a full image, only the beginning of the file. + /// + /// # Returns + /// A flag indicating if a JPEG XL signature was found and what type. + /// - [`JxlSignature::NotEnoughBytes`] if not enough bytes were passed to + /// determine if a valid signature is there. + /// - [`JxlSignature::Invalid`] if no valid signature found for JPEG XL decoding. + /// - [`JxlSignature::Codestream`] if a valid JPEG XL codestream signature was + /// found. + /// - [`JxlSignature::Container`] if a valid JPEG XL container signature was found. pub fn JxlSignatureCheck(buf: *const u8, len: usize) -> JxlSignature; + + /// Creates an instance of [`JxlDecoder`] and initializes it. + /// + /// `memory_manager` will be used for all the library dynamic allocations made + /// from this instance. The parameter may be `NULL`, in which case the default + /// allocator will be used. See [`crate::common::memory_manager`] for details. + /// + /// # Parameters + /// - `memory_manager`: custom allocator function. It may be `NULL`. The memory + /// manager will be copied internally. + /// + /// # Returns + /// - `NULL` if the instance cannot be allocated or initialized. + /// - Pointer to initialized [`JxlDecoder`] otherwise. pub fn JxlDecoderCreate(memory_manager: *const JxlMemoryManager) -> *mut JxlDecoder; + + /// Re-initializes a [`JxlDecoder`] instance, so it can be re-used for decoding + /// another image. All state and settings are reset as if the object was + /// newly created with [`JxlDecoderCreate`], but the memory manager is kept. + /// + /// # Parameters + /// - `dec`: instance to be re-initialized. pub fn JxlDecoderReset(dec: *mut JxlDecoder); + + /// Deinitializes and frees [`JxlDecoder`] instance. + /// + /// # Parameters + /// - `dec`: instance to be cleaned up and deallocated. pub fn JxlDecoderDestroy(dec: *mut JxlDecoder); + + /// Rewinds decoder to the beginning. The same input must be given again from + /// the beginning of the file and the decoder will emit events from the beginning + /// again. When rewinding (as opposed to [`JxlDecoderReset`]), the decoder can + /// keep state about the image, which it can use to skip to a requested frame + /// more efficiently with [`JxlDecoderSkipFrames`]. Settings such as parallel + /// runner or subscribed events are kept. After rewind, [`JxlDecoderSubscribeEvents`] + /// can be used again, and it is feasible to leave out events that were already + /// handled before, such as [`JxlDecoderStatus::BasicInfo`] and [`JxlDecoderStatus::ColorEncoding`], + /// since they will provide the same information as before. + /// The difference to [`JxlDecoderReset`] is that some state is kept, namely + /// settings set by a call to + /// - [`JxlDecoderSetCoalescing`], + /// - [`JxlDecoderSetDesiredIntensityTarget`], + /// - [`JxlDecoderSetDecompressBoxes`], + /// - [`JxlDecoderSetKeepOrientation`], + /// - [`JxlDecoderSetUnpremultiplyAlpha`], + /// - [`JxlDecoderSetParallelRunner`], + /// - [`JxlDecoderSetRenderSpotcolors`], and + /// - [`JxlDecoderSubscribeEvents`]. + /// + /// # Parameters + /// - `dec`: decoder object pub fn JxlDecoderRewind(dec: *mut JxlDecoder); + + /// Makes the decoder skip the next `amount` frames. It still needs to process + /// the input, but will not output the frame events. It can be more efficient + /// when skipping frames, and even more so when using this after [`JxlDecoderRewind`]. + /// If the decoder is already processing a frame (could have emitted [`JxlDecoderStatus::Frame`] + /// but not yet [`JxlDecoderStatus::FullImage`]), it starts skipping from the next frame. + /// If the amount is larger than the amount of frames remaining in the image, all remaining + /// frames are skipped. Calling this function multiple times adds the amount to skip to the + /// already existing amount. + /// + /// A frame here is defined as a frame that without skipping emits events such + /// as [`JxlDecoderStatus::Frame`] and [`JxlDecoderStatus::FullImage`], frames that are internal + /// to the file format but are not rendered as part of an animation, or are not + /// the final still frame of a still image, are not counted. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `amount`: the amount of frames to skip pub fn JxlDecoderSkipFrames(dec: *mut JxlDecoder, amount: usize); + /// Skips processing the current frame. Can be called after frame processing + /// already started, signaled by a [`JxlDecoderStatus::NeedImageOutBuffer`] event, + /// but before the corresponding [`JxlDecoderStatus::FullImage`] event. The next signaled + /// event will be another [`JxlDecoderStatus::Frame`], or [`JxlDecoderStatus::Success`] if there + /// are no more frames. If pixel data is required from the already processed part + /// of the frame, [`JxlDecoderFlushImage`] must be called before this. + /// + /// # Parameters + /// - `dec`: decoder object + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] if there is a frame to skip, and + /// - [`JxlDecoderStatus::Error`] if the function was not called during frame processing. pub fn JxlDecoderSkipCurrentFrame(dec: *mut JxlDecoder) -> JxlDecoderStatus; + /// Set the parallel runner for multithreading. May only be set before starting + /// decoding. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `parallel_runner`: function pointer to runner for multithreading. It may + /// be `NULL` to use the default, single-threaded, runner. A multithreaded + /// runner should be set to reach fast performance. + /// - `parallel_runner_opaque`: opaque pointer for `parallel_runner`. + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] if the runner was set, [`JxlDecoderStatus::Error`] + /// otherwise (the previous runner remains set). pub fn JxlDecoderSetParallelRunner( dec: *mut JxlDecoder, parallel_runner: JxlParallelRunner, parallel_runner_opaque: *mut c_void, ) -> JxlDecoderStatus; + /// Returns a hint indicating how many more bytes the decoder is expected to + /// need to make [`JxlDecoderGetBasicInfo`] available after the next + /// [`JxlDecoderProcessInput`] call. This is a suggested large enough value for + /// the amount of bytes to provide in the next [`JxlDecoderSetInput`] call, but + /// it is not guaranteed to be an upper bound nor a lower bound. This number does + /// not include bytes that have already been released from the input. Can be used + /// before the first [`JxlDecoderProcessInput`] call, and is correct the first + /// time in most cases. If not, [`JxlDecoderSizeHintBasicInfo`] can be called + /// again to get an updated hint. + /// + /// # Parameters + /// - `dec`: decoder object + /// + /// # Returns + /// - the size hint in bytes if the basic info is not yet fully decoded. + /// - 0 when the basic info is already available. pub fn JxlDecoderSizeHintBasicInfo(dec: *const JxlDecoder) -> usize; + /// Select for which informative events, i.e. [`JxlDecoderStatus::BasicInfo`], etc., the + /// decoder should return with a status. It is not required to subscribe to any + /// events, data can still be requested from the decoder as soon as it is available. + /// By default, the decoder is subscribed to no events (`events_wanted == 0`), and + /// the decoder will then only return when it cannot continue because it needs + /// more input data or more output buffer. This function may only be called + /// before using [`JxlDecoderProcessInput`]. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `events_wanted`: bitfield of desired events. + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] if no error, [`JxlDecoderStatus::Error`] otherwise. pub fn JxlDecoderSubscribeEvents( dec: *mut JxlDecoder, events_wanted: c_int, ) -> JxlDecoderStatus; + /// Enables or disables preserving of as-in-bitstream pixeldata + /// orientation. Some images are encoded with an Orientation tag + /// indicating that the decoder must perform a rotation and/or + /// mirroring to the encoded image data. + /// + /// - If `skip_reorientation` is [`JxlBool::False`] (the default): the decoder + /// will apply the transformation from the orientation setting, hence + /// rendering the image according to its specified intent. When + /// producing a [`JxlBasicInfo`], the decoder will always set the + /// orientation field to [`JxlOrientation::Identity`] (matching the returned + /// pixel data) and also align xsize and ysize so that they correspond + /// to the width and the height of the returned pixel data. + /// - If `skip_reorientation` is [`JxlBool::True`]: the decoder will skip + /// applying the transformation from the orientation setting, returning + /// the image in the as-in-bitstream pixeldata orientation. + /// This may be faster to decode since the decoder doesn't have to apply the + /// transformation, but can cause wrong display of the image if the + /// orientation tag is not correctly taken into account by the user. + /// + /// By default, this option is disabled, and the returned pixel data is + /// re-oriented according to the image's Orientation setting. + /// + /// This function must be called at the beginning, before decoding is performed. + /// + /// See [`JxlBasicInfo`] for the orientation field, and [`JxlOrientation`] for the + /// possible values. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `skip_reorientation`: [`JxlBool::True`] to enable, [`JxlBool::False`] to disable. + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] if no error, [`JxlDecoderStatus::Error`] otherwise. pub fn JxlDecoderSetKeepOrientation( dec: *mut JxlDecoder, keep_orientation: JxlBool, ) -> JxlDecoderStatus; + /// Enables or disables preserving of associated alpha channels. If + /// `unpremul_alpha` is set to [`JxlBool::False`] then for associated alpha channel, + /// the pixel data is returned with premultiplied colors. If it is set to [`JxlBool::True`], + /// the colors will be unpremultiplied based on the alpha channel. This + /// function has no effect if the image does not have an associated alpha + /// channel. + /// + /// By default, this option is disabled, and the returned pixel data is "as is". + /// + /// This function must be called at the beginning, before decoding is performed. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `unpremul_alpha`: [`JxlBool::True`] to enable, [`JxlBool::False`] to disable. + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] if no error, [`JxlDecoderStatus::Error`] otherwise. pub fn JxlDecoderSetUnpremultiplyAlpha( dec: *mut JxlDecoder, unpremul_alpha: JxlBool, ) -> JxlDecoderStatus; + /// Enables or disables rendering spot colors. By default, spot colors + /// are rendered, which is OK for viewing the decoded image. If `render_spotcolors` + /// is [`JxlBool::False`], then spot colors are not rendered, and have to be + /// retrieved separately using [`JxlDecoderSetExtraChannelBuffer`]. This is + /// useful for e.g. printing applications. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `render_spotcolors`: [`JxlBool::True`] to enable (default), [`JxlBool::False`] to disable. + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] if no error, [`JxlDecoderStatus::Error`] otherwise. pub fn JxlDecoderSetRenderSpotcolors( dec: *mut JxlDecoder, render_spotcolors: JxlBool, ) -> JxlDecoderStatus; + /// Enables or disables coalescing of zero-duration frames. By default, frames + /// are returned with coalescing enabled, i.e. all frames have the image + /// dimensions, and are blended if needed. When coalescing is disabled, frames + /// can have arbitrary dimensions, a non-zero crop offset, and blending is not + /// performed. For display, coalescing is recommended. For loading a multi-layer + /// still image as separate layers (as opposed to the merged image), coalescing + /// has to be disabled. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `coalescing`: [`JxlBool::True`] to enable coalescing (default), [`JxlBool::False`] to + /// disable it. + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] if no error, [`JxlDecoderStatus::Error`] otherwise. pub fn JxlDecoderSetCoalescing(dec: *mut JxlDecoder, coalescing: JxlBool) -> JxlDecoderStatus; + /// Decodes JPEG XL file using the available bytes. Requires input has been + /// set with [`JxlDecoderSetInput`]. After [`JxlDecoderProcessInput`], input + /// can optionally be released with [`JxlDecoderReleaseInput`] and then set + /// again to next bytes in the stream. [`JxlDecoderReleaseInput`] returns how + /// many bytes are not yet processed, before a next call to [`JxlDecoderProcessInput`] + /// all unprocessed bytes must be provided again (the address need not match, but the contents must), + /// and more bytes may be concatenated after the unprocessed bytes. + /// + /// The returned status indicates whether the decoder needs more input bytes, or + /// more output buffer for a certain type of output data. No matter what the + /// returned status is (other than [`JxlDecoderStatus::Error`]), new information, + /// such as [`JxlDecoderGetBasicInfo`], may have become available after this call. + /// When the return value is not [`JxlDecoderStatus::Error`] or [`JxlDecoderStatus::Success`], the + /// decoding requires more [`JxlDecoderProcessInput`] calls to continue. + /// + /// # Parameters + /// - `dec`: decoder object + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] when decoding finished and all events handled. + /// If you still have more unprocessed input data anyway, then you can still + /// continue by using [`JxlDecoderSetInput`] and calling [`JxlDecoderProcessInput`] again, + /// similar to handling [`JxlDecoderStatus::NeedMoreInput`]. [`JxlDecoderStatus::Success`] can occur instead of + /// [`JxlDecoderStatus::NeedMoreInput`] when, for example, the input data ended right at + /// the boundary of a box of the container format, all essential codestream + /// boxes were already decoded, but extra metadata boxes are still present in + /// the next data. [`JxlDecoderProcessInput`] cannot return success if all + /// codestream boxes have not been seen yet. + /// - [`JxlDecoderStatus::Error`] when decoding failed, e.g. invalid codestream. + /// - [`JxlDecoderStatus::NeedMoreInput`] when more input data is necessary. + /// - [`JxlDecoderStatus::BasicInfo`] when basic info such as image dimensions is + /// available and this informative event is subscribed to. + /// - [`JxlDecoderStatus::ColorEncoding`] when color profile information is + /// available and this informative event is subscribed to. + /// - [`JxlDecoderStatus::PreviewImage`] when preview pixel information is + /// available and output in the preview buffer. + /// - [`JxlDecoderStatus::FullImage`] when all pixel information at highest detail + /// is available and has been output in the pixel buffer. pub fn JxlDecoderProcessInput(dec: *mut JxlDecoder) -> JxlDecoderStatus; + /// Sets input data for [`JxlDecoderProcessInput`]. The data is owned by the + /// caller and may be used by the decoder until [`JxlDecoderReleaseInput`] is + /// called or the decoder is destroyed or reset, so it must be kept alive until then. + /// Cannot be called if [`JxlDecoderSetInput`] was already called and [`JxlDecoderReleaseInput`] + /// was not yet called, and cannot be called after [`JxlDecoderCloseInput`] indicating the end + /// of input was called. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `data`: pointer to next bytes to read from + /// - `size`: amount of bytes available starting from data + /// + /// # Returns + /// - [`JxlDecoderStatus::Error`] if input was already set without releasing or [`JxlDecoderCloseInput`] + /// was already called + /// - [`JxlDecoderStatus::Success`] otherwise pub fn JxlDecoderSetInput( dec: *mut JxlDecoder, data: *const u8, size: usize, ) -> JxlDecoderStatus; + /// Releases input which was provided with [`JxlDecoderSetInput`]. Between + /// [`JxlDecoderProcessInput`] and [`JxlDecoderReleaseInput`], the user may not + /// alter the data in the buffer. Calling [`JxlDecoderReleaseInput`] is required + /// whenever any input is already set and new input needs to be added with + /// [`JxlDecoderSetInput`], but is not required before [`JxlDecoderDestroy`] or + /// [`JxlDecoderReset`]. Calling [`JxlDecoderReleaseInput`] when no input is set + /// is not an error and returns `0`. + /// + /// # Parameters + /// - `dec`: decoder object + /// + /// # Returns + /// The amount of bytes the decoder has not yet processed that are still + /// remaining in the data set by [`JxlDecoderSetInput`], or `0` if no input is + /// set or [`JxlDecoderReleaseInput`] was already called. For a next call to + /// [`JxlDecoderProcessInput`], the buffer must start with these unprocessed + /// bytes. From this value it is possible to infer the position of certain JPEG + /// XL codestream elements (e.g. end of headers, frame start/end). See the + /// documentation of individual values of [`JxlDecoderStatus`] for more + /// information. pub fn JxlDecoderReleaseInput(dec: *mut JxlDecoder) -> usize; + /// Marks the input as finished, indicates that no more [`JxlDecoderSetInput`] + /// will be called. This function allows the decoder to determine correctly if it + /// should return success, need more input or error in certain cases. For + /// backwards compatibility with a previous version of the API, using this + /// function is optional when not using the [`JxlDecoderStatus::Box`] event (the decoder + /// is able to determine the end of the image frames without marking the end), + /// but using this function is required when using [`JxlDecoderStatus::Box`] for getting + /// metadata box contents. This function does not replace [`JxlDecoderReleaseInput`], + /// that function should still be called if its return value is needed. + /// + /// [`JxlDecoderCloseInput`] should be called as soon as all known input bytes + /// are set (e.g. at the beginning when not streaming but setting all input + /// at once), before the final [`JxlDecoderProcessInput`] calls. + /// + /// # Parameters + /// - `dec`: decoder object pub fn JxlDecoderCloseInput(dec: *mut JxlDecoder); + /// Outputs the basic image information, such as image dimensions, bit depth and + /// all other [`JxlBasicInfo`] fields, if available. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `info`: struct to copy the information into, or `NULL` to only check + /// whether the information is available through the return value. + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] if the value is available + /// - [`JxlDecoderStatus::NeedMoreInput`] if not yet available + /// - [`JxlDecoderStatus::Error`] in case of other error conditions. pub fn JxlDecoderGetBasicInfo( dec: *const JxlDecoder, info: *mut JxlBasicInfo, ) -> JxlDecoderStatus; + /// Outputs information for extra channel at the given index. The index must be + /// smaller than `num_extra_channels` in the associated [`JxlBasicInfo`]. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `index`: index of the extra channel to query. + /// - `info`: struct to copy the information into, or `NULL` to only check + /// whether the information is available through the return value. + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] if the value is available + /// - [`JxlDecoderStatus::NeedMoreInput`] if not yet available + /// - [`JxlDecoderStatus::Error`] in case of other error conditions. pub fn JxlDecoderGetExtraChannelInfo( dec: *const JxlDecoder, index: usize, info: *mut JxlExtraChannelInfo, ) -> JxlDecoderStatus; + /// Outputs name for extra channel at the given index in UTF-8. The index must be + /// smaller than `num_extra_channels` in the associated [`JxlBasicInfo`]. The + /// buffer for name must have at least `name_length + 1` bytes allocated, gotten + /// from the associated [`JxlExtraChannelInfo`]. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `index`: index of the extra channel to query. + /// - `name`: buffer to copy the name into + /// - `size`: size of the name buffer in bytes + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] if the value is available + /// - [`JxlDecoderStatus::NeedMoreInput`] if not yet available + /// - [`JxlDecoderStatus::Error`] in case of other error conditions. pub fn JxlDecoderGetExtraChannelName( dec: *const JxlDecoder, index: usize, @@ -179,18 +781,106 @@ extern "C" { size: usize, ) -> JxlDecoderStatus; + /// Outputs the color profile as JPEG XL encoded structured data, if available. + /// This is an alternative to an ICC Profile, which can represent a more limited + /// amount of color spaces, but represents them exactly through enum values. + /// + /// It is often possible to use [`JxlDecoderGetColorAsICCProfile`] as an + /// alternative anyway. The following scenarios are possible: + /// - The JPEG XL image has an attached ICC Profile, in that case, the encoded + /// structured data is not available and this function will return an error + /// status. [`JxlDecoderGetColorAsICCProfile`] should be called instead. + /// - The JPEG XL image has an encoded structured color profile, and it + /// represents an RGB or grayscale color space. This function will return it. + /// You can still use [`JxlDecoderGetColorAsICCProfile`] as well as an + /// alternative if desired, though depending on which RGB color space is + /// represented, the ICC profile may be a close approximation. It is also not + /// always feasible to deduce from an ICC profile which named color space it + /// exactly represents, if any, as it can represent any arbitrary space. + /// HDR color spaces such as those using PQ and HLG are also potentially + /// problematic, in that: while ICC profiles can encode a transfer function + /// that happens to approximate those of PQ and HLG (HLG for only one given + /// system gamma at a time, and necessitating a 3D LUT if gamma is to be + /// different from `1`), they cannot (before ICCv4.4) semantically signal that + /// this is the color space that they represent. Therefore, they will + /// typically not actually be interpreted as representing an HDR color space. + /// This is especially detrimental to PQ which will then be interpreted as if + /// the maximum signal value represented SDR white instead of 10000 cd/m^2, + /// meaning that the image will be displayed two orders of magnitude (5-7 EV) + /// too dim. + /// - The JPEG XL image has an encoded structured color profile, and it + /// indicates an unknown or xyb color space. In that case, [`JxlDecoderGetColorAsICCProfile`] + /// is not available. + /// + /// When rendering an image on a system where ICC-based color management is used, + /// [`JxlDecoderGetColorAsICCProfile`] should generally be used first as it will + /// return a ready-to-use profile (with the aforementioned caveat about HDR). + /// When knowledge about the nominal color space is desired if available, [`JxlDecoderGetColorAsEncodedProfile`] + /// should be used first. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `target`: whether to get the original color profile from the metadata + /// or the color profile of the decoded pixels. + /// - `color_encoding`: struct to copy the information into, or `NULL` to only + /// check whether the information is available through the return value. + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] if the data is available and returned + /// - [`JxlDecoderStatus::NeedMoreInput`] if not yet available + /// - [`JxlDecoderStatus::Error`] in case the encoded structured color profile does not exist in the + /// codestream. pub fn JxlDecoderGetColorAsEncodedProfile( dec: *const JxlDecoder, target: JxlColorProfileTarget, color_encoding: *mut JxlColorEncoding, ) -> JxlDecoderStatus; + /// Outputs the size in bytes of the ICC profile returned by [`JxlDecoderGetColorAsICCProfile`], if available, + /// or indicates there is none available. In most cases, the image will have an ICC profile available, but + /// if it does not, [`JxlDecoderGetColorAsEncodedProfile`] must be used instead. + /// + /// See [`JxlDecoderGetColorAsEncodedProfile`] for more information. The ICC + /// profile is either the exact ICC profile attached to the codestream metadata, + /// or a close approximation generated from JPEG XL encoded structured data, + /// depending on what is encoded in the codestream. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `target`: whether to get the original color profile from the metadata + /// or the color profile of the decoded pixels. + /// - `size`: variable to output the size into, or `NULL` to only check the + /// return status. + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] if the ICC profile is available + /// - [`JxlDecoderStatus::NeedMoreInput`] if the decoder has not yet received enough + /// input data to determine whether an ICC profile is available or what its + /// size is + /// - [`JxlDecoderStatus::Error`] in case the ICC profile is not available and + /// cannot be generated. pub fn JxlDecoderGetICCProfileSize( dec: *const JxlDecoder, target: JxlColorProfileTarget, size: *mut usize, ) -> JxlDecoderStatus; + /// Outputs ICC profile if available. The profile is only available if + /// [`JxlDecoderGetICCProfileSize`] returns success. The output buffer must have + /// at least as many bytes as given by [`JxlDecoderGetICCProfileSize`]. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `target`: whether to get the original color profile from the metadata + /// or the color profile of the decoded pixels. + /// - `icc_profile`: buffer to copy the ICC profile into + /// - `size`: size of the `icc_profile` buffer in bytes + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`]: if the profile was successfully returned + /// - [`JxlDecoderStatus::NeedMoreInput`]: if not yet available + /// - [`JxlDecoderStatus::Error`]: if the profile doesn't exist or the output size is not + /// large enough. pub fn JxlDecoderGetColorAsICCProfile( dec: *const JxlDecoder, target: JxlColorProfileTarget, @@ -198,16 +888,83 @@ extern "C" { size: usize, ) -> JxlDecoderStatus; + /// Sets the desired output color profile of the decoded image by calling + /// [`JxlDecoderSetOutputColorProfile`], passing on `color_encoding` and + /// setting `icc_data` to `NULL`. See [`JxlDecoderSetOutputColorProfile`] for + /// details. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `color_encoding`: the default color encoding to set + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] if the preference was set successfully, [`JxlDecoderStatus::Error`] otherwise. pub fn JxlDecoderSetPreferredColorProfile( dec: *mut JxlDecoder, color_encoding: *const JxlColorEncoding, ) -> JxlDecoderStatus; + /// Requests that the decoder perform tone mapping to the peak display luminance + /// passed as `desired_intensity_target`, if appropriate. + /// + /// # Note + /// This is provided for convenience and the exact tone mapping that is + /// performed is not meant to be considered authoritative in any way. It may + /// change from version to version. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `desired_intensity_target`: the intended target peak luminance + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] if the preference was set successfully, [`JxlDecoderStatus::Error`] otherwise. pub fn JxlDecoderSetDesiredIntensityTarget( dec: *mut JxlDecoder, desired_intensity_target: f32, ) -> JxlDecoderStatus; + /// Sets the desired output color profile of the decoded image either from a + /// color encoding or an ICC profile. Valid calls of this function have either + /// `color_encoding` or `icc_data` set to `NULL` and `icc_size` must be `0` if and + /// only if `icc_data` is `NULL`. + /// + /// Depending on whether a color management system (CMS) has been set the + /// behavior is as follows: + /// + /// If a color management system (CMS) has been set with [`JxlDecoderSetCms`], + /// and the CMS supports output to the desired color encoding or ICC profile, + /// then it will provide the output in that color encoding or ICC profile. If the + /// desired color encoding or the ICC is not supported, then an error will be + /// returned. + /// + /// If no CMS has been set with [`JxlDecoderSetCms`], there are two cases: + /// + /// 1. Calling this function with a color encoding will convert XYB images to + /// the desired color encoding. In this case, if the requested color encoding has + /// a narrower gamut, or the white points differ, then the resulting image can + /// have significant color distortion. Non-XYB images will not be converted to + /// the desired color space. + /// + /// 2. Calling this function with an ICC profile will result in an error. + /// + /// If called with an ICC profile (after a call to [`JxlDecoderSetCms`]), the + /// ICC profile has to be a valid RGB or grayscale color profile. + /// + /// Can only be set after the [`JxlDecoderStatus::ColorEncoding`] event occurred and + /// before any other event occurred, and should be used before getting + /// [`JxlColorProfileTarget::Data`]. + /// + /// This function must not be called before [`JxlDecoderSetCms`]. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `color_encoding`: the output color encoding + /// - `icc_data`: bytes of the icc profile + /// - `icc_size`: size of the icc profile in bytes + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] if the color profile was set successfully, + /// [`JxlDecoderStatus::Error`] otherwise. pub fn JxlDecoderSetOutputColorProfile( dec: *mut JxlDecoder, color_encoding: *const JxlColorEncoding, @@ -215,14 +972,51 @@ extern "C" { icc_size: usize, ) -> JxlDecoderStatus; + /// Sets the color management system (CMS) that will be used for color + /// conversion (if applicable) during decoding. May only be set before starting + /// decoding and must not be called after [`JxlDecoderSetOutputColorProfile`]. + /// + /// See [`JxlDecoderSetOutputColorProfile`] for how color conversions are done + /// depending on whether or not a CMS has been set with [`JxlDecoderSetCms`]. + /// + /// # Parameters + /// - `dec`: decoder object. + /// - `cms`: structure representing a CMS implementation. See [`JxlCmsInterface`] for more details. pub fn JxlDecoderSetCms(dec: *mut JxlDecoder, cms: JxlCmsInterface) -> JxlDecoderStatus; + /// Returns the minimum size in bytes of the preview image output pixel buffer + /// for the given format. This is the buffer for [`JxlDecoderSetPreviewOutBuffer`]. + /// Requires the preview header information is available in the decoder. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `format`: format of pixels + /// - `size`: output value, buffer size in bytes + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] on success + /// - [`JxlDecoderStatus::Error`] on error, such as information not available yet. pub fn JxlDecoderPreviewOutBufferSize( dec: *const JxlDecoder, format: *const JxlPixelFormat, size: *mut usize, ) -> JxlDecoderStatus; + /// Sets the buffer to write the low-resolution preview image + /// to. The size of the buffer must be at least as large as given by [`JxlDecoderPreviewOutBufferSize`]. + /// The buffer follows the format described by [`JxlPixelFormat`]. The preview image dimensions are given by the + /// [`JxlPreviewHeader`]. The buffer is owned by the caller. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `format`: format of pixels. Object owned by user and its contents are + /// copied internally. + /// - `buffer`: buffer type to output the pixel data to + /// - `size`: size of buffer in bytes + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] on success, [`JxlDecoderStatus::Error`] on error, such as + /// size too small. pub fn JxlDecoderSetPreviewOutBuffer( dec: *mut JxlDecoder, format: *const JxlPixelFormat, @@ -230,29 +1024,102 @@ extern "C" { size: usize, ) -> JxlDecoderStatus; + /// Outputs the information from the frame, such as duration when `have_animation`. + /// This function can be called when [`JxlDecoderStatus::Frame`] occurred for the current + /// frame, even when `have_animation` in the [`JxlBasicInfo`] is [`JxlBool::False`]. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `header`: struct to copy the information into, or `NULL` to only check + /// whether the information is available through the return value. + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] if the value is available + /// - [`JxlDecoderStatus::NeedMoreInput`] if not yet available + /// - [`JxlDecoderStatus::Error`] in case of other error conditions. pub fn JxlDecoderGetFrameHeader( dec: *const JxlDecoder, header: *mut JxlFrameHeader, ) -> JxlDecoderStatus; + /// Outputs name for the current frame. The buffer for name must have at least + /// `name_length + 1` bytes allocated, gotten from the associated [`JxlFrameHeader`]. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `name`: buffer to copy the name into + /// - `size`: size of the name buffer in bytes, including zero termination + /// character, so this must be at least [`JxlFrameHeader::name_length`] + 1. + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] if the value is available + /// - [`JxlDecoderStatus::NeedMoreInput`] if not yet available + /// - [`JxlDecoderStatus::Error`] in case of other error conditions. pub fn JxlDecoderGetFrameName( dec: *const JxlDecoder, name: *mut c_char, size: usize, ) -> JxlDecoderStatus; + /// Outputs the blend information for the current frame for a specific extra + /// channel. This function can be called once the [`JxlDecoderStatus::Frame`] event occurred + /// for the current frame, even if the `have_animation` field in the [`JxlBasicInfo`] is [`JxlBool::False`]. + /// This information is only useful if coalescing is disabled; otherwise the decoder will have performed + /// blending already. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `index`: the index of the extra channel + /// - `blend_info`: struct to copy the information into + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] on success + /// - [`JxlDecoderStatus::Error`] on error pub fn JxlDecoderGetExtraChannelBlendInfo( dec: *const JxlDecoder, index: usize, blend_info: *mut JxlBlendInfo, ); + /// Returns the minimum size in bytes of the image output pixel buffer for the + /// given format. This is the buffer for [`JxlDecoderSetImageOutBuffer`]. + /// Requires that the basic image information is available in the decoder in the + /// case of coalescing enabled (default). In case coalescing is disabled, this + /// can only be called after the [`JxlDecoderStatus::Frame`] event occurs. In that case, + /// it will return the size required to store the possibly cropped frame (which + /// can be larger or smaller than the image dimensions). + /// + /// # Parameters + /// - `dec`: decoder object + /// - `format`: format of the pixels. + /// - `size`: output value, buffer size in bytes + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] on success, [`JxlDecoderStatus::Error`] on error, such as + /// information not available yet. pub fn JxlDecoderImageOutBufferSize( dec: *const JxlDecoder, format: *const JxlPixelFormat, size: *mut usize, ) -> JxlDecoderStatus; + /// Sets the buffer to write the full resolution image to. This can be set when + /// the [`JxlDecoderStatus::Frame`] event occurs, must be set when the + /// [`JxlDecoderStatus::NeedImageOutBuffer`] event occurs, and applies only for the + /// current frame. The size of the buffer must be at least as large as given + /// by [`JxlDecoderImageOutBufferSize`]. The buffer follows the format described + /// by [`JxlPixelFormat`]. The buffer is owned by the caller. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `format`: format of the pixels. Object owned by user and its contents + /// are copied internally. + /// - `buffer`: buffer type to output the pixel data to + /// - `size`: size of buffer in bytes + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] on success, [`JxlDecoderStatus::Error`] on error, such as + /// size too small. pub fn JxlDecoderSetImageOutBuffer( dec: *mut JxlDecoder, format: *const JxlPixelFormat, @@ -260,6 +1127,48 @@ extern "C" { size: usize, ) -> JxlDecoderStatus; + /// Sets pixel output callback. This is an alternative to [`JxlDecoderSetImageOutBuffer`]. + /// This can be set when the [`JxlDecoderStatus::Frame`] event occurs, must be set when the + /// [`JxlDecoderStatus::NeedImageOutBuffer`] event occurs, and applies only for the current frame. + /// Only one of [`JxlDecoderSetImageOutBuffer`] or [`JxlDecoderSetImageOutCallback`] may be used + /// for the same frame, not both at the same time. + /// + /// The callback will be called multiple times, to receive the image + /// data in small chunks. The callback receives a horizontal stripe of pixel + /// data, `1` pixel high, xsize pixels wide, called a scanline. The xsize here is + /// not the same as the full image width, the scanline may be a partial section, + /// and xsize may differ between calls. The user can then process and/or copy the + /// partial scanline to an image buffer. The callback may be called + /// simultaneously by different threads when using a threaded parallel runner, on + /// different pixels. + /// + /// If [`JxlDecoderFlushImage`] is not used, then each pixel will be visited + /// exactly once by the different callback calls, during processing with one or + /// more [`JxlDecoderProcessInput`] calls. These pixels are decoded to full + /// detail, they are not part of a lower resolution or lower quality progressive + /// pass, but the final pass. + /// + /// If [`JxlDecoderFlushImage`] is used, then in addition each pixel will be + /// visited zero or one times during the blocking [`JxlDecoderFlushImage`] call. + /// Pixels visited as a result of [`JxlDecoderFlushImage`] may represent a lower + /// resolution or lower quality intermediate progressive pass of the image. Any + /// visited pixel will be of a quality at least as good or better than previous + /// visits of this pixel. A pixel may be visited zero times if it cannot be + /// decoded yet or if it was already decoded to full precision (this behavior is + /// not guaranteed). + /// + /// # Parameters + /// - `dec`: decoder object + /// - `format`: format of the pixels. Object owned by user; its contents are + /// copied internally. + /// - `callback`: the callback function receiving partial scanlines of pixel + /// data. + /// - `opaque`: optional user data, which will be passed on to the callback, + /// may be `NULL`. + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] on success, [`JxlDecoderStatus::Error`] on error, such + /// as [`JxlDecoderSetImageOutBuffer`] already set. pub fn JxlDecoderSetImageOutCallback( dec: *mut JxlDecoder, format: *const JxlPixelFormat, @@ -267,6 +1176,27 @@ extern "C" { opaque: *mut c_void, ) -> JxlDecoderStatus; + /// Similar to [`JxlDecoderSetImageOutCallback`] except that the callback is + /// allowed an initialization phase during which it is informed of how many + /// threads will call it concurrently, and those calls are further informed of + /// which thread they are occurring in. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `format`: format of the pixels. Object owned by user; its contents are + /// copied internally. + /// - `init_callback`: initialization callback. + /// - `run_callback`: the callback function receiving partial scanlines of + /// pixel data. + /// - `destroy_callback`: clean-up callback invoked after all calls to `run_callback`. + /// May be `NULL` if no clean-up is necessary. + /// - `init_opaque`: optional user data passed to `init_callback`, may be `NULL` + /// (unlike the return value from `init_callback` which may only be `NULL` if + /// initialization failed). + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] on success, [`JxlDecoderStatus::Error`] on error, such + /// as [`JxlDecoderSetImageOutBuffer`] having already been called. pub fn JxlDecoderSetMultithreadedImageOutCallback( dec: *mut JxlDecoder, format: *const JxlPixelFormat, @@ -276,6 +1206,21 @@ extern "C" { init_opaque: *mut c_void, ) -> JxlDecoderStatus; + /// Returns the minimum size in bytes of an extra channel pixel buffer for the + /// given format. This is the buffer for [`JxlDecoderSetExtraChannelBuffer`]. + /// Requires the basic image information is available in the decoder. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `format`: format of the pixels. The `num_channels` value is ignored and is + /// always treated to be `1`. + /// - `size`: output value, buffer size in bytes + /// - `index`: which extra channel to get, matching the index used in [`JxlDecoderGetExtraChannelInfo`]. + /// Must be smaller than `num_extra_channels` in the associated [`JxlBasicInfo`]. + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] on success + /// - [`JxlDecoderStatus::Error`] on error, such as information not available yet or invalid index. pub fn JxlDecoderExtraChannelBufferSize( dec: *const JxlDecoder, format: *const JxlPixelFormat, @@ -283,6 +1228,33 @@ extern "C" { index: u32, ) -> JxlDecoderStatus; + /// Sets the buffer to write an extra channel to. This can be set when + /// the [`JxlDecoderStatus::Frame`] or [`JxlDecoderStatus::NeedImageOutBuffer`] event occurs, + /// and applies only for the current frame. The size of the buffer must be at + /// least as large as given by [`JxlDecoderExtraChannelBufferSize`]. The buffer + /// follows the format described by [`JxlPixelFormat`], but where `num_channels` + /// is `1`. The buffer is owned by the caller. The amount of extra channels is + /// given by the `num_extra_channels` field in the associated [`JxlBasicInfo`], + /// and the information of individual extra channels can be queried with [`JxlDecoderGetExtraChannelInfo`]. + /// To get multiple extra channels, this function must be called multiple times, once for each wanted index. + /// Not all images have extra channels. The alpha channel is an extra channel and can be gotten + /// as part of the color channels when using an RGBA pixel buffer with [`JxlDecoderSetImageOutBuffer`], + /// but additionally also can be gotten separately as extra channel. The color channels themselves cannot be gotten + /// this way. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `format`: format of the pixels. Object owned by user and its contents + /// are copied internally. The `num_channels` value is ignored and is always + /// treated to be `1`. + /// - `buffer`: buffer type to output the pixel data to + /// - `size`: size of buffer in bytes + /// - `index`: which extra channel to get, matching the index used in [`JxlDecoderGetExtraChannelInfo`]. + /// Must be smaller than `num_extra_channels` in the associated [`JxlBasicInfo`]. + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] on success, [`JxlDecoderStatus::Error`] on error, such as + /// size too small or invalid index. pub fn JxlDecoderSetExtraChannelBuffer( dec: *mut JxlDecoder, format: *const JxlPixelFormat, @@ -291,46 +1263,268 @@ extern "C" { index: u32, ) -> JxlDecoderStatus; + /// Sets output buffer for reconstructed JPEG codestream. + /// + /// The data is owned by the caller and may be used by the decoder until [`JxlDecoderReleaseJPEGBuffer`] + /// is called or the decoder is destroyed or reset so must be kept alive until then. + /// + /// If a JPEG buffer was set before and released with [`JxlDecoderReleaseJPEGBuffer`], + /// bytes that the decoder has already output should not be included, + /// only the remaining bytes output must be set. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `data`: pointer to next bytes to write to + /// - `size`: amount of bytes available starting from data + /// + /// # Returns + /// - [`JxlDecoderStatus::Error`] if output buffer was already set and [`JxlDecoderReleaseJPEGBuffer`] + /// was not called on it, [`JxlDecoderStatus::Success`] otherwise pub fn JxlDecoderSetJPEGBuffer( dec: *mut JxlDecoder, data: *mut u8, size: usize, ) -> JxlDecoderStatus; + /// Releases buffer which was provided with [`JxlDecoderSetJPEGBuffer`]. + /// + /// Calling [`JxlDecoderReleaseJPEGBuffer`] is required whenever + /// a buffer is already set and a new buffer needs to be added with [`JxlDecoderSetJPEGBuffer`], + /// but is not required before [`JxlDecoderDestroy`] or [`JxlDecoderReset`]. + /// + /// Calling [`JxlDecoderReleaseJPEGBuffer`] when no buffer is set is + /// not an error and returns `0`. + /// + /// # Parameters + /// - `dec`: decoder object + /// + /// # Returns + /// - The amount of bytes the decoder has not yet written to of the data + /// set by [`JxlDecoderSetJPEGBuffer`], or `0` if no buffer is set or + /// [`JxlDecoderReleaseJPEGBuffer`] was already called. pub fn JxlDecoderReleaseJPEGBuffer(dec: *mut JxlDecoder) -> usize; + /// Sets output buffer for box output codestream. + /// + /// The data is owned by the caller and may be used by the decoder until [`JxlDecoderReleaseBoxBuffer`] + /// is called or the decoder is destroyed or reset so must be kept alive until then. + /// + /// If for the current box a box buffer was set before and released with [`JxlDecoderReleaseBoxBuffer`], + /// bytes that the decoder has already output should not be included, only the remaining bytes output must be set. + /// + /// The [`JxlDecoderReleaseBoxBuffer`] must be used at the next [`JxlDecoderStatus::Box`] event or final + /// [`JxlDecoderStatus::Success`] event to compute the size of the output box bytes. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `data`: pointer to next bytes to write to + /// - `size`: amount of bytes available starting from data + /// + /// # Returns + /// - [`JxlDecoderStatus::Error`] if output buffer was already set and [`JxlDecoderReleaseBoxBuffer`] + /// was not called on it, [`JxlDecoderStatus::Success`] otherwise pub fn JxlDecoderSetBoxBuffer( dec: *mut JxlDecoder, data: *mut u8, size: usize, ) -> JxlDecoderStatus; + /// Releases buffer which was provided with [`JxlDecoderSetBoxBuffer`]. + /// + /// Calling [`JxlDecoderReleaseBoxBuffer`] is required whenever a buffer is already set and + /// a new buffer needs to be added with [`JxlDecoderSetBoxBuffer`], but is not required before + /// [`JxlDecoderDestroy`] or [`JxlDecoderReset`]. + /// + /// Calling [`JxlDecoderReleaseBoxBuffer`] when no buffer is set is not an error and returns `0`. + /// + /// # Parameters + /// - `dec`: decoder object + /// + /// # Returns + /// - The amount of bytes the decoder has not yet written to of the data set by [`JxlDecoderSetBoxBuffer`], + /// or `0` if no buffer is set or [`JxlDecoderReleaseBoxBuffer`] was already called., pub fn JxlDecoderReleaseBoxBuffer(dec: *mut JxlDecoder) -> usize; + /// Configures whether to get boxes in raw mode or in decompressed mode. In raw + /// mode, boxes are output as their bytes appear in the container file, which may + /// be decompressed, or compressed if their type is "brob". In decompressed mode, + /// "brob" boxes are decompressed with Brotli before outputting them. The size of + /// the decompressed stream is not known before the decompression has already + /// finished. + /// + /// The default mode is raw. This setting can only be changed before decoding, or + /// directly after a [`JxlDecoderStatus::Box`] event, and is remembered until the decoder + /// is reset or destroyed. + /// + /// Enabling decompressed mode requires Brotli support from the library. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `decompress`: [`JxlBool::True`] to transparently decompress, [`JxlBool::False`] + /// to get boxes in raw mode. + /// + /// # Returns + /// - [`JxlDecoderStatus::Error`] if decompressed mode is set and Brotli is not + /// available, [`JxlDecoderStatus::Success`] otherwise. pub fn JxlDecoderSetDecompressBoxes( dec: *mut JxlDecoder, decompress: JxlBool, ) -> JxlDecoderStatus; + /// Outputs the type of the current box, after a [`JxlDecoderStatus::Box`] event occurred, + /// as `4` characters without null termination character. In case of a compressed + /// "brob" box, this will return "brob" if the decompressed argument is + /// [`JxlBool::False`], or the underlying box type if the decompressed argument is + /// [`JxlBool::True`]. + /// + /// The following box types are currently described in ISO/IEC 18181-2: + /// - "Exif": a box with EXIF metadata. Starts with a 4-byte tiff header offset + /// (big-endian `uint32`) that indicates the start of the actual EXIF data + /// (which starts with a tiff header). Usually the offset will be zero and the + /// EXIF data starts immediately after the offset field. The Exif orientation + /// should be ignored by applications; the JPEG XL codestream orientation + /// takes precedence and libjxl will by default apply the correct orientation + /// automatically (see [`JxlDecoderSetKeepOrientation`]). + /// - "xml ": a box with XML data, in particular XMP metadata. + /// - "jumb": a JUMBF superbox (JPEG Universal Metadata Box Format, ISO/IEC + /// 19566-5). + /// - "JXL ": mandatory signature box, must come first, `12` bytes long + /// including the box header + /// - "ftyp": a second mandatory signature box, must come second, `20` bytes + /// long including the box header + /// - "jxll": a JXL level box. This indicates if the codestream is level `5` or + /// level `10` compatible. If not present, it is level `5`. Level `10` allows + /// more features such as very high image resolution and bit-depths above `16` + /// bits per channel. Added automatically by the encoder when + /// [`crate::encoder::encode::JxlEncoderSetCodestreamLevel`] is used + /// - "jxlc": a box with the image codestream, in case the codestream is not + /// split across multiple boxes. The codestream contains the JPEG XL image + /// itself, including the basic info such as image dimensions, ICC color + /// profile, and all the pixel data of all the image frames. + /// - "jxlp": a codestream box in case it is split across multiple boxes. + /// The contents are the same as in case of a jxlc box, when concatenated. + /// - "brob": a Brotli-compressed box, which otherwise represents an existing + /// type of box such as Exif or "xml ". When [`JxlDecoderSetDecompressBoxes`] + /// is set to [`JxlBool::True`], these boxes will be transparently decompressed by the + /// decoder. + /// - "jxli": frame index box, can list the keyframes in case of a JPEG XL + /// animation allowing the decoder to jump to individual frames more + /// efficiently. + /// - "jbrd": JPEG reconstruction box, contains the information required to + /// byte-for-byte losslessly reconstruct a JPEG-1 image. The JPEG DCT + /// coefficients (pixel content) themselves as well as the ICC profile are + /// encoded in the JXL codestream (jxlc or jxlp) itself. EXIF, XMP and JUMBF + /// metadata is encoded in the corresponding boxes. The jbrd box itself + /// contains information such as the remaining app markers of the JPEG-1 file + /// and everything else required to fit the information together into the + /// exact original JPEG file. + /// + /// Other application-specific boxes can exist. Their typename should not begin + /// with "jxl" or "JXL" or conflict with other existing typenames. + /// + /// The signature, jxl* and jbrd boxes are processed by the decoder and would + /// typically be ignored by applications. The typical way to use this function is + /// to check if an encountered box contains metadata that the application is + /// interested in (e.g. EXIF or XMP metadata), in order to conditionally set a + /// box buffer. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `type`: buffer to copy the type into + /// - `decompressed`: which box type to get: [`JxlBool::False`] to get the raw box type, + /// which can be `"brob"`, [`JxlBool::True`] to get the underlying box type. + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] if the value is available + /// - [`JxlDecoderStatus::Error`] if not, for example the JPEG XL file does not use the container format. pub fn JxlDecoderGetBoxType( dec: *mut JxlDecoder, box_type: &mut JxlBoxType, decompressed: JxlBool, ) -> JxlDecoderStatus; + /// Returns the size of a box as it appears in the container file, after the + /// [`JxlDecoderStatus::Box`] event. This includes all the box headers. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `size`: raw size of the box in bytes + /// + /// # Returns + /// - [`JxlDecoderStatus::Error`] if no box size is available, [`JxlDecoderStatus::Success`] otherwise. pub fn JxlDecoderGetBoxSizeRaw(dec: *mut JxlDecoder, size: *mut u64) -> JxlDecoderStatus; + /// Returns the size of the contents of a box, after the [`JxlDecoderStatus::Box`] event. + /// This does not include any of the headers of the box. For compressed "brob" boxes, + /// this is the size of the compressed content. Even when [`JxlDecoderSetDecompressBoxes`] is enabled, + /// the return value of function does not change, and the decompressed size is not known before it + /// has already been decompressed and output. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `size`: size of the payload of the box in bytes + /// + /// # Returns + /// - [`JxlDecoderStatus::Error`] if no box size is available, [`JxlDecoderStatus::Success`] + /// otherwise. pub fn JxlDecoderGetBoxSizeContents(dec: *mut JxlDecoder, size: *mut u64) -> JxlDecoderStatus; + /// Configures at which progressive steps in frame decoding the [`JxlDecoderStatus::FrameProgression`] event occurs. + /// The default value for the level of detail if this function is never called is [`JxlProgressiveDetail::DC`]. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `detail`: at which level of detail to trigger [`JxlDecoderStatus::FrameProgression`] + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] on success, [`JxlDecoderStatus::Error`] on error, such as + /// an invalid value for the progressive detail. pub fn JxlDecoderSetProgressiveDetail( dec: *mut JxlDecoder, detail: JxlProgressiveDetail, ) -> JxlDecoderStatus; + /// Returns the intended downsampling ratio for the progressive frame produced + /// by [`JxlDecoderFlushImage`] after the latest [`JxlDecoderStatus::FrameProgression`] event. + /// + /// # Parameters + /// - `dec`: decoder object + /// + /// # Returns + /// The intended downsampling ratio, can be `1`, `2`, `4` or `8`. pub fn JxlDecoderGetIntendedDownsamplingRatio(dec: *const JxlDecoder) -> usize; + /// Outputs progressive step towards the decoded image so far when only partial + /// input was received. If the flush was successful, the buffer set with [`JxlDecoderSetImageOutBuffer`] + /// will contain partial image data. + /// + /// Can be called when [`JxlDecoderProcessInput`] returns [`JxlDecoderStatus::NeedMoreInput`], after the + /// [`JxlDecoderStatus::Frame`] event already occurred and before the [`JxlDecoderStatus::FullImage`] event + /// occurred for a frame. + /// + /// # Parameters + /// - `dec`: decoder object + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] if image data was flushed to the output buffer, + /// - [`JxlDecoderStatus::Error`] when no flush was done, e.g., if not enough image data was available yet + /// even for flush, or no output buffer was set yet. This error is not fatal, it only indicates no flushed + /// image is available right now. Regular decoding can still be performed. pub fn JxlDecoderFlushImage(dec: *mut JxlDecoder) -> JxlDecoderStatus; + /// Sets the bit depth of the output buffer or callback. + /// + /// Can be called after [`JxlDecoderSetImageOutBuffer`] or + /// [`JxlDecoderSetImageOutCallback`]. For float pixel data types, only the default + /// [`JxlBitDepthType::FromPixelFormat`] setting is supported. + /// + /// # Parameters + /// - `dec`: decoder object + /// - `bit_depth`: the bit depth setting of the pixel output + /// + /// # Returns + /// - [`JxlDecoderStatus::Success`] on success, [`JxlDecoderStatus::Error`] on error, such as + /// incompatible custom bit depth and pixel data type. pub fn JxlDecoderSetImageOutBitDepth( dec: *mut JxlDecoder, bit_depth: *const JxlBitDepth, diff --git a/jpegxl-sys/src/encoder.rs b/jpegxl-sys/src/encoder.rs new file mode 100644 index 0000000..514d86f --- /dev/null +++ b/jpegxl-sys/src/encoder.rs @@ -0,0 +1,21 @@ +/* +This file is part of jpegxl-sys. + +jpegxl-sys is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +jpegxl-sys is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with jpegxl-sys. If not, see . +*/ + +//! `jxl_encoder`: JPEG XL encoder. + +pub mod encode; +pub mod stats; diff --git a/jpegxl-sys/src/encoder/encode.rs b/jpegxl-sys/src/encoder/encode.rs new file mode 100644 index 0000000..e1d24a7 --- /dev/null +++ b/jpegxl-sys/src/encoder/encode.rs @@ -0,0 +1,1598 @@ +/* +This file is part of jpegxl-sys. + +jpegxl-sys is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +jpegxl-sys is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with jpegxl-sys. If not, see . +*/ + +//! Encoding API for JPEG XL. + +use std::ffi::{c_char, c_void}; + +use super::stats::JxlEncoderStats; +use crate::{ + color::{cms_interface::JxlCmsInterface, color_encoding::JxlColorEncoding}, + common::memory_manager::JxlMemoryManager, + common::types::{JxlBitDepth, JxlBool, JxlBoxType, JxlPixelFormat}, + metadata::codestream_header::{ + JxlBasicInfo, JxlBlendInfo, JxlExtraChannelInfo, JxlExtraChannelType, JxlFrameHeader, + }, + threads::parallel_runner::JxlParallelRunner, +}; + +#[cfg(doc)] +use crate::common::{ + encoder::stats::JxlEncoderStatsCreate, + types::{JxlBitDepthType, JxlDataType}, +}; + +/// Opaque structure that holds the JPEG XL encoder. +/// +/// Allocated and initialized with [`JxlEncoderCreate`]. +/// Cleaned up and deallocated with [`JxlEncoderDestroy`]. +#[repr(C)] +pub struct JxlEncoder { + _unused: [u8; 0], +} + +/// Settings and metadata for a single image frame. This includes encoder options +/// for a frame such as compression quality and speed. +/// +/// Allocated and initialized with [`JxlEncoderFrameSettingsCreate`]. +/// Cleaned up and deallocated when the encoder is destroyed with +/// [`JxlEncoderDestroy`]. +#[repr(C)] +pub struct JxlEncoderFrameSettings { + _unused: [u8; 0], +} + +/// Return value for multiple encoder functions. +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum JxlEncoderStatus { + /// Function call finished successfully, or encoding is finished and there is + /// nothing more to be done + Success = 0, + /// An error occurred, for example out of memory. + Error = 1, + /// The encoder needs more output buffer to continue encoding. + NeedMoreOutput = 2, +} + +/// Error conditions: +/// API usage errors have the 0x80 bit set to 1 +/// Other errors have the 0x80 bit set to 0 +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum JxlEncoderError { + /// No error + OK = 0, + + /// Generic encoder error due to unspecified cause + Generic = 1, + + /// Out of memory. TODO: not really used + OutOfMemory = 2, + + /// JPEG bitstream reconstruction data could not be represented (e.g. too much tail data) + Jbrd = 3, + + /// Input is invalid (e.g. corrupt JPEG file or ICC profile) + BadInput = 4, + + /// The encoder doesn't (yet) support this. Either no version of libjxl + /// supports this, and the API is used incorrectly, or the libjxl version + /// should have been checked before trying to do this. + NotSupported = 0x80, + + /// The encoder API is used in an incorrect way. + /// In this case, a debug build of libjxl should output a specific error + /// message. (if not, please open an issue about it) + ApiUsage = 0x81, +} + +/// Id of encoder options for a frame. This includes options such as setting +/// encoding effort/speed or overriding the use of certain coding tools, for this +/// frame. This does not include non-frame related encoder options such as for +/// boxes. +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum JxlEncoderFrameSettingId { + /// Sets encoder effort/speed level without affecting decoding speed. Valid + /// values are, from faster to slower speed: 1:lightning 2:thunder 3:falcon + /// 4:cheetah 5:hare 6:wombat 7:squirrel 8:kitten 9:tortoise 10:glacier. + /// Default: squirrel (7). + Effort = 0, + + /// Sets the decoding speed tier for the provided options. Minimum is 0 + /// (slowest to decode, best quality/density), and maximum is 4 (fastest to + /// decode, at the cost of some quality/density). Default is 0. + DecodingSpeed = 1, + + /// Sets resampling option. If enabled, the image is downsampled before + /// compression, and upsampled to original size in the decoder. Integer option, + /// use -1 for the default behavior (resampling only applied for low quality), + /// 1 for no downsampling (1x1), 2 for 2x2 downsampling, 4 for 4x4 + /// downsampling, 8 for 8x8 downsampling. + Resampling = 2, + + /// Similar to [`Self::Resampling`], but for extra channels. + /// Integer option, use -1 for the default behavior (depends on encoder + /// implementation), 1 for no downsampling (1x1), 2 for 2x2 downsampling, 4 for + /// 4x4 downsampling, 8 for 8x8 downsampling. + ExtraChannelResampling = 3, + + /// Indicates the frame added with [`JxlEncoderAddImageFrame`] is already + /// downsampled by the downsampling factor set with [`Self::Resampling`]. The input frame + /// must then be given in the downsampled resolution, not the full image resolution. + /// The downsampled resolution is given by `ceil(xsize / resampling)`, `ceil(ysize / resampling)` + /// with `xsize` and `ysize` the dimensions given in the basic info, and `resampling` + /// the factor set with [`Self::Resampling`]. + /// Use 0 to disable, 1 to enable. Default value is 0. + AlreadyDownsampled = 4, + + /// Adds noise to the image emulating photographic film noise, the higher the + /// given number, the grainier the image will be. As an example, a value of 100 + /// gives low noise whereas a value of 3200 gives a lot of noise. The default + /// value is 0. + PhotonNoise = 5, + + /// Enables adaptive noise generation. This setting is not recommended for + /// use, please use [`Self::PhotonNoise`] instead. + /// Use -1 for the default (encoder chooses), 0 to disable, 1 to enable. + Noise = 6, + + /// Enables or disables dots generation. Use -1 for the default (encoder + /// chooses), 0 to disable, 1 to enable. + Dots = 7, + + /// Enables or disables patches generation. Use -1 for the default (encoder + /// chooses), 0 to disable, 1 to enable. + Patches = 8, + + /// Edge preserving filter level, -1 to 3. Use -1 for the default (encoder + /// chooses), 0 to 3 to set a strength. + Epf = 9, + + /// Enables or disables the gaborish filter. Use -1 for the default (encoder + /// chooses), 0 to disable, 1 to enable. + Gaborish = 10, + + /// Enables modular encoding. Use -1 for default (encoder + /// chooses), 0 to enforce `VarDCT` mode (e.g. for photographic images), 1 to + /// enforce modular mode (e.g. for lossless images). + Modular = 11, + + /// Enables or disables preserving color of invisible pixels. Use -1 for the + /// default (1 if lossless, 0 if lossy), 0 to disable, 1 to enable. + KeepInvisible = 12, + + /// Determines the order in which 256x256 regions are stored in the codestream + /// for progressive rendering. Use -1 for the encoder + /// default, 0 for scanline order, 1 for center-first order. + GroupOrder = 13, + + /// Determines the horizontal position of center for the center-first group + /// order. Use -1 to automatically use the middle of the image, 0..xsize to + /// specifically set it. + GroupOrderCenterX = 14, + + /// Determines the center for the center-first group order. Use -1 to + /// automatically use the middle of the image, 0..ysize to specifically set it. + GroupOrderCenterY = 15, + + /// Enables or disables progressive encoding for modular mode. Use -1 for the + /// encoder default, 0 to disable, 1 to enable. + Responsive = 16, + + /// Set the progressive mode for the AC coefficients of `VarDCT`, using spectral + /// progression from the DCT coefficients. Use -1 for the encoder default, 0 to + /// disable, 1 to enable. + ProgressiveAc = 17, + + /// Set the progressive mode for the AC coefficients of `VarDCT`, using + /// quantization of the least significant bits. Use -1 for the encoder default, + /// 0 to disable, 1 to enable. + QprogressiveAc = 18, + + /// Set the progressive mode using lower-resolution DC images for `VarDCT`. Use + /// -1 for the encoder default, 0 to disable, 1 to have an extra 64x64 lower + /// resolution pass, 2 to have a 512x512 and 64x64 lower resolution pass. + ProgressiveDc = 19, + + /// Use Global channel palette if the amount of colors is smaller than this + /// percentage of range. Use 0-100 to set an explicit percentage, -1 to use the + /// encoder default. Used for modular encoding. + ChannelColorsGlobalPercent = 20, + + /// Use Local (per-group) channel palette if the amount of colors is smaller + /// than this percentage of range. Use 0-100 to set an explicit percentage, -1 + /// to use the encoder default. Used for modular encoding. + ChannelColorsGroupPercent = 21, + + /// Use color palette if amount of colors is smaller than or equal to this + /// amount, or -1 to use the encoder default. Used for modular encoding. + PaletteColors = 22, + + /// Enables or disables delta palette. Use -1 for the default (encoder + /// chooses), 0 to disable, 1 to enable. Used in modular mode. + LossyPalette = 23, + + /// Color transform for internal encoding: -1 = default, 0=XYB, 1=none (RGB), + /// 2=YCbCr. The XYB setting performs the forward XYB transform. None and + /// YCbCr both perform no transform, but YCbCr is used to indicate that the + /// encoded data losslessly represents YCbCr values. + ColorTransform = 24, + + /// Reversible color transform for modular encoding: -1=default, 0-41=RCT + /// index, e.g. index 0 = none, index 6 = `YCoCg`. + /// If this option is set to a non-default value, the RCT will be globally + /// applied to the whole frame. + /// The default behavior is to try several RCTs locally per modular group, + /// depending on the speed and distance setting. + ModularColorSpace = 25, + + /// Group size for modular encoding: -1=default, 0=128, 1=256, 2=512, 3=1024. + ModularGroupSize = 26, + + /// Predictor for modular encoding. -1 = default, 0=zero, 1=left, 2=top, + /// 3=avg0, 4=select, 5=gradient, 6=weighted, 7=topright, 8=topleft, + /// 9=leftleft, 10=avg1, 11=avg2, 12=avg3, 13=toptop predictive average 14=mix + /// 5 and 6, 15=mix everything. + ModularPredictor = 27, + + /// Fraction of pixels used to learn MA trees as a percentage. -1 = default, + /// 0 = no MA and fast decode, 50 = default value, 100 = all, values above + /// 100 are also permitted. Higher values use more encoder memory. + ModularMaTreeLearningPercent = 28, + + /// Number of extra (previous-channel) MA tree properties to use. -1 = + /// default, 0-11 = valid values. Recommended values are in the range 0 to 3, + /// or 0 to amount of channels minus 1 (including all extra channels, and + /// excluding color channels when using `VarDCT` mode). Higher value gives slower + /// encoding and slower decoding. + ModularNbPrevChannels = 29, + + /// Enable or disable CFL (chroma-from-luma) for lossless JPEG recompression. + /// -1 = default, 0 = disable CFL, 1 = enable CFL. + JpegReconCfl = 30, + + /// Prepare the frame for indexing in the frame index box. + /// 0 = ignore this frame (same as not setting a value), + /// 1 = index this frame within the Frame Index Box. + /// If any frames are indexed, the first frame needs to + /// be indexed, too. If the first frame is not indexed, and + /// a later frame is attempted to be indexed, [`JxlEncoderStatus::Error`] will occur. + /// If non-keyframes, i.e., frames with cropping, blending or patches are + /// attempted to be indexed, [`JxlEncoderStatus::Error`] will occur. + IndexBox = 31, + + /// Sets brotli encode effort for use in JPEG recompression and + /// compressed metadata boxes (brob). Can be -1 (default) or 0 (fastest) to 11 + /// (slowest). Default is based on the general encode effort in case of JPEG + /// recompression, and 4 for brob boxes. + BrotliEffort = 32, + + /// Enables or disables brotli compression of metadata boxes derived from + /// a JPEG frame when using [`JxlEncoderAddJPEGFrame`]. This has no effect on + /// boxes added using [`JxlEncoderAddBox`]. -1 = default, 0 = disable + /// compression, 1 = enable compression. + JpegCompressBoxes = 33, + + /// Control what kind of buffering is used, when using chunked image frames. + /// -1 = default (let the encoder decide) + /// 0 = buffers everything, basically the same as non-streamed code path + /// (mainly for testing) + /// 1 = buffers everything for images that are smaller than 2048 x 2048, and + /// uses streaming input and output for larger images + /// 2 = uses streaming input and output for all images that are larger than + /// one group, i.e. 256 x 256 pixels by default + /// 3 = currently same as 2 + /// + /// When using streaming input and output the encoder minimizes memory usage at + /// the cost of compression density. Also note that images produced with + /// streaming mode might not be progressively decodeable. + Buffering = 34, + + /// Keep or discard Exif metadata boxes derived from a JPEG frame when using + /// [`JxlEncoderAddJPEGFrame`]. This has no effect on boxes added using + /// [`JxlEncoderAddBox`]. When [`JxlEncoderStoreJPEGMetadata`] is set to 1, + /// this option cannot be set to 0. Even when Exif metadata is discarded, the + /// orientation will still be applied. 0 = discard Exif metadata, 1 = keep Exif + /// metadata (default). + JpegKeepExif = 35, + + /// Keep or discard XMP metadata boxes derived from a JPEG frame when using + /// [`JxlEncoderAddJPEGFrame`]. This has no effect on boxes added using + /// [`JxlEncoderAddBox`]. When [`JxlEncoderStoreJPEGMetadata`] is set to 1, + /// this option cannot be set to 0. 0 = discard XMP metadata, 1 = keep XMP + /// metadata (default). + JpegKeepXmp = 36, + + /// Keep or discard JUMBF metadata boxes derived from a JPEG frame when using + /// [`JxlEncoderAddJPEGFrame`]. This has no effect on boxes added using + /// [`JxlEncoderAddBox`]. 0 = discard JUMBF metadata, 1 = keep JUMBF metadata + /// (default). + JpegKeepJumbf = 37, + + /// If this mode is disabled, the encoder will not make any image quality + /// decisions that are computed based on the full image, but stored only once + /// (e.g. the X quant multiplier in the frame header). Used mainly for testing + /// equivalence of streaming and non-streaming code. + /// 0 = disabled, 1 = enabled (default) + UseFullImageHeuristics = 38, + + /// Disable perceptual optimizations. 0 = optimizations enabled (default), 1 = + /// optimizations disabled. + DisablePerceptualHeuristics = 39, + + /// Enum value not to be used as an option. This value is added to force the + /// C compiler to have the enum to take a known size. + FillEnum = 65535, +} + +/// The [`JxlEncoderOutputProcessor`] structure provides an interface for the +/// encoder's output processing. Users of the library, who want to do streaming +/// encoding, should implement the required callbacks for buffering, writing, +/// seeking (if supported), and setting a finalized position during the encoding +/// process. +/// +/// At a high level, the processor can be in one of two states: +/// - With an active buffer: This indicates that a buffer has been acquired using +/// `get_buffer` and encoded data can be written to it. +/// - Without an active buffer: In this state, no data can be written. A new +/// buffer must be acquired after releasing any previously active buffer. +/// +/// The library will not acquire more than one buffer at a given time. +/// +/// The state of the processor includes `position` and `finalized position`, +/// which have the following meaning. +/// +/// - position: Represents the current position, in bytes, within the output +/// stream where the encoded data will be written next. This position moves +/// forward with each `release_buffer` call as data is written, and can also be +/// adjusted through the optional seek callback, if provided. At this position +/// the next write will occur. +/// +/// - finalized position: A position in the output stream that ensures all bytes +/// before this point are finalized and won't be changed by later writes. +/// +/// All fields but `seek` are required, `seek` is optional and can be `None`. +#[repr(C)] +#[derive(Debug, Clone)] +pub struct JxlEncoderOutputProcessor { + /// An opaque pointer that the client can use to store custom data. + /// This data will be passed to the associated callback functions. + opaque: *mut c_void, + /// Acquires a buffer at the current position into which the library will write + /// the output data. + /// + /// If the `size` argument points to 0 and the returned value is NULL, this + /// will be interpreted as asking the output writing to stop. In such a case, + /// the library will return an error. The client is expected to set the size of + /// the returned buffer based on the suggested `size` when this function is + /// called. + /// + /// # Parameters + /// - `opaque`: User supplied parameters to the callback. + /// - `size`: Points to a suggested buffer size when called; must be set to + /// the size of the returned buffer once the function returns. + /// + /// # Returns + /// A pointer to the acquired buffer or NULL to indicate a stop + /// condition. + get_buffer: extern "C-unwind" fn(opaque: *mut c_void, size: *mut usize) -> *mut c_void, + /// Notifies the user of library that the current buffer's data has been + /// written and can be released. This function should advance the current + /// osition of the buffer by `written_bytes` number of bytes. + /// + /// # Parameters + /// - `opaque`: user supplied parameters to the callback + /// - `written_bytes`: the number of bytes written to the buffer. + release_buffer: extern "C-unwind" fn(opaque: *mut c_void, written_bytes: usize), + /// Seeks to a specific position in the output. This function is optional and + /// can be set to `None` if the output doesn't support seeking. Can only be done + /// when there is no buffer. Cannot be used to seek before the finalized + /// position. + /// + /// # Parameters + /// - `opaque`: User supplied parameters to the callback. + /// - `position`: The position to seek to, in bytes. + seek: Option, + /// Sets a finalized position on the output data, at a specific position. + /// Seeking will never request a position before the finalized position. + /// + /// Will only be called if there is no active buffer. + /// + /// # Parameters + /// - `opaque`: User supplied parameters to the callback. + /// - `finalized_position`: The position, in bytes, where the finalized + /// position should be set. + set_finalized_position: extern "C-unwind" fn(opaque: *mut c_void, finalized_position: u64), +} + +/// This struct provides callback functions to pass pixel data in a streaming +/// manner instead of requiring the entire frame data in memory at once. +#[repr(C)] +#[derive(Debug, Clone)] +pub struct JxlChunkedFrameInputSource { + /// A pointer to any user-defined data or state. This can be used to pass + /// information to the callback functions. + opaque: *mut c_void, + + /// Get the pixel format that color channel data will be provided in. + /// When called, `pixel_format` points to a suggested pixel format; if + /// color channel data can be given in this pixel format, processing might + /// be more efficient. + /// + /// This function will be called exactly once, before any call to + /// [`Self::get_color_channels_data`]. + /// + /// # Parameters + /// - `opaque`: User supplied parameters to the callback. + /// - `pixel_format`: Format for pixels. + get_color_channels_pixel_format: + extern "C-unwind" fn(opaque: *mut c_void, pixel_format: *mut JxlPixelFormat), + + /// Callback to retrieve a rectangle of color channel data at a specific + /// location. It is guaranteed that `xpos` and `ypos` are multiples of 8. `xsize`, + /// `ysize` will be multiples of 8, unless the resulting rectangle would be out + /// of image bounds. Moreover, `xsize` and `ysize` will be at most 2048. The + /// returned data will be assumed to be in the format returned by the + /// (preceding) call to [`Self::get_color_channels_pixel_format`], except the `align` + /// parameter of the pixel format will be ignored. Instead, the `i`-th row will + /// be assumed to start at position `return_value + i * *row_offset`, with the + /// value of `*row_offset` decided by the callee. + /// + /// Note that multiple calls to `get_color_channel_data_at` may happen before a + /// call to [`Self::release_buffer`]. + /// + /// # Parameters + /// - `opaque`: User supplied parameters to the callback. + /// - `xpos`: Horizontal position for the data. + /// - `ypos`: Vertical position for the data. + /// - `xsize`: Horizontal size of the requested rectangle of data. + /// - `ysize`: Vertical size of the requested rectangle of data. + /// - `row_offset`: Pointer to the byte offset between consecutive rows of + /// the retrieved pixel data. + /// + /// # Returns + /// Pointer to the retrieved pixel data. + get_color_channels_data_at: extern "C-unwind" fn( + opaque: *mut c_void, + xpos: usize, + ypos: usize, + xsize: usize, + ysize: usize, + row_offset: *mut usize, + ) -> *const c_void, + + /// Get the pixel format that extra channel data will be provided in. + /// When called, `pixel_format` points to a suggested pixel format; if + /// extra channel data can be given in this pixel format, processing might + /// be more efficient. + /// + /// This function will be called exactly once per index, before any call to + /// [`Self::get_extra_channel_data_at`] with that given index. + /// + /// # Parameters + /// - `opaque`: User supplied parameters to the callback. + /// - `ec_index`: Zero-indexed index of the extra channel. + /// - `pixel_format`: Format for extra channel data. + get_extra_channel_pixel_format: extern "C-unwind" fn( + opaque: *mut c_void, + ec_index: usize, + pixel_format: *mut JxlPixelFormat, + ), + + /// Callback to retrieve a rectangle of extra channel `ec_index` data at a + /// specific location. It is guaranteed that `xpos` and `ypos` are multiples of + /// 8. `xsize`, `ysize` will be multiples of 8, unless the resulting rectangle + /// would be out of image bounds. Moreover, `xsize` and `ysize` will be at most + /// 2048. The returned data will be assumed to be in the format returned by the + /// (preceding) call to [`Self::get_extra_channel_pixel_format`] with the + /// corresponding extra channel index `ec_index`, except the `align` parameter + /// of the pixel format will be ignored. Instead, the `i`-th row will be + /// assumed to start at position `return_value + i * *row_offset`, with the + /// value of `*row_offset` decided by the callee. + /// + /// Note that multiple calls to `get_extra_channel_data_at` may happen before a + /// call to [`Self::release_buffer`]. + /// + /// # Parameters + /// - `opaque`: User supplied parameters to the callback. + /// - `xpos`: Horizontal position for the data. + /// - `ypos`: Vertical position for the data. + /// - `xsize`: Horizontal size of the requested rectangle of data. + /// - `ysize`: Vertical size of the requested rectangle of data. + /// - `row_offset`: Pointer to the byte offset between consecutive rows of + /// the retrieved pixel data. + /// + /// # Returns + /// Pointer to the retrieved pixel data. + get_extra_channel_data_at: extern "C-unwind" fn( + opaque: *mut c_void, + ec_index: usize, + xpos: usize, + ypos: usize, + xsize: usize, + ysize: usize, + row_offset: *mut usize, + ) -> *const c_void, + + /// Releases the buffer `buf` (obtained through a call to + /// [`Self::get_color_channels_data_at`] or [`Self::get_extra_channel_data_at`]). This function + /// will be called exactly once per call to [`Self::get_color_channels_data_at`] or + /// [`Self::get_extra_channel_data_at`]. + /// + /// # Parameters + /// - `opaque`: User supplied parameters to the callback. + /// - `buf`: Pointer returned by [`Self::get_color_channels_data_at`] or + /// [`Self::get_extra_channel_data_at`]. + release_buffer: extern "C-unwind" fn(opaque: *mut c_void, buf: *const c_void), +} + +/// Function type for [`JxlEncoderSetDebugImageCallback`]. +/// +/// The callback may be called simultaneously by different threads when using a +/// threaded parallel runner, on different debug images. +/// +/// # Parameters +/// - `opaque`: Optional user data, as given to [`JxlEncoderSetDebugImageCallback`]. +/// - `label`: Label of debug image, can be used in filenames. +/// - `xsize`: Width of debug image. +/// - `ysize`: Height of debug image. +/// - `color`: Color encoding of debug image. +/// - `pixels`: Pixel data of debug image as big-endian 16-bit unsigned samples. +/// The memory is not owned by the user, and is only valid during the time the +/// callback is running. +pub type JxlDebugImageCallback = extern "C-unwind" fn( + opaque: *mut c_void, + label: *const c_char, + xsize: usize, + ysize: usize, + color: *const JxlColorEncoding, + pixels: *const u16, +); + +extern "C" { + /// Encoder library version. + /// + /// # Returns + /// The encoder library version as an integer: + /// `MAJOR_VERSION * 1000000 + MINOR_VERSION * 1000 + PATCH_VERSION`. + /// For example, version 1.2.3 would return 1002003. + pub fn JxlEncoderVersion() -> u32; + + /// Creates an instance of `JxlEncoder` and initializes it. + /// + /// # Parameters + /// - `memory_manager`: Custom allocator function. It may be `NULL`. The memory + /// manager will be copied internally. If `NULL`, the default allocator will be used. + /// See [`crate::common::memory_manager`] for details. + /// + /// # Returns + /// - `NULL` if the instance cannot be allocated or initialized. + /// - Pointer to initialized [`JxlEncoder`] otherwise. + pub fn JxlEncoderCreate(memory_manager: *const JxlMemoryManager) -> *mut JxlEncoder; + + /// Re-initializes a [`JxlEncoder`] instance, so it can be re-used for encoding + /// another image. All state and settings are reset as if the object was + /// newly created with [`JxlEncoderCreate`], but the memory manager is kept. + /// + /// # Parameters + /// - `enc`: Instance to be re-initialized. + pub fn JxlEncoderReset(enc: *mut JxlEncoder); + + /// Deinitializes and frees a [`JxlEncoder`] instance. + /// + /// # Parameters + /// - `enc`: Instance to be cleaned up and deallocated. + pub fn JxlEncoderDestroy(enc: *mut JxlEncoder); + + /// Sets the color management system (CMS) that will be used for color conversion + /// (if applicable) during encoding. May only be set before starting encoding. If + /// left unset, the default CMS implementation will be used. + /// + /// # Parameters + /// - `enc`: Encoder object. + /// - `cms`: Structure representing a CMS implementation. See [`JxlCmsInterface`] for more details. + pub fn JxlEncoderSetCms(enc: *mut JxlEncoder, cms: JxlCmsInterface); + + /// Set the parallel runner for multithreading. May only be set before starting + /// encoding. + /// + /// # Parameters + /// - `enc`: Encoder object. + /// - `parallel_runner`: Function pointer to runner for multithreading. It may + /// be `NULL` to use the default, single-threaded, runner. A multithreaded + /// runner should be set to reach fast performance. + /// - `parallel_runner_opaque`: Opaque pointer for `parallel_runner`. + /// + /// # Returns + /// - `JxlEncoderStatus::Success` if the runner was set. + /// - `JxlEncoderStatus::Error` otherwise (the previous runner remains set). + pub fn JxlEncoderSetParallelRunner( + enc: *mut JxlEncoder, + parallel_runner: JxlParallelRunner, + parallel_runner_opaque: *mut c_void, + ) -> JxlEncoderStatus; + + /// Get the (last) error code in case [`JxlEncoderStatus::Error`] was returned. + /// + /// # Parameters + /// - `enc`: Encoder object. + /// + /// # Returns + /// The [`JxlEncoderError`] that caused the (last) [`JxlEncoderStatus::Error`] to be returned. + pub fn JxlEncoderGetError(enc: *mut JxlEncoder) -> JxlEncoderError; + + /// Encodes a JPEG XL file using the available bytes. `*avail_out` indicates how + /// many output bytes are available, and `*next_out` points to the input bytes. + /// `*avail_out` will be decremented by the amount of bytes that have been + /// processed by the encoder and `*next_out` will be incremented by the same + /// amount, so `*next_out` will now point at the amount of `*avail_out` unprocessed + /// bytes. + /// + /// The returned status indicates whether the encoder needs more output bytes. + /// When the return value is not [`JxlEncoderStatus::Error`] or [`JxlEncoderStatus::Success`], the + /// encoding requires more [`JxlEncoderProcessOutput`] calls to continue. + /// + /// The caller must guarantee that `*avail_out >= 32` when calling + /// [`JxlEncoderProcessOutput`]; otherwise, [`JxlEncoderStatus::NeedMoreOutput`] will + /// be returned. It is guaranteed that, if `*avail_out >= 32`, at least one byte of + /// output will be written. + /// + /// This encodes the frames and/or boxes added so far. If the last frame or last + /// box has been added, [`JxlEncoderCloseInput`], [`JxlEncoderCloseFrames`] + /// and/or [`JxlEncoderCloseBoxes`] must be called before the next + /// [`JxlEncoderProcessOutput`] call, or the codestream won't be encoded + /// correctly. + /// + /// # Parameters + /// - `enc`: Encoder object. + /// - `next_out`: Pointer to next bytes to write to. + /// - `avail_out`: Amount of bytes available starting from `*next_out`. + /// + /// # Returns + /// - [`JxlEncoderStatus::Success`] when encoding finished and all events handled. + /// - [`JxlEncoderStatus::Error`] when encoding failed, e.g. invalid input. + /// - [`JxlEncoderStatus::NeedMoreOutput`] more output buffer is necessary. + pub fn JxlEncoderProcessOutput( + enc: *mut JxlEncoder, + next_out: *mut *mut u8, + avail_out: *mut usize, + ) -> JxlEncoderStatus; + + /// Sets the frame information for this frame to the encoder. This includes + /// animation information such as frame duration to store in the frame header. + /// The frame header fields represent the frame as passed to the encoder, but not + /// necessarily the exact values as they will be encoded file format: the encoder + /// could change crop and blending options of a frame for more efficient encoding + /// or introduce additional internal frames. Animation duration and time code + /// information is not altered since those are immutable metadata of the frame. + /// + /// It is not required to use this function, however if `have_animation` is set + /// to true in the basic info, then this function should be used to set the + /// time duration of this individual frame. By default individual frames have a + /// time duration of 0, making them form a composite still. See [`JxlFrameHeader`] + /// for more information. + /// + /// This information is stored in the [`JxlEncoderFrameSettings`] and so is used + /// for any frame encoded with these [`JxlEncoderFrameSettings`]. It is ok to + /// change between [`JxlEncoderAddImageFrame`] calls, each added image frame + /// will have the frame header that was set in the options at the time of calling + /// [`JxlEncoderAddImageFrame`]. + /// + /// The `is_last` and `name_length` fields of the [`JxlFrameHeader`] are ignored, + /// use [`JxlEncoderCloseFrames`] to indicate last frame, and [`JxlEncoderSetFrameName`] + /// to indicate the name and its length instead. + /// Calling this function will clear any name that was previously set with [`JxlEncoderSetFrameName`]. + /// + /// # Parameters + /// - `frame_settings`: set of options and metadata for this frame. Also + /// includes reference to the encoder object. + /// - `frame_header`: frame header data to set. Object owned by the caller and + /// does not need to be kept in memory, its information is copied internally. + /// + /// # Returns + /// - [`JxlEncoderStatus::Success`] on success + /// - [`JxlEncoderStatus::Error`] on error + pub fn JxlEncoderSetFrameHeader( + frame_settings: *mut JxlEncoderFrameSettings, + frame_header: *const JxlFrameHeader, + ) -> JxlEncoderStatus; + + /// Sets blend info of an extra channel. The blend info of extra channels is set + /// separately from that of the color channels, the color channels are set with + /// [`JxlEncoderSetFrameHeader`]. + /// + /// # Parameters + /// - `frame_settings`: set of options and metadata for this frame. Also + /// includes reference to the encoder object. + /// - `index`: index of the extra channel to use. + /// - `blend_info`: blend info to set for the extra channel. + /// + /// # Returns + /// - [`JxlEncoderStatus::Success`] on success. + /// - [`JxlEncoderStatus::Error`] on error. + pub fn JxlEncoderSetExtraChannelBlendInfo( + frame_settings: *mut JxlEncoderFrameSettings, + index: usize, + blend_info: *const JxlBlendInfo, + ) -> JxlEncoderStatus; + + /// Sets the name of the animation frame. This function is optional, frames are + /// not required to have a name. This setting is a part of the frame header, and + /// the same principles as for [`JxlEncoderSetFrameHeader`] apply. The + /// `name_length` field of [`JxlFrameHeader`] is ignored by the encoder, this + /// function determines the name length instead as the length in bytes of the C + /// string. + /// + /// The maximum possible name length is 1071 bytes (excluding terminating null + /// character). + /// + /// Calling [`JxlEncoderSetFrameHeader`] clears any name that was + /// previously set. + /// + /// # Parameters + /// - `frame_settings`: set of options and metadata for this frame. Also + /// includes reference to the encoder object. + /// - `frame_name`: name of the next frame to be encoded, as a UTF-8 encoded C + /// string (zero terminated). Owned by the caller, and copied internally. + /// + /// # Returns + /// - [`JxlEncoderStatus::Success`] on success + /// - [`JxlEncoderStatus::Error`] on error + pub fn JxlEncoderSetFrameName( + frame_settings: *mut JxlEncoderFrameSettings, + frame_name: *const u8, + ) -> JxlEncoderStatus; + + /// Sets the bit depth of the input buffer. + /// + /// For float pixel formats, only the default [`JxlBitDepthType::FromPixelFormat`] + /// setting is allowed, while for unsigned pixel formats, + /// [`JxlBitDepthType::FromCodestream`] setting is also allowed. See the comment + /// on [`JxlEncoderAddImageFrame`] for the effects of the bit depth setting. + /// + /// # Parameters + /// - `frame_settings`: Set of options and metadata for this frame. Also + /// includes reference to the encoder object. + /// - `bit_depth`: The bit depth setting of the pixel input. + /// + /// # Returns + /// - [`JxlEncoderStatus::Success`] on success. + /// - [`JxlEncoderStatus::Error`] on error. + pub fn JxlEncoderSetFrameBitDepth( + frame_settings: *mut JxlEncoderFrameSettings, + bit_depth: *const JxlBitDepth, + ) -> JxlEncoderStatus; + + /// Sets the buffer to read JPEG encoded bytes from for the next frame to encode. + /// + /// If [`JxlEncoderSetBasicInfo`] has not yet been called, calling + /// [`JxlEncoderAddJPEGFrame`] will implicitly call it with the parameters of + /// the added JPEG frame. + /// + /// If [`JxlEncoderSetColorEncoding`] or [`JxlEncoderSetICCProfile`] has not + /// yet been called, calling [`JxlEncoderAddJPEGFrame`] will implicitly call it + /// with the parameters of the added JPEG frame. + /// + /// If the encoder is set to store JPEG reconstruction metadata using [`JxlEncoderStoreJPEGMetadata`] + /// and a single JPEG frame is added, it will be possible to losslessly reconstruct the JPEG codestream. + /// + /// If this is the last frame, [`JxlEncoderCloseInput`] or [`JxlEncoderCloseFrames`] must be called before the next + /// [`JxlEncoderProcessOutput`] call. + /// + /// Note, this can only be used to add JPEG frames for lossless compression. To + /// encode with lossy compression, the JPEG must be decoded manually and a pixel + /// buffer added using [`JxlEncoderAddImageFrame`]. + /// + /// # Parameters + /// - `frame_settings`: set of options and metadata for this frame. Also + /// includes reference to the encoder object. + /// - `buffer`: bytes to read JPEG from. Owned by the caller and its contents + /// are copied internally. + /// - `size`: size of buffer in bytes. + /// + /// # Returns + /// - [`JxlEncoderStatus::Success`] on success + /// - [`JxlEncoderStatus::Error`] on error + pub fn JxlEncoderAddJPEGFrame( + options: *const JxlEncoderFrameSettings, + buffer: *const u8, + size: usize, + ) -> JxlEncoderStatus; + + /// Sets the buffer to read pixels from for the next image to encode. Must call + /// [`JxlEncoderSetBasicInfo`] before [`JxlEncoderAddImageFrame`]. + /// + /// Currently only some data types for pixel formats are supported: + /// - [`JxlDataType::Uint8`], with range 0..255 + /// - [`JxlDataType::Uint16`], with range 0..65535 + /// - [`JxlDataType::Float16`], with nominal range 0..1 + /// - [`JxlDataType::Float`], with nominal range 0..1 + /// + /// Note: the sample data type in `pixel_format` is allowed to be different from + /// what is described in the [`JxlBasicInfo`]. The type in `pixel_format`, + /// together with an optional [`JxlBitDepth`] parameter set by [`JxlEncoderSetFrameBitDepth`] + /// describes the format of the uncompressed pixel buffer. The `bits_per_sample` and `exponent_bits_per_sample` + /// in the [`JxlBasicInfo`] describes what will actually be encoded in the JPEG XL + /// codestream. For example, to encode a 12-bit image, you would set + /// `bits_per_sample` to 12, while the input frame buffer can be in the following + /// formats: + /// - if pixel format is in [`JxlDataType::Uint16`] with default bit depth setting + /// (i.e. [`JxlBitDepthType::FromPixelFormat`]), input sample values are + /// rescaled to 16-bit, i.e. multiplied by 65535/4095; + /// - if pixel format is in [`JxlDataType::Uint16`] with [`JxlBitDepthType::FromCodestream`] bit depth setting, + /// input sample values are provided unscaled; + /// - if pixel format is in [`JxlDataType::Float`], input sample values are + /// rescaled to 0..1, i.e. multiplied by 1.0/4095.0. While it is allowed, it is + /// obviously not recommended to use a `pixel_format` with lower precision than + /// what is specified in the [`JxlBasicInfo`]. + /// + /// We support interleaved channels as described by the [`JxlPixelFormat`]: + /// - single-channel data, e.g. grayscale + /// - single-channel + alpha + /// - trichromatic, e.g. RGB + /// - trichromatic + alpha + /// + /// Extra channels not handled here need to be set by [`JxlEncoderSetExtraChannelBuffer`]. + /// If the image has alpha, and alpha is not passed here, it will implicitly be + /// set to all-opaque (an alpha value of 1.0 everywhere). + /// + /// The pixels are assumed to be encoded in the original profile that is set with + /// [`JxlEncoderSetColorEncoding`] or [`JxlEncoderSetICCProfile`]. If none of + /// these functions were used, the pixels are assumed to be nonlinear sRGB for + /// integer data types ([`JxlDataType::Uint8`], [`JxlDataType::Uint16`]), and linear + /// sRGB for floating point data types ([`JxlDataType::Float16`], [`JxlDataType::Float`]). + /// + /// Sample values in floating-point pixel formats are allowed to be outside the + /// nominal range, e.g. to represent out-of-sRGB-gamut colors in the + /// `uses_original_profile=false` case. They are however not allowed to be NaN or + /// +-infinity. + /// + /// If this is the last frame, [`JxlEncoderCloseInput`] or [`JxlEncoderCloseFrames`] must be called before the next + /// [`JxlEncoderProcessOutput`] call. + /// + /// # Parameters + /// - `frame_settings`: set of options and metadata for this frame. Also + /// includes reference to the encoder object. + /// - `pixel_format`: format for pixels. Object owned by the caller and its + /// contents are copied internally. + /// - `buffer`: buffer type to input the pixel data from. Owned by the caller + /// and its contents are copied internally. + /// - `size`: size of buffer in bytes. This size should match what is implied + /// by the frame dimensions and the pixel format. + /// + /// # Returns + /// - [`JxlEncoderStatus::Success`] on success + /// - [`JxlEncoderStatus::Error`] on error + pub fn JxlEncoderAddImageFrame( + options: *const JxlEncoderFrameSettings, + pixel_format: *const JxlPixelFormat, + buffer: *const c_void, + size: usize, + ) -> JxlEncoderStatus; + + /// Sets the output processor for the encoder. This processor determines how the + /// encoder will handle buffering, writing, seeking (if supported), and + /// setting a finalized position during the encoding process. + /// + /// This should not be used when using [`JxlEncoderProcessOutput`]. + /// + /// # Parameters + /// - `enc`: Encoder object. + /// - `output_processor`: The struct containing the callbacks for managing + /// output. + /// + /// # Returns + /// - [`JxlEncoderStatus::Success`] on success. + /// - [`JxlEncoderStatus::Error`] on error. + pub fn JxlEncoderSetOutputProcessor( + enc: *mut JxlEncoder, + output_processor: JxlEncoderOutputProcessor, + ) -> JxlEncoderStatus; + + /// Flushes any buffered input in the encoder, ensuring that all available input + /// data has been processed and written to the output. + /// + /// This function can only be used after [`JxlEncoderSetOutputProcessor`]. + /// Before making the last call to [`JxlEncoderFlushInput`], users should call + /// [`JxlEncoderCloseInput`] to signal the end of input data. + /// + /// This should not be used when using [`JxlEncoderProcessOutput`]. + /// + /// # Parameters + /// - `enc`: Encoder object. + /// + /// # Returns + /// - [`JxlEncoderStatus::Success`] on success. + /// - [`JxlEncoderStatus::Error`] on error. + pub fn JxlEncoderFlushInput(enc: *mut JxlEncoder) -> JxlEncoderStatus; + + /// Adds a frame to the encoder using a chunked input source. + /// + /// This function gives a way to encode a frame by providing pixel data in a + /// chunked or streaming manner, which can be especially useful when dealing with + /// large images that may not fit entirely in memory or when trying to optimize + /// memory usage. The input data is provided through callbacks defined in the + /// [`JxlChunkedFrameInputSource`] struct. Once the frame data has been + /// completely retrieved, this function will flush the input and close it if it + /// is the last frame. + /// + /// # Parameters + /// - `frame_settings`: Set of options and metadata for this frame. Also + /// includes reference to the encoder object. + /// - `is_last_frame`: Indicates if this is the last frame. + /// - `chunked_frame_input`: Struct providing callback methods for retrieving + /// pixel data in chunks. + /// + /// # Returns + /// Returns a status indicating the success or failure of adding the + /// frame. + pub fn JxlEncoderAddChunkedFrame( + frame_settings: *const JxlEncoderFrameSettings, + is_last_frame: JxlBool, + chunked_frame_input: JxlChunkedFrameInputSource, + ) -> JxlEncoderStatus; + + /// Sets the buffer to read pixels from for an extra channel at a given index. + /// The index must be smaller than the `num_extra_channels` in the associated + /// [`JxlBasicInfo`]. Must call [`JxlEncoderSetExtraChannelInfo`] before + /// [`JxlEncoderSetExtraChannelBuffer`]. + /// + /// TODO: mention what data types in pixel formats are supported. + /// + /// It is required to call this function for every extra channel, except for the + /// alpha channel if that was already set through [`JxlEncoderAddImageFrame`]. + /// + /// # Parameters + /// - `frame_settings`: Set of options and metadata for this frame. Also + /// includes reference to the encoder object. + /// - `pixel_format`: Format for pixels. Object owned by the caller and its + /// contents are copied internally. The `num_channels` value is ignored, since the + /// number of channels for an extra channel is always assumed to be one. + /// - `buffer`: Buffer type to input the pixel data from. Owned by the caller + /// and its contents are copied internally. + /// - `size`: Size of buffer in bytes. This size should match what is implied + /// by the frame dimensions and the pixel format. + /// - `index`: Index of the extra channel to use. + /// + /// # Returns + /// - [`JxlEncoderStatus::Success`] on success. + /// - [`JxlEncoderStatus::Error`] on error. + pub fn JxlEncoderSetExtraChannelBuffer( + frame_settings: *const JxlEncoderFrameSettings, + pixel_format: *const JxlPixelFormat, + buffer: *const c_void, + size: usize, + index: u32, + ) -> JxlEncoderStatus; + + /// Adds a metadata box to the file format. [`JxlEncoderProcessOutput`] must be + /// used to effectively write the box to the output. [`JxlEncoderUseBoxes`] must + /// be enabled before using this function. + /// + /// Boxes allow inserting application-specific data and metadata (Exif, XML/XMP, + /// JUMBF and user defined boxes). + /// + /// The box format follows ISO BMFF and shares features and box types with other + /// image and video formats, including the Exif, XML and JUMBF boxes. The box + /// format for JPEG XL is specified in ISO/IEC 18181-2. + /// + /// Boxes in general don't contain other boxes inside, except a JUMBF superbox. + /// Boxes follow each other sequentially and are byte-aligned. If the container + /// format is used, the JXL stream consists of concatenated boxes. + /// It is also possible to use a direct codestream without boxes, but in that + /// case metadata cannot be added. + /// + /// Each box generally has the following byte structure in the file: + /// - 4 bytes: box size including box header (Big endian. If set to 0, an + /// 8-byte 64-bit size follows instead). + /// - 4 bytes: type, e.g. "JXL " for the signature box, "jxlc" for a codestream + /// box. + /// - N bytes: box contents. + /// + /// Only the box contents are provided to the contents argument of this function, + /// the encoder encodes the size header itself. Most boxes are written + /// automatically by the encoder as needed ("JXL ", "ftyp", "jxll", "jxlc", + /// "jxlp", "jxli", "jbrd"), and this function only needs to be called to add + /// optional metadata when encoding from pixels (using [`JxlEncoderAddImageFrame`]). + /// When recompressing JPEG files (using [`JxlEncoderAddJPEGFrame`]), + /// if the input JPEG contains EXIF, XMP or JUMBF + /// metadata, the corresponding boxes are already added automatically. + /// + /// Box types are given by 4 characters. The following boxes can be added with + /// this function: + /// - "Exif": a box with EXIF metadata, can be added by libjxl users, or is + /// automatically added when needed for JPEG reconstruction. The contents of + /// this box must be prepended by a 4-byte tiff header offset, which may + /// be 4 zero bytes in case the tiff header follows immediately. + /// The EXIF metadata must be in sync with what is encoded in the JPEG XL + /// codestream, specifically the image orientation. While this is not + /// recommended in practice, in case of conflicting metadata, the JPEG XL + /// codestream takes precedence. + /// - "xml ": a box with XML data, in particular XMP metadata, can be added by + /// libjxl users, or is automatically added when needed for JPEG reconstruction + /// - "jumb": a JUMBF superbox, which can contain boxes with different types of + /// metadata inside. This box type can be added by the encoder transparently, + /// and other libraries to create and handle JUMBF content exist. + /// - Application-specific boxes. Their typename should not begin with "jxl" or + /// "JXL" or conflict with other existing typenames, and they should be + /// registered with MP4RA (mp4ra.org). + /// + /// These boxes can be stored uncompressed or Brotli-compressed (using a "brob" + /// box), depending on the `compress_box` parameter. + /// + /// # Parameters + /// - `enc`: encoder object. + /// - `box_type`: the box type, e.g. "Exif" for EXIF metadata, "xml " for XMP or + /// IPTC metadata, "jumb" for JUMBF metadata. + /// - `contents`: the full contents of the box, for example EXIF + /// data. ISO BMFF box header must not be included, only the contents. Owned by + /// the caller and its contents are copied internally. + /// - `size`: size of the box contents. + /// - `compress_box`: Whether to compress this box as a "brob" box. Requires + /// Brotli support. + /// + /// # Returns + /// - [`JxlEncoderStatus::Success`] on success. + /// - [`JxlEncoderStatus::Error`] on error, such as + /// when using this function without [`JxlEncoderUseContainer`], or adding a box + /// type that would result in an invalid file format. + pub fn JxlEncoderAddBox( + enc: *mut JxlEncoder, + box_type: *const JxlBoxType, + contents: *const u8, + size: usize, + compress_box: JxlBool, + ) -> JxlEncoderStatus; + + /// Indicates the intention to add metadata boxes. This allows [`JxlEncoderAddBox`] to be used. + /// When using this function, then it is required to use [`JxlEncoderCloseBoxes`] at the end. + /// + /// By default the encoder assumes no metadata boxes will be added. + /// + /// This setting can only be set at the beginning, before encoding starts. + /// + /// # Parameters + /// - `enc`: encoder object. + pub fn JxlEncoderUseBoxes(enc: *mut JxlEncoder) -> JxlEncoderStatus; + + /// Declares that no further boxes will be added with [`JxlEncoderAddBox`]. + /// This function must be called after the last box is added so the encoder knows + /// the stream will be finished. It is not necessary to use this function if + /// [`JxlEncoderUseBoxes`] is not used. Further frames may still be added. + /// + /// Must be called between [`JxlEncoderAddBox`] of the last box + /// and the next call to [`JxlEncoderProcessOutput`], or [`JxlEncoderProcessOutput`] + /// won't output the last box correctly. + /// + /// NOTE: if you don't need to close frames and boxes at separate times, you can + /// use [`JxlEncoderCloseInput`] instead to close both at once. + /// + /// # Parameters + /// - `enc`: encoder object. + pub fn JxlEncoderCloseBoxes(enc: *mut JxlEncoder); + + /// Declares that no frames will be added and [`JxlEncoderAddImageFrame`] and + /// [`JxlEncoderAddJPEGFrame`] won't be called anymore. Further metadata boxes + /// may still be added. This function or [`JxlEncoderCloseInput`] must be called + /// after adding the last frame and the next call to + /// [`JxlEncoderProcessOutput`], or the frame won't be properly marked as last. + /// + /// NOTE: if you don't need to close frames and boxes at separate times, you can + /// use [`JxlEncoderCloseInput`] instead to close both at once. + /// + /// # Parameters + /// - `enc`: encoder object. + pub fn JxlEncoderCloseFrames(enc: *mut JxlEncoder); + + /// Closes any input to the encoder, equivalent to calling [`JxlEncoderCloseFrames`] + /// as well as calling [`JxlEncoderCloseBoxes`] if needed. No further input of any kind + /// may be given to the encoder, but further [`JxlEncoderProcessOutput`] calls should be + /// done to create the final output. + /// + /// The requirements of both [`JxlEncoderCloseFrames`] and [`JxlEncoderCloseBoxes`] apply + /// to this function. Either this function or the other two must be called after the final + /// frame and/or box, and the next [`JxlEncoderProcessOutput`] call, or the codestream won't + /// be encoded correctly. + /// + /// # Parameters + /// - `enc`: encoder object. + pub fn JxlEncoderCloseInput(enc: *mut JxlEncoder); + + /// Sets the original color encoding of the image encoded by this encoder. This + /// is an alternative to [`JxlEncoderSetICCProfile`] and only one of these two + /// must be used. This one sets the color encoding as a [`JxlColorEncoding`], + /// while the other sets it as ICC binary data. Must be called after + /// [`JxlEncoderSetBasicInfo`]. + /// + /// # Parameters + /// - `enc`: encoder object. + /// - `color`: color encoding. Object owned by the caller and its contents are + /// copied internally. + /// + /// # Returns + /// - [`JxlEncoderStatus::Success`] if the operation was successful. + /// - [`JxlEncoderStatus::Error`] otherwise. + pub fn JxlEncoderSetColorEncoding( + enc: *mut JxlEncoder, + color: *const JxlColorEncoding, + ) -> JxlEncoderStatus; + + /// Sets the original color encoding of the image encoded by this encoder as an + /// ICC color profile. This is an alternative to [`JxlEncoderSetColorEncoding`] + /// and only one of these two must be used. This one sets the color encoding as + /// ICC binary data, while the other defines it as a [`JxlColorEncoding`]. Must + /// be called after [`JxlEncoderSetBasicInfo`]. + /// + /// # Parameters + /// - `enc`: encoder object. + /// - `icc_profile`: bytes of the original ICC profile + /// - `size`: size of the `icc_profile` buffer in bytes + /// + /// # Returns + /// - [`JxlEncoderStatus::Success`] if the operation was successful. + /// - [`JxlEncoderStatus::Error`] otherwise. + pub fn JxlEncoderSetICCProfile( + enc: *mut JxlEncoder, + icc_profile: *const u8, + size: usize, + ) -> JxlEncoderStatus; + + /// Initializes a [`JxlBasicInfo`] struct to default values. + /// For forwards-compatibility, this function has to be called before values + /// are assigned to the struct fields. + /// The default values correspond to an 8-bit RGB image, no alpha or any + /// other extra channels. + /// + /// # Parameters + /// - `info`: global image metadata. Object owned by the caller. + pub fn JxlEncoderInitBasicInfo(info: *mut JxlBasicInfo); + + /// Initializes a [`JxlFrameHeader`] struct to default values. + /// For forwards-compatibility, this function has to be called before values + /// are assigned to the struct fields. + /// The default values correspond to a frame with no animation duration and the + /// 'replace' blend mode. After using this function, animation duration must + /// be set, and for composite still, blend settings must be set. + /// + /// # Parameters + /// - `frame_header`: frame metadata. Object owned by the caller. + pub fn JxlEncoderInitFrameHeader(frame_header: *mut JxlFrameHeader); + + /// Initializes a [`JxlBlendInfo`] struct to default values. + /// For forwards-compatibility, this function has to be called before values + /// are assigned to the struct fields. + /// + /// # Parameters + /// - `blend_info`: blending info. Object owned by the caller. + pub fn JxlEncoderInitBlendInfo(blend_info: *mut JxlBlendInfo); + + /// Sets the global metadata of the image encoded by this encoder. + /// + /// If the [`JxlBasicInfo`] contains information of extra channels beyond an + /// alpha channel, then [`JxlEncoderSetExtraChannelInfo`] must be called between + /// [`JxlEncoderSetBasicInfo`] and [`JxlEncoderAddImageFrame`]. In order to + /// indicate extra channels, the value of `info.num_extra_channels` should be set + /// to the number of extra channels, also counting the alpha channel if present. + /// + /// # Parameters + /// - `enc`: encoder object. + /// - `info`: global image metadata. Object owned by the caller and its + /// contents are copied internally. + /// + /// # Returns + /// - [`JxlEncoderStatus::Success`] if the operation was successful. + /// - [`JxlEncoderStatus::Error`] otherwise. + pub fn JxlEncoderSetBasicInfo( + enc: *mut JxlEncoder, + info: *const JxlBasicInfo, + ) -> JxlEncoderStatus; + + /// Sets the upsampling method the decoder will use in case there are frames + /// with [`JxlEncoderFrameSettingsSetOption`] set. This is useful in combination + /// with the [`JxlEncoderFrameSettingsSetOption`] option, to control + /// the type of upsampling that will be used. + /// + /// # Parameters + /// - `enc`: encoder object. + /// - `factor`: upsampling factor to configure (1, 2, 4 or 8; for 1 this + /// function has no effect at all) + /// - `mode`: upsampling mode to use for this upsampling: + /// - `-1`: default (good for photographic images, no signaling overhead) + /// - `0`: nearest neighbor (good for pixel art) + /// - `1`: 'pixel dots' (same as NN for 2x, diamond-shaped 'pixel dots' for 4x/8x) + /// + /// # Returns + /// - [`JxlEncoderStatus::Success`] if the operation was successful, + /// - [`JxlEncoderStatus::Error`] otherwise + pub fn JxlEncoderSetUpsamplingMode( + enc: *mut JxlEncoder, + factor: i64, + mode: i64, + ) -> JxlEncoderStatus; + + /// Initializes a [`JxlExtraChannelInfo`] struct to default values. + /// For forwards-compatibility, this function has to be called before values + /// are assigned to the struct fields. + /// The default values correspond to an 8-bit channel of the provided type. + /// + /// # Parameters + /// - `channel_type`: type of the extra channel. + /// - `info`: global extra channel metadata. Object owned by the caller and its + /// contents are copied internally. + pub fn JxlEncoderInitExtraChannelInfo( + channel_type: JxlExtraChannelType, + info: *mut JxlExtraChannelInfo, + ); + + /// Sets information for the extra channel at the given index. The index + /// must be smaller than `num_extra_channels` in the associated [`JxlBasicInfo`]. + /// + /// # Parameters + /// - `enc`: encoder object. + /// - `index`: index of the extra channel to set. + /// - `info`: global extra channel metadata. Object owned by the caller and its + /// contents are copied internally. + /// + /// # Returns + /// - [`JxlEncoderStatus::Success`] on success. + /// - [`JxlEncoderStatus::Error`] on error. + pub fn JxlEncoderSetExtraChannelInfo( + enc: *mut JxlEncoder, + index: usize, + info: *const JxlExtraChannelInfo, + ) -> JxlEncoderStatus; + + /// Sets the name for the extra channel at the given index in UTF-8. The index + /// must be smaller than the `num_extra_channels` in the associated [`JxlBasicInfo`]. + /// + /// TODO: remove size parameter for consistency with [`JxlEncoderSetFrameName`] + /// + /// # Parameters + /// - `enc`: encoder object. + /// - `index`: index of the extra channel to set. + /// - `name`: buffer with the name of the extra channel. + /// - `size`: size of the name buffer in bytes, not counting the terminating + /// character. + /// + /// # Returns + /// - [`JxlEncoderStatus::Success`] on success. + /// - [`JxlEncoderStatus::Error`] on error. + pub fn JxlEncoderSetExtraChannelName( + enc: *mut JxlEncoder, + index: usize, + name: *const u8, + size: usize, + ) -> JxlEncoderStatus; + + /// Sets a frame-specific option of integer type to the encoder options. + /// The [`FrameSetting`] argument determines which option is set. + /// + /// # Parameters + /// - `frame_settings`: set of options and metadata for this frame. Also + /// includes reference to the encoder object. + /// - `option`: ID of the option to set. + /// - `value`: Integer value to set for this option. + /// + /// # Returns + /// - [`JxlEncoderStatus::Success`] if the operation was successful. + /// - [`JxlEncoderStatus::Error`] in case of an error, such as invalid or unknown option id, or + /// invalid integer value for the given option. If an error is returned, the + /// state of the [`JxlEncoderFrameSettings`] object is still valid and is the same as before + /// this function was called. + pub fn JxlEncoderFrameSettingsSetOption( + frame_settings: *mut JxlEncoderFrameSettings, + option: JxlEncoderFrameSettingId, + value: i64, + ) -> JxlEncoderStatus; + + /// Sets a frame-specific option of float type to the encoder options. + /// The [`FrameSetting`] argument determines which option is set. + /// + /// # Parameters + /// - `frame_settings`: set of options and metadata for this frame. Also + /// includes reference to the encoder object. + /// - `option`: ID of the option to set. + /// - `value`: Float value to set for this option. + /// + /// # Returns + /// - [`JxlEncoderStatus::Success`] if the operation was successful. + /// - [`JxlEncoderStatus::Error`] in case of an error, such as invalid or unknown option id, or + /// invalid float value for the given option. If an error is returned, the + /// state of the [`JxlEncoderFrameSettings`] object is still valid and is the same as before + /// this function was called. + pub fn JxlEncoderFrameSettingsSetFloatOption( + frame_settings: *mut JxlEncoderFrameSettings, + option: JxlEncoderFrameSettingId, + value: f32, + ) -> JxlEncoderStatus; + + /// Forces the encoder to use the box-based container format (BMFF) even + /// when not necessary. + /// + /// When using [`JxlEncoderUseBoxes`], [`JxlEncoderStoreJPEGMetadata`] or + /// [`JxlEncoderSetCodestreamLevel`] with level 10, the encoder will automatically + /// also use the container format, it is not necessary to use + /// [`JxlEncoderUseContainer`] for those use cases. + /// + /// By default this setting is disabled. + /// + /// This setting can only be set at the beginning, before encoding starts. + /// + /// # Parameters + /// - `enc`: encoder object. + /// - `use_container`: true if the encoder should always output the JPEG XL + /// container format, false to only output it when necessary. + /// + /// # Returns + /// - [`JxlEncoderStatus::Success`] if the operation was successful. + /// - [`JxlEncoderStatus::Error`] otherwise. + pub fn JxlEncoderUseContainer(enc: *mut JxlEncoder, use_container: bool) -> JxlEncoderStatus; + + /// Configure the encoder to store JPEG reconstruction metadata in the JPEG XL + /// container. + /// + /// If this is set to true and a single JPEG frame is added, it will be + /// possible to losslessly reconstruct the JPEG codestream. + /// + /// This setting can only be set at the beginning, before encoding starts. + /// + /// # Parameters + /// - `enc`: encoder object. + /// - `store_jpeg_metadata`: true if the encoder should store JPEG metadata. + /// + /// # Returns + /// - [`JxlEncoderStatus::Success`] if the operation was successful. + /// - [`JxlEncoderStatus::Error`] otherwise. + pub fn JxlEncoderStoreJPEGMetadata( + enc: *mut JxlEncoder, + store_jpeg_metadata: bool, + ) -> JxlEncoderStatus; + + /// Sets the feature level of the JPEG XL codestream. Valid values are 5 and + /// 10, or -1 (to choose automatically). Using the minimum required level, or + /// level 5 in most cases, is recommended for compatibility with all decoders. + /// + /// Level 5: for end-user image delivery, this level is the most widely + /// supported level by image decoders and the recommended level to use unless a + /// level 10 feature is absolutely necessary. Supports a maximum resolution + /// 268435456 pixels total with a maximum width or height of 262144 pixels, + /// maximum 16-bit color channel depth, maximum 120 frames per second for + /// animation, maximum ICC color profile size of 4 MiB, it allows all color + /// models and extra channel types except CMYK and the [`JxlExtraChannelType::Black`] + /// extra channel, and a maximum of 4 extra channels in addition to the 3 color + /// channels. It also sets boundaries to certain internally used coding tools. + /// + /// Level 10: this level removes or increases the bounds of most of the level + /// 5 limitations, allows CMYK color and up to 32 bits per color channel, but + /// may be less widely supported. + /// + /// The default value is -1. This means the encoder will automatically choose + /// between level 5 and level 10 based on what information is inside the [`JxlBasicInfo`] + /// structure. Do note that some level 10 features, particularly those used by animated + /// JPEG XL codestreams, might require level 10, even though the [`JxlBasicInfo`] only + /// suggests level 5. In this case, the level must be explicitly set to 10, otherwise + /// the encoder will return an error. The encoder will restrict internal encoding choices + /// to those compatible with the level setting. + /// + /// This setting can only be set at the beginning, before encoding starts. + /// + /// # Parameters + /// - `enc`: encoder object. + /// - `level`: the level value to set, must be -1, 5, or 10. + /// + /// # Returns + /// - [`JxlEncoderStatus::Success`] if the operation was successful. + /// - [`JxlEncoderStatus::Error`] otherwise. + pub fn JxlEncoderSetCodestreamLevel(enc: *mut JxlEncoder, level: i32) -> JxlEncoderStatus; + + /// Returns the codestream level required to support the currently configured + /// settings and basic info. This function can only be used at the beginning, + /// before encoding starts, but after setting basic info. + /// + /// This does not support per-frame settings, only global configuration, such as + /// the image dimensions, that are known at the time of writing the header of + /// the JPEG XL file. + /// + /// If this returns 5, nothing needs to be done and the codestream can be + /// compatible with any decoder. If this returns 10, [`JxlEncoderSetCodestreamLevel`] + /// has to be used to set the codestream level to 10, or the encoder can be configured + /// differently to allow using the more compatible level 5. + /// + /// # Parameters + /// - `enc`: encoder object. + /// + /// # Returns + /// - `-1`: if no level can support the configuration (e.g. image dimensions + /// larger than even level 10 supports), + /// - `5`: if level 5 is supported, + /// - `10`: if setting the codestream level to 10 is required. + pub fn JxlEncoderGetRequiredCodestreamLevel(enc: *mut JxlEncoder) -> i32; + + /// Enables lossless encoding. + /// + /// This is not an option like the others on itself, but rather while enabled it + /// overrides a set of existing options (such as distance, modular mode and + /// color transform) that enables bit-for-bit lossless encoding. + /// + /// When disabled, those options are not overridden, but since those options + /// could still have been manually set to a combination that operates losslessly, + /// using this function with lossless set to [`JxlBool::False`] does not + /// guarantee lossy encoding, though the default set of options is lossy. + /// + /// # Parameters + /// - `frame_settings`: set of options and metadata for this frame. Also + /// includes reference to the encoder object. + /// - `lossless`: whether to override options for lossless mode + /// + /// # Returns + /// - [`JxlEncoderStatus::Success`] if the operation was successful, [`JxlEncoderStatus::Error`] otherwise. + pub fn JxlEncoderSetFrameLossless( + frame_settings: *mut JxlEncoderFrameSettings, + lossless: bool, + ) -> JxlEncoderStatus; + + /// Sets the distance level for lossy compression: target max butteraugli + /// distance, lower = higher quality. Range: 0 .. 25. + /// 0.0 = mathematically lossless (however, use [`JxlEncoderSetFrameLossless`] + /// instead to use true lossless, as setting distance to 0 alone is not the only + /// requirement). 1.0 = visually lossless. Recommended range: 0.5 .. 3.0. Default + /// value: 1.0. + /// + /// # Parameters + /// - `frame_settings`: set of options and metadata for this frame. Also + /// includes reference to the encoder object. + /// - `distance`: the distance value to set. + /// + /// # Returns + /// - [`JxlEncoderStatus::Success`] if the operation was successful, [`JxlEncoderStatus::Error`] otherwise. + pub fn JxlEncoderSetFrameDistance( + options: *mut JxlEncoderFrameSettings, + distance: f32, + ) -> JxlEncoderStatus; + + /// Sets the distance level for lossy compression of extra channels. + /// The distance is as in [`JxlEncoderSetFrameDistance`] (lower = higher + /// quality). If not set, or if set to the special value -1, the distance that + /// was set with [`JxlEncoderSetFrameDistance`] will be used. + /// + /// # Parameters + /// - `frame_settings`: set of options and metadata for this frame. Also + /// includes reference to the encoder object. + /// - `index`: index of the extra channel to set a distance value for. + /// - `distance`: the distance value to set. + /// + /// # Returns + /// - [`JxlEncoderStatus::Success`] if the operation was successful, [`JxlEncoderStatus::Error`] otherwise. + pub fn JxlEncoderSetExtraChannelDistance( + frame_settings: *mut JxlEncoderFrameSettings, + index: usize, + distance: f32, + ) -> JxlEncoderStatus; + + /// Maps JPEG-style quality factor to distance. + /// + /// This function takes in input a JPEG-style quality factor `quality` and + /// produces as output a `distance` value suitable to be used with + /// [`JxlEncoderSetFrameDistance`] and [`JxlEncoderSetExtraChannelDistance`]. + /// + /// The `distance` value influences the level of compression, with lower values + /// indicating higher quality: + /// - 0.0 implies lossless compression (however, note that calling + /// [`JxlEncoderSetFrameLossless`] is required). + /// - 1.0 represents a visually lossy compression, which is also the default + /// setting. + /// + /// The `quality` parameter, ranging up to 100, is inversely related to + /// `distance`: + /// - A `quality` of 100.0 maps to a `distance` of 0.0 (lossless). + /// - A `quality` of 90.0 corresponds to a `distance` of 1.0. + /// + /// Recommended Range: + /// - `distance`: 0.5 to 3.0. + /// - corresponding `quality`: approximately 96 to 68. + /// + /// Allowed Range: + /// - `distance`: 0.0 to 25.0. + /// - corresponding `quality`: 100.0 to 0.0. + /// + /// Note: the `quality` parameter has no consistent psychovisual meaning + /// across different codecs and libraries. Using the mapping defined by + /// [`JxlEncoderDistanceFromQuality`] will result in a visual quality roughly + /// equivalent to what would be obtained with `libjpeg-turbo` with the same + /// `quality` parameter, but that is by no means guaranteed; do not assume that + /// the same quality value will result in similar file sizes and image quality + /// across different codecs. + pub fn JxlEncoderDistanceFromQuality(quality: f32) -> f32; + + /// Create a new set of encoder options, with all values initially copied from + /// the `source` options, or set to default if `source` is `NULL`. + /// + /// The returned pointer is an opaque struct tied to the encoder and it will be + /// deallocated by the encoder when [`JxlEncoderDestroy`] is called. For + /// functions taking both a [`JxlEncoder`] and a [`JxlEncoderFrameSettings`], + /// only [`JxlEncoderFrameSettings`] created with this function for the same + /// encoder instance can be used. + /// + /// # Parameters + /// - `enc`: encoder object. + /// - `source`: source options to copy initial values from, or `NULL` to get + /// defaults initialized to defaults. + /// + /// # Returns + /// The opaque struct pointer identifying a new set of encoder options. + pub fn JxlEncoderFrameSettingsCreate( + enc: *mut JxlEncoder, + source: *const JxlEncoderFrameSettings, + ) -> *mut JxlEncoderFrameSettings; + + /// Sets a color encoding to be sRGB. + /// + /// # Parameters + /// - `color_encoding`: color encoding instance. + /// - `is_gray`: whether the color encoding should be gray scale or color. + pub fn JxlColorEncodingSetToSRGB(color_encoding: *mut JxlColorEncoding, is_gray: bool); + + /// Sets a color encoding to be linear sRGB. + /// + /// # Parameters + /// - `color_encoding`: [color encoding instance](JxlColorEncoding). + /// - `is_gray`: whether the color encoding should be gray scale or color. + pub fn JxlColorEncodingSetToLinearSRGB(color_encoding: *mut JxlColorEncoding, is_gray: bool); + + /// Enables usage of expert options. + /// + /// At the moment, the only expert option is setting an effort value of 11, + /// which gives the best compression for pixel-lossless modes but is very slow. + /// + /// # Parameters + /// - `enc`: encoder object. + pub fn JxlEncoderAllowExpertOptions(enc: *mut JxlEncoder); + + /// Sets the given debug image callback that will be used by the encoder to + /// output various debug images during encoding. + /// + /// This only has any effect if the encoder was compiled with the appropriate + /// debug build flags. + /// + /// # Parameters + /// - `frame_settings`: set of options and metadata for this frame. Also + /// includes reference to the encoder object. + /// - `callback`: used to return the debug image. + /// - `opaque`: user supplied parameter to the image callback. + pub fn JxlEncoderSetDebugImageCallback( + frame_settings: *mut JxlEncoderFrameSettings, + callback: JxlDebugImageCallback, + opaque: *mut c_void, + ); + + /// Sets the given stats object for gathering various statistics during encoding. + /// + /// This only has any effect if the encoder was compiled with the appropriate + /// debug build flags. + /// + /// # Parameters + /// - `frame_settings`: set of options and metadata for this frame. Also + /// includes reference to the encoder object. + /// - `stats`: object that can be used to query the gathered stats (created + /// by [`JxlEncoderStatsCreate`]) + pub fn JxlEncoderCollectStats( + frame_settings: *mut JxlEncoderFrameSettings, + stats: *mut JxlEncoderStats, + ); +} diff --git a/jpegxl-sys/src/encoder/stats.rs b/jpegxl-sys/src/encoder/stats.rs new file mode 100644 index 0000000..4ee94dc --- /dev/null +++ b/jpegxl-sys/src/encoder/stats.rs @@ -0,0 +1,96 @@ +/* +This file is part of jpegxl-sys. + +jpegxl-sys is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +jpegxl-sys is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with jpegxl-sys. If not, see . +*/ + +//! API to collect various statistics from JXL encoder. + +#[cfg(doc)] +use crate::encoder::encode::JxlEncoderCollectStats; + +/// Opaque structure that holds the encoder statistics. +/// +/// Allocated and initialized with [`JxlEncoderStatsCreate`]. +/// Cleaned up and deallocated with [`JxlEncoderStatsDestroy`]. +#[repr(C)] +pub struct JxlEncoderStats { + _unused: [u8; 0], +} + +extern "C" { + /// Creates an instance of [`JxlEncoderStats`] and initializes it. + /// + /// # Returns + /// A pointer to the initialized [`JxlEncoderStats`] instance. + pub fn JxlEncoderStatsCreate() -> *mut JxlEncoderStats; + + /// Deinitializes and frees [`JxlEncoderStats`] instance. + /// + /// # Parameters + /// - `stats`: Instance to be cleaned up and deallocated. No-op if `stats` is + /// a null pointer. + pub fn JxlEncoderStatsDestroy(stats: *mut JxlEncoderStats); + + /// Returns the value of the statistics corresponding to the given key. + /// + /// # Parameters + /// - `stats`: Object that was passed to the encoder with a + /// [`JxlEncoderCollectStats`] function. + /// - `key`: The particular statistics to query. + /// + /// # Returns + /// The value of the statistics. + pub fn JxlEncoderStatsGet(stats: *const JxlEncoderStats, key: JxlEncoderStatsKey) -> usize; + + /** Updates the values of the given stats object with that of an other. + * + * @param stats object whose values will be updated (usually added together) + * @param other stats object whose values will be merged with stats + */ + pub fn JxlEncoderStatsMerge(stats: *mut JxlEncoderStats, other: *const JxlEncoderStats); +} + +/// Data type for querying [`JxlEncoderStats`] object +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum JxlEncoderStatsKey { + HeaderBits, + TocBits, + DictionaryBits, + SplinesBits, + NoiseBits, + QuantBits, + ModularTreeBits, + ModularGlobalBits, + DcBits, + ModularDcGroupBits, + ControlFieldsBits, + CoefOrderBits, + AcHistogramBits, + AcBits, + ModularAcGroupBits, + NumSmallBlocks, + NumDct4x8Blocks, + NumAfvBlocks, + NumDct8Blocks, + NumDct8x32Blocks, + NumDct16Blocks, + NumDct16x32Blocks, + NumDct32Blocks, + NumDct32x64Blocks, + NumDct64Blocks, + NumButteraugliIters, + NumStats, +} diff --git a/jpegxl-sys/src/metadata.rs b/jpegxl-sys/src/metadata.rs new file mode 100644 index 0000000..057597e --- /dev/null +++ b/jpegxl-sys/src/metadata.rs @@ -0,0 +1,22 @@ +/* +This file is part of jpegxl-sys. + +jpegxl-sys is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +jpegxl-sys is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with jpegxl-sys. If not, see . +*/ + +//! `jxl_metadata`: JPEG XL metadata structures. + +pub mod codestream_header; +pub mod compressed_icc; +pub mod gain_map; diff --git a/jpegxl-sys/src/metadata/codestream_header.rs b/jpegxl-sys/src/metadata/codestream_header.rs new file mode 100644 index 0000000..9219b95 --- /dev/null +++ b/jpegxl-sys/src/metadata/codestream_header.rs @@ -0,0 +1,388 @@ +/* +This file is part of jpegxl-sys. + +jpegxl-sys is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +jpegxl-sys is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with jpegxl-sys. If not, see . +*/ + +//! Definitions of structs and enums for the metadata from the JPEG XL +//! codestream headers (signature, metadata, preview dimensions, ...), excluding +//! color encoding which is in [`crate::color::color_encoding`]. + +use crate::common::types::JxlBool; + +#[cfg(doc)] +use crate::{ + color::color_encoding::{JxlColorEncoding, JxlColorSpace}, + decode::{ + JxlColorProfileTarget, JxlDecoderGetExtraChannelBlendInfo, JxlDecoderGetExtraChannelInfo, + }, + encoder::encode::{JxlEncoderCloseFrames, JxlEncoderSetFrameName}, +}; + +/// Image orientation metadata. +/// +/// Values 1..8 match the EXIF definitions. +/// The name indicates the operation to perform to transform from the encoded +/// image to the display image. +#[repr(C)] +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +pub enum JxlOrientation { + Identity = 1, + FlipHorizontal = 2, + Rotate180 = 3, + FlipVertical = 4, + Transpose = 5, + Rotate90Cw = 6, + AntiTranspose = 7, + Rotate90Ccw = 8, +} + +/// Given type of an extra channel. +#[repr(C)] +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +pub enum JxlExtraChannelType { + Alpha, + Depth, + SpotColor, + SelectionMask, + Black, + Cfa, + Thermal, + Reserved0, + Reserved1, + Reserved2, + Reserved3, + Reserved4, + Reserved5, + Reserved6, + Reserved7, + Unknown, + Optional, +} + +/// The codestream preview header +#[repr(C)] +#[derive(Debug, Clone)] +pub struct JxlPreviewHeader { + /// Preview width in pixels + pub xsize: u32, + /// Preview height in pixels + pub ysize: u32, +} + +/// The codestream animation header, optionally present in the beginning of +/// the codestream, and if it is it applies to all animation frames, unlike +/// [`JxlFrameHeader`] which applies to an individual frame. +#[repr(C)] +#[derive(Debug, Clone)] +pub struct JxlAnimationHeader { + /// Numerator of ticks per second of a single animation frame time unit + pub tps_numerator: u32, + + /// Denominator of ticks per second of a single animation frame time unit + pub tps_denominator: u32, + + /// Amount of animation loops, or 0 to repeat infinitely + pub num_loops: u32, + + /// Whether animation time codes are present at animation frames in the + /// codestream + pub have_timecodes: JxlBool, +} + +/// Basic image information. This information is available from the file +/// signature and first part of the codestream header. +#[repr(C)] +#[derive(Debug, Clone)] +pub struct JxlBasicInfo { + /// Whether the codestream is embedded in the container format. If true, + /// metadata information and extensions may be available in addition to the + /// codestream. + pub have_container: JxlBool, + + /// Width of the image in pixels, before applying orientation. + pub xsize: u32, + + /// Height of the image in pixels, before applying orientation. + pub ysize: u32, + + /// Original image color channel bit depth. + pub bits_per_sample: u32, + + /// Original image color channel floating point exponent bits, or 0 if they + /// are unsigned integer. For example, if the original data is half-precision + /// (binary16) floating point, `bits_per_sample` is 16 and + /// `exponent_bits_per_sample` is 5, and so on for other floating point + /// precisions. + pub exponent_bits_per_sample: u32, + + /// Upper bound on the intensity level present in the image in nits. For + /// unsigned integer pixel encodings, this is the brightness of the largest + /// representable value. The image does not necessarily contain a pixel + /// actually this bright. An encoder is allowed to set 255 for SDR images + /// without computing a histogram. + /// Leaving this set to its default of 0 lets libjxl choose a sensible default + /// value based on the color encoding. + pub intensity_target: f32, + + /// Lower bound on the intensity level present in the image. This may be + /// loose, i.e. lower than the actual darkest pixel. When tone mapping, a + /// decoder will map `[min_nits, intensity_target]` to the display range. + pub min_nits: f32, + + /// See the description of [`Self::linear_below`]. + pub relative_to_max_display: JxlBool, + + /// The tone mapping will leave unchanged (linear mapping) any pixels whose + /// brightness is strictly below this. The interpretation depends on + /// `relative_to_max_display`. If true, this is a ratio \[0, 1\] of the maximum + /// display brightness \[nits\], otherwise an absolute brightness \[nits\]. + pub linear_below: f32, + + /// Whether the data in the codestream is encoded in the original color + /// profile that is attached to the codestream metadata header, or is + /// encoded in an internally supported absolute color space (which the decoder + /// can always convert to linear or non-linear sRGB or to XYB). If the original + /// profile is used, the decoder outputs pixel data in the color space matching + /// that profile, but doesn't convert it to any other color space. If the + /// original profile is not used, the decoder only outputs the data as sRGB + /// (linear if outputting to floating point, nonlinear with standard sRGB + /// transfer function if outputting to unsigned integers) but will not convert + /// it to to the original color profile. The decoder also does not convert to + /// the target display color profile. To convert the pixel data produced by + /// the decoder to the original color profile, one of the `JxlDecoderGetColor*` + /// functions needs to be called with + /// [`JxlColorProfileTarget::Data`] to get the color profile of the decoder + /// output, and then an external CMS can be used for conversion. Note that for + /// lossy compression, this should be set to false for most use cases, and if + /// needed, the image should be converted to the original color profile after + /// decoding, as described above. + pub uses_original_profile: JxlBool, + + /// Indicates a preview image exists near the beginning of the codestream. + /// The preview itself or its dimensions are not included in the basic info. + pub have_preview: JxlBool, + + /// Indicates animation frames exist in the codestream. The animation + /// information is not included in the basic info. + pub have_animation: JxlBool, + + /// Image orientation, value 1-8 matching the values used by JEITA CP-3451C + /// (Exif version 2.3). + pub orientation: JxlOrientation, + + /// Number of color channels encoded in the image, this is either 1 for + /// grayscale data, or 3 for colored data. This count does not include + /// the alpha channel or other extra channels. To check presence of an alpha + /// channel, such as in the case of RGBA color, check `alpha_bits != 0`. + /// If and only if this is `1`, the [`JxlColorSpace`] in the [`JxlColorEncoding`] is + /// [`JxlColorSpace::Gray`]. + pub num_color_channels: u32, + + /// Number of additional image channels. This includes the main alpha channel, + /// but can also include additional channels such as depth, additional alpha + /// channels, spot colors, and so on. Information about the extra channels + /// can be queried with [`JxlDecoderGetExtraChannelInfo`]. The main alpha + /// channel, if it exists, also has its information available in the + /// `alpha_bits`, `alpha_exponent_bits` and `alpha_premultiplied` fields in this + /// [`JxlBasicInfo`]. + pub num_extra_channels: u32, + + /// Bit depth of the encoded alpha channel, or 0 if there is no alpha channel. + /// If present, matches the `alpha_bits` value of the [`JxlExtraChannelInfo`] + /// associated with this alpha channel. + pub alpha_bits: u32, + + /// Alpha channel floating point exponent bits, or 0 if they are unsigned. If + /// present, matches the `alpha_bits` value of the [`JxlExtraChannelInfo`] associated + /// with this alpha channel. integer. + pub alpha_exponent_bits: u32, + + /// Whether the alpha channel is premultiplied. Only used if there is a main + /// alpha channel. Matches the `alpha_premultiplied` value of the + /// [`JxlExtraChannelInfo`] associated with this alpha channel. + pub alpha_premultiplied: JxlBool, + + /// Dimensions of encoded preview image, only used if `have_preview` is + /// [`JxlBool::True`]. + pub preview: JxlPreviewHeader, + + /// Animation header with global animation properties for all frames, only + /// used if `have_animation` is [`JxlBool::True`]. + pub animation: JxlAnimationHeader, + + /// Intrinsic width of the image. + /// The intrinsic size can be different from the actual size in pixels + /// (as given by xsize and ysize) and it denotes the recommended dimensions + /// for displaying the image, i.e. applications are advised to resample the + /// decoded image to the intrinsic dimensions. + pub intrinsic_xsize: u32, + + /// Intrinsic height of the image. + /// The intrinsic size can be different from the actual size in pixels + /// (as given by xsize and ysize) and it denotes the recommended dimensions + /// for displaying the image, i.e. applications are advised to resample the + /// decoded image to the intrinsic dimensions. + pub intrinsic_ysize: u32, + + /// Padding for forwards-compatibility, in case more fields are exposed + /// in a future version of the library. + _padding: [u8; 100], +} + +/// Information for a single extra channel. +#[repr(C)] +#[derive(Debug, Clone)] +pub struct JxlExtraChannelInfo { + /// Given type of an extra channel. + pub r#type: JxlExtraChannelType, + + /// Total bits per sample for this channel. + pub bits_per_sample: u32, + + /// Floating point exponent bits per channel, or 0 if they are unsigned + /// integer. + pub exponent_bits_per_sample: u32, + + /// The exponent the channel is downsampled by on each axis. + /// TODO(lode): expand this comment to match the JPEG XL specification, + /// specify how to upscale, how to round the size computation, and to which + /// extra channels this field applies. + pub dim_shift: u32, + + /// Length of the extra channel name in bytes, or 0 if no name. + /// Excludes null termination character. + pub name_length: u32, + + /// Whether alpha channel uses premultiplied alpha. Only applicable if + /// type is [`JxlExtraChannelType::Alpha`]. + pub alpha_premultiplied: JxlBool, + + /// Spot color of the current spot channel in linear RGBA. Only applicable if + /// type is [`JxlExtraChannelType::SpotColor`]. + pub spot_color: [f32; 4], + + /// Only applicable if type is [`JxlExtraChannelType::Cfa`]. + /// TODO(lode): add comment about the meaning of this field. + pub cfa_channel: u32, +} +/// Extensions in the codestream header. +#[repr(C)] +#[derive(Debug, Clone)] +pub struct JxlHeaderExtensions { + /// Extension bits. + pub extensions: u64, +} +/// Frame blend modes. +/// When decoding, if coalescing is enabled (default), this can be ignored. +#[repr(C)] +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +pub enum JxlBlendMode { + Replace = 0, + Add = 1, + Blend = 2, + MULADD = 3, + MUL = 4, +} + +/// The information about blending the color channels or a single extra channel. +/// When decoding, if coalescing is enabled (default), this can be ignored and +/// the blend mode is considered to be [`JxlBlendMode::Replace`]. +/// When encoding, these settings apply to the pixel data given to the encoder. +#[repr(C)] +#[derive(Debug, Clone)] +pub struct JxlBlendInfo { + /// Blend mode. + pub blendmode: JxlBlendMode, + /// Reference frame ID to use as the 'bottom' layer (0-3). + pub source: u32, + /// Which extra channel to use as the 'alpha' channel for blend modes + /// [`JxlBlendMode::Blend`] and [`JxlBlendMode::MULADD`]. + pub alpha: u32, + /// Clamp values to \[0,1\] for the purpose of blending. + pub clamp: JxlBool, +} + +/// The information about layers. +/// When decoding, if coalescing is enabled (default), this can be ignored. +/// When encoding, these settings apply to the pixel data given to the encoder, +/// the encoder could choose an internal representation that differs. +#[repr(C)] +#[derive(Debug, Clone)] +pub struct JxlLayerInfo { + /// Whether cropping is applied for this frame. When decoding, if false, + /// [`Self::crop_x0`] and [`Self::crop_y0`] are set to zero, and [`Self::xsize`] and [`Self::ysize`] to the main + /// image dimensions. When encoding and this is false, those fields are + /// ignored. When decoding, if coalescing is enabled (default), this is always + /// false, regardless of the internal encoding in the JPEG XL codestream. + pub have_crop: JxlBool, + + /// Horizontal offset of the frame (can be negative). + pub crop_x0: i32, + + /// Vertical offset of the frame (can be negative). + pub crop_y0: i32, + + /// Width of the frame (number of columns). + pub xsize: u32, + + /// Height of the frame (number of rows). + pub ysize: u32, + + /// The blending info for the color channels. Blending info for extra channels + /// has to be retrieved separately using [`JxlDecoderGetExtraChannelBlendInfo`]. + pub blend_info: JxlBlendInfo, + + /// After blending, save the frame as reference frame with this ID (0-3). + /// Special case: if the frame duration is nonzero, ID 0 means "will not be + /// referenced in the future". This value is not used for the last frame. + /// When encoding, ID 3 is reserved to frames that are generated internally by + /// the encoder, and should not be used by applications. + pub save_as_reference: u32, +} + +///The header of one displayed frame or non-coalesced layer. +#[repr(C)] +#[derive(Debug, Clone)] +pub struct JxlFrameHeader { + /// How long to wait after rendering in ticks. The duration in seconds of a + /// tick is given by [`JxlAnimationHeader::tps_numerator`] and [`JxlAnimationHeader::tps_denominator`] in + /// [`JxlAnimationHeader`]. + pub duration: u32, + + /// SMPTE timecode of the current frame in form 0xHHMMSSFF, or 0. The bits are + /// interpreted from most-significant to least-significant as hour, minute, + /// second, and frame. If timecode is nonzero, it is strictly larger than that + /// of a previous frame with nonzero duration. These values are only available + /// if `have_timecodes` in [`JxlAnimationHeader`] is [`JxlBool::True`]. + /// This value is only used if `have_timecodes` in [`JxlAnimationHeader`] is + /// [`JxlBool::True`]. + pub timecode: u32, + + /// Length of the frame name in bytes, or 0 if no name. + /// Excludes null termination character. This value is set by the decoder. + /// For the encoder, this value is ignored and [`JxlEncoderSetFrameName`] is + /// used instead to set the name and the length. + pub name_length: u32, + + /** Indicates this is the last animation frame. This value is set by the + * decoder to indicate no further frames follow. For the encoder, it is not + * required to set this value and it is ignored, [`JxlEncoderCloseFrames`] is + * used to indicate the last frame to the encoder instead. + */ + pub is_last: JxlBool, + /** Information about the layer in case of no coalescing. + */ + pub layer_info: JxlLayerInfo, +} diff --git a/jpegxl-sys/src/threads.rs b/jpegxl-sys/src/threads.rs new file mode 100644 index 0000000..3c248f5 --- /dev/null +++ b/jpegxl-sys/src/threads.rs @@ -0,0 +1,22 @@ +/* +This file is part of jpegxl-sys. + +jpegxl-sys is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +jpegxl-sys is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with jpegxl-sys. If not, see . +*/ + +//! `libjxl_threads`: Parallel processing support for JPEG XL. + +pub mod parallel_runner; +pub mod resizable_parallel_runner; +pub mod thread_parallel_runner; diff --git a/jpegxl-sys/src/threads/parallel_runner.rs b/jpegxl-sys/src/threads/parallel_runner.rs new file mode 100644 index 0000000..2cd5208 --- /dev/null +++ b/jpegxl-sys/src/threads/parallel_runner.rs @@ -0,0 +1,122 @@ +/* +This file is part of jpegxl-sys. + +jpegxl-sys is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +jpegxl-sys is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with jpegxl-sys. If not, see . +*/ + +//! API for running data operations in parallel in a multi-threaded environment. +//! This module allows the JPEG XL caller to define their own way of creating and +//! assigning threads. +//! +//! The [`JxlParallelRunner`] function type defines a parallel data processing +//! runner that may be implemented by the caller to allow the library to process +//! in multiple threads. The multi-threaded processing in this library only +//! requires to run the same function over each number of a range, possibly +//! running each call in a different thread. The JPEG XL caller is responsible +//! for implementing this logic using the thread APIs available in their system. +//! For convenience, a C++ implementation based on `std::thread` is provided in +//! [`super::thread_parallel_runner`] (part of the `jpegxl_threads` library). +//! +//! Thread pools usually store small numbers of heterogeneous tasks in a queue. +//! When tasks are identical or differ only by an integer input parameter, it is +//! much faster to store just one function of an integer parameter and call it +//! for each value. Conventional vector-of-tasks can be run in parallel using a +//! lambda function adapter that simply calls `task_funcs[task]`. +//! +//! If no multi-threading is desired, a `NULL` value of [`JxlParallelRunner`] +//! will use an internal implementation without multi-threading. + +use std::ffi::{c_int, c_void}; + +/// Return code used in the `JxlParallel*` functions as return value. A value +/// of [`JXL_PARALLEL_RET_SUCCESS`] means success and any other value means error. +/// The special value [`JXL_PARALLEL_RET_RUNNER_ERROR`] can be used by the runner +/// to indicate any other error. +pub type JxlParallelRetCode = c_int; + +/// Code returned by the [`JxlParallelRunInit`] function to indicate success. +pub const JXL_PARALLEL_RET_SUCCESS: JxlParallelRetCode = 0; + +/// Code returned by the [`JxlParallelRunInit`] function to indicate a general error. +pub const JXL_PARALLEL_RET_RUNNER_ERROR: JxlParallelRetCode = -1; + +/// Parallel run initialization callback. See [`JxlParallelRunner`] for details. +/// +/// This function MUST be called by the [`JxlParallelRunner`] only once, on the +/// same thread that called [`JxlParallelRunner`], before any parallel +/// execution. The purpose of this call is to provide the maximum number of +/// threads that the [`JxlParallelRunner`] will use, which can be used by JPEG XL +/// to allocate per-thread storage if needed. +/// +/// # Parameters +/// - `jpegxl_opaque`: the `jpegxl_opaque` handle provided to +/// [`JxlParallelRunner`] must be passed here. +/// - `num_threads`: the maximum number of threads. This value must be +/// positive. +/// +/// # Returns +/// - `0` if the initialization process was successful. +/// - An error code if there was an error, which should be returned by +/// [`JxlParallelRunner`]. +pub type JxlParallelRunInit = unsafe extern "C-unwind" fn( + jpegxl_opaque: *mut c_void, + num_threads: usize, +) -> JxlParallelRetCode; + +/// Parallel run data processing callback. See [`JxlParallelRunner`] for +/// details. +/// +/// This function MUST be called once for every number in the range `[start_range, +/// end_range)` (including `start_range` but not including `end_range`) passing this +/// number as the `value`. Calls for different values may be executed from +/// different threads in parallel. +/// +/// # Parameters +/// - `jpegxl_opaque`: the `jpegxl_opaque` handle provided to +/// [`JxlParallelRunner`] must be passed here. +/// - `value`: the number in the range `[start_range, end_range)` of the call. +/// - `thread_id`: the thread number where this function is being called from. +/// This must be lower than the `num_threads` value passed to +/// [`JxlParallelRunInit`]. +pub type JxlParallelRunFunction = + unsafe extern "C-unwind" fn(jpegxl_opaque: *mut c_void, value: u32, thread_id: usize); + +/// [`JxlParallelRunner`] function type. A parallel runner implementation can be +/// provided by a JPEG XL caller to allow running computations in multiple +/// threads. This function must call the initialization function [`init`](JxlParallelRunInit) in the +/// same thread that called it and then call the passed [`func`](JxlParallelRunFunction) once for every +/// number in the range `[start_range, end_range)` (including `start_range` but not +/// including `end_range`) possibly from different multiple threads in parallel. +/// +/// The [`JxlParallelRunner`] function does not need to be re-entrant. This +/// means that the same [`JxlParallelRunner`] function with the same +/// `runner_opaque` provided parameter will not be called from the library from +/// either [`init`](JxlParallelRunInit) or [`func`](JxlParallelRunFunction) in the same decoder or encoder instance. +/// However, a single decoding or encoding instance may call the provided [`JxlParallelRunner`] multiple +/// times for different parts of the decoding or encoding process. +/// +/// # Returns +/// - `0`: if the [`init`](JxlParallelRunInit) call succeeded (returned `0`) and no other error +/// occurred in the runner code. +/// - [`JXL_PARALLEL_RET_RUNNER_ERROR`]: if an error occurred in the runner +/// code, for example, setting up the threads. +/// - The return value of [`init()`](JxlParallelRunInit) if non-zero. +pub type JxlParallelRunner = unsafe extern "C-unwind" fn( + runner_opaque: *mut c_void, + jpegxl_opaque: *mut c_void, + init: JxlParallelRunInit, + func: JxlParallelRunFunction, + start_range: u32, + end_range: u32, +) -> JxlParallelRetCode; diff --git a/jpegxl-sys/src/threads/resizable_parallel_runner.rs b/jpegxl-sys/src/threads/resizable_parallel_runner.rs new file mode 100644 index 0000000..4b57ad2 --- /dev/null +++ b/jpegxl-sys/src/threads/resizable_parallel_runner.rs @@ -0,0 +1,68 @@ +/*! +This file is part of jpegxl-sys. + +jpegxl-sys is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +jpegxl-sys is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with jpegxl-sys. If not, see . +*/ + +//! Implementation using `std::thread` of a resizeable [`JxlParallelRunner`]. + +//! Implementation of [`JxlParallelRunner`] than can be used to enable +//! multithreading when using the JPEG XL library. This uses `std::thread` +//! internally and related synchronization functions. The number of threads +//! created can be changed after creation of the thread pool; the threads +//! (including the main thread) are re-used for every +//! `ResizableParallelRunner::Runner` call. Only one concurrent +//! [`JxlResizableParallelRunner`] call per instance is allowed at a time. +//! +//! This is a scalable, lower-overhead thread pool runner, especially suitable +//! for data-parallel computations in the fork-join model, where clients need to +//! know when all tasks have completed. +//! +//! Compared to the implementation in [`super::thread_parallel_runner`], this +//! implementation is tuned for execution on lower-powered systems, including +//! for example ARM CPUs with big.LITTLE computation models. + +use std::ffi::c_void; + +#[cfg(doc)] +use super::parallel_runner::JxlParallelRunner; +use super::parallel_runner::{JxlParallelRetCode, JxlParallelRunFunction, JxlParallelRunInit}; +use crate::common::memory_manager::JxlMemoryManager; + +extern "C-unwind" { + /// Parallel runner internally using `std::thread`. Use as [`JxlParallelRunner`]. + pub fn JxlResizableParallelRunner( + runner_opaque: *mut c_void, + jpegxl_opaque: *mut c_void, + init: JxlParallelRunInit, + func: JxlParallelRunFunction, + start_range: u32, + end_range: u32, + ) -> JxlParallelRetCode; + + /// Creates the runner for [`JxlResizableParallelRunner`]. Use as the opaque + /// runner. The runner will execute tasks on the calling thread until + /// [`JxlResizableParallelRunnerSetThreads`] is called. + pub fn JxlResizableParallelRunnerCreate(memory_manager: *const JxlMemoryManager) + -> *mut c_void; + + /// Changes the number of threads for [`JxlResizableParallelRunner`]. + pub fn JxlResizableParallelRunnerSetThreads(runner_opaque: *mut c_void, num_threads: usize); + + /// Suggests a number of threads to use for an image of given size. + pub fn JxlResizableParallelRunnerSuggestThreads(xsize: u64, ysize: u64) -> u32; + + /// Destroys the runner created by [`JxlResizableParallelRunnerCreate`]. + pub fn JxlResizableParallelRunnerDestroy(runner_opaque: *mut c_void); +} diff --git a/jpegxl-sys/src/threads/thread_parallel_runner.rs b/jpegxl-sys/src/threads/thread_parallel_runner.rs new file mode 100644 index 0000000..dadff93 --- /dev/null +++ b/jpegxl-sys/src/threads/thread_parallel_runner.rs @@ -0,0 +1,66 @@ +/* +This file is part of jpegxl-sys. + +jpegxl-sys is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +jpegxl-sys is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with jpegxl-sys. If not, see . +*/ + +//! Implementation using `std::thread` of a [`JxlParallelRunner`]. + +//! Implementation of [`JxlParallelRunner`] that can be used to enable +//! multithreading when using the JPEG XL library. This uses `std::thread` +//! internally and related synchronization functions. The number of threads +//! created is fixed at construction time and the threads are re-used for every +//! `ThreadParallelRunner::Runner` call. Only one concurrent +//! `JxlThreadParallelRunner` call per instance is allowed at a time. +//! +//! This is a scalable, lower-overhead thread pool runner, especially suitable +//! for data-parallel computations in the fork-join model, where clients need to +//! know when all tasks have completed. +//! +//! This thread pool can efficiently load-balance millions of tasks using an +//! atomic counter, thus avoiding per-task virtual or system calls. With 48 +//! hyperthreads and 1M tasks that add to an atomic counter, overall runtime is +//! 10-20x higher when using `std::async`, and ~200x for a queue-based thread +//! pool. + +use std::ffi::c_void; + +#[cfg(doc)] +use super::parallel_runner::JxlParallelRunner; +use super::parallel_runner::{JxlParallelRetCode, JxlParallelRunFunction, JxlParallelRunInit}; +use crate::common::memory_manager::JxlMemoryManager; + +extern "C-unwind" { + /// Parallel runner internally using `std::thread`. Use as [`JxlParallelRunner`]. + pub fn JxlThreadParallelRunner( + runner_opaque: *mut c_void, + jpegxl_opaque: *mut c_void, + init: JxlParallelRunInit, + func: JxlParallelRunFunction, + start_range: u32, + end_range: u32, + ) -> JxlParallelRetCode; + + /// Creates the runner for [`JxlThreadParallelRunner`]. Use as the opaque runner. + pub fn JxlThreadParallelRunnerCreate( + memory_manager: *const JxlMemoryManager, + num_worker_threads: usize, + ) -> *mut c_void; + + /// Destroys the runner created by [`JxlThreadParallelRunnerCreate`]. + pub fn JxlThreadParallelRunnerDestroy(runner_opaque: *mut c_void); + + /// Returns a default `num_worker_threads` value for [`JxlThreadParallelRunnerCreate`]. + pub fn JxlThreadParallelRunnerDefaultNumWorkerThreads() -> usize; +}