use super::document::{CPDF_DOCS, CPDF_RANGES};
use super::{clear_error, set_error};
use crate::cpdf::stamps::{self, Colour, Font, Justification, Position};
use crate::ffi::Handle;
use std::ffi::{CStr, c_char, c_double, c_int};
macro_rules! get_doc_clone {
($handle:expr) => {
match CPDF_DOCS.get($handle) {
Some(arc) => arc.lock().unwrap().clone(),
None => {
set_error(1, &format!("invalid document handle: {}", $handle));
return 0;
}
}
};
}
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 0;
}
}
};
}
macro_rules! ok_or_error {
($result:expr) => {
match $result {
Ok(doc) => CPDF_DOCS.insert(doc),
Err(e) => {
set_error(1, &e.to_string());
0
}
}
};
}
fn decode_position(code: c_int, arg: c_double) -> Position {
match code {
0 => Position::TopLeft(arg),
1 => Position::Top(arg),
2 => Position::TopRight(arg),
3 => Position::Left(arg),
4 => Position::Centre,
5 => Position::Right(arg),
6 => Position::BottomLeft(arg),
7 => Position::Bottom(arg),
8 => Position::BottomRight(arg),
9 => Position::Diagonal,
10 => Position::ReverseDiagonal,
_ => Position::Centre,
}
}
fn decode_justification(code: c_int) -> Justification {
match code {
0 => Justification::Left,
1 => Justification::Centre,
2 => Justification::Right,
_ => Justification::Left,
}
}
fn cstr_to_str(ptr: *const c_char) -> &'static str {
if ptr.is_null() {
""
} else {
unsafe { CStr::from_ptr(ptr) }.to_str().unwrap_or("")
}
}
#[unsafe(no_mangle)]
pub extern "C" fn cpdf_stampOn(
over: Handle,
under: Handle,
range_h: Handle,
scale_to_fit: c_int,
) -> Handle {
clear_error();
let o = get_doc_clone!(over);
let u = get_doc_clone!(under);
let r = get_range!(range_h);
ok_or_error!(stamps::stamp_on(o, u, &r, scale_to_fit != 0))
}
#[unsafe(no_mangle)]
pub extern "C" fn cpdf_stampUnder(
under: Handle,
over: Handle,
range_h: Handle,
scale_to_fit: c_int,
) -> Handle {
clear_error();
let u = get_doc_clone!(under);
let o = get_doc_clone!(over);
let r = get_range!(range_h);
ok_or_error!(stamps::stamp_under(u, o, &r, scale_to_fit != 0))
}
#[unsafe(no_mangle)]
pub extern "C" fn cpdf_combinePages(
under: Handle,
over: Handle,
scale_to_fit: c_int,
swap: c_int,
) -> Handle {
clear_error();
let u = get_doc_clone!(under);
let o = get_doc_clone!(over);
ok_or_error!(stamps::combine_pages(u, o, scale_to_fit != 0, swap != 0))
}
#[unsafe(no_mangle)]
#[allow(clippy::too_many_arguments)]
pub extern "C" fn cpdf_addText(
doc: Handle,
range_h: Handle,
text: *const c_char,
position_code: c_int,
position_arg: c_double,
linespacing: c_double,
font_size: c_double,
font_code: c_int,
r: c_double,
g: c_double,
b: c_double,
underneath: c_int,
opacity: c_double,
justification_code: c_int,
) -> Handle {
clear_error();
let d = get_doc_clone!(doc);
let rng = get_range!(range_h);
let t = cstr_to_str(text);
let pos = decode_position(position_code, position_arg);
let font = match Font::from_code(font_code) {
Ok(f) => f,
Err(e) => {
set_error(1, &e.to_string());
return 0;
}
};
let colour = Colour::Rgb(r, g, b);
let just = decode_justification(justification_code);
ok_or_error!(stamps::add_text(
d,
&rng,
t,
&pos,
linespacing,
font_size,
&font,
&colour,
underneath != 0,
opacity,
just,
))
}
#[unsafe(no_mangle)]
#[allow(clippy::too_many_arguments)]
pub extern "C" fn cpdf_addPageNumbers(
doc: Handle,
range_h: Handle,
format: *const c_char,
position_code: c_int,
position_arg: c_double,
font_size: c_double,
font_code: c_int,
r: c_double,
g: c_double,
b: c_double,
start_value: c_int,
) -> Handle {
clear_error();
let d = get_doc_clone!(doc);
let rng = get_range!(range_h);
let fmt = cstr_to_str(format);
let pos = decode_position(position_code, position_arg);
let font = match Font::from_code(font_code) {
Ok(f) => f,
Err(e) => {
set_error(1, &e.to_string());
return 0;
}
};
let colour = Colour::Rgb(r, g, b);
ok_or_error!(stamps::add_page_numbers(
d,
&rng,
fmt,
&pos,
font_size,
&font,
&colour,
start_value.max(1) as usize,
))
}
#[unsafe(no_mangle)]
#[allow(clippy::too_many_arguments)]
pub extern "C" fn cpdf_addWatermarkText(
doc: Handle,
text: *const c_char,
font_code: c_int,
font_size: c_double,
r: c_double,
g: c_double,
b: c_double,
opacity: c_double,
angle_deg: c_double,
) -> Handle {
clear_error();
let d = get_doc_clone!(doc);
let t = cstr_to_str(text);
let font = match Font::from_code(font_code) {
Ok(f) => f,
Err(e) => {
set_error(1, &e.to_string());
return 0;
}
};
let colour = Colour::Rgb(r, g, b);
ok_or_error!(stamps::add_watermark_text(
d, t, &font, font_size, &colour, opacity, angle_deg,
))
}
#[unsafe(no_mangle)]
#[allow(clippy::too_many_arguments)]
pub extern "C" fn cpdf_addRectangle(
doc: Handle,
range_h: Handle,
x: c_double,
y: c_double,
w: c_double,
h: c_double,
r: c_double,
g: c_double,
b: c_double,
outline: c_int,
linewidth: c_double,
opacity: c_double,
) -> Handle {
clear_error();
let d = get_doc_clone!(doc);
let rng = get_range!(range_h);
let colour = Colour::Rgb(r, g, b);
ok_or_error!(stamps::add_rectangle(
d,
&rng,
x,
y,
w,
h,
&colour,
outline != 0,
linewidth,
opacity,
))
}