use super::pdf_native_conversion;
use crate::ffi::pdf_object::types::PdfObjHandle;
use crate::pdf::image::PdfImage;
use std::sync::LazyLock;
use super::{Handle, HandleStore};
pub static PDF_IMAGES: LazyLock<HandleStore<PdfImage>> = LazyLock::new(HandleStore::default);
#[unsafe(no_mangle)]
pub extern "C" fn mp_pdf_image_from_dict(
dict_ptr: PdfObjHandle,
data: *const u8,
data_len: usize,
) -> super::Handle {
if dict_ptr == 0 {
return 0;
}
let dict = match pdf_native_conversion::pdf_obj_to_dict(dict_ptr) {
Some(d) => d,
None => return 0,
};
let data_vec = if data.is_null() || data_len == 0 {
Vec::new()
} else {
unsafe { std::slice::from_raw_parts(data, data_len) }.to_vec()
};
let image = match PdfImage::from_pdf_dict(&dict, data_vec) {
Ok(img) => img,
Err(_) => return 0,
};
PDF_IMAGES.insert(image)
}
#[unsafe(no_mangle)]
pub extern "C" fn mp_pdf_image_width(img: super::Handle) -> u32 {
if img == 0 {
return 0;
}
PDF_IMAGES
.get(img)
.and_then(|arc| arc.lock().ok().map(|i| i.width))
.unwrap_or(0)
}
#[unsafe(no_mangle)]
pub extern "C" fn mp_pdf_image_height(img: super::Handle) -> u32 {
if img == 0 {
return 0;
}
PDF_IMAGES
.get(img)
.and_then(|arc| arc.lock().ok().map(|i| i.height))
.unwrap_or(0)
}
#[unsafe(no_mangle)]
pub extern "C" fn mp_pdf_image_to_rgba(
img: super::Handle,
out_buf: *mut u8,
out_len: usize,
) -> i32 {
if img == 0 || out_buf.is_null() {
return -1;
}
let rgba = match PDF_IMAGES.get(img) {
Some(arc) => match arc.lock() {
Ok(i) => match i.to_rgba() {
Ok(r) => r,
Err(_) => return -2,
},
Err(_) => return -1,
},
None => return -1,
};
let written = rgba.len().min(out_len);
if written > 0 {
unsafe { std::ptr::copy_nonoverlapping(rgba.as_ptr(), out_buf, written) };
}
written as i32
}
#[unsafe(no_mangle)]
pub extern "C" fn mp_pdf_image_free(img: super::Handle) {
if img == 0 {
return;
}
PDF_IMAGES.remove(img);
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ffi::pdf_object::{pdf_dict_puts, pdf_new_dict, pdf_new_int, pdf_new_name};
use std::ffi::CStr;
fn make_image_dict() -> PdfObjHandle {
let dict = pdf_new_dict(0, 0, 8);
pdf_dict_puts(0, dict, c"Width".as_ptr(), pdf_new_int(0, 10));
pdf_dict_puts(0, dict, c"Height".as_ptr(), pdf_new_int(0, 10));
pdf_dict_puts(0, dict, c"BitsPerComponent".as_ptr(), pdf_new_int(0, 8));
pdf_dict_puts(
0,
dict,
c"ColorSpace".as_ptr(),
pdf_new_name(0, c"DeviceRGB".as_ptr()),
);
dict
}
#[test]
fn test_mp_pdf_image_from_dict_and_free() {
let dict = make_image_dict();
let data = vec![0u8; 10 * 10 * 3];
let img = mp_pdf_image_from_dict(dict, data.as_ptr(), data.len());
assert_ne!(img, 0);
mp_pdf_image_free(img);
}
#[test]
fn test_mp_pdf_image_width_height() {
let dict = make_image_dict();
let data = vec![0u8; 300];
let img = mp_pdf_image_from_dict(dict, data.as_ptr(), data.len());
assert_ne!(img, 0);
assert_eq!(mp_pdf_image_width(img), 10);
assert_eq!(mp_pdf_image_height(img), 10);
mp_pdf_image_free(img);
}
#[test]
fn test_mp_pdf_image_to_rgba() {
let dict = make_image_dict();
let data = vec![255u8; 300];
let img = mp_pdf_image_from_dict(dict, data.as_ptr(), data.len());
assert_ne!(img, 0);
let mut rgba = vec![0u8; 400];
let n = mp_pdf_image_to_rgba(img, rgba.as_mut_ptr(), 400);
assert_eq!(n, 400);
assert_eq!(rgba[0..4], [255, 255, 255, 255]);
mp_pdf_image_free(img);
}
#[test]
fn test_mp_pdf_image_null_checks() {
assert_eq!(mp_pdf_image_from_dict(0, std::ptr::null(), 0), 0);
assert_eq!(mp_pdf_image_width(0), 0);
assert_eq!(mp_pdf_image_height(0), 0);
}
}