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_DOCUMENT, FPDF_LINECAP_BUTT, FPDF_LINECAP_PROJECTING_SQUARE, FPDF_LINECAP_ROUND,
15 FPDF_LINEJOIN_BEVEL, FPDF_LINEJOIN_MITER, FPDF_LINEJOIN_ROUND, FPDF_PAGEOBJECT,
16 FPDF_PAGEOBJ_FORM, FPDF_PAGEOBJ_IMAGE, FPDF_PAGEOBJ_PATH, FPDF_PAGEOBJ_SHADING,
17 FPDF_PAGEOBJ_TEXT, 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::document::PdfDocument;
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::{create_transform_getters, create_transform_setters};
41use std::convert::TryInto;
42use std::os::raw::{c_int, c_uint};
43
44#[cfg(any(feature = "pdfium_future", feature = "pdfium_7350"))]
45use crate::pdf::document::page::objects::common::PdfPageObjectIndex;
46
47#[cfg(any(
48 feature = "pdfium_future",
49 feature = "pdfium_7543",
50 feature = "pdfium_7350",
51 feature = "pdfium_7215",
52 feature = "pdfium_7123",
53 feature = "pdfium_6996"
54))]
55use crate::error::PdfiumInternalError;
56
57#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Eq, Hash)]
64pub enum PdfPageObjectType {
65 Unsupported = FPDF_PAGEOBJ_UNKNOWN as isize,
67
68 Text = FPDF_PAGEOBJ_TEXT as isize,
70
71 Path = FPDF_PAGEOBJ_PATH as isize,
73
74 Image = FPDF_PAGEOBJ_IMAGE as isize,
76
77 Shading = FPDF_PAGEOBJ_SHADING as isize,
80
81 XObjectForm = FPDF_PAGEOBJ_FORM as isize,
88}
89
90impl PdfPageObjectType {
91 pub(crate) fn from_pdfium(value: u32) -> Result<PdfPageObjectType, PdfiumError> {
92 match value {
93 FPDF_PAGEOBJ_UNKNOWN => Ok(PdfPageObjectType::Unsupported),
94 FPDF_PAGEOBJ_TEXT => Ok(PdfPageObjectType::Text),
95 FPDF_PAGEOBJ_PATH => Ok(PdfPageObjectType::Path),
96 FPDF_PAGEOBJ_IMAGE => Ok(PdfPageObjectType::Image),
97 FPDF_PAGEOBJ_SHADING => Ok(PdfPageObjectType::Shading),
98 FPDF_PAGEOBJ_FORM => Ok(PdfPageObjectType::XObjectForm),
99 _ => Err(PdfiumError::UnknownPdfPageObjectType),
100 }
101 }
102}
103
104#[derive(Debug, Copy, Clone, PartialEq)]
113pub enum PdfPageObjectBlendMode {
114 Normal,
116
117 Multiply,
123
124 Screen,
132
133 Overlay,
138
139 Darken,
142
143 Lighten,
146
147 ColorDodge,
150
151 ColorBurn,
154
155 HardLight,
158
159 SoftLight,
162
163 Difference,
166
167 Exclusion,
170
171 HSLColor,
174
175 HSLHue,
178
179 HSLLuminosity,
182
183 HSLSaturation,
186}
187
188impl PdfPageObjectBlendMode {
189 pub(crate) fn as_pdfium(&self) -> &str {
190 match self {
191 PdfPageObjectBlendMode::HSLColor => "Color",
192 PdfPageObjectBlendMode::ColorBurn => "ColorBurn",
193 PdfPageObjectBlendMode::ColorDodge => "ColorDodge",
194 PdfPageObjectBlendMode::Darken => "Darken",
195 PdfPageObjectBlendMode::Difference => "Difference",
196 PdfPageObjectBlendMode::Exclusion => "Exclusion",
197 PdfPageObjectBlendMode::HardLight => "HardLight",
198 PdfPageObjectBlendMode::HSLHue => "Hue",
199 PdfPageObjectBlendMode::Lighten => "Lighten",
200 PdfPageObjectBlendMode::HSLLuminosity => "Luminosity",
201 PdfPageObjectBlendMode::Multiply => "Multiply",
202 PdfPageObjectBlendMode::Normal => "Normal",
203 PdfPageObjectBlendMode::Overlay => "Overlay",
204 PdfPageObjectBlendMode::HSLSaturation => "Saturation",
205 PdfPageObjectBlendMode::Screen => "Screen",
206 PdfPageObjectBlendMode::SoftLight => "SoftLight",
207 }
208 }
209}
210
211#[derive(Debug, Copy, Clone, PartialEq)]
219pub enum PdfPageObjectLineJoin {
220 Miter = FPDF_LINEJOIN_MITER as isize,
224
225 Round = FPDF_LINEJOIN_ROUND as isize,
230
231 Bevel = FPDF_LINEJOIN_BEVEL as isize,
234}
235
236impl PdfPageObjectLineJoin {
237 pub(crate) fn from_pdfium(value: c_int) -> Option<Self> {
238 match value as u32 {
239 FPDF_LINEJOIN_MITER => Some(Self::Miter),
240 FPDF_LINEJOIN_ROUND => Some(Self::Round),
241 FPDF_LINEJOIN_BEVEL => Some(Self::Bevel),
242 _ => None,
243 }
244 }
245
246 pub(crate) fn as_pdfium(&self) -> u32 {
247 match self {
248 PdfPageObjectLineJoin::Miter => FPDF_LINEJOIN_MITER,
249 PdfPageObjectLineJoin::Round => FPDF_LINEJOIN_ROUND,
250 PdfPageObjectLineJoin::Bevel => FPDF_LINEJOIN_BEVEL,
251 }
252 }
253}
254
255#[derive(Debug, Copy, Clone, PartialEq)]
260pub enum PdfPageObjectLineCap {
261 Butt = FPDF_LINECAP_BUTT as isize,
264
265 Round = FPDF_LINECAP_ROUND as isize,
268
269 Square = FPDF_LINECAP_PROJECTING_SQUARE as isize,
272}
273
274impl PdfPageObjectLineCap {
275 pub(crate) fn from_pdfium(value: c_int) -> Option<Self> {
276 match value as u32 {
277 FPDF_LINECAP_BUTT => Some(Self::Butt),
278 FPDF_LINECAP_ROUND => Some(Self::Round),
279 FPDF_LINECAP_PROJECTING_SQUARE => Some(Self::Square),
280 _ => None,
281 }
282 }
283
284 pub(crate) fn as_pdfium(&self) -> u32 {
285 match self {
286 PdfPageObjectLineCap::Butt => FPDF_LINECAP_BUTT,
287 PdfPageObjectLineCap::Round => FPDF_LINECAP_ROUND,
288 PdfPageObjectLineCap::Square => FPDF_LINECAP_PROJECTING_SQUARE,
289 }
290 }
291}
292
293pub enum PdfPageObject<'a> {
295 Text(PdfPageTextObject<'a>),
297
298 Path(PdfPagePathObject<'a>),
300
301 Image(PdfPageImageObject<'a>),
303
304 Shading(PdfPageShadingObject<'a>),
307
308 XObjectForm(PdfPageXObjectFormObject<'a>),
315
316 Unsupported(PdfPageUnsupportedObject<'a>),
322}
323
324impl<'a> PdfPageObject<'a> {
325 pub(crate) fn from_pdfium(
326 object_handle: FPDF_PAGEOBJECT,
327 ownership: PdfPageObjectOwnership,
328 bindings: &'a dyn PdfiumLibraryBindings,
329 ) -> Self {
330 match PdfPageObjectType::from_pdfium(bindings.FPDFPageObj_GetType(object_handle) as u32)
331 .unwrap_or(PdfPageObjectType::Unsupported)
332 {
333 PdfPageObjectType::Unsupported => PdfPageObject::Unsupported(
334 PdfPageUnsupportedObject::from_pdfium(object_handle, ownership, bindings),
335 ),
336 PdfPageObjectType::Text => PdfPageObject::Text(PdfPageTextObject::from_pdfium(
337 object_handle,
338 ownership,
339 bindings,
340 )),
341 PdfPageObjectType::Path => PdfPageObject::Path(PdfPagePathObject::from_pdfium(
342 object_handle,
343 ownership,
344 bindings,
345 )),
346 PdfPageObjectType::Image => PdfPageObject::Image(PdfPageImageObject::from_pdfium(
347 object_handle,
348 ownership,
349 bindings,
350 )),
351 PdfPageObjectType::Shading => PdfPageObject::Shading(
352 PdfPageShadingObject::from_pdfium(object_handle, ownership, bindings),
353 ),
354 PdfPageObjectType::XObjectForm => PdfPageObject::XObjectForm(
355 PdfPageXObjectFormObject::from_pdfium(object_handle, ownership, bindings),
356 ),
357 }
358 }
359
360 #[inline]
361 pub(crate) fn unwrap_as_trait(&self) -> &dyn PdfPageObjectPrivate<'a> {
362 match self {
363 PdfPageObject::Text(object) => object,
364 PdfPageObject::Path(object) => object,
365 PdfPageObject::Image(object) => object,
366 PdfPageObject::Shading(object) => object,
367 PdfPageObject::XObjectForm(object) => object,
368 PdfPageObject::Unsupported(object) => object,
369 }
370 }
371
372 #[inline]
373 pub(crate) fn unwrap_as_trait_mut(&mut self) -> &mut dyn PdfPageObjectPrivate<'a> {
374 match self {
375 PdfPageObject::Text(object) => object,
376 PdfPageObject::Path(object) => object,
377 PdfPageObject::Image(object) => object,
378 PdfPageObject::Shading(object) => object,
379 PdfPageObject::XObjectForm(object) => object,
380 PdfPageObject::Unsupported(object) => object,
381 }
382 }
383
384 #[inline]
391 pub fn object_type(&self) -> PdfPageObjectType {
392 match self {
393 PdfPageObject::Text(_) => PdfPageObjectType::Text,
394 PdfPageObject::Path(_) => PdfPageObjectType::Path,
395 PdfPageObject::Image(_) => PdfPageObjectType::Image,
396 PdfPageObject::Shading(_) => PdfPageObjectType::Shading,
397 PdfPageObject::XObjectForm(_) => PdfPageObjectType::XObjectForm,
398 PdfPageObject::Unsupported(_) => PdfPageObjectType::Unsupported,
399 }
400 }
401
402 #[inline]
408 pub fn is_supported(&self) -> bool {
409 !self.is_unsupported()
410 }
411
412 #[inline]
418 pub fn is_unsupported(&self) -> bool {
419 self.object_type() == PdfPageObjectType::Unsupported
420 }
421
422 #[inline]
425 pub fn as_text_object(&self) -> Option<&PdfPageTextObject<'_>> {
426 match self {
427 PdfPageObject::Text(object) => Some(object),
428 _ => None,
429 }
430 }
431
432 #[inline]
435 pub fn as_text_object_mut(&mut self) -> Option<&mut PdfPageTextObject<'a>> {
436 match self {
437 PdfPageObject::Text(object) => Some(object),
438 _ => None,
439 }
440 }
441
442 #[inline]
445 pub fn as_path_object(&self) -> Option<&PdfPagePathObject<'_>> {
446 match self {
447 PdfPageObject::Path(object) => Some(object),
448 _ => None,
449 }
450 }
451
452 #[inline]
455 pub fn as_path_object_mut(&mut self) -> Option<&mut PdfPagePathObject<'a>> {
456 match self {
457 PdfPageObject::Path(object) => Some(object),
458 _ => None,
459 }
460 }
461
462 #[inline]
465 pub fn as_image_object(&self) -> Option<&PdfPageImageObject<'_>> {
466 match self {
467 PdfPageObject::Image(object) => Some(object),
468 _ => None,
469 }
470 }
471
472 #[inline]
475 pub fn as_image_object_mut(&mut self) -> Option<&mut PdfPageImageObject<'a>> {
476 match self {
477 PdfPageObject::Image(object) => Some(object),
478 _ => None,
479 }
480 }
481
482 #[inline]
485 pub fn as_shading_object(&self) -> Option<&PdfPageShadingObject<'_>> {
486 match self {
487 PdfPageObject::Shading(object) => Some(object),
488 _ => None,
489 }
490 }
491
492 #[inline]
495 pub fn as_shading_object_mut(&mut self) -> Option<&mut PdfPageShadingObject<'a>> {
496 match self {
497 PdfPageObject::Shading(object) => Some(object),
498 _ => None,
499 }
500 }
501
502 #[inline]
505 pub fn as_x_object_form_object(&self) -> Option<&PdfPageXObjectFormObject<'_>> {
506 match self {
507 PdfPageObject::XObjectForm(object) => Some(object),
508 _ => None,
509 }
510 }
511
512 #[inline]
515 pub fn as_x_object_form_object_mut(&mut self) -> Option<&mut PdfPageXObjectFormObject<'a>> {
516 match self {
517 PdfPageObject::XObjectForm(object) => Some(object),
518 _ => None,
519 }
520 }
521
522 pub fn get_clip_path(&self) -> Option<PdfClipPath<'_>> {
524 let path_handle = self
525 .bindings()
526 .FPDFPageObj_GetClipPath(self.object_handle());
527
528 if path_handle.is_null() {
529 return None;
530 }
531
532 return Some(PdfClipPath::from_pdfium(
533 path_handle,
534 self.ownership().clone(),
535 self.bindings(),
536 ));
537 }
538
539 #[cfg(any(
540 feature = "pdfium_future",
541 feature = "pdfium_7543",
542 feature = "pdfium_7350",
543 feature = "pdfium_7215",
544 feature = "pdfium_7123",
545 feature = "pdfium_6996"
546 ))]
547 pub fn set_active(&mut self) -> Result<(), PdfiumError> {
550 if self.bindings().is_true(
551 self.bindings()
552 .FPDFPageObj_SetIsActive(self.object_handle(), self.bindings().TRUE()),
553 ) {
554 Ok(())
555 } else {
556 Err(PdfiumError::PdfiumLibraryInternalError(
557 PdfiumInternalError::Unknown,
558 ))
559 }
560 }
561
562 #[cfg(any(
563 feature = "pdfium_future",
564 feature = "pdfium_7543",
565 feature = "pdfium_7350",
566 feature = "pdfium_7215",
567 feature = "pdfium_7123",
568 feature = "pdfium_6996"
569 ))]
570 pub fn is_active(&self) -> Result<bool, PdfiumError> {
572 let mut result = self.bindings().FALSE();
573
574 if self.bindings().is_true(
575 self.bindings()
576 .FPDFPageObj_GetIsActive(self.object_handle(), &mut result),
577 ) {
578 Ok(self.bindings().is_true(result))
579 } else {
580 Err(PdfiumError::PdfiumLibraryInternalError(
581 PdfiumInternalError::Unknown,
582 ))
583 }
584 }
585
586 #[cfg(any(
587 feature = "pdfium_future",
588 feature = "pdfium_7543",
589 feature = "pdfium_7350",
590 feature = "pdfium_7215",
591 feature = "pdfium_7123",
592 feature = "pdfium_6996"
593 ))]
594 pub fn set_inactive(&mut self) -> Result<(), PdfiumError> {
597 if self.bindings().is_true(
598 self.bindings()
599 .FPDFPageObj_SetIsActive(self.object_handle(), self.bindings().FALSE()),
600 ) {
601 Ok(())
602 } else {
603 Err(PdfiumError::PdfiumLibraryInternalError(
604 PdfiumInternalError::Unknown,
605 ))
606 }
607 }
608
609 #[cfg(any(
610 feature = "pdfium_future",
611 feature = "pdfium_7543",
612 feature = "pdfium_7350",
613 feature = "pdfium_7215",
614 feature = "pdfium_7123",
615 feature = "pdfium_6996"
616 ))]
617 #[inline]
619 pub fn is_inactive(&self) -> Result<bool, PdfiumError> {
620 self.is_active().map(|result| !result)
621 }
622
623 create_transform_setters!(
624 &mut Self,
625 Result<(), PdfiumError>,
626 "this [PdfPageObject]",
627 "this [PdfPageObject].",
628 "this [PdfPageObject],"
629 );
630
631 create_transform_getters!(
635 "this [PdfPageObject]",
636 "this [PdfPageObject].",
637 "this [PdfPageObject],"
638 );
639
640 }
643
644pub trait PdfPageObjectCommon<'a> {
646 fn has_transparency(&self) -> bool;
648
649 fn bounds(&self) -> Result<PdfQuadPoints, PdfiumError>;
656
657 #[inline]
659 fn width(&self) -> Result<PdfPoints, PdfiumError> {
660 Ok(self.bounds()?.width())
661 }
662
663 #[inline]
665 fn height(&self) -> Result<PdfPoints, PdfiumError> {
666 Ok(self.bounds()?.height())
667 }
668
669 #[inline]
671 fn is_inside_rect(&self, rect: &PdfRect) -> bool {
672 self.bounds()
673 .map(|bounds| bounds.to_rect().is_inside(rect))
674 .unwrap_or(false)
675 }
676
677 #[inline]
680 fn does_overlap_rect(&self, rect: &PdfRect) -> bool {
681 self.bounds()
682 .map(|bounds| bounds.to_rect().does_overlap(rect))
683 .unwrap_or(false)
684 }
685
686 fn transform_from(&mut self, other: &PdfPageObject) -> Result<(), PdfiumError>;
691
692 fn set_blend_mode(&mut self, blend_mode: PdfPageObjectBlendMode) -> Result<(), PdfiumError>;
696
697 fn fill_color(&self) -> Result<PdfColor, PdfiumError>;
699
700 fn set_fill_color(&mut self, fill_color: PdfColor) -> Result<(), PdfiumError>;
702
703 fn stroke_color(&self) -> Result<PdfColor, PdfiumError>;
705
706 fn set_stroke_color(&mut self, stroke_color: PdfColor) -> Result<(), PdfiumError>;
711
712 fn stroke_width(&self) -> Result<PdfPoints, PdfiumError>;
714
715 fn set_stroke_width(&mut self, stroke_width: PdfPoints) -> Result<(), PdfiumError>;
725
726 fn line_join(&self) -> Result<PdfPageObjectLineJoin, PdfiumError>;
729
730 fn set_line_join(&mut self, line_join: PdfPageObjectLineJoin) -> Result<(), PdfiumError>;
733
734 fn line_cap(&self) -> Result<PdfPageObjectLineCap, PdfiumError>;
737
738 fn set_line_cap(&mut self, line_cap: PdfPageObjectLineCap) -> Result<(), PdfiumError>;
741
742 fn dash_phase(&self) -> Result<PdfPoints, PdfiumError>;
758
759 fn set_dash_phase(&mut self, dash_phase: PdfPoints) -> Result<(), PdfiumError>;
775
776 fn dash_array(&self) -> Result<Vec<PdfPoints>, PdfiumError>;
792
793 fn set_dash_array(&mut self, array: &[PdfPoints], phase: PdfPoints) -> Result<(), PdfiumError>;
809
810 #[deprecated(
811 since = "0.8.32",
812 note = "This function has been retired in favour of the PdfPageObject::copy_to_page() function."
813 )]
814 fn is_copyable(&self) -> bool;
833
834 #[deprecated(
835 since = "0.8.32",
836 note = "This function has been retired in favour of the PdfPageObject::copy_to_page() function."
837 )]
838 fn try_copy<'b>(&self, document: &'b PdfDocument<'b>)
860 -> Result<PdfPageObject<'b>, PdfiumError>;
861
862 fn copy_to_page<'b>(
866 &mut self,
867 page: &mut PdfPage<'b>,
868 ) -> Result<PdfPageObject<'b>, PdfiumError>;
869
870 fn move_to_page(&mut self, page: &mut PdfPage) -> Result<(), PdfiumError>;
877
878 fn move_to_annotation(&mut self, annotation: &mut PdfPageAnnotation)
885 -> Result<(), PdfiumError>;
886}
887
888impl<'a, T> PdfPageObjectCommon<'a> for T
891where
892 T: PdfPageObjectPrivate<'a>,
893{
894 #[inline]
895 fn has_transparency(&self) -> bool {
896 self.has_transparency_impl()
897 }
898
899 #[inline]
900 fn bounds(&self) -> Result<PdfQuadPoints, PdfiumError> {
901 self.bounds_impl()
902 }
903
904 #[inline]
905 fn transform_from(&mut self, other: &PdfPageObject) -> Result<(), PdfiumError> {
906 self.reset_matrix_impl(other.matrix()?)
907 }
908
909 #[inline]
910 fn set_blend_mode(&mut self, blend_mode: PdfPageObjectBlendMode) -> Result<(), PdfiumError> {
911 self.bindings()
912 .FPDFPageObj_SetBlendMode(self.object_handle(), blend_mode.as_pdfium());
913
914 Ok(())
915 }
916
917 #[inline]
918 fn fill_color(&self) -> Result<PdfColor, PdfiumError> {
919 let mut r = 0;
920
921 let mut g = 0;
922
923 let mut b = 0;
924
925 let mut a = 0;
926
927 if self
928 .bindings()
929 .is_true(self.bindings().FPDFPageObj_GetFillColor(
930 self.object_handle(),
931 &mut r,
932 &mut g,
933 &mut b,
934 &mut a,
935 ))
936 {
937 Ok(PdfColor::new(
938 r.try_into()
939 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
940 g.try_into()
941 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
942 b.try_into()
943 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
944 a.try_into()
945 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
946 ))
947 } else {
948 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
949 }
950 }
951
952 #[inline]
953 fn set_fill_color(&mut self, fill_color: PdfColor) -> Result<(), PdfiumError> {
954 if self
955 .bindings()
956 .is_true(self.bindings().FPDFPageObj_SetFillColor(
957 self.object_handle(),
958 fill_color.red() as c_uint,
959 fill_color.green() as c_uint,
960 fill_color.blue() as c_uint,
961 fill_color.alpha() as c_uint,
962 ))
963 {
964 Ok(())
965 } else {
966 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
967 }
968 }
969
970 #[inline]
971 fn stroke_color(&self) -> Result<PdfColor, PdfiumError> {
972 let mut r = 0;
973
974 let mut g = 0;
975
976 let mut b = 0;
977
978 let mut a = 0;
979
980 if self
981 .bindings()
982 .is_true(self.bindings().FPDFPageObj_GetStrokeColor(
983 self.object_handle(),
984 &mut r,
985 &mut g,
986 &mut b,
987 &mut a,
988 ))
989 {
990 Ok(PdfColor::new(
991 r.try_into()
992 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
993 g.try_into()
994 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
995 b.try_into()
996 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
997 a.try_into()
998 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
999 ))
1000 } else {
1001 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1002 }
1003 }
1004
1005 #[inline]
1006 fn set_stroke_color(&mut self, stroke_color: PdfColor) -> Result<(), PdfiumError> {
1007 if self
1008 .bindings()
1009 .is_true(self.bindings().FPDFPageObj_SetStrokeColor(
1010 self.object_handle(),
1011 stroke_color.red() as c_uint,
1012 stroke_color.green() as c_uint,
1013 stroke_color.blue() as c_uint,
1014 stroke_color.alpha() as c_uint,
1015 ))
1016 {
1017 Ok(())
1018 } else {
1019 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1020 }
1021 }
1022
1023 #[inline]
1024 fn stroke_width(&self) -> Result<PdfPoints, PdfiumError> {
1025 let mut width = 0.0;
1026
1027 if self.bindings().is_true(
1028 self.bindings()
1029 .FPDFPageObj_GetStrokeWidth(self.object_handle(), &mut width),
1030 ) {
1031 Ok(PdfPoints::new(width))
1032 } else {
1033 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1034 }
1035 }
1036
1037 #[inline]
1038 fn set_stroke_width(&mut self, stroke_width: PdfPoints) -> Result<(), PdfiumError> {
1039 if self.bindings().is_true(
1040 self.bindings()
1041 .FPDFPageObj_SetStrokeWidth(self.object_handle(), stroke_width.value),
1042 ) {
1043 Ok(())
1044 } else {
1045 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1046 }
1047 }
1048
1049 #[inline]
1050 fn line_join(&self) -> Result<PdfPageObjectLineJoin, PdfiumError> {
1051 PdfPageObjectLineJoin::from_pdfium(
1052 self.bindings()
1053 .FPDFPageObj_GetLineJoin(self.object_handle()),
1054 )
1055 .ok_or(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1056 }
1057
1058 #[inline]
1059 fn set_line_join(&mut self, line_join: PdfPageObjectLineJoin) -> Result<(), PdfiumError> {
1060 if self.bindings().is_true(
1061 self.bindings()
1062 .FPDFPageObj_SetLineJoin(self.object_handle(), line_join.as_pdfium() as c_int),
1063 ) {
1064 Ok(())
1065 } else {
1066 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1067 }
1068 }
1069
1070 #[inline]
1071 fn line_cap(&self) -> Result<PdfPageObjectLineCap, PdfiumError> {
1072 PdfPageObjectLineCap::from_pdfium(
1073 self.bindings().FPDFPageObj_GetLineCap(self.object_handle()),
1074 )
1075 .ok_or(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1076 }
1077
1078 #[inline]
1079 fn set_line_cap(&mut self, line_cap: PdfPageObjectLineCap) -> Result<(), PdfiumError> {
1080 if self.bindings().is_true(
1081 self.bindings()
1082 .FPDFPageObj_SetLineCap(self.object_handle(), line_cap.as_pdfium() as c_int),
1083 ) {
1084 Ok(())
1085 } else {
1086 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1087 }
1088 }
1089
1090 #[inline]
1091 fn dash_phase(&self) -> Result<PdfPoints, PdfiumError> {
1092 let mut phase = 0.0;
1093
1094 if self.bindings().is_true(
1095 self.bindings()
1096 .FPDFPageObj_GetDashPhase(self.object_handle(), &mut phase),
1097 ) {
1098 Ok(PdfPoints::new(phase))
1099 } else {
1100 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1101 }
1102 }
1103
1104 #[inline]
1105 fn set_dash_phase(&mut self, dash_phase: PdfPoints) -> Result<(), PdfiumError> {
1106 if self.bindings().is_true(
1107 self.bindings()
1108 .FPDFPageObj_SetDashPhase(self.object_handle(), dash_phase.value),
1109 ) {
1110 Ok(())
1111 } else {
1112 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1113 }
1114 }
1115
1116 #[inline]
1117 fn dash_array(&self) -> Result<Vec<PdfPoints>, PdfiumError> {
1118 let dash_count = self
1119 .bindings()
1120 .FPDFPageObj_GetDashCount(self.object_handle()) as usize;
1121
1122 let mut dash_array = vec![0.0; dash_count];
1123
1124 if self
1125 .bindings()
1126 .is_true(self.bindings().FPDFPageObj_GetDashArray(
1127 self.object_handle(),
1128 dash_array.as_mut_ptr(),
1129 dash_count,
1130 ))
1131 {
1132 Ok(dash_array
1133 .iter()
1134 .map(|dash| PdfPoints::new(*dash))
1135 .collect())
1136 } else {
1137 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1138 }
1139 }
1140
1141 fn set_dash_array(&mut self, array: &[PdfPoints], phase: PdfPoints) -> Result<(), PdfiumError> {
1142 let dash_array = array.iter().map(|dash| dash.value).collect::<Vec<_>>();
1143
1144 if self
1145 .bindings()
1146 .is_true(self.bindings().FPDFPageObj_SetDashArray(
1147 self.object_handle(),
1148 dash_array.as_ptr(),
1149 dash_array.len(),
1150 phase.value,
1151 ))
1152 {
1153 Ok(())
1154 } else {
1155 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1156 }
1157 }
1158
1159 #[inline]
1160 fn is_copyable(&self) -> bool {
1161 self.is_copyable_impl()
1162 }
1163
1164 #[inline]
1165 fn try_copy<'b>(
1166 &self,
1167 document: &'b PdfDocument<'b>,
1168 ) -> Result<PdfPageObject<'b>, PdfiumError> {
1169 self.try_copy_impl(document.handle(), document.bindings())
1170 }
1171
1172 #[inline]
1173 fn copy_to_page<'b>(
1174 &mut self,
1175 page: &mut PdfPage<'b>,
1176 ) -> Result<PdfPageObject<'b>, PdfiumError> {
1177 self.copy_to_page_impl(page)
1178 }
1179
1180 fn move_to_page(&mut self, page: &mut PdfPage) -> Result<(), PdfiumError> {
1181 match self.ownership() {
1182 PdfPageObjectOwnership::Document(ownership) => {
1183 if ownership.document_handle() != page.document_handle() {
1184 return Err(PdfiumError::CannotMoveObjectAcrossDocuments);
1185 }
1186 }
1187 PdfPageObjectOwnership::Page(_) => self.remove_object_from_page()?,
1188 PdfPageObjectOwnership::AttachedAnnotation(_)
1189 | PdfPageObjectOwnership::UnattachedAnnotation(_) => {
1190 self.remove_object_from_annotation()?
1191 }
1192 PdfPageObjectOwnership::Unowned => {}
1193 }
1194
1195 self.add_object_to_page(page.objects_mut())
1196 }
1197
1198 fn move_to_annotation(
1199 &mut self,
1200 annotation: &mut PdfPageAnnotation,
1201 ) -> Result<(), PdfiumError> {
1202 match self.ownership() {
1203 PdfPageObjectOwnership::Document(ownership) => {
1204 let annotation_document_handle = match annotation.ownership() {
1205 PdfPageObjectOwnership::Document(ownership) => {
1206 Some(ownership.document_handle())
1207 }
1208 PdfPageObjectOwnership::Page(ownership) => Some(ownership.document_handle()),
1209 PdfPageObjectOwnership::AttachedAnnotation(ownership) => {
1210 Some(ownership.document_handle())
1211 }
1212 PdfPageObjectOwnership::UnattachedAnnotation(_)
1213 | PdfPageObjectOwnership::Unowned => None,
1214 };
1215
1216 if let Some(annotation_document_handle) = annotation_document_handle {
1217 if ownership.document_handle() != annotation_document_handle {
1218 return Err(PdfiumError::CannotMoveObjectAcrossDocuments);
1219 }
1220 }
1221 }
1222 PdfPageObjectOwnership::Page(_) => self.remove_object_from_page()?,
1223 PdfPageObjectOwnership::AttachedAnnotation(_)
1224 | PdfPageObjectOwnership::UnattachedAnnotation(_) => {
1225 self.remove_object_from_annotation()?
1226 }
1227 PdfPageObjectOwnership::Unowned => {}
1228 }
1229
1230 self.add_object_to_annotation(annotation.objects())
1231 }
1232}
1233
1234impl<'a> PdfPageObjectPrivate<'a> for PdfPageObject<'a> {
1235 #[inline]
1236 fn bindings(&self) -> &dyn PdfiumLibraryBindings {
1237 self.unwrap_as_trait().bindings()
1238 }
1239
1240 #[inline]
1241 fn object_handle(&self) -> FPDF_PAGEOBJECT {
1242 self.unwrap_as_trait().object_handle()
1243 }
1244
1245 #[inline]
1246 fn ownership(&self) -> &PdfPageObjectOwnership {
1247 self.unwrap_as_trait().ownership()
1248 }
1249
1250 #[inline]
1251 fn set_ownership(&mut self, ownership: PdfPageObjectOwnership) {
1252 self.unwrap_as_trait_mut().set_ownership(ownership);
1253 }
1254
1255 #[inline]
1256 fn add_object_to_page(&mut self, page_objects: &mut PdfPageObjects) -> Result<(), PdfiumError> {
1257 self.unwrap_as_trait_mut().add_object_to_page(page_objects)
1258 }
1259
1260 #[cfg(any(feature = "pdfium_future", feature = "pdfium_7350"))]
1261 #[inline]
1262 fn insert_object_on_page(
1263 &mut self,
1264 page_objects: &mut PdfPageObjects,
1265 index: PdfPageObjectIndex,
1266 ) -> Result<(), PdfiumError> {
1267 self.unwrap_as_trait_mut()
1268 .insert_object_on_page(page_objects, index)
1269 }
1270
1271 #[inline]
1272 fn remove_object_from_page(&mut self) -> Result<(), PdfiumError> {
1273 self.unwrap_as_trait_mut().remove_object_from_page()
1274 }
1275
1276 #[inline]
1277 fn add_object_to_annotation(
1278 &mut self,
1279 annotation_objects: &PdfPageAnnotationObjects,
1280 ) -> Result<(), PdfiumError> {
1281 self.unwrap_as_trait_mut()
1282 .add_object_to_annotation(annotation_objects)
1283 }
1284
1285 #[inline]
1286 fn remove_object_from_annotation(&mut self) -> Result<(), PdfiumError> {
1287 self.unwrap_as_trait_mut().remove_object_from_annotation()
1288 }
1289
1290 #[inline]
1291 fn is_copyable_impl(&self) -> bool {
1292 self.unwrap_as_trait().is_copyable_impl()
1293 }
1294
1295 #[inline]
1296 fn try_copy_impl<'b>(
1297 &self,
1298 document: FPDF_DOCUMENT,
1299 bindings: &'b dyn PdfiumLibraryBindings,
1300 ) -> Result<PdfPageObject<'b>, PdfiumError> {
1301 self.unwrap_as_trait().try_copy_impl(document, bindings)
1302 }
1303
1304 #[inline]
1305 fn copy_to_page_impl<'b>(
1306 &mut self,
1307 page: &mut PdfPage<'b>,
1308 ) -> Result<PdfPageObject<'b>, PdfiumError> {
1309 self.unwrap_as_trait_mut().copy_to_page_impl(page)
1310 }
1311}
1312
1313impl<'a> From<PdfPageXObjectFormObject<'a>> for PdfPageObject<'a> {
1314 #[inline]
1315 fn from(object: PdfPageXObjectFormObject<'a>) -> Self {
1316 Self::XObjectForm(object)
1317 }
1318}
1319
1320impl<'a> From<PdfPageImageObject<'a>> for PdfPageObject<'a> {
1321 #[inline]
1322 fn from(object: PdfPageImageObject<'a>) -> Self {
1323 Self::Image(object)
1324 }
1325}
1326
1327impl<'a> From<PdfPagePathObject<'a>> for PdfPageObject<'a> {
1328 #[inline]
1329 fn from(object: PdfPagePathObject<'a>) -> Self {
1330 Self::Path(object)
1331 }
1332}
1333
1334impl<'a> From<PdfPageShadingObject<'a>> for PdfPageObject<'a> {
1335 #[inline]
1336 fn from(object: PdfPageShadingObject<'a>) -> Self {
1337 Self::Shading(object)
1338 }
1339}
1340
1341impl<'a> From<PdfPageTextObject<'a>> for PdfPageObject<'a> {
1342 #[inline]
1343 fn from(object: PdfPageTextObject<'a>) -> Self {
1344 Self::Text(object)
1345 }
1346}
1347
1348impl<'a> From<PdfPageUnsupportedObject<'a>> for PdfPageObject<'a> {
1349 #[inline]
1350 fn from(object: PdfPageUnsupportedObject<'a>) -> Self {
1351 Self::Unsupported(object)
1352 }
1353}
1354
1355impl<'a> Drop for PdfPageObject<'a> {
1356 #[inline]
1358 fn drop(&mut self) {
1359 if !self.ownership().is_owned() {
1370 self.bindings().FPDFPageObj_Destroy(self.object_handle());
1371 }
1372 }
1373}
1374
1375#[cfg(test)]
1376mod tests {
1377 use crate::prelude::*;
1378 use crate::utils::test::test_bind_to_pdfium;
1379
1380 #[test]
1381 fn test_apply_matrix() -> Result<(), PdfiumError> {
1382 let pdfium = test_bind_to_pdfium();
1383
1384 let mut document = pdfium.create_new_pdf()?;
1385
1386 let mut page = document
1387 .pages_mut()
1388 .create_page_at_start(PdfPagePaperSize::a4())?;
1389
1390 let font = document.fonts_mut().times_roman();
1391
1392 let mut object = page.objects_mut().create_text_object(
1393 PdfPoints::ZERO,
1394 PdfPoints::ZERO,
1395 "My new text object",
1396 font,
1397 PdfPoints::new(10.0),
1398 )?;
1399
1400 object.translate(PdfPoints::new(100.0), PdfPoints::new(100.0))?;
1403 object.flip_vertically()?;
1404 object.rotate_clockwise_degrees(45.0)?;
1405 object.scale(3.0, 4.0)?;
1406
1407 let previous_matrix = object.matrix()?;
1408
1409 object.apply_matrix(PdfMatrix::IDENTITY)?;
1412
1413 assert_eq!(previous_matrix, object.matrix()?);
1414
1415 Ok(())
1416 }
1417
1418 #[test]
1419 fn test_reset_matrix_to_identity() -> Result<(), PdfiumError> {
1420 let pdfium = test_bind_to_pdfium();
1421
1422 let mut document = pdfium.create_new_pdf()?;
1423
1424 let mut page = document
1425 .pages_mut()
1426 .create_page_at_start(PdfPagePaperSize::a4())?;
1427
1428 let font = document.fonts_mut().times_roman();
1429
1430 let mut object = page.objects_mut().create_text_object(
1431 PdfPoints::ZERO,
1432 PdfPoints::ZERO,
1433 "My new text object",
1434 font,
1435 PdfPoints::new(10.0),
1436 )?;
1437
1438 object.translate(PdfPoints::new(100.0), PdfPoints::new(100.0))?;
1441 object.flip_vertically()?;
1442 object.rotate_clockwise_degrees(45.0)?;
1443 object.scale(3.0, 4.0)?;
1444
1445 let previous_matrix = object.matrix()?;
1446
1447 object.reset_matrix_to_identity()?;
1451
1452 assert_ne!(previous_matrix, object.matrix()?);
1453 assert_eq!(object.matrix()?, PdfMatrix::IDENTITY);
1454
1455 Ok(())
1456 }
1457
1458 #[test]
1459 fn test_transform_captured_in_content_regeneration() -> Result<(), PdfiumError> {
1460 let pdfium = test_bind_to_pdfium();
1466
1467 let mut document = pdfium.create_new_pdf()?;
1468
1469 let x = PdfPoints::new(100.0);
1470 let y = PdfPoints::new(400.0);
1471
1472 let object_matrix_before_rotation = {
1473 let mut page = document
1474 .pages_mut()
1475 .create_page_at_start(PdfPagePaperSize::a4())?;
1476
1477 let font = document
1478 .fonts_mut()
1479 .new_built_in(PdfFontBuiltin::TimesRoman);
1480
1481 let mut object = page.objects_mut().create_text_object(
1482 x,
1483 y,
1484 "Hello world!",
1485 font,
1486 PdfPoints::new(20.0),
1487 )?;
1488
1489 let object_matrix_before_rotation = object.matrix()?;
1490
1491 object.rotate_clockwise_degrees(45.0)?;
1495
1496 object_matrix_before_rotation
1497 };
1498
1499 assert_eq!(
1505 object_matrix_before_rotation.rotate_clockwise_degrees(45.0)?,
1506 document.pages().first()?.objects().first()?.matrix()?
1507 );
1508
1509 Ok(())
1510 }
1511}