Source code

Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use crate::decoder::JxlApiDecoder;
use std::slice;
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum JxlDecoderStatus {
Ok = 0,
NeedMoreData = 1,
Error = 2,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Default)]
pub struct JxlBasicInfo {
pub width: u32,
pub height: u32,
pub has_alpha: bool,
pub alpha_premultiplied: bool,
pub is_animated: bool,
pub num_loops: u32,
pub valid: bool,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Default)]
pub struct JxlFrameInfo {
pub duration_ms: i32,
pub frame_duration_valid: bool,
}
#[no_mangle]
pub extern "C" fn jxl_decoder_new(metadata_only: bool, premultiply: bool) -> *mut JxlApiDecoder {
Box::into_raw(Box::new(JxlApiDecoder::new(metadata_only, premultiply)))
}
/// # Safety
/// `decoder` must be a valid pointer returned by `jxl_decoder_new` and must not
/// have been previously destroyed. After this call, `decoder` is invalid.
#[no_mangle]
pub unsafe extern "C" fn jxl_decoder_destroy(decoder: *mut JxlApiDecoder) {
if !decoder.is_null() {
// SAFETY: Caller guarantees `decoder` is a valid pointer from `jxl_decoder_new`
// and has not been destroyed. We take ownership and drop it.
let _ = unsafe { Box::from_raw(decoder) };
}
}
/// # Safety
/// - `decoder` must be a valid pointer returned by `jxl_decoder_new`.
/// - `data` must be a valid pointer to a `*const u8` pointer.
/// - `data_len` must be a valid pointer to a `usize`.
/// - `*data` must point to a valid byte slice of length `*data_len`, or be null
/// when `*data_len` is 0.
/// - If `output_buffer` is non-null, it must point to a valid writable buffer
/// of at least `output_buffer_len` bytes.
#[no_mangle]
pub unsafe extern "C" fn jxl_decoder_process_data(
decoder: *mut JxlApiDecoder,
data: *mut *const u8,
data_len: *mut usize,
output_buffer: *mut u8,
output_buffer_len: usize,
) -> JxlDecoderStatus {
debug_assert!(!decoder.is_null() && !data.is_null() && !data_len.is_null());
// SAFETY: Caller guarantees `decoder` is a valid, non-null pointer from `jxl_decoder_new`.
let decoder = unsafe { &mut *decoder };
// SAFETY: Caller guarantees `data` and `data_len` are valid pointers, and that
// `*data` points to a valid byte slice of length `*data_len` (or is null when
// `*data_len` is 0).
let mut data_slice = if unsafe { (*data).is_null() } {
&[]
} else {
unsafe { slice::from_raw_parts(*data, *data_len) }
};
let output_slice = if output_buffer.is_null() {
None
} else {
// SAFETY: Caller guarantees that when `output_buffer` is non-null, it points
// to a valid writable buffer of at least `output_buffer_len` bytes.
Some(unsafe { slice::from_raw_parts_mut(output_buffer, output_buffer_len) })
};
let result = decoder.process_data(&mut data_slice, output_slice);
// SAFETY: Caller guarantees `data` and `data_len` are valid, writable pointers.
// We update them to reflect how much data was consumed.
unsafe {
*data = data_slice.as_ptr();
*data_len = data_slice.len();
}
match result {
Ok(true) => JxlDecoderStatus::Ok,
Ok(false) => JxlDecoderStatus::NeedMoreData,
Err(_) => JxlDecoderStatus::Error,
}
}
/// # Safety
/// `decoder` must be a valid pointer returned by `jxl_decoder_new`.
#[no_mangle]
pub unsafe extern "C" fn jxl_decoder_get_basic_info(decoder: *const JxlApiDecoder) -> JxlBasicInfo {
debug_assert!(!decoder.is_null());
// SAFETY: Caller guarantees `decoder` is a valid, non-null pointer from `jxl_decoder_new`.
let decoder = unsafe { &*decoder };
let Some(info) = decoder.get_basic_info() else {
return JxlBasicInfo::default();
};
JxlBasicInfo {
width: info.width,
height: info.height,
has_alpha: info.has_alpha,
alpha_premultiplied: info.alpha_premultiplied,
is_animated: info.is_animated,
num_loops: info.num_loops,
valid: true,
}
}
/// # Safety
/// `decoder` must be a valid pointer returned by `jxl_decoder_new`.
#[no_mangle]
pub unsafe extern "C" fn jxl_decoder_get_frame_info(decoder: *const JxlApiDecoder) -> JxlFrameInfo {
debug_assert!(!decoder.is_null());
// SAFETY: Caller guarantees `decoder` is a valid, non-null pointer from `jxl_decoder_new`.
let decoder = unsafe { &*decoder };
match decoder.frame_duration {
Some(duration) => JxlFrameInfo {
duration_ms: duration.clamp(0.0, i32::MAX as f64) as i32,
frame_duration_valid: true,
},
None => JxlFrameInfo {
duration_ms: 0,
frame_duration_valid: false,
},
}
}
/// # Safety
/// `decoder` must be a valid pointer returned by `jxl_decoder_new`.
#[no_mangle]
pub unsafe extern "C" fn jxl_decoder_is_frame_ready(decoder: *const JxlApiDecoder) -> bool {
debug_assert!(!decoder.is_null());
// SAFETY: Caller guarantees `decoder` is a valid, non-null pointer from `jxl_decoder_new`.
let decoder = unsafe { &*decoder };
decoder.frame_ready
}
/// # Safety
/// `decoder` must be a valid pointer returned by `jxl_decoder_new`.
#[no_mangle]
pub unsafe extern "C" fn jxl_decoder_has_more_frames(decoder: *const JxlApiDecoder) -> bool {
debug_assert!(!decoder.is_null());
// SAFETY: Caller guarantees `decoder` is a valid, non-null pointer from `jxl_decoder_new`.
let decoder = unsafe { &*decoder };
decoder.inner.has_more_frames()
}