use super::document::{CPDF_DOCS, CPDF_RANGES};
use super::{clear_error, set_error};
use crate::cpdf::images;
use crate::ffi::Handle;
use std::ffi::{CStr, c_char, c_double, c_int};
macro_rules! get_doc_ref {
($handle:expr) => {
match CPDF_DOCS.get($handle) {
Some(arc) => arc,
None => {
set_error(1, &format!("invalid document handle: {}", $handle));
return std::ptr::null_mut();
}
}
};
}
macro_rules! get_range {
($handle:expr) => {
match CPDF_RANGES.get($handle) {
Some(arc) => arc.lock().unwrap().clone(),
None => {
set_error(1, &format!("invalid range handle: {}", $handle));
return std::ptr::null_mut();
}
}
};
($handle:expr, $ret:expr) => {
match CPDF_RANGES.get($handle) {
Some(arc) => arc.lock().unwrap().clone(),
None => {
set_error(1, &format!("invalid range handle: {}", $handle));
return $ret;
}
}
};
}
#[unsafe(no_mangle)]
pub extern "C" fn cpdf_getImageListJSON(
doc: Handle,
range_h: Handle,
len_out: *mut usize,
) -> *mut u8 {
clear_error();
let d = get_doc_ref!(doc);
let guard = d.lock().unwrap();
let r = get_range!(range_h);
match images::list_images_json(&guard, &r) {
Ok(json) => {
let bytes = json.into_bytes();
let len = bytes.len();
let ptr = unsafe {
let layout = std::alloc::Layout::from_size_align_unchecked(len, 1);
let p = std::alloc::alloc(layout);
if p.is_null() {
set_error(1, "allocation failed");
return std::ptr::null_mut();
}
std::ptr::copy_nonoverlapping(bytes.as_ptr(), p, len);
p
};
if !len_out.is_null() {
unsafe { *len_out = len };
}
ptr
}
Err(e) => {
set_error(1, &e.to_string());
std::ptr::null_mut()
}
}
}
#[unsafe(no_mangle)]
pub extern "C" fn cpdf_imageResolutionJSON(
doc: Handle,
range_h: Handle,
min_dpi: c_double,
len_out: *mut usize,
) -> *mut u8 {
clear_error();
let d = get_doc_ref!(doc);
let guard = d.lock().unwrap();
let r = get_range!(range_h);
match images::image_resolution(&guard, &r, min_dpi) {
Ok(info) => {
let json = match serde_json::to_string_pretty(&info) {
Ok(j) => j,
Err(e) => {
set_error(1, &e.to_string());
return std::ptr::null_mut();
}
};
let bytes = json.into_bytes();
let len = bytes.len();
let ptr = unsafe {
let layout = std::alloc::Layout::from_size_align_unchecked(len, 1);
let p = std::alloc::alloc(layout);
if p.is_null() {
set_error(1, "allocation failed");
return std::ptr::null_mut();
}
std::ptr::copy_nonoverlapping(bytes.as_ptr(), p, len);
p
};
if !len_out.is_null() {
unsafe { *len_out = len };
}
ptr
}
Err(e) => {
set_error(1, &e.to_string());
std::ptr::null_mut()
}
}
}
#[unsafe(no_mangle)]
pub extern "C" fn cpdf_extractImages(
doc: Handle,
range_h: Handle,
output_dir: *const c_char,
) -> c_int {
clear_error();
let d = match CPDF_DOCS.get(doc) {
Some(arc) => arc,
None => {
set_error(1, &format!("invalid document handle: {}", doc));
return 1;
}
};
let guard = d.lock().unwrap();
let r = get_range!(range_h, 1);
let dir = if output_dir.is_null() {
"."
} else {
unsafe { CStr::from_ptr(output_dir) }
.to_str()
.unwrap_or(".")
};
match images::extract_images(&guard, &r, dir) {
Ok(()) => 0,
Err(e) => {
set_error(1, &e.to_string());
1
}
}
}