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