pub(crate) mod internal {
use crate::bindgen::{FPDF_ANNOTATION, FPDF_PAGE, FPDF_PAGEOBJECT, FS_MATRIX, FS_RECTF};
use crate::bindings::PdfiumLibraryBindings;
use crate::error::{PdfiumError, PdfiumInternalError};
use crate::page::{PdfPoints, PdfRect};
use crate::page_annotation_objects::PdfPageAnnotationObjects;
use crate::page_object::PdfPageObjectCommon;
use crate::page_objects::PdfPageObjects;
pub(crate) trait PdfPageObjectPrivate<'a>: PdfPageObjectCommon<'a> {
fn get_object_handle(&self) -> &FPDF_PAGEOBJECT;
fn get_page_handle(&self) -> &Option<FPDF_PAGE>;
fn set_page_handle(&mut self, page: FPDF_PAGE);
fn clear_page_handle(&mut self);
fn get_annotation_handle(&self) -> &Option<FPDF_ANNOTATION>;
fn set_annotation_handle(&mut self, annotation: FPDF_ANNOTATION);
fn clear_annotation_handle(&mut self);
fn bindings(&self) -> &dyn PdfiumLibraryBindings;
#[inline]
fn is_object_memory_owned_by_container(&self) -> bool {
self.get_page_handle().is_some() || self.get_annotation_handle().is_some()
}
#[inline]
fn add_object_to_page(&mut self, page_objects: &PdfPageObjects) -> Result<(), PdfiumError> {
self.add_object_to_page_handle(*page_objects.get_page_handle())
}
fn add_object_to_page_handle(&mut self, page_handle: FPDF_PAGE) -> Result<(), PdfiumError> {
self.bindings()
.FPDFPage_InsertObject(page_handle, *self.get_object_handle());
if let Some(error) = self.bindings().get_pdfium_last_error() {
Err(PdfiumError::PdfiumLibraryInternalError(error))
} else {
self.set_page_handle(page_handle);
Ok(())
}
}
fn remove_object_from_page(&mut self) -> Result<(), PdfiumError> {
if let Some(page_handle) = self.get_page_handle() {
if self.bindings().is_true(
self.bindings()
.FPDFPage_RemoveObject(*page_handle, *self.get_object_handle()),
) {
self.clear_page_handle();
Ok(())
} else {
Err(PdfiumError::PdfiumLibraryInternalError(
self.bindings()
.get_pdfium_last_error()
.unwrap_or(PdfiumInternalError::Unknown),
))
}
} else {
Err(PdfiumError::PageObjectNotAttachedToPage)
}
}
#[inline]
fn add_object_to_annotation(
&mut self,
annotation_objects: &PdfPageAnnotationObjects,
) -> Result<(), PdfiumError> {
self.add_object_to_annotation_handle(*annotation_objects.get_annotation_handle())
}
fn add_object_to_annotation_handle(
&mut self,
annotation_handle: FPDF_ANNOTATION,
) -> Result<(), PdfiumError> {
self.bindings()
.FPDFAnnot_AppendObject(annotation_handle, *self.get_object_handle());
if let Some(error) = self.bindings().get_pdfium_last_error() {
Err(PdfiumError::PdfiumLibraryInternalError(error))
} else {
self.set_annotation_handle(annotation_handle);
Ok(())
}
}
fn remove_object_from_annotation(&mut self) -> Result<(), PdfiumError> {
if let Some(annotation_handle) = self.get_annotation_handle() {
let index = {
let mut result = None;
for i in 0..self.bindings().FPDFAnnot_GetObjectCount(*annotation_handle) {
if *self.get_object_handle()
== self.bindings().FPDFAnnot_GetObject(*annotation_handle, i)
{
result = Some(i);
break;
}
}
result
};
if let Some(index) = index {
if self.bindings().is_true(
self.bindings()
.FPDFAnnot_RemoveObject(*annotation_handle, index),
) {
self.clear_page_handle();
Ok(())
} else {
Err(PdfiumError::PdfiumLibraryInternalError(
self.bindings()
.get_pdfium_last_error()
.unwrap_or(PdfiumInternalError::Unknown),
))
}
} else {
Err(PdfiumError::PageObjectNotAttachedToAnnotation)
}
} else {
Err(PdfiumError::PageObjectNotAttachedToAnnotation)
}
}
#[inline]
fn has_transparency_impl(&self) -> bool {
let bindings = self.bindings();
bindings.is_true(bindings.FPDFPageObj_HasTransparency(*self.get_object_handle()))
}
#[inline]
fn bounds_impl(&self) -> Result<PdfRect, PdfiumError> {
let mut left = 0.0;
let mut bottom = 0.0;
let mut right = 0.0;
let mut top = 0.0;
let result = self.bindings().FPDFPageObj_GetBounds(
*self.get_object_handle(),
&mut left,
&mut bottom,
&mut right,
&mut top,
);
PdfRect::from_pdfium_as_result(
result,
FS_RECTF {
left,
top,
right,
bottom,
},
self.bindings(),
)
}
#[inline]
fn transform_impl(
&self,
a: f64,
b: f64,
c: f64,
d: f64,
e: f64,
f: f64,
) -> Result<(), PdfiumError> {
self.bindings()
.FPDFPageObj_Transform(*self.get_object_handle(), a, b, c, d, e, f);
match self.bindings().get_pdfium_last_error() {
Some(err) => Err(PdfiumError::PdfiumLibraryInternalError(err)),
None => Ok(()),
}
}
fn matrix(&self) -> Result<FS_MATRIX, PdfiumError> {
let mut matrix = FS_MATRIX {
a: 0.0,
b: 0.0,
c: 0.0,
d: 0.0,
e: 0.0,
f: 0.0,
};
if self.bindings().is_true(
self.bindings()
.FPDFPageObj_GetMatrix(*self.get_object_handle(), &mut matrix),
) {
Ok(matrix)
} else {
Err(PdfiumError::PdfiumLibraryInternalError(
self.bindings()
.get_pdfium_last_error()
.unwrap_or(PdfiumInternalError::Unknown),
))
}
}
fn set_matrix(&self, matrix: FS_MATRIX) -> Result<(), PdfiumError> {
if self.bindings().is_true(
self.bindings()
.FPDFPageObj_SetMatrix(*self.get_object_handle(), &matrix),
) {
Ok(())
} else {
Err(PdfiumError::PdfiumLibraryInternalError(
self.bindings()
.get_pdfium_last_error()
.unwrap_or(PdfiumInternalError::Unknown),
))
}
}
#[inline]
fn get_horizontal_translation_impl(&self) -> PdfPoints {
self.matrix()
.map(|matrix| PdfPoints::new(matrix.e))
.unwrap_or(PdfPoints::ZERO)
}
#[inline]
fn get_vertical_translation_impl(&self) -> PdfPoints {
self.matrix()
.map(|matrix| PdfPoints::new(matrix.f))
.unwrap_or(PdfPoints::ZERO)
}
#[inline]
fn get_horizontal_scale_impl(&self) -> f64 {
self.matrix().map(|matrix| matrix.a).unwrap_or(0.0) as f64
}
#[inline]
fn get_vertical_scale_impl(&self) -> f64 {
self.matrix().map(|matrix| matrix.d).unwrap_or(0.0) as f64
}
#[inline]
fn get_x_axis_skew_radians_impl(&self) -> f32 {
self.matrix().map(|matrix| matrix.b.atan()).unwrap_or(0.0)
}
#[inline]
fn get_y_axis_skew_radians_impl(&self) -> f32 {
self.matrix().map(|matrix| matrix.c.atan()).unwrap_or(0.0)
}
#[inline]
fn get_rotation_counter_clockwise_radians_impl(&self) -> f32 {
self.matrix()
.map(|matrix| matrix.b.atan2(matrix.a))
.unwrap_or(0.0)
}
}
}
#[cfg(test)]
pub mod tests {
use crate::prelude::*;
use crate::utils::test::test_bind_to_pdfium;
#[test]
fn test_object_get_translation() -> Result<(), PdfiumError> {
let pdfium = test_bind_to_pdfium();
let document = pdfium.create_new_pdf()?;
let mut page = document
.pages()
.create_page_at_start(PdfPagePaperSize::a4())?;
let mut object = PdfPagePathObject::new_rect(
&document,
PdfRect::new_from_values(100.0, 100.0, 400.0, 400.0),
Some(PdfColor::SOLID_RED),
Some(PdfPoints::new(1.0)),
None,
)?;
object.translate(PdfPoints::new(250.0), PdfPoints::new(350.0))?;
let object = page.objects_mut().add_path_object(object)?;
assert_eq!(object.get_horizontal_translation().value, 250.0);
assert_eq!(object.get_vertical_translation().value, 350.0);
assert_eq!(object.get_horizontal_scale(), 1.0);
assert_eq!(object.get_vertical_scale(), 1.0);
assert_eq!(object.get_rotation_clockwise_degrees(), 0.0);
Ok(())
}
#[test]
fn test_object_get_scale() -> Result<(), PdfiumError> {
let pdfium = test_bind_to_pdfium();
let document = pdfium.create_new_pdf()?;
let mut page = document
.pages()
.create_page_at_start(PdfPagePaperSize::a4())?;
let mut object = PdfPagePathObject::new_rect(
&document,
PdfRect::new_from_values(100.0, 100.0, 400.0, 400.0),
Some(PdfColor::SOLID_RED),
Some(PdfPoints::new(1.0)),
None,
)?;
object.scale(1.75, 2.25)?;
let object = page.objects_mut().add_path_object(object)?;
assert_eq!(object.get_horizontal_scale(), 1.75);
assert_eq!(object.get_vertical_scale(), 2.25);
assert_eq!(object.get_horizontal_translation().value, 0.0);
assert_eq!(object.get_vertical_translation().value, 0.0);
assert_eq!(object.get_rotation_clockwise_degrees(), 0.0);
Ok(())
}
#[test]
fn test_object_get_rotation() -> Result<(), PdfiumError> {
let pdfium = test_bind_to_pdfium();
let document = pdfium.create_new_pdf()?;
let mut page = document
.pages()
.create_page_at_start(PdfPagePaperSize::a4())?;
let mut object = PdfPagePathObject::new_rect(
&document,
PdfRect::new_from_values(100.0, 100.0, 400.0, 400.0),
Some(PdfColor::SOLID_RED),
Some(PdfPoints::new(1.0)),
None,
)?;
object.rotate_clockwise_degrees(35.0)?;
let object = page.objects_mut().add_path_object(object)?;
assert_eq!(object.get_rotation_clockwise_degrees(), 35.0);
assert_eq!(object.get_horizontal_translation().value, 0.0);
assert_eq!(object.get_vertical_translation().value, 0.0);
assert_eq!(object.get_horizontal_scale(), 0.8191520571708679); assert_eq!(object.get_vertical_scale(), 0.8191520571708679);
Ok(())
}
#[test]
fn test_object_get_skew() -> Result<(), PdfiumError> {
let pdfium = test_bind_to_pdfium();
let document = pdfium.create_new_pdf()?;
let mut page = document
.pages()
.create_page_at_start(PdfPagePaperSize::a4())?;
let mut object = PdfPagePathObject::new_rect(
&document,
PdfRect::new_from_values(100.0, 100.0, 400.0, 400.0),
Some(PdfColor::SOLID_RED),
Some(PdfPoints::new(1.0)),
None,
)?;
object.skew_degrees(15.5, 25.5)?;
let object = page.objects_mut().add_path_object(object)?;
assert_eq!(
(object.get_x_axis_skew_degrees() * 10.0).round() / 10.0,
15.5
); assert_eq!(
(object.get_y_axis_skew_degrees() * 10.0).round() / 10.0,
25.5
); assert_eq!(object.get_horizontal_translation().value, 0.0);
assert_eq!(object.get_vertical_translation().value, 0.0);
assert_eq!(object.get_horizontal_scale(), 1.0);
assert_eq!(object.get_vertical_scale(), 1.0);
assert_eq!(
(object.get_rotation_counter_clockwise_degrees() * 10.0).round() / 10.0,
15.5
);
Ok(())
}
}