1pub(crate) mod content_mark;
4pub(crate) mod content_marks;
5pub(crate) mod group;
6pub(crate) mod image;
7pub(crate) mod ownership;
8pub(crate) mod path;
9pub(crate) mod private;
10pub(crate) mod shading;
11pub(crate) mod text;
12pub(crate) mod unsupported;
13pub(crate) mod x_object_form;
14
15use crate::bindgen::{
16 FPDF_DOCUMENT, FPDF_LINECAP_BUTT, FPDF_LINECAP_PROJECTING_SQUARE, FPDF_LINECAP_ROUND, FPDF_LINEJOIN_BEVEL,
17 FPDF_LINEJOIN_MITER, FPDF_LINEJOIN_ROUND, FPDF_PAGEOBJ_FORM, FPDF_PAGEOBJ_IMAGE, FPDF_PAGEOBJ_PATH,
18 FPDF_PAGEOBJ_SHADING, FPDF_PAGEOBJ_TEXT, FPDF_PAGEOBJ_UNKNOWN, FPDF_PAGEOBJECT,
19};
20use crate::bindings::PdfiumLibraryBindings;
21use crate::error::PdfiumError;
22use crate::pdf::color::PdfColor;
23use crate::pdf::document::PdfDocument;
24use crate::pdf::document::page::annotation::objects::PdfPageAnnotationObjects;
25use crate::pdf::document::page::annotation::private::internal::PdfPageAnnotationPrivate;
26use crate::pdf::document::page::annotation::{PdfPageAnnotation, PdfPageAnnotationCommon};
27use crate::pdf::document::page::object::content_marks::PdfPageObjectContentMarks;
28use crate::pdf::document::page::object::image::PdfPageImageObject;
29use crate::pdf::document::page::object::path::PdfPagePathObject;
30use crate::pdf::document::page::object::private::internal::PdfPageObjectPrivate;
31use crate::pdf::document::page::object::shading::PdfPageShadingObject;
32use crate::pdf::document::page::object::text::PdfPageTextObject;
33use crate::pdf::document::page::object::unsupported::PdfPageUnsupportedObject;
34use crate::pdf::document::page::object::x_object_form::PdfPageXObjectFormObject;
35use crate::pdf::document::page::objects::PdfPageObjects;
36use crate::pdf::document::page::{PdfPage, PdfPageObjectOwnership};
37use crate::pdf::matrix::{PdfMatrix, PdfMatrixValue};
38use crate::pdf::path::clip_path::PdfClipPath;
39use crate::pdf::points::PdfPoints;
40use crate::pdf::quad_points::PdfQuadPoints;
41use crate::pdf::rect::PdfRect;
42use crate::{create_transform_getters, create_transform_setters};
43use std::convert::TryInto;
44use std::os::raw::{c_int, c_uint};
45
46use crate::error::PdfiumInternalError;
47
48#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Eq, Hash)]
55pub enum PdfPageObjectType {
56 Unsupported = FPDF_PAGEOBJ_UNKNOWN as isize,
58
59 Text = FPDF_PAGEOBJ_TEXT as isize,
61
62 Path = FPDF_PAGEOBJ_PATH as isize,
64
65 Image = FPDF_PAGEOBJ_IMAGE as isize,
67
68 Shading = FPDF_PAGEOBJ_SHADING as isize,
71
72 XObjectForm = FPDF_PAGEOBJ_FORM as isize,
79}
80
81impl PdfPageObjectType {
82 pub(crate) fn from_pdfium(value: u32) -> Result<PdfPageObjectType, PdfiumError> {
83 match value {
84 FPDF_PAGEOBJ_UNKNOWN => Ok(PdfPageObjectType::Unsupported),
85 FPDF_PAGEOBJ_TEXT => Ok(PdfPageObjectType::Text),
86 FPDF_PAGEOBJ_PATH => Ok(PdfPageObjectType::Path),
87 FPDF_PAGEOBJ_IMAGE => Ok(PdfPageObjectType::Image),
88 FPDF_PAGEOBJ_SHADING => Ok(PdfPageObjectType::Shading),
89 FPDF_PAGEOBJ_FORM => Ok(PdfPageObjectType::XObjectForm),
90 _ => Err(PdfiumError::UnknownPdfPageObjectType),
91 }
92 }
93}
94
95#[derive(Debug, Copy, Clone, PartialEq)]
104pub enum PdfPageObjectBlendMode {
105 Normal,
107
108 Multiply,
114
115 Screen,
123
124 Overlay,
129
130 Darken,
133
134 Lighten,
137
138 ColorDodge,
141
142 ColorBurn,
145
146 HardLight,
149
150 SoftLight,
153
154 Difference,
157
158 Exclusion,
161
162 HSLColor,
165
166 HSLHue,
169
170 HSLLuminosity,
173
174 HSLSaturation,
177}
178
179impl PdfPageObjectBlendMode {
180 pub(crate) fn as_pdfium(&self) -> &str {
181 match self {
182 PdfPageObjectBlendMode::HSLColor => "Color",
183 PdfPageObjectBlendMode::ColorBurn => "ColorBurn",
184 PdfPageObjectBlendMode::ColorDodge => "ColorDodge",
185 PdfPageObjectBlendMode::Darken => "Darken",
186 PdfPageObjectBlendMode::Difference => "Difference",
187 PdfPageObjectBlendMode::Exclusion => "Exclusion",
188 PdfPageObjectBlendMode::HardLight => "HardLight",
189 PdfPageObjectBlendMode::HSLHue => "Hue",
190 PdfPageObjectBlendMode::Lighten => "Lighten",
191 PdfPageObjectBlendMode::HSLLuminosity => "Luminosity",
192 PdfPageObjectBlendMode::Multiply => "Multiply",
193 PdfPageObjectBlendMode::Normal => "Normal",
194 PdfPageObjectBlendMode::Overlay => "Overlay",
195 PdfPageObjectBlendMode::HSLSaturation => "Saturation",
196 PdfPageObjectBlendMode::Screen => "Screen",
197 PdfPageObjectBlendMode::SoftLight => "SoftLight",
198 }
199 }
200}
201
202#[derive(Debug, Copy, Clone, PartialEq)]
210pub enum PdfPageObjectLineJoin {
211 Miter = FPDF_LINEJOIN_MITER as isize,
215
216 Round = FPDF_LINEJOIN_ROUND as isize,
221
222 Bevel = FPDF_LINEJOIN_BEVEL as isize,
225}
226
227impl PdfPageObjectLineJoin {
228 pub(crate) fn from_pdfium(value: c_int) -> Option<Self> {
229 match value as u32 {
230 FPDF_LINEJOIN_MITER => Some(Self::Miter),
231 FPDF_LINEJOIN_ROUND => Some(Self::Round),
232 FPDF_LINEJOIN_BEVEL => Some(Self::Bevel),
233 _ => None,
234 }
235 }
236
237 pub(crate) fn as_pdfium(&self) -> u32 {
238 match self {
239 PdfPageObjectLineJoin::Miter => FPDF_LINEJOIN_MITER,
240 PdfPageObjectLineJoin::Round => FPDF_LINEJOIN_ROUND,
241 PdfPageObjectLineJoin::Bevel => FPDF_LINEJOIN_BEVEL,
242 }
243 }
244}
245
246#[derive(Debug, Copy, Clone, PartialEq)]
251pub enum PdfPageObjectLineCap {
252 Butt = FPDF_LINECAP_BUTT as isize,
255
256 Round = FPDF_LINECAP_ROUND as isize,
259
260 Square = FPDF_LINECAP_PROJECTING_SQUARE as isize,
263}
264
265impl PdfPageObjectLineCap {
266 pub(crate) fn from_pdfium(value: c_int) -> Option<Self> {
267 match value as u32 {
268 FPDF_LINECAP_BUTT => Some(Self::Butt),
269 FPDF_LINECAP_ROUND => Some(Self::Round),
270 FPDF_LINECAP_PROJECTING_SQUARE => Some(Self::Square),
271 _ => None,
272 }
273 }
274
275 pub(crate) fn as_pdfium(&self) -> u32 {
276 match self {
277 PdfPageObjectLineCap::Butt => FPDF_LINECAP_BUTT,
278 PdfPageObjectLineCap::Round => FPDF_LINECAP_ROUND,
279 PdfPageObjectLineCap::Square => FPDF_LINECAP_PROJECTING_SQUARE,
280 }
281 }
282}
283
284pub enum PdfPageObject<'a> {
286 Text(PdfPageTextObject<'a>),
288
289 Path(PdfPagePathObject<'a>),
291
292 Image(PdfPageImageObject<'a>),
294
295 Shading(PdfPageShadingObject<'a>),
298
299 XObjectForm(PdfPageXObjectFormObject<'a>),
306
307 Unsupported(PdfPageUnsupportedObject<'a>),
313}
314
315impl<'a> PdfPageObject<'a> {
316 pub(crate) fn from_pdfium(
317 object_handle: FPDF_PAGEOBJECT,
318 ownership: PdfPageObjectOwnership,
319 bindings: &'a dyn PdfiumLibraryBindings,
320 ) -> Self {
321 match PdfPageObjectType::from_pdfium(bindings.FPDFPageObj_GetType(object_handle) as u32)
322 .unwrap_or(PdfPageObjectType::Unsupported)
323 {
324 PdfPageObjectType::Unsupported => PdfPageObject::Unsupported(PdfPageUnsupportedObject::from_pdfium(
325 object_handle,
326 ownership,
327 bindings,
328 )),
329 PdfPageObjectType::Text => {
330 PdfPageObject::Text(PdfPageTextObject::from_pdfium(object_handle, ownership, bindings))
331 }
332 PdfPageObjectType::Path => {
333 PdfPageObject::Path(PdfPagePathObject::from_pdfium(object_handle, ownership, bindings))
334 }
335 PdfPageObjectType::Image => {
336 PdfPageObject::Image(PdfPageImageObject::from_pdfium(object_handle, ownership, bindings))
337 }
338 PdfPageObjectType::Shading => {
339 PdfPageObject::Shading(PdfPageShadingObject::from_pdfium(object_handle, ownership, bindings))
340 }
341 PdfPageObjectType::XObjectForm => PdfPageObject::XObjectForm(PdfPageXObjectFormObject::from_pdfium(
342 object_handle,
343 ownership,
344 bindings,
345 )),
346 }
347 }
348
349 #[inline]
350 pub(crate) fn unwrap_as_trait(&self) -> &dyn PdfPageObjectPrivate<'a> {
351 match self {
352 PdfPageObject::Text(object) => object,
353 PdfPageObject::Path(object) => object,
354 PdfPageObject::Image(object) => object,
355 PdfPageObject::Shading(object) => object,
356 PdfPageObject::XObjectForm(object) => object,
357 PdfPageObject::Unsupported(object) => object,
358 }
359 }
360
361 #[inline]
362 pub(crate) fn unwrap_as_trait_mut(&mut self) -> &mut dyn PdfPageObjectPrivate<'a> {
363 match self {
364 PdfPageObject::Text(object) => object,
365 PdfPageObject::Path(object) => object,
366 PdfPageObject::Image(object) => object,
367 PdfPageObject::Shading(object) => object,
368 PdfPageObject::XObjectForm(object) => object,
369 PdfPageObject::Unsupported(object) => object,
370 }
371 }
372
373 #[inline]
380 pub fn object_type(&self) -> PdfPageObjectType {
381 match self {
382 PdfPageObject::Text(_) => PdfPageObjectType::Text,
383 PdfPageObject::Path(_) => PdfPageObjectType::Path,
384 PdfPageObject::Image(_) => PdfPageObjectType::Image,
385 PdfPageObject::Shading(_) => PdfPageObjectType::Shading,
386 PdfPageObject::XObjectForm(_) => PdfPageObjectType::XObjectForm,
387 PdfPageObject::Unsupported(_) => PdfPageObjectType::Unsupported,
388 }
389 }
390
391 #[inline]
397 pub fn is_supported(&self) -> bool {
398 !self.is_unsupported()
399 }
400
401 #[inline]
407 pub fn is_unsupported(&self) -> bool {
408 self.object_type() == PdfPageObjectType::Unsupported
409 }
410
411 #[inline]
414 pub fn as_text_object(&self) -> Option<&PdfPageTextObject<'_>> {
415 match self {
416 PdfPageObject::Text(object) => Some(object),
417 _ => None,
418 }
419 }
420
421 #[inline]
424 pub fn as_text_object_mut(&mut self) -> Option<&mut PdfPageTextObject<'a>> {
425 match self {
426 PdfPageObject::Text(object) => Some(object),
427 _ => None,
428 }
429 }
430
431 #[inline]
434 pub fn as_path_object(&self) -> Option<&PdfPagePathObject<'_>> {
435 match self {
436 PdfPageObject::Path(object) => Some(object),
437 _ => None,
438 }
439 }
440
441 #[inline]
444 pub fn as_path_object_mut(&mut self) -> Option<&mut PdfPagePathObject<'a>> {
445 match self {
446 PdfPageObject::Path(object) => Some(object),
447 _ => None,
448 }
449 }
450
451 #[inline]
454 pub fn as_image_object(&self) -> Option<&PdfPageImageObject<'_>> {
455 match self {
456 PdfPageObject::Image(object) => Some(object),
457 _ => None,
458 }
459 }
460
461 #[inline]
464 pub fn as_image_object_mut(&mut self) -> Option<&mut PdfPageImageObject<'a>> {
465 match self {
466 PdfPageObject::Image(object) => Some(object),
467 _ => None,
468 }
469 }
470
471 #[inline]
474 pub fn as_shading_object(&self) -> Option<&PdfPageShadingObject<'_>> {
475 match self {
476 PdfPageObject::Shading(object) => Some(object),
477 _ => None,
478 }
479 }
480
481 #[inline]
484 pub fn as_shading_object_mut(&mut self) -> Option<&mut PdfPageShadingObject<'a>> {
485 match self {
486 PdfPageObject::Shading(object) => Some(object),
487 _ => None,
488 }
489 }
490
491 #[inline]
494 pub fn as_x_object_form_object(&self) -> Option<&PdfPageXObjectFormObject<'_>> {
495 match self {
496 PdfPageObject::XObjectForm(object) => Some(object),
497 _ => None,
498 }
499 }
500
501 #[inline]
504 pub fn as_x_object_form_object_mut(&mut self) -> Option<&mut PdfPageXObjectFormObject<'a>> {
505 match self {
506 PdfPageObject::XObjectForm(object) => Some(object),
507 _ => None,
508 }
509 }
510
511 pub fn get_clip_path(&self) -> Option<PdfClipPath<'_>> {
513 let path_handle = self.bindings().FPDFPageObj_GetClipPath(self.object_handle());
514
515 if path_handle.is_null() {
516 return None;
517 }
518
519 Some(PdfClipPath::from_pdfium(
520 path_handle,
521 *self.ownership(),
522 self.bindings(),
523 ))
524 }
525
526 pub fn set_active(&mut self) -> Result<(), PdfiumError> {
529 if self.bindings().is_true(
530 self.bindings()
531 .FPDFPageObj_SetIsActive(self.object_handle(), self.bindings().TRUE()),
532 ) {
533 Ok(())
534 } else {
535 Err(PdfiumError::PdfiumLibraryInternalError(PdfiumInternalError::Unknown))
536 }
537 }
538
539 pub fn is_active(&self) -> Result<bool, PdfiumError> {
541 let mut result = self.bindings().FALSE();
542
543 if self.bindings().is_true(
544 self.bindings()
545 .FPDFPageObj_GetIsActive(self.object_handle(), &mut result),
546 ) {
547 Ok(self.bindings().is_true(result))
548 } else {
549 Err(PdfiumError::PdfiumLibraryInternalError(PdfiumInternalError::Unknown))
550 }
551 }
552
553 pub fn set_inactive(&mut self) -> Result<(), PdfiumError> {
556 if self.bindings().is_true(
557 self.bindings()
558 .FPDFPageObj_SetIsActive(self.object_handle(), self.bindings().FALSE()),
559 ) {
560 Ok(())
561 } else {
562 Err(PdfiumError::PdfiumLibraryInternalError(PdfiumInternalError::Unknown))
563 }
564 }
565
566 #[inline]
568 pub fn is_inactive(&self) -> Result<bool, PdfiumError> {
569 self.is_active().map(|result| !result)
570 }
571
572 create_transform_setters!(
573 &mut Self,
574 Result<(), PdfiumError>,
575 "this [PdfPageObject]",
576 "this [PdfPageObject].",
577 "this [PdfPageObject],"
578 );
579
580 create_transform_getters!("this [PdfPageObject]", "this [PdfPageObject].", "this [PdfPageObject],");
581}
582
583pub trait PdfPageObjectCommon<'a> {
585 fn has_transparency(&self) -> bool;
587
588 fn bounds(&self) -> Result<PdfQuadPoints, PdfiumError>;
595
596 #[inline]
598 fn width(&self) -> Result<PdfPoints, PdfiumError> {
599 Ok(self.bounds()?.width())
600 }
601
602 #[inline]
604 fn height(&self) -> Result<PdfPoints, PdfiumError> {
605 Ok(self.bounds()?.height())
606 }
607
608 #[inline]
610 fn is_inside_rect(&self, rect: &PdfRect) -> bool {
611 self.bounds()
612 .map(|bounds| bounds.to_rect().is_inside(rect))
613 .unwrap_or(false)
614 }
615
616 #[inline]
619 fn does_overlap_rect(&self, rect: &PdfRect) -> bool {
620 self.bounds()
621 .map(|bounds| bounds.to_rect().does_overlap(rect))
622 .unwrap_or(false)
623 }
624
625 fn transform_from(&mut self, other: &PdfPageObject) -> Result<(), PdfiumError>;
630
631 fn set_blend_mode(&mut self, blend_mode: PdfPageObjectBlendMode) -> Result<(), PdfiumError>;
635
636 fn fill_color(&self) -> Result<PdfColor, PdfiumError>;
638
639 fn set_fill_color(&mut self, fill_color: PdfColor) -> Result<(), PdfiumError>;
641
642 fn stroke_color(&self) -> Result<PdfColor, PdfiumError>;
644
645 fn set_stroke_color(&mut self, stroke_color: PdfColor) -> Result<(), PdfiumError>;
650
651 fn stroke_width(&self) -> Result<PdfPoints, PdfiumError>;
653
654 fn set_stroke_width(&mut self, stroke_width: PdfPoints) -> Result<(), PdfiumError>;
664
665 fn line_join(&self) -> Result<PdfPageObjectLineJoin, PdfiumError>;
668
669 fn set_line_join(&mut self, line_join: PdfPageObjectLineJoin) -> Result<(), PdfiumError>;
672
673 fn line_cap(&self) -> Result<PdfPageObjectLineCap, PdfiumError>;
676
677 fn set_line_cap(&mut self, line_cap: PdfPageObjectLineCap) -> Result<(), PdfiumError>;
680
681 fn dash_phase(&self) -> Result<PdfPoints, PdfiumError>;
697
698 fn set_dash_phase(&mut self, dash_phase: PdfPoints) -> Result<(), PdfiumError>;
714
715 fn dash_array(&self) -> Result<Vec<PdfPoints>, PdfiumError>;
731
732 fn set_dash_array(&mut self, array: &[PdfPoints], phase: PdfPoints) -> Result<(), PdfiumError>;
748
749 #[deprecated(
750 since = "0.8.32",
751 note = "This function has been retired in favour of the PdfPageObject::copy_to_page() function."
752 )]
753 fn is_copyable(&self) -> bool;
772
773 #[deprecated(
774 since = "0.8.32",
775 note = "This function has been retired in favour of the PdfPageObject::copy_to_page() function."
776 )]
777 fn try_copy<'b>(&self, document: &'b PdfDocument<'b>) -> Result<PdfPageObject<'b>, PdfiumError>;
799
800 fn copy_to_page<'b>(&mut self, page: &mut PdfPage<'b>) -> Result<PdfPageObject<'b>, PdfiumError>;
804
805 fn move_to_page(&mut self, page: &mut PdfPage) -> Result<(), PdfiumError>;
812
813 fn move_to_annotation(&mut self, annotation: &mut PdfPageAnnotation) -> Result<(), PdfiumError>;
820
821 fn marked_content_id(&self) -> Option<i32>;
827
828 fn content_marks(&self) -> PdfPageObjectContentMarks<'_>;
834}
835
836impl<'a, T> PdfPageObjectCommon<'a> for T
837where
838 T: PdfPageObjectPrivate<'a>,
839{
840 #[inline]
841 fn has_transparency(&self) -> bool {
842 self.has_transparency_impl()
843 }
844
845 #[inline]
846 fn bounds(&self) -> Result<PdfQuadPoints, PdfiumError> {
847 self.bounds_impl()
848 }
849
850 #[inline]
851 fn transform_from(&mut self, other: &PdfPageObject) -> Result<(), PdfiumError> {
852 self.reset_matrix_impl(other.matrix()?)
853 }
854
855 #[inline]
856 fn set_blend_mode(&mut self, blend_mode: PdfPageObjectBlendMode) -> Result<(), PdfiumError> {
857 self.bindings()
858 .FPDFPageObj_SetBlendMode(self.object_handle(), blend_mode.as_pdfium());
859
860 Ok(())
861 }
862
863 #[inline]
864 fn fill_color(&self) -> Result<PdfColor, PdfiumError> {
865 let mut r = 0;
866
867 let mut g = 0;
868
869 let mut b = 0;
870
871 let mut a = 0;
872
873 if self.bindings().is_true(self.bindings().FPDFPageObj_GetFillColor(
874 self.object_handle(),
875 &mut r,
876 &mut g,
877 &mut b,
878 &mut a,
879 )) {
880 Ok(PdfColor::new(
881 r.try_into()
882 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
883 g.try_into()
884 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
885 b.try_into()
886 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
887 a.try_into()
888 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
889 ))
890 } else {
891 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
892 }
893 }
894
895 #[inline]
896 fn set_fill_color(&mut self, fill_color: PdfColor) -> Result<(), PdfiumError> {
897 if self.bindings().is_true(self.bindings().FPDFPageObj_SetFillColor(
898 self.object_handle(),
899 fill_color.red() as c_uint,
900 fill_color.green() as c_uint,
901 fill_color.blue() as c_uint,
902 fill_color.alpha() as c_uint,
903 )) {
904 Ok(())
905 } else {
906 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
907 }
908 }
909
910 #[inline]
911 fn stroke_color(&self) -> Result<PdfColor, PdfiumError> {
912 let mut r = 0;
913
914 let mut g = 0;
915
916 let mut b = 0;
917
918 let mut a = 0;
919
920 if self.bindings().is_true(self.bindings().FPDFPageObj_GetStrokeColor(
921 self.object_handle(),
922 &mut r,
923 &mut g,
924 &mut b,
925 &mut a,
926 )) {
927 Ok(PdfColor::new(
928 r.try_into()
929 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
930 g.try_into()
931 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
932 b.try_into()
933 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
934 a.try_into()
935 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
936 ))
937 } else {
938 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
939 }
940 }
941
942 #[inline]
943 fn set_stroke_color(&mut self, stroke_color: PdfColor) -> Result<(), PdfiumError> {
944 if self.bindings().is_true(self.bindings().FPDFPageObj_SetStrokeColor(
945 self.object_handle(),
946 stroke_color.red() as c_uint,
947 stroke_color.green() as c_uint,
948 stroke_color.blue() as c_uint,
949 stroke_color.alpha() as c_uint,
950 )) {
951 Ok(())
952 } else {
953 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
954 }
955 }
956
957 #[inline]
958 fn stroke_width(&self) -> Result<PdfPoints, PdfiumError> {
959 let mut width = 0.0;
960
961 if self.bindings().is_true(
962 self.bindings()
963 .FPDFPageObj_GetStrokeWidth(self.object_handle(), &mut width),
964 ) {
965 Ok(PdfPoints::new(width))
966 } else {
967 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
968 }
969 }
970
971 #[inline]
972 fn set_stroke_width(&mut self, stroke_width: PdfPoints) -> Result<(), PdfiumError> {
973 if self.bindings().is_true(
974 self.bindings()
975 .FPDFPageObj_SetStrokeWidth(self.object_handle(), stroke_width.value),
976 ) {
977 Ok(())
978 } else {
979 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
980 }
981 }
982
983 #[inline]
984 fn line_join(&self) -> Result<PdfPageObjectLineJoin, PdfiumError> {
985 PdfPageObjectLineJoin::from_pdfium(self.bindings().FPDFPageObj_GetLineJoin(self.object_handle()))
986 .ok_or(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
987 }
988
989 #[inline]
990 fn set_line_join(&mut self, line_join: PdfPageObjectLineJoin) -> Result<(), PdfiumError> {
991 if self.bindings().is_true(
992 self.bindings()
993 .FPDFPageObj_SetLineJoin(self.object_handle(), line_join.as_pdfium() as c_int),
994 ) {
995 Ok(())
996 } else {
997 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
998 }
999 }
1000
1001 #[inline]
1002 fn line_cap(&self) -> Result<PdfPageObjectLineCap, PdfiumError> {
1003 PdfPageObjectLineCap::from_pdfium(self.bindings().FPDFPageObj_GetLineCap(self.object_handle()))
1004 .ok_or(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1005 }
1006
1007 #[inline]
1008 fn set_line_cap(&mut self, line_cap: PdfPageObjectLineCap) -> Result<(), PdfiumError> {
1009 if self.bindings().is_true(
1010 self.bindings()
1011 .FPDFPageObj_SetLineCap(self.object_handle(), line_cap.as_pdfium() as c_int),
1012 ) {
1013 Ok(())
1014 } else {
1015 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1016 }
1017 }
1018
1019 #[inline]
1020 fn dash_phase(&self) -> Result<PdfPoints, PdfiumError> {
1021 let mut phase = 0.0;
1022
1023 if self.bindings().is_true(
1024 self.bindings()
1025 .FPDFPageObj_GetDashPhase(self.object_handle(), &mut phase),
1026 ) {
1027 Ok(PdfPoints::new(phase))
1028 } else {
1029 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1030 }
1031 }
1032
1033 #[inline]
1034 fn set_dash_phase(&mut self, dash_phase: PdfPoints) -> Result<(), PdfiumError> {
1035 if self.bindings().is_true(
1036 self.bindings()
1037 .FPDFPageObj_SetDashPhase(self.object_handle(), dash_phase.value),
1038 ) {
1039 Ok(())
1040 } else {
1041 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1042 }
1043 }
1044
1045 #[inline]
1046 fn dash_array(&self) -> Result<Vec<PdfPoints>, PdfiumError> {
1047 let dash_count = self.bindings().FPDFPageObj_GetDashCount(self.object_handle()) as usize;
1048
1049 let mut dash_array = vec![0.0; dash_count];
1050
1051 if self.bindings().is_true(self.bindings().FPDFPageObj_GetDashArray(
1052 self.object_handle(),
1053 dash_array.as_mut_ptr(),
1054 dash_count,
1055 )) {
1056 Ok(dash_array.iter().map(|dash| PdfPoints::new(*dash)).collect())
1057 } else {
1058 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1059 }
1060 }
1061
1062 fn set_dash_array(&mut self, array: &[PdfPoints], phase: PdfPoints) -> Result<(), PdfiumError> {
1063 let dash_array = array.iter().map(|dash| dash.value).collect::<Vec<_>>();
1064
1065 if self.bindings().is_true(self.bindings().FPDFPageObj_SetDashArray(
1066 self.object_handle(),
1067 dash_array.as_ptr(),
1068 dash_array.len(),
1069 phase.value,
1070 )) {
1071 Ok(())
1072 } else {
1073 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1074 }
1075 }
1076
1077 #[inline]
1078 fn is_copyable(&self) -> bool {
1079 self.is_copyable_impl()
1080 }
1081
1082 #[inline]
1083 fn try_copy<'b>(&self, document: &'b PdfDocument<'b>) -> Result<PdfPageObject<'b>, PdfiumError> {
1084 self.try_copy_impl(document.handle(), document.bindings())
1085 }
1086
1087 #[inline]
1088 fn copy_to_page<'b>(&mut self, page: &mut PdfPage<'b>) -> Result<PdfPageObject<'b>, PdfiumError> {
1089 self.copy_to_page_impl(page)
1090 }
1091
1092 fn move_to_page(&mut self, page: &mut PdfPage) -> Result<(), PdfiumError> {
1093 match self.ownership() {
1094 PdfPageObjectOwnership::Document(ownership) => {
1095 if ownership.document_handle() != page.document_handle() {
1096 return Err(PdfiumError::CannotMoveObjectAcrossDocuments);
1097 }
1098 }
1099 PdfPageObjectOwnership::Page(_) => self.remove_object_from_page()?,
1100 PdfPageObjectOwnership::AttachedAnnotation(_) | PdfPageObjectOwnership::UnattachedAnnotation(_) => {
1101 self.remove_object_from_annotation()?
1102 }
1103 PdfPageObjectOwnership::Unowned => {}
1104 }
1105
1106 self.add_object_to_page(page.objects_mut())
1107 }
1108
1109 fn move_to_annotation(&mut self, annotation: &mut PdfPageAnnotation) -> Result<(), PdfiumError> {
1110 match self.ownership() {
1111 PdfPageObjectOwnership::Document(ownership) => {
1112 let annotation_document_handle = match annotation.ownership() {
1113 PdfPageObjectOwnership::Document(ownership) => Some(ownership.document_handle()),
1114 PdfPageObjectOwnership::Page(ownership) => Some(ownership.document_handle()),
1115 PdfPageObjectOwnership::AttachedAnnotation(ownership) => Some(ownership.document_handle()),
1116 PdfPageObjectOwnership::UnattachedAnnotation(_) | PdfPageObjectOwnership::Unowned => None,
1117 };
1118
1119 if let Some(annotation_document_handle) = annotation_document_handle
1120 && ownership.document_handle() != annotation_document_handle
1121 {
1122 return Err(PdfiumError::CannotMoveObjectAcrossDocuments);
1123 }
1124 }
1125 PdfPageObjectOwnership::Page(_) => self.remove_object_from_page()?,
1126 PdfPageObjectOwnership::AttachedAnnotation(_) | PdfPageObjectOwnership::UnattachedAnnotation(_) => {
1127 self.remove_object_from_annotation()?
1128 }
1129 PdfPageObjectOwnership::Unowned => {}
1130 }
1131
1132 self.add_object_to_annotation(annotation.objects())
1133 }
1134
1135 #[inline]
1136 fn marked_content_id(&self) -> Option<i32> {
1137 let mcid = self.bindings().FPDFPageObj_GetMarkedContentID(self.object_handle());
1138
1139 if mcid == -1 { None } else { Some(mcid) }
1140 }
1141
1142 #[inline]
1143 fn content_marks(&self) -> PdfPageObjectContentMarks<'_> {
1144 PdfPageObjectContentMarks::from_pdfium(self.object_handle(), self.bindings())
1145 }
1146}
1147
1148impl<'a> PdfPageObjectPrivate<'a> for PdfPageObject<'a> {
1149 #[inline]
1150 fn bindings(&self) -> &dyn PdfiumLibraryBindings {
1151 self.unwrap_as_trait().bindings()
1152 }
1153
1154 #[inline]
1155 fn object_handle(&self) -> FPDF_PAGEOBJECT {
1156 self.unwrap_as_trait().object_handle()
1157 }
1158
1159 #[inline]
1160 fn ownership(&self) -> &PdfPageObjectOwnership {
1161 self.unwrap_as_trait().ownership()
1162 }
1163
1164 #[inline]
1165 fn set_ownership(&mut self, ownership: PdfPageObjectOwnership) {
1166 self.unwrap_as_trait_mut().set_ownership(ownership);
1167 }
1168
1169 #[inline]
1170 fn add_object_to_page(&mut self, page_objects: &mut PdfPageObjects) -> Result<(), PdfiumError> {
1171 self.unwrap_as_trait_mut().add_object_to_page(page_objects)
1172 }
1173
1174 #[inline]
1175 fn remove_object_from_page(&mut self) -> Result<(), PdfiumError> {
1176 self.unwrap_as_trait_mut().remove_object_from_page()
1177 }
1178
1179 #[inline]
1180 fn add_object_to_annotation(&mut self, annotation_objects: &PdfPageAnnotationObjects) -> Result<(), PdfiumError> {
1181 self.unwrap_as_trait_mut().add_object_to_annotation(annotation_objects)
1182 }
1183
1184 #[inline]
1185 fn remove_object_from_annotation(&mut self) -> Result<(), PdfiumError> {
1186 self.unwrap_as_trait_mut().remove_object_from_annotation()
1187 }
1188
1189 #[inline]
1190 fn is_copyable_impl(&self) -> bool {
1191 self.unwrap_as_trait().is_copyable_impl()
1192 }
1193
1194 #[inline]
1195 fn try_copy_impl<'b>(
1196 &self,
1197 document: FPDF_DOCUMENT,
1198 bindings: &'b dyn PdfiumLibraryBindings,
1199 ) -> Result<PdfPageObject<'b>, PdfiumError> {
1200 self.unwrap_as_trait().try_copy_impl(document, bindings)
1201 }
1202
1203 #[inline]
1204 fn copy_to_page_impl<'b>(&mut self, page: &mut PdfPage<'b>) -> Result<PdfPageObject<'b>, PdfiumError> {
1205 self.unwrap_as_trait_mut().copy_to_page_impl(page)
1206 }
1207}
1208
1209impl<'a> From<PdfPageXObjectFormObject<'a>> for PdfPageObject<'a> {
1210 #[inline]
1211 fn from(object: PdfPageXObjectFormObject<'a>) -> Self {
1212 Self::XObjectForm(object)
1213 }
1214}
1215
1216impl<'a> From<PdfPageImageObject<'a>> for PdfPageObject<'a> {
1217 #[inline]
1218 fn from(object: PdfPageImageObject<'a>) -> Self {
1219 Self::Image(object)
1220 }
1221}
1222
1223impl<'a> From<PdfPagePathObject<'a>> for PdfPageObject<'a> {
1224 #[inline]
1225 fn from(object: PdfPagePathObject<'a>) -> Self {
1226 Self::Path(object)
1227 }
1228}
1229
1230impl<'a> From<PdfPageShadingObject<'a>> for PdfPageObject<'a> {
1231 #[inline]
1232 fn from(object: PdfPageShadingObject<'a>) -> Self {
1233 Self::Shading(object)
1234 }
1235}
1236
1237impl<'a> From<PdfPageTextObject<'a>> for PdfPageObject<'a> {
1238 #[inline]
1239 fn from(object: PdfPageTextObject<'a>) -> Self {
1240 Self::Text(object)
1241 }
1242}
1243
1244impl<'a> From<PdfPageUnsupportedObject<'a>> for PdfPageObject<'a> {
1245 #[inline]
1246 fn from(object: PdfPageUnsupportedObject<'a>) -> Self {
1247 Self::Unsupported(object)
1248 }
1249}
1250
1251impl<'a> Drop for PdfPageObject<'a> {
1252 #[inline]
1254 fn drop(&mut self) {
1255 if !self.ownership().is_owned() {
1256 self.bindings().FPDFPageObj_Destroy(self.object_handle());
1257 }
1258 }
1259}
1260
1261#[cfg(test)]
1262mod tests {
1263 use crate::prelude::*;
1264 use crate::utils::test::test_bind_to_pdfium;
1265
1266 #[test]
1267 fn test_apply_matrix() -> Result<(), PdfiumError> {
1268 let pdfium = test_bind_to_pdfium();
1269
1270 let mut document = pdfium.create_new_pdf()?;
1271
1272 let mut page = document.pages_mut().create_page_at_start(PdfPagePaperSize::a4())?;
1273
1274 let font = document.fonts_mut().times_roman();
1275
1276 let mut object = page.objects_mut().create_text_object(
1277 PdfPoints::ZERO,
1278 PdfPoints::ZERO,
1279 "My new text object",
1280 font,
1281 PdfPoints::new(10.0),
1282 )?;
1283
1284 object.translate(PdfPoints::new(100.0), PdfPoints::new(100.0))?;
1285 object.flip_vertically()?;
1286 object.rotate_clockwise_degrees(45.0)?;
1287 object.scale(3.0, 4.0)?;
1288
1289 let previous_matrix = object.matrix()?;
1290
1291 object.apply_matrix(PdfMatrix::IDENTITY)?;
1292
1293 assert_eq!(previous_matrix, object.matrix()?);
1294
1295 Ok(())
1296 }
1297
1298 #[test]
1299 fn test_reset_matrix_to_identity() -> Result<(), PdfiumError> {
1300 let pdfium = test_bind_to_pdfium();
1301
1302 let mut document = pdfium.create_new_pdf()?;
1303
1304 let mut page = document.pages_mut().create_page_at_start(PdfPagePaperSize::a4())?;
1305
1306 let font = document.fonts_mut().times_roman();
1307
1308 let mut object = page.objects_mut().create_text_object(
1309 PdfPoints::ZERO,
1310 PdfPoints::ZERO,
1311 "My new text object",
1312 font,
1313 PdfPoints::new(10.0),
1314 )?;
1315
1316 object.translate(PdfPoints::new(100.0), PdfPoints::new(100.0))?;
1317 object.flip_vertically()?;
1318 object.rotate_clockwise_degrees(45.0)?;
1319 object.scale(3.0, 4.0)?;
1320
1321 let previous_matrix = object.matrix()?;
1322
1323 object.reset_matrix_to_identity()?;
1324
1325 assert_ne!(previous_matrix, object.matrix()?);
1326 assert_eq!(object.matrix()?, PdfMatrix::IDENTITY);
1327
1328 Ok(())
1329 }
1330
1331 #[test]
1332 fn test_transform_captured_in_content_regeneration() -> Result<(), PdfiumError> {
1333 let pdfium = test_bind_to_pdfium();
1334
1335 let mut document = pdfium.create_new_pdf()?;
1336
1337 let x = PdfPoints::new(100.0);
1338 let y = PdfPoints::new(400.0);
1339
1340 let object_matrix_before_rotation = {
1341 let mut page = document.pages_mut().create_page_at_start(PdfPagePaperSize::a4())?;
1342
1343 let font = document.fonts_mut().new_built_in(PdfFontBuiltin::TimesRoman);
1344
1345 let mut object = page
1346 .objects_mut()
1347 .create_text_object(x, y, "Hello world!", font, PdfPoints::new(20.0))?;
1348
1349 let object_matrix_before_rotation = object.matrix()?;
1350
1351 object.rotate_clockwise_degrees(45.0)?;
1352
1353 object_matrix_before_rotation
1354 };
1355
1356 assert_eq!(
1357 object_matrix_before_rotation.rotate_clockwise_degrees(45.0)?,
1358 document.pages().first()?.objects().first()?.matrix()?
1359 );
1360
1361 Ok(())
1362 }
1363}