1pub mod content_mark;
4pub mod group;
5pub mod image;
6pub mod ownership;
7pub mod path;
8pub(crate) mod private; pub mod shading;
10pub mod text;
11pub mod unsupported;
12pub mod x_object_form;
13
14use crate::bindgen::{
15 FPDF_LINECAP_BUTT, FPDF_LINECAP_PROJECTING_SQUARE, FPDF_LINECAP_ROUND, FPDF_LINEJOIN_BEVEL,
16 FPDF_LINEJOIN_MITER, FPDF_LINEJOIN_ROUND, FPDF_PAGEOBJECT, FPDF_PAGEOBJ_FORM,
17 FPDF_PAGEOBJ_IMAGE, FPDF_PAGEOBJ_PATH, FPDF_PAGEOBJ_SHADING, FPDF_PAGEOBJ_TEXT,
18 FPDF_PAGEOBJ_UNKNOWN,
19};
20use crate::bindings::PdfiumLibraryBindings;
21use crate::error::PdfiumError;
22use crate::pdf::color::PdfColor;
23use crate::pdf::document::page::annotation::objects::PdfPageAnnotationObjects;
24use crate::pdf::document::page::annotation::private::internal::PdfPageAnnotationPrivate;
25use crate::pdf::document::page::annotation::{PdfPageAnnotation, PdfPageAnnotationCommon};
26use crate::pdf::document::page::object::image::PdfPageImageObject;
27use crate::pdf::document::page::object::path::PdfPagePathObject;
28use crate::pdf::document::page::object::private::internal::PdfPageObjectPrivate;
29use crate::pdf::document::page::object::shading::PdfPageShadingObject;
30use crate::pdf::document::page::object::text::PdfPageTextObject;
31use crate::pdf::document::page::object::unsupported::PdfPageUnsupportedObject;
32use crate::pdf::document::page::object::x_object_form::PdfPageXObjectFormObject;
33use crate::pdf::document::page::objects::PdfPageObjects;
34use crate::pdf::document::page::{PdfPage, PdfPageObjectOwnership};
35use crate::pdf::matrix::{PdfMatrix, PdfMatrixValue};
36use crate::pdf::path::clip_path::PdfClipPath;
37use crate::pdf::points::PdfPoints;
38use crate::pdf::quad_points::PdfQuadPoints;
39use crate::pdf::rect::PdfRect;
40use crate::pdfium::PdfiumLibraryBindingsAccessor;
41use crate::{create_transform_getters, create_transform_setters};
42use std::convert::TryInto;
43use std::os::raw::{c_int, c_uint};
44
45#[cfg(any(
46 feature = "pdfium_future",
47 feature = "pdfium_7881",
48 feature = "pdfium_7763",
49 feature = "pdfium_7543",
50 feature = "pdfium_7350"
51))]
52use crate::pdf::document::page::objects::common::PdfPageObjectIndex;
53
54#[cfg(any(
55 feature = "pdfium_future",
56 feature = "pdfium_7881",
57 feature = "pdfium_7763",
58 feature = "pdfium_7543",
59 feature = "pdfium_7350",
60 feature = "pdfium_7215",
61 feature = "pdfium_7123",
62 feature = "pdfium_6996"
63))]
64use crate::error::PdfiumInternalError;
65
66#[cfg(doc)]
67use crate::pdf::document::PdfDocument;
68
69#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Eq, Hash)]
76pub enum PdfPageObjectType {
77 Unsupported = FPDF_PAGEOBJ_UNKNOWN as isize,
79
80 Text = FPDF_PAGEOBJ_TEXT as isize,
82
83 Path = FPDF_PAGEOBJ_PATH as isize,
85
86 Image = FPDF_PAGEOBJ_IMAGE as isize,
88
89 Shading = FPDF_PAGEOBJ_SHADING as isize,
92
93 XObjectForm = FPDF_PAGEOBJ_FORM as isize,
100}
101
102impl PdfPageObjectType {
103 pub(crate) fn from_pdfium(value: u32) -> Result<PdfPageObjectType, PdfiumError> {
104 match value {
105 FPDF_PAGEOBJ_UNKNOWN => Ok(PdfPageObjectType::Unsupported),
106 FPDF_PAGEOBJ_TEXT => Ok(PdfPageObjectType::Text),
107 FPDF_PAGEOBJ_PATH => Ok(PdfPageObjectType::Path),
108 FPDF_PAGEOBJ_IMAGE => Ok(PdfPageObjectType::Image),
109 FPDF_PAGEOBJ_SHADING => Ok(PdfPageObjectType::Shading),
110 FPDF_PAGEOBJ_FORM => Ok(PdfPageObjectType::XObjectForm),
111 _ => Err(PdfiumError::UnknownPdfPageObjectType),
112 }
113 }
114}
115
116#[derive(Debug, Copy, Clone, PartialEq)]
125pub enum PdfPageObjectBlendMode {
126 Normal,
128
129 Multiply,
135
136 Screen,
144
145 Overlay,
150
151 Darken,
154
155 Lighten,
158
159 ColorDodge,
162
163 ColorBurn,
166
167 HardLight,
170
171 SoftLight,
174
175 Difference,
178
179 Exclusion,
182
183 HSLColor,
186
187 HSLHue,
190
191 HSLLuminosity,
194
195 HSLSaturation,
198}
199
200impl PdfPageObjectBlendMode {
201 pub(crate) fn as_pdfium(&self) -> &str {
202 match self {
203 PdfPageObjectBlendMode::HSLColor => "Color",
204 PdfPageObjectBlendMode::ColorBurn => "ColorBurn",
205 PdfPageObjectBlendMode::ColorDodge => "ColorDodge",
206 PdfPageObjectBlendMode::Darken => "Darken",
207 PdfPageObjectBlendMode::Difference => "Difference",
208 PdfPageObjectBlendMode::Exclusion => "Exclusion",
209 PdfPageObjectBlendMode::HardLight => "HardLight",
210 PdfPageObjectBlendMode::HSLHue => "Hue",
211 PdfPageObjectBlendMode::Lighten => "Lighten",
212 PdfPageObjectBlendMode::HSLLuminosity => "Luminosity",
213 PdfPageObjectBlendMode::Multiply => "Multiply",
214 PdfPageObjectBlendMode::Normal => "Normal",
215 PdfPageObjectBlendMode::Overlay => "Overlay",
216 PdfPageObjectBlendMode::HSLSaturation => "Saturation",
217 PdfPageObjectBlendMode::Screen => "Screen",
218 PdfPageObjectBlendMode::SoftLight => "SoftLight",
219 }
220 }
221}
222
223#[derive(Debug, Copy, Clone, PartialEq)]
231pub enum PdfPageObjectLineJoin {
232 Miter = FPDF_LINEJOIN_MITER as isize,
236
237 Round = FPDF_LINEJOIN_ROUND as isize,
242
243 Bevel = FPDF_LINEJOIN_BEVEL as isize,
246}
247
248impl PdfPageObjectLineJoin {
249 pub(crate) fn from_pdfium(value: c_int) -> Option<Self> {
250 match value as u32 {
251 FPDF_LINEJOIN_MITER => Some(Self::Miter),
252 FPDF_LINEJOIN_ROUND => Some(Self::Round),
253 FPDF_LINEJOIN_BEVEL => Some(Self::Bevel),
254 _ => None,
255 }
256 }
257
258 pub(crate) fn as_pdfium(&self) -> u32 {
259 match self {
260 PdfPageObjectLineJoin::Miter => FPDF_LINEJOIN_MITER,
261 PdfPageObjectLineJoin::Round => FPDF_LINEJOIN_ROUND,
262 PdfPageObjectLineJoin::Bevel => FPDF_LINEJOIN_BEVEL,
263 }
264 }
265}
266
267#[derive(Debug, Copy, Clone, PartialEq)]
272pub enum PdfPageObjectLineCap {
273 Butt = FPDF_LINECAP_BUTT as isize,
276
277 Round = FPDF_LINECAP_ROUND as isize,
280
281 Square = FPDF_LINECAP_PROJECTING_SQUARE as isize,
284}
285
286impl PdfPageObjectLineCap {
287 pub(crate) fn from_pdfium(value: c_int) -> Option<Self> {
288 match value as u32 {
289 FPDF_LINECAP_BUTT => Some(Self::Butt),
290 FPDF_LINECAP_ROUND => Some(Self::Round),
291 FPDF_LINECAP_PROJECTING_SQUARE => Some(Self::Square),
292 _ => None,
293 }
294 }
295
296 pub(crate) fn as_pdfium(&self) -> u32 {
297 match self {
298 PdfPageObjectLineCap::Butt => FPDF_LINECAP_BUTT,
299 PdfPageObjectLineCap::Round => FPDF_LINECAP_ROUND,
300 PdfPageObjectLineCap::Square => FPDF_LINECAP_PROJECTING_SQUARE,
301 }
302 }
303}
304
305pub enum PdfPageObject<'a> {
307 Text(PdfPageTextObject<'a>),
309
310 Path(PdfPagePathObject<'a>),
312
313 Image(PdfPageImageObject<'a>),
315
316 Shading(PdfPageShadingObject<'a>),
319
320 XObjectForm(PdfPageXObjectFormObject<'a>),
327
328 Unsupported(PdfPageUnsupportedObject<'a>),
334}
335
336impl<'a> PdfPageObject<'a> {
337 pub(crate) fn from_pdfium(
338 object_handle: FPDF_PAGEOBJECT,
339 ownership: PdfPageObjectOwnership,
340 bindings: &'a dyn PdfiumLibraryBindings,
341 ) -> Self {
342 match PdfPageObjectType::from_pdfium(
343 unsafe { bindings.FPDFPageObj_GetType(object_handle) } as u32
344 )
345 .unwrap_or(PdfPageObjectType::Unsupported)
346 {
347 PdfPageObjectType::Unsupported => PdfPageObject::Unsupported(
348 PdfPageUnsupportedObject::from_pdfium(object_handle, ownership),
349 ),
350 PdfPageObjectType::Text => {
351 PdfPageObject::Text(PdfPageTextObject::from_pdfium(object_handle, ownership))
352 }
353 PdfPageObjectType::Path => {
354 PdfPageObject::Path(PdfPagePathObject::from_pdfium(object_handle, ownership))
355 }
356 PdfPageObjectType::Image => {
357 PdfPageObject::Image(PdfPageImageObject::from_pdfium(object_handle, ownership))
358 }
359 PdfPageObjectType::Shading => {
360 PdfPageObject::Shading(PdfPageShadingObject::from_pdfium(object_handle, ownership))
361 }
362 PdfPageObjectType::XObjectForm => PdfPageObject::XObjectForm(
363 PdfPageXObjectFormObject::from_pdfium(object_handle, ownership),
364 ),
365 }
366 }
367
368 #[inline]
369 pub(crate) fn unwrap_as_trait(&self) -> &dyn PdfPageObjectPrivate<'a> {
370 match self {
371 PdfPageObject::Text(object) => object,
372 PdfPageObject::Path(object) => object,
373 PdfPageObject::Image(object) => object,
374 PdfPageObject::Shading(object) => object,
375 PdfPageObject::XObjectForm(object) => object,
376 PdfPageObject::Unsupported(object) => object,
377 }
378 }
379
380 #[inline]
381 pub(crate) fn unwrap_as_trait_mut(&mut self) -> &mut dyn PdfPageObjectPrivate<'a> {
382 match self {
383 PdfPageObject::Text(object) => object,
384 PdfPageObject::Path(object) => object,
385 PdfPageObject::Image(object) => object,
386 PdfPageObject::Shading(object) => object,
387 PdfPageObject::XObjectForm(object) => object,
388 PdfPageObject::Unsupported(object) => object,
389 }
390 }
391
392 #[inline]
399 pub fn object_type(&self) -> PdfPageObjectType {
400 match self {
401 PdfPageObject::Text(_) => PdfPageObjectType::Text,
402 PdfPageObject::Path(_) => PdfPageObjectType::Path,
403 PdfPageObject::Image(_) => PdfPageObjectType::Image,
404 PdfPageObject::Shading(_) => PdfPageObjectType::Shading,
405 PdfPageObject::XObjectForm(_) => PdfPageObjectType::XObjectForm,
406 PdfPageObject::Unsupported(_) => PdfPageObjectType::Unsupported,
407 }
408 }
409
410 #[inline]
416 pub fn is_supported(&self) -> bool {
417 !self.is_unsupported()
418 }
419
420 #[inline]
426 pub fn is_unsupported(&self) -> bool {
427 self.object_type() == PdfPageObjectType::Unsupported
428 }
429
430 #[inline]
433 pub fn as_text_object(&self) -> Option<&PdfPageTextObject<'_>> {
434 match self {
435 PdfPageObject::Text(object) => Some(object),
436 _ => None,
437 }
438 }
439
440 #[inline]
443 pub fn as_text_object_mut(&mut self) -> Option<&mut PdfPageTextObject<'a>> {
444 match self {
445 PdfPageObject::Text(object) => Some(object),
446 _ => None,
447 }
448 }
449
450 #[inline]
453 pub fn as_path_object(&self) -> Option<&PdfPagePathObject<'_>> {
454 match self {
455 PdfPageObject::Path(object) => Some(object),
456 _ => None,
457 }
458 }
459
460 #[inline]
463 pub fn as_path_object_mut(&mut self) -> Option<&mut PdfPagePathObject<'a>> {
464 match self {
465 PdfPageObject::Path(object) => Some(object),
466 _ => None,
467 }
468 }
469
470 #[inline]
473 pub fn as_image_object(&self) -> Option<&PdfPageImageObject<'_>> {
474 match self {
475 PdfPageObject::Image(object) => Some(object),
476 _ => None,
477 }
478 }
479
480 #[inline]
483 pub fn as_image_object_mut(&mut self) -> Option<&mut PdfPageImageObject<'a>> {
484 match self {
485 PdfPageObject::Image(object) => Some(object),
486 _ => None,
487 }
488 }
489
490 #[inline]
493 pub fn as_shading_object(&self) -> Option<&PdfPageShadingObject<'_>> {
494 match self {
495 PdfPageObject::Shading(object) => Some(object),
496 _ => None,
497 }
498 }
499
500 #[inline]
503 pub fn as_shading_object_mut(&mut self) -> Option<&mut PdfPageShadingObject<'a>> {
504 match self {
505 PdfPageObject::Shading(object) => Some(object),
506 _ => None,
507 }
508 }
509
510 #[inline]
513 pub fn as_x_object_form_object(&self) -> Option<&PdfPageXObjectFormObject<'_>> {
514 match self {
515 PdfPageObject::XObjectForm(object) => Some(object),
516 _ => None,
517 }
518 }
519
520 #[inline]
523 pub fn as_x_object_form_object_mut(&mut self) -> Option<&mut PdfPageXObjectFormObject<'a>> {
524 match self {
525 PdfPageObject::XObjectForm(object) => Some(object),
526 _ => None,
527 }
528 }
529
530 pub fn get_clip_path(&self) -> Option<PdfClipPath<'_>> {
532 let path_handle = unsafe {
533 self.bindings()
534 .FPDFPageObj_GetClipPath(self.object_handle())
535 };
536
537 if path_handle.is_null() {
538 return None;
539 }
540
541 return Some(PdfClipPath::from_pdfium(
542 path_handle,
543 self.ownership().clone(),
544 ));
545 }
546
547 #[cfg(any(
548 feature = "pdfium_future",
549 feature = "pdfium_7881",
550 feature = "pdfium_7763",
551 feature = "pdfium_7543",
552 feature = "pdfium_7350",
553 feature = "pdfium_7215",
554 feature = "pdfium_7123",
555 feature = "pdfium_6996"
556 ))]
557 pub fn set_active(&mut self) -> Result<(), PdfiumError> {
560 if self.bindings().is_true(unsafe {
561 self.bindings()
562 .FPDFPageObj_SetIsActive(self.object_handle(), self.bindings().TRUE())
563 }) {
564 Ok(())
565 } else {
566 Err(PdfiumError::PdfiumLibraryInternalError(
567 PdfiumInternalError::Unknown,
568 ))
569 }
570 }
571
572 #[cfg(any(
573 feature = "pdfium_future",
574 feature = "pdfium_7881",
575 feature = "pdfium_7763",
576 feature = "pdfium_7543",
577 feature = "pdfium_7350",
578 feature = "pdfium_7215",
579 feature = "pdfium_7123",
580 feature = "pdfium_6996"
581 ))]
582 pub fn is_active(&self) -> Result<bool, PdfiumError> {
584 let mut result = self.bindings().FALSE();
585
586 if self.bindings().is_true(unsafe {
587 self.bindings()
588 .FPDFPageObj_GetIsActive(self.object_handle(), &mut result)
589 }) {
590 Ok(self.bindings().is_true(result))
591 } else {
592 Err(PdfiumError::PdfiumLibraryInternalError(
593 PdfiumInternalError::Unknown,
594 ))
595 }
596 }
597
598 #[cfg(any(
599 feature = "pdfium_future",
600 feature = "pdfium_7881",
601 feature = "pdfium_7763",
602 feature = "pdfium_7543",
603 feature = "pdfium_7350",
604 feature = "pdfium_7215",
605 feature = "pdfium_7123",
606 feature = "pdfium_6996"
607 ))]
608 pub fn set_inactive(&mut self) -> Result<(), PdfiumError> {
611 if self.bindings().is_true(unsafe {
612 self.bindings()
613 .FPDFPageObj_SetIsActive(self.object_handle(), self.bindings().FALSE())
614 }) {
615 Ok(())
616 } else {
617 Err(PdfiumError::PdfiumLibraryInternalError(
618 PdfiumInternalError::Unknown,
619 ))
620 }
621 }
622
623 #[cfg(any(
624 feature = "pdfium_future",
625 feature = "pdfium_7881",
626 feature = "pdfium_7763",
627 feature = "pdfium_7543",
628 feature = "pdfium_7350",
629 feature = "pdfium_7215",
630 feature = "pdfium_7123",
631 feature = "pdfium_6996"
632 ))]
633 #[inline]
635 pub fn is_inactive(&self) -> Result<bool, PdfiumError> {
636 self.is_active().map(|result| !result)
637 }
638
639 create_transform_setters!(
640 &mut Self,
641 Result<(), PdfiumError>,
642 "this [PdfPageObject]",
643 "this [PdfPageObject].",
644 "this [PdfPageObject],"
645 );
646
647 create_transform_getters!(
651 "this [PdfPageObject]",
652 "this [PdfPageObject].",
653 "this [PdfPageObject],"
654 );
655
656 }
659
660impl<'a> PdfiumLibraryBindingsAccessor<'a> for PdfPageObject<'a> {}
661
662#[cfg(feature = "thread_safe")]
663unsafe impl<'a> Send for PdfPageObject<'a> {}
664
665#[cfg(feature = "thread_safe")]
666unsafe impl<'a> Sync for PdfPageObject<'a> {}
667
668pub trait PdfPageObjectCommon<'a> {
670 fn has_transparency(&self) -> bool;
672
673 fn bounds(&self) -> Result<PdfQuadPoints, PdfiumError>;
680
681 #[inline]
683 fn width(&self) -> Result<PdfPoints, PdfiumError> {
684 Ok(self.bounds()?.width())
685 }
686
687 #[inline]
689 fn height(&self) -> Result<PdfPoints, PdfiumError> {
690 Ok(self.bounds()?.height())
691 }
692
693 #[inline]
695 fn is_inside_rect(&self, rect: &PdfRect) -> bool {
696 self.bounds()
697 .map(|bounds| bounds.to_rect().is_inside(rect))
698 .unwrap_or(false)
699 }
700
701 #[inline]
704 fn does_overlap_rect(&self, rect: &PdfRect) -> bool {
705 self.bounds()
706 .map(|bounds| bounds.to_rect().does_overlap(rect))
707 .unwrap_or(false)
708 }
709
710 fn transform_from(&mut self, other: &PdfPageObject) -> Result<(), PdfiumError>;
715
716 fn set_blend_mode(&mut self, blend_mode: PdfPageObjectBlendMode) -> Result<(), PdfiumError>;
720
721 fn fill_color(&self) -> Result<PdfColor, PdfiumError>;
723
724 fn set_fill_color(&mut self, fill_color: PdfColor) -> Result<(), PdfiumError>;
726
727 fn stroke_color(&self) -> Result<PdfColor, PdfiumError>;
729
730 fn set_stroke_color(&mut self, stroke_color: PdfColor) -> Result<(), PdfiumError>;
735
736 fn stroke_width(&self) -> Result<PdfPoints, PdfiumError>;
738
739 fn set_stroke_width(&mut self, stroke_width: PdfPoints) -> Result<(), PdfiumError>;
749
750 fn line_join(&self) -> Result<PdfPageObjectLineJoin, PdfiumError>;
753
754 fn set_line_join(&mut self, line_join: PdfPageObjectLineJoin) -> Result<(), PdfiumError>;
757
758 fn line_cap(&self) -> Result<PdfPageObjectLineCap, PdfiumError>;
761
762 fn set_line_cap(&mut self, line_cap: PdfPageObjectLineCap) -> Result<(), PdfiumError>;
765
766 fn dash_phase(&self) -> Result<PdfPoints, PdfiumError>;
782
783 fn set_dash_phase(&mut self, dash_phase: PdfPoints) -> Result<(), PdfiumError>;
799
800 fn dash_array(&self) -> Result<Vec<PdfPoints>, PdfiumError>;
816
817 fn set_dash_array(&mut self, array: &[PdfPoints], phase: PdfPoints) -> Result<(), PdfiumError>;
833
834 fn copy_to_page<'b>(
838 &mut self,
839 page: &mut PdfPage<'b>,
840 ) -> Result<PdfPageObject<'b>, PdfiumError>;
841
842 fn move_to_page(&mut self, page: &mut PdfPage) -> Result<(), PdfiumError>;
849
850 fn move_to_annotation(&mut self, annotation: &mut PdfPageAnnotation)
857 -> Result<(), PdfiumError>;
858}
859
860impl<'a, T> PdfPageObjectCommon<'a> for T
863where
864 T: PdfPageObjectPrivate<'a>,
865{
866 #[inline]
867 fn has_transparency(&self) -> bool {
868 self.has_transparency_impl()
869 }
870
871 #[inline]
872 fn bounds(&self) -> Result<PdfQuadPoints, PdfiumError> {
873 self.bounds_impl()
874 }
875
876 #[inline]
877 fn transform_from(&mut self, other: &PdfPageObject) -> Result<(), PdfiumError> {
878 self.reset_matrix_impl(other.matrix()?)
879 }
880
881 #[inline]
882 fn set_blend_mode(&mut self, blend_mode: PdfPageObjectBlendMode) -> Result<(), PdfiumError> {
883 unsafe {
884 self.bindings()
885 .FPDFPageObj_SetBlendMode(self.object_handle(), blend_mode.as_pdfium());
886 }
887
888 Ok(())
889 }
890
891 #[inline]
892 fn fill_color(&self) -> Result<PdfColor, PdfiumError> {
893 let mut r = 0;
894 let mut g = 0;
895 let mut b = 0;
896 let mut a = 0;
897
898 if self.bindings().is_true(unsafe {
899 self.bindings().FPDFPageObj_GetFillColor(
900 self.object_handle(),
901 &mut r,
902 &mut g,
903 &mut b,
904 &mut a,
905 )
906 }) {
907 Ok(PdfColor::new(
908 r.try_into()
909 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
910 g.try_into()
911 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
912 b.try_into()
913 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
914 a.try_into()
915 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
916 ))
917 } else {
918 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
919 }
920 }
921
922 #[inline]
923 fn set_fill_color(&mut self, fill_color: PdfColor) -> Result<(), PdfiumError> {
924 if self.bindings().is_true(unsafe {
925 self.bindings().FPDFPageObj_SetFillColor(
926 self.object_handle(),
927 fill_color.red() as c_uint,
928 fill_color.green() as c_uint,
929 fill_color.blue() as c_uint,
930 fill_color.alpha() as c_uint,
931 )
932 }) {
933 Ok(())
934 } else {
935 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
936 }
937 }
938
939 #[inline]
940 fn stroke_color(&self) -> Result<PdfColor, PdfiumError> {
941 let mut r = 0;
942 let mut g = 0;
943 let mut b = 0;
944 let mut a = 0;
945
946 if self.bindings().is_true(unsafe {
947 self.bindings().FPDFPageObj_GetStrokeColor(
948 self.object_handle(),
949 &mut r,
950 &mut g,
951 &mut b,
952 &mut a,
953 )
954 }) {
955 Ok(PdfColor::new(
956 r.try_into()
957 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
958 g.try_into()
959 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
960 b.try_into()
961 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
962 a.try_into()
963 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
964 ))
965 } else {
966 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
967 }
968 }
969
970 #[inline]
971 fn set_stroke_color(&mut self, stroke_color: PdfColor) -> Result<(), PdfiumError> {
972 if self.bindings().is_true(unsafe {
973 self.bindings().FPDFPageObj_SetStrokeColor(
974 self.object_handle(),
975 stroke_color.red() as c_uint,
976 stroke_color.green() as c_uint,
977 stroke_color.blue() as c_uint,
978 stroke_color.alpha() as c_uint,
979 )
980 }) {
981 Ok(())
982 } else {
983 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
984 }
985 }
986
987 #[inline]
988 fn stroke_width(&self) -> Result<PdfPoints, PdfiumError> {
989 let mut width = 0.0;
990
991 if self.bindings().is_true(unsafe {
992 self.bindings()
993 .FPDFPageObj_GetStrokeWidth(self.object_handle(), &mut width)
994 }) {
995 Ok(PdfPoints::new(width))
996 } else {
997 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
998 }
999 }
1000
1001 #[inline]
1002 fn set_stroke_width(&mut self, stroke_width: PdfPoints) -> Result<(), PdfiumError> {
1003 if self.bindings().is_true(unsafe {
1004 self.bindings()
1005 .FPDFPageObj_SetStrokeWidth(self.object_handle(), stroke_width.value)
1006 }) {
1007 Ok(())
1008 } else {
1009 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1010 }
1011 }
1012
1013 #[inline]
1014 fn line_join(&self) -> Result<PdfPageObjectLineJoin, PdfiumError> {
1015 PdfPageObjectLineJoin::from_pdfium(unsafe {
1016 self.bindings()
1017 .FPDFPageObj_GetLineJoin(self.object_handle())
1018 })
1019 .ok_or(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1020 }
1021
1022 #[inline]
1023 fn set_line_join(&mut self, line_join: PdfPageObjectLineJoin) -> Result<(), PdfiumError> {
1024 if self.bindings().is_true(unsafe {
1025 self.bindings()
1026 .FPDFPageObj_SetLineJoin(self.object_handle(), line_join.as_pdfium() as c_int)
1027 }) {
1028 Ok(())
1029 } else {
1030 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1031 }
1032 }
1033
1034 #[inline]
1035 fn line_cap(&self) -> Result<PdfPageObjectLineCap, PdfiumError> {
1036 PdfPageObjectLineCap::from_pdfium(unsafe {
1037 self.bindings().FPDFPageObj_GetLineCap(self.object_handle())
1038 })
1039 .ok_or(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1040 }
1041
1042 #[inline]
1043 fn set_line_cap(&mut self, line_cap: PdfPageObjectLineCap) -> Result<(), PdfiumError> {
1044 if self.bindings().is_true(unsafe {
1045 self.bindings()
1046 .FPDFPageObj_SetLineCap(self.object_handle(), line_cap.as_pdfium() as c_int)
1047 }) {
1048 Ok(())
1049 } else {
1050 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1051 }
1052 }
1053
1054 #[inline]
1055 fn dash_phase(&self) -> Result<PdfPoints, PdfiumError> {
1056 let mut phase = 0.0;
1057
1058 if self.bindings().is_true(unsafe {
1059 self.bindings()
1060 .FPDFPageObj_GetDashPhase(self.object_handle(), &mut phase)
1061 }) {
1062 Ok(PdfPoints::new(phase))
1063 } else {
1064 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1065 }
1066 }
1067
1068 #[inline]
1069 fn set_dash_phase(&mut self, dash_phase: PdfPoints) -> Result<(), PdfiumError> {
1070 if self.bindings().is_true(unsafe {
1071 self.bindings()
1072 .FPDFPageObj_SetDashPhase(self.object_handle(), dash_phase.value)
1073 }) {
1074 Ok(())
1075 } else {
1076 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1077 }
1078 }
1079
1080 #[inline]
1081 fn dash_array(&self) -> Result<Vec<PdfPoints>, PdfiumError> {
1082 let dash_count = unsafe {
1083 self.bindings()
1084 .FPDFPageObj_GetDashCount(self.object_handle())
1085 } as usize;
1086
1087 let mut dash_array = vec![0.0; dash_count];
1088
1089 if self.bindings().is_true(unsafe {
1090 self.bindings().FPDFPageObj_GetDashArray(
1091 self.object_handle(),
1092 dash_array.as_mut_ptr(),
1093 dash_count,
1094 )
1095 }) {
1096 Ok(dash_array
1097 .iter()
1098 .map(|dash| PdfPoints::new(*dash))
1099 .collect())
1100 } else {
1101 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1102 }
1103 }
1104
1105 fn set_dash_array(&mut self, array: &[PdfPoints], phase: PdfPoints) -> Result<(), PdfiumError> {
1106 let dash_array = array.iter().map(|dash| dash.value).collect::<Vec<_>>();
1107
1108 if self.bindings().is_true(unsafe {
1109 self.bindings().FPDFPageObj_SetDashArray(
1110 self.object_handle(),
1111 dash_array.as_ptr(),
1112 dash_array.len(),
1113 phase.value,
1114 )
1115 }) {
1116 Ok(())
1117 } else {
1118 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1119 }
1120 }
1121
1122 #[inline]
1123 fn copy_to_page<'b>(
1124 &mut self,
1125 page: &mut PdfPage<'b>,
1126 ) -> Result<PdfPageObject<'b>, PdfiumError> {
1127 self.copy_to_page_impl(page)
1128 }
1129
1130 fn move_to_page(&mut self, page: &mut PdfPage) -> Result<(), PdfiumError> {
1131 match self.ownership() {
1132 PdfPageObjectOwnership::Document(ownership) => {
1133 if ownership.document_handle() != page.document_handle() {
1134 return Err(PdfiumError::CannotMoveObjectAcrossDocuments);
1135 }
1136 }
1137 PdfPageObjectOwnership::Page(_) => self.remove_object_from_page()?,
1138 PdfPageObjectOwnership::AttachedAnnotation(_)
1139 | PdfPageObjectOwnership::UnattachedAnnotation(_) => {
1140 self.remove_object_from_annotation()?
1141 }
1142 PdfPageObjectOwnership::Unowned => {}
1143 }
1144
1145 self.add_object_to_page(page.objects_mut())
1146 }
1147
1148 fn move_to_annotation(
1149 &mut self,
1150 annotation: &mut PdfPageAnnotation,
1151 ) -> Result<(), PdfiumError> {
1152 match self.ownership() {
1153 PdfPageObjectOwnership::Document(ownership) => {
1154 let annotation_document_handle = match annotation.ownership() {
1155 PdfPageObjectOwnership::Document(ownership) => {
1156 Some(ownership.document_handle())
1157 }
1158 PdfPageObjectOwnership::Page(ownership) => Some(ownership.document_handle()),
1159 PdfPageObjectOwnership::AttachedAnnotation(ownership) => {
1160 Some(ownership.document_handle())
1161 }
1162 PdfPageObjectOwnership::UnattachedAnnotation(_)
1163 | PdfPageObjectOwnership::Unowned => None,
1164 };
1165
1166 if let Some(annotation_document_handle) = annotation_document_handle {
1167 if ownership.document_handle() != annotation_document_handle {
1168 return Err(PdfiumError::CannotMoveObjectAcrossDocuments);
1169 }
1170 }
1171 }
1172 PdfPageObjectOwnership::Page(_) => self.remove_object_from_page()?,
1173 PdfPageObjectOwnership::AttachedAnnotation(_)
1174 | PdfPageObjectOwnership::UnattachedAnnotation(_) => {
1175 self.remove_object_from_annotation()?
1176 }
1177 PdfPageObjectOwnership::Unowned => {}
1178 }
1179
1180 self.add_object_to_annotation(annotation.objects())
1181 }
1182}
1183
1184impl<'a> PdfPageObjectPrivate<'a> for PdfPageObject<'a> {
1185 #[inline]
1186 fn object_handle(&self) -> FPDF_PAGEOBJECT {
1187 self.unwrap_as_trait().object_handle()
1188 }
1189
1190 #[inline]
1191 fn ownership(&self) -> &PdfPageObjectOwnership {
1192 self.unwrap_as_trait().ownership()
1193 }
1194
1195 #[inline]
1196 fn set_ownership(&mut self, ownership: PdfPageObjectOwnership) {
1197 self.unwrap_as_trait_mut().set_ownership(ownership);
1198 }
1199
1200 #[inline]
1201 fn add_object_to_page(&mut self, page_objects: &mut PdfPageObjects) -> Result<(), PdfiumError> {
1202 self.unwrap_as_trait_mut().add_object_to_page(page_objects)
1203 }
1204
1205 #[cfg(any(
1206 feature = "pdfium_future",
1207 feature = "pdfium_7881",
1208 feature = "pdfium_7763",
1209 feature = "pdfium_7543",
1210 feature = "pdfium_7350"
1211 ))]
1212 #[inline]
1213 fn insert_object_on_page(
1214 &mut self,
1215 page_objects: &mut PdfPageObjects,
1216 index: PdfPageObjectIndex,
1217 ) -> Result<(), PdfiumError> {
1218 self.unwrap_as_trait_mut()
1219 .insert_object_on_page(page_objects, index)
1220 }
1221
1222 #[inline]
1223 fn remove_object_from_page(&mut self) -> Result<(), PdfiumError> {
1224 self.unwrap_as_trait_mut().remove_object_from_page()
1225 }
1226
1227 #[inline]
1228 fn add_object_to_annotation(
1229 &mut self,
1230 annotation_objects: &PdfPageAnnotationObjects,
1231 ) -> Result<(), PdfiumError> {
1232 self.unwrap_as_trait_mut()
1233 .add_object_to_annotation(annotation_objects)
1234 }
1235
1236 #[inline]
1237 fn remove_object_from_annotation(&mut self) -> Result<(), PdfiumError> {
1238 self.unwrap_as_trait_mut().remove_object_from_annotation()
1239 }
1240
1241 #[inline]
1242 fn copy_to_page_impl<'b>(
1243 &mut self,
1244 page: &mut PdfPage<'b>,
1245 ) -> Result<PdfPageObject<'b>, PdfiumError> {
1246 self.unwrap_as_trait_mut().copy_to_page_impl(page)
1247 }
1248}
1249
1250impl<'a> From<PdfPageXObjectFormObject<'a>> for PdfPageObject<'a> {
1251 #[inline]
1252 fn from(object: PdfPageXObjectFormObject<'a>) -> Self {
1253 Self::XObjectForm(object)
1254 }
1255}
1256
1257impl<'a> From<PdfPageImageObject<'a>> for PdfPageObject<'a> {
1258 #[inline]
1259 fn from(object: PdfPageImageObject<'a>) -> Self {
1260 Self::Image(object)
1261 }
1262}
1263
1264impl<'a> From<PdfPagePathObject<'a>> for PdfPageObject<'a> {
1265 #[inline]
1266 fn from(object: PdfPagePathObject<'a>) -> Self {
1267 Self::Path(object)
1268 }
1269}
1270
1271impl<'a> From<PdfPageShadingObject<'a>> for PdfPageObject<'a> {
1272 #[inline]
1273 fn from(object: PdfPageShadingObject<'a>) -> Self {
1274 Self::Shading(object)
1275 }
1276}
1277
1278impl<'a> From<PdfPageTextObject<'a>> for PdfPageObject<'a> {
1279 #[inline]
1280 fn from(object: PdfPageTextObject<'a>) -> Self {
1281 Self::Text(object)
1282 }
1283}
1284
1285impl<'a> From<PdfPageUnsupportedObject<'a>> for PdfPageObject<'a> {
1286 #[inline]
1287 fn from(object: PdfPageUnsupportedObject<'a>) -> Self {
1288 Self::Unsupported(object)
1289 }
1290}
1291
1292#[cfg(test)]
1293mod tests {
1294 use crate::prelude::*;
1295 use crate::utils::test::test_bind_to_pdfium;
1296
1297 #[test]
1298 fn test_apply_matrix() -> Result<(), PdfiumError> {
1299 let pdfium = test_bind_to_pdfium();
1300
1301 let mut document = pdfium.create_new_pdf()?;
1302
1303 let mut page = document
1304 .pages_mut()
1305 .create_page_at_start(PdfPagePaperSize::a4())?;
1306
1307 let font = document.fonts_mut().times_roman();
1308
1309 let mut object = page.objects_mut().create_text_object(
1310 PdfPoints::ZERO,
1311 PdfPoints::ZERO,
1312 "My new text object",
1313 font,
1314 PdfPoints::new(10.0),
1315 )?;
1316
1317 object.translate(PdfPoints::new(100.0), PdfPoints::new(100.0))?;
1320 object.flip_vertically()?;
1321 object.rotate_clockwise_degrees(45.0)?;
1322 object.scale(3.0, 4.0)?;
1323
1324 let previous_matrix = object.matrix()?;
1325
1326 object.apply_matrix(PdfMatrix::IDENTITY)?;
1329
1330 assert_eq!(previous_matrix, object.matrix()?);
1331
1332 Ok(())
1333 }
1334
1335 #[test]
1336 fn test_reset_matrix_to_identity() -> Result<(), PdfiumError> {
1337 let pdfium = test_bind_to_pdfium();
1338
1339 let mut document = pdfium.create_new_pdf()?;
1340
1341 let mut page = document
1342 .pages_mut()
1343 .create_page_at_start(PdfPagePaperSize::a4())?;
1344
1345 let font = document.fonts_mut().times_roman();
1346
1347 let mut object = page.objects_mut().create_text_object(
1348 PdfPoints::ZERO,
1349 PdfPoints::ZERO,
1350 "My new text object",
1351 font,
1352 PdfPoints::new(10.0),
1353 )?;
1354
1355 object.translate(PdfPoints::new(100.0), PdfPoints::new(100.0))?;
1358 object.flip_vertically()?;
1359 object.rotate_clockwise_degrees(45.0)?;
1360 object.scale(3.0, 4.0)?;
1361
1362 let previous_matrix = object.matrix()?;
1363
1364 object.reset_matrix_to_identity()?;
1368
1369 assert_ne!(previous_matrix, object.matrix()?);
1370 assert_eq!(object.matrix()?, PdfMatrix::IDENTITY);
1371
1372 Ok(())
1373 }
1374
1375 #[test]
1376 fn test_transform_captured_in_content_regeneration() -> Result<(), PdfiumError> {
1377 let pdfium = test_bind_to_pdfium();
1383
1384 let mut document = pdfium.create_new_pdf()?;
1385
1386 let x = PdfPoints::new(100.0);
1387 let y = PdfPoints::new(400.0);
1388
1389 let object_matrix_before_rotation = {
1390 let mut page = document
1391 .pages_mut()
1392 .create_page_at_start(PdfPagePaperSize::a4())?;
1393
1394 let font = document
1395 .fonts_mut()
1396 .new_built_in(PdfFontBuiltin::TimesRoman);
1397
1398 let mut object = page.objects_mut().create_text_object(
1399 x,
1400 y,
1401 "Hello world!",
1402 font,
1403 PdfPoints::new(20.0),
1404 )?;
1405
1406 let object_matrix_before_rotation = object.matrix()?;
1407
1408 object.rotate_clockwise_degrees(45.0)?;
1412
1413 object_matrix_before_rotation
1414 };
1415
1416 assert_eq!(
1422 object_matrix_before_rotation.rotate_clockwise_degrees(45.0)?,
1423 document.pages().first()?.objects().first()?.matrix()?
1424 );
1425
1426 Ok(())
1427 }
1428}