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
1292impl<'a> Drop for PdfPageObject<'a> {
1293 #[inline]
1295 fn drop(&mut self) {
1296 if !self.ownership().is_owned() {
1307 unsafe {
1308 self.bindings().FPDFPageObj_Destroy(self.object_handle());
1309 }
1310 }
1311 }
1312}
1313
1314#[cfg(test)]
1315mod tests {
1316 use crate::prelude::*;
1317 use crate::utils::test::test_bind_to_pdfium;
1318
1319 #[test]
1320 fn test_apply_matrix() -> Result<(), PdfiumError> {
1321 let pdfium = test_bind_to_pdfium();
1322
1323 let mut document = pdfium.create_new_pdf()?;
1324
1325 let mut page = document
1326 .pages_mut()
1327 .create_page_at_start(PdfPagePaperSize::a4())?;
1328
1329 let font = document.fonts_mut().times_roman();
1330
1331 let mut object = page.objects_mut().create_text_object(
1332 PdfPoints::ZERO,
1333 PdfPoints::ZERO,
1334 "My new text object",
1335 font,
1336 PdfPoints::new(10.0),
1337 )?;
1338
1339 object.translate(PdfPoints::new(100.0), PdfPoints::new(100.0))?;
1342 object.flip_vertically()?;
1343 object.rotate_clockwise_degrees(45.0)?;
1344 object.scale(3.0, 4.0)?;
1345
1346 let previous_matrix = object.matrix()?;
1347
1348 object.apply_matrix(PdfMatrix::IDENTITY)?;
1351
1352 assert_eq!(previous_matrix, object.matrix()?);
1353
1354 Ok(())
1355 }
1356
1357 #[test]
1358 fn test_reset_matrix_to_identity() -> Result<(), PdfiumError> {
1359 let pdfium = test_bind_to_pdfium();
1360
1361 let mut document = pdfium.create_new_pdf()?;
1362
1363 let mut page = document
1364 .pages_mut()
1365 .create_page_at_start(PdfPagePaperSize::a4())?;
1366
1367 let font = document.fonts_mut().times_roman();
1368
1369 let mut object = page.objects_mut().create_text_object(
1370 PdfPoints::ZERO,
1371 PdfPoints::ZERO,
1372 "My new text object",
1373 font,
1374 PdfPoints::new(10.0),
1375 )?;
1376
1377 object.translate(PdfPoints::new(100.0), PdfPoints::new(100.0))?;
1380 object.flip_vertically()?;
1381 object.rotate_clockwise_degrees(45.0)?;
1382 object.scale(3.0, 4.0)?;
1383
1384 let previous_matrix = object.matrix()?;
1385
1386 object.reset_matrix_to_identity()?;
1390
1391 assert_ne!(previous_matrix, object.matrix()?);
1392 assert_eq!(object.matrix()?, PdfMatrix::IDENTITY);
1393
1394 Ok(())
1395 }
1396
1397 #[test]
1398 fn test_transform_captured_in_content_regeneration() -> Result<(), PdfiumError> {
1399 let pdfium = test_bind_to_pdfium();
1405
1406 let mut document = pdfium.create_new_pdf()?;
1407
1408 let x = PdfPoints::new(100.0);
1409 let y = PdfPoints::new(400.0);
1410
1411 let object_matrix_before_rotation = {
1412 let mut page = document
1413 .pages_mut()
1414 .create_page_at_start(PdfPagePaperSize::a4())?;
1415
1416 let font = document
1417 .fonts_mut()
1418 .new_built_in(PdfFontBuiltin::TimesRoman);
1419
1420 let mut object = page.objects_mut().create_text_object(
1421 x,
1422 y,
1423 "Hello world!",
1424 font,
1425 PdfPoints::new(20.0),
1426 )?;
1427
1428 let object_matrix_before_rotation = object.matrix()?;
1429
1430 object.rotate_clockwise_degrees(45.0)?;
1434
1435 object_matrix_before_rotation
1436 };
1437
1438 assert_eq!(
1444 object_matrix_before_rotation.rotate_clockwise_degrees(45.0)?,
1445 document.pages().first()?.objects().first()?.matrix()?
1446 );
1447
1448 Ok(())
1449 }
1450}