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(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#[cfg(doc)]
58use crate::pdf::document::PdfDocument;
59
60#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Eq, Hash)]
67pub enum PdfPageObjectType {
68 Unsupported = FPDF_PAGEOBJ_UNKNOWN as isize,
70
71 Text = FPDF_PAGEOBJ_TEXT as isize,
73
74 Path = FPDF_PAGEOBJ_PATH as isize,
76
77 Image = FPDF_PAGEOBJ_IMAGE as isize,
79
80 Shading = FPDF_PAGEOBJ_SHADING as isize,
83
84 XObjectForm = FPDF_PAGEOBJ_FORM as isize,
91}
92
93impl PdfPageObjectType {
94 pub(crate) fn from_pdfium(value: u32) -> Result<PdfPageObjectType, PdfiumError> {
95 match value {
96 FPDF_PAGEOBJ_UNKNOWN => Ok(PdfPageObjectType::Unsupported),
97 FPDF_PAGEOBJ_TEXT => Ok(PdfPageObjectType::Text),
98 FPDF_PAGEOBJ_PATH => Ok(PdfPageObjectType::Path),
99 FPDF_PAGEOBJ_IMAGE => Ok(PdfPageObjectType::Image),
100 FPDF_PAGEOBJ_SHADING => Ok(PdfPageObjectType::Shading),
101 FPDF_PAGEOBJ_FORM => Ok(PdfPageObjectType::XObjectForm),
102 _ => Err(PdfiumError::UnknownPdfPageObjectType),
103 }
104 }
105}
106
107#[derive(Debug, Copy, Clone, PartialEq)]
116pub enum PdfPageObjectBlendMode {
117 Normal,
119
120 Multiply,
126
127 Screen,
135
136 Overlay,
141
142 Darken,
145
146 Lighten,
149
150 ColorDodge,
153
154 ColorBurn,
157
158 HardLight,
161
162 SoftLight,
165
166 Difference,
169
170 Exclusion,
173
174 HSLColor,
177
178 HSLHue,
181
182 HSLLuminosity,
185
186 HSLSaturation,
189}
190
191impl PdfPageObjectBlendMode {
192 pub(crate) fn as_pdfium(&self) -> &str {
193 match self {
194 PdfPageObjectBlendMode::HSLColor => "Color",
195 PdfPageObjectBlendMode::ColorBurn => "ColorBurn",
196 PdfPageObjectBlendMode::ColorDodge => "ColorDodge",
197 PdfPageObjectBlendMode::Darken => "Darken",
198 PdfPageObjectBlendMode::Difference => "Difference",
199 PdfPageObjectBlendMode::Exclusion => "Exclusion",
200 PdfPageObjectBlendMode::HardLight => "HardLight",
201 PdfPageObjectBlendMode::HSLHue => "Hue",
202 PdfPageObjectBlendMode::Lighten => "Lighten",
203 PdfPageObjectBlendMode::HSLLuminosity => "Luminosity",
204 PdfPageObjectBlendMode::Multiply => "Multiply",
205 PdfPageObjectBlendMode::Normal => "Normal",
206 PdfPageObjectBlendMode::Overlay => "Overlay",
207 PdfPageObjectBlendMode::HSLSaturation => "Saturation",
208 PdfPageObjectBlendMode::Screen => "Screen",
209 PdfPageObjectBlendMode::SoftLight => "SoftLight",
210 }
211 }
212}
213
214#[derive(Debug, Copy, Clone, PartialEq)]
222pub enum PdfPageObjectLineJoin {
223 Miter = FPDF_LINEJOIN_MITER as isize,
227
228 Round = FPDF_LINEJOIN_ROUND as isize,
233
234 Bevel = FPDF_LINEJOIN_BEVEL as isize,
237}
238
239impl PdfPageObjectLineJoin {
240 pub(crate) fn from_pdfium(value: c_int) -> Option<Self> {
241 match value as u32 {
242 FPDF_LINEJOIN_MITER => Some(Self::Miter),
243 FPDF_LINEJOIN_ROUND => Some(Self::Round),
244 FPDF_LINEJOIN_BEVEL => Some(Self::Bevel),
245 _ => None,
246 }
247 }
248
249 pub(crate) fn as_pdfium(&self) -> u32 {
250 match self {
251 PdfPageObjectLineJoin::Miter => FPDF_LINEJOIN_MITER,
252 PdfPageObjectLineJoin::Round => FPDF_LINEJOIN_ROUND,
253 PdfPageObjectLineJoin::Bevel => FPDF_LINEJOIN_BEVEL,
254 }
255 }
256}
257
258#[derive(Debug, Copy, Clone, PartialEq)]
263pub enum PdfPageObjectLineCap {
264 Butt = FPDF_LINECAP_BUTT as isize,
267
268 Round = FPDF_LINECAP_ROUND as isize,
271
272 Square = FPDF_LINECAP_PROJECTING_SQUARE as isize,
275}
276
277impl PdfPageObjectLineCap {
278 pub(crate) fn from_pdfium(value: c_int) -> Option<Self> {
279 match value as u32 {
280 FPDF_LINECAP_BUTT => Some(Self::Butt),
281 FPDF_LINECAP_ROUND => Some(Self::Round),
282 FPDF_LINECAP_PROJECTING_SQUARE => Some(Self::Square),
283 _ => None,
284 }
285 }
286
287 pub(crate) fn as_pdfium(&self) -> u32 {
288 match self {
289 PdfPageObjectLineCap::Butt => FPDF_LINECAP_BUTT,
290 PdfPageObjectLineCap::Round => FPDF_LINECAP_ROUND,
291 PdfPageObjectLineCap::Square => FPDF_LINECAP_PROJECTING_SQUARE,
292 }
293 }
294}
295
296pub enum PdfPageObject<'a> {
298 Text(PdfPageTextObject<'a>),
300
301 Path(PdfPagePathObject<'a>),
303
304 Image(PdfPageImageObject<'a>),
306
307 Shading(PdfPageShadingObject<'a>),
310
311 XObjectForm(PdfPageXObjectFormObject<'a>),
318
319 Unsupported(PdfPageUnsupportedObject<'a>),
325}
326
327impl<'a> PdfPageObject<'a> {
328 pub(crate) fn from_pdfium(
329 object_handle: FPDF_PAGEOBJECT,
330 ownership: PdfPageObjectOwnership,
331 bindings: &'a dyn PdfiumLibraryBindings,
332 ) -> Self {
333 match PdfPageObjectType::from_pdfium(
334 unsafe { bindings.FPDFPageObj_GetType(object_handle) } as u32
335 )
336 .unwrap_or(PdfPageObjectType::Unsupported)
337 {
338 PdfPageObjectType::Unsupported => PdfPageObject::Unsupported(
339 PdfPageUnsupportedObject::from_pdfium(object_handle, ownership),
340 ),
341 PdfPageObjectType::Text => {
342 PdfPageObject::Text(PdfPageTextObject::from_pdfium(object_handle, ownership))
343 }
344 PdfPageObjectType::Path => {
345 PdfPageObject::Path(PdfPagePathObject::from_pdfium(object_handle, ownership))
346 }
347 PdfPageObjectType::Image => {
348 PdfPageObject::Image(PdfPageImageObject::from_pdfium(object_handle, ownership))
349 }
350 PdfPageObjectType::Shading => {
351 PdfPageObject::Shading(PdfPageShadingObject::from_pdfium(object_handle, ownership))
352 }
353 PdfPageObjectType::XObjectForm => PdfPageObject::XObjectForm(
354 PdfPageXObjectFormObject::from_pdfium(object_handle, ownership),
355 ),
356 }
357 }
358
359 #[inline]
360 pub(crate) fn unwrap_as_trait(&self) -> &dyn PdfPageObjectPrivate<'a> {
361 match self {
362 PdfPageObject::Text(object) => object,
363 PdfPageObject::Path(object) => object,
364 PdfPageObject::Image(object) => object,
365 PdfPageObject::Shading(object) => object,
366 PdfPageObject::XObjectForm(object) => object,
367 PdfPageObject::Unsupported(object) => object,
368 }
369 }
370
371 #[inline]
372 pub(crate) fn unwrap_as_trait_mut(&mut self) -> &mut dyn PdfPageObjectPrivate<'a> {
373 match self {
374 PdfPageObject::Text(object) => object,
375 PdfPageObject::Path(object) => object,
376 PdfPageObject::Image(object) => object,
377 PdfPageObject::Shading(object) => object,
378 PdfPageObject::XObjectForm(object) => object,
379 PdfPageObject::Unsupported(object) => object,
380 }
381 }
382
383 #[inline]
390 pub fn object_type(&self) -> PdfPageObjectType {
391 match self {
392 PdfPageObject::Text(_) => PdfPageObjectType::Text,
393 PdfPageObject::Path(_) => PdfPageObjectType::Path,
394 PdfPageObject::Image(_) => PdfPageObjectType::Image,
395 PdfPageObject::Shading(_) => PdfPageObjectType::Shading,
396 PdfPageObject::XObjectForm(_) => PdfPageObjectType::XObjectForm,
397 PdfPageObject::Unsupported(_) => PdfPageObjectType::Unsupported,
398 }
399 }
400
401 #[inline]
407 pub fn is_supported(&self) -> bool {
408 !self.is_unsupported()
409 }
410
411 #[inline]
417 pub fn is_unsupported(&self) -> bool {
418 self.object_type() == PdfPageObjectType::Unsupported
419 }
420
421 #[inline]
424 pub fn as_text_object(&self) -> Option<&PdfPageTextObject<'_>> {
425 match self {
426 PdfPageObject::Text(object) => Some(object),
427 _ => None,
428 }
429 }
430
431 #[inline]
434 pub fn as_text_object_mut(&mut self) -> Option<&mut PdfPageTextObject<'a>> {
435 match self {
436 PdfPageObject::Text(object) => Some(object),
437 _ => None,
438 }
439 }
440
441 #[inline]
444 pub fn as_path_object(&self) -> Option<&PdfPagePathObject<'_>> {
445 match self {
446 PdfPageObject::Path(object) => Some(object),
447 _ => None,
448 }
449 }
450
451 #[inline]
454 pub fn as_path_object_mut(&mut self) -> Option<&mut PdfPagePathObject<'a>> {
455 match self {
456 PdfPageObject::Path(object) => Some(object),
457 _ => None,
458 }
459 }
460
461 #[inline]
464 pub fn as_image_object(&self) -> Option<&PdfPageImageObject<'_>> {
465 match self {
466 PdfPageObject::Image(object) => Some(object),
467 _ => None,
468 }
469 }
470
471 #[inline]
474 pub fn as_image_object_mut(&mut self) -> Option<&mut PdfPageImageObject<'a>> {
475 match self {
476 PdfPageObject::Image(object) => Some(object),
477 _ => None,
478 }
479 }
480
481 #[inline]
484 pub fn as_shading_object(&self) -> Option<&PdfPageShadingObject<'_>> {
485 match self {
486 PdfPageObject::Shading(object) => Some(object),
487 _ => None,
488 }
489 }
490
491 #[inline]
494 pub fn as_shading_object_mut(&mut self) -> Option<&mut PdfPageShadingObject<'a>> {
495 match self {
496 PdfPageObject::Shading(object) => Some(object),
497 _ => None,
498 }
499 }
500
501 #[inline]
504 pub fn as_x_object_form_object(&self) -> Option<&PdfPageXObjectFormObject<'_>> {
505 match self {
506 PdfPageObject::XObjectForm(object) => Some(object),
507 _ => None,
508 }
509 }
510
511 #[inline]
514 pub fn as_x_object_form_object_mut(&mut self) -> Option<&mut PdfPageXObjectFormObject<'a>> {
515 match self {
516 PdfPageObject::XObjectForm(object) => Some(object),
517 _ => None,
518 }
519 }
520
521 pub fn get_clip_path(&self) -> Option<PdfClipPath<'_>> {
523 let path_handle = unsafe {
524 self.bindings()
525 .FPDFPageObj_GetClipPath(self.object_handle())
526 };
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 ));
536 }
537
538 #[cfg(any(
539 feature = "pdfium_future",
540 feature = "pdfium_7543",
541 feature = "pdfium_7350",
542 feature = "pdfium_7215",
543 feature = "pdfium_7123",
544 feature = "pdfium_6996"
545 ))]
546 pub fn set_active(&mut self) -> Result<(), PdfiumError> {
549 if self.bindings().is_true(unsafe {
550 self.bindings()
551 .FPDFPageObj_SetIsActive(self.object_handle(), self.bindings().TRUE())
552 }) {
553 Ok(())
554 } else {
555 Err(PdfiumError::PdfiumLibraryInternalError(
556 PdfiumInternalError::Unknown,
557 ))
558 }
559 }
560
561 #[cfg(any(
562 feature = "pdfium_future",
563 feature = "pdfium_7543",
564 feature = "pdfium_7350",
565 feature = "pdfium_7215",
566 feature = "pdfium_7123",
567 feature = "pdfium_6996"
568 ))]
569 pub fn is_active(&self) -> Result<bool, PdfiumError> {
571 let mut result = self.bindings().FALSE();
572
573 if self.bindings().is_true(unsafe {
574 self.bindings()
575 .FPDFPageObj_GetIsActive(self.object_handle(), &mut result)
576 }) {
577 Ok(self.bindings().is_true(result))
578 } else {
579 Err(PdfiumError::PdfiumLibraryInternalError(
580 PdfiumInternalError::Unknown,
581 ))
582 }
583 }
584
585 #[cfg(any(
586 feature = "pdfium_future",
587 feature = "pdfium_7543",
588 feature = "pdfium_7350",
589 feature = "pdfium_7215",
590 feature = "pdfium_7123",
591 feature = "pdfium_6996"
592 ))]
593 pub fn set_inactive(&mut self) -> Result<(), PdfiumError> {
596 if self.bindings().is_true(unsafe {
597 self.bindings()
598 .FPDFPageObj_SetIsActive(self.object_handle(), self.bindings().FALSE())
599 }) {
600 Ok(())
601 } else {
602 Err(PdfiumError::PdfiumLibraryInternalError(
603 PdfiumInternalError::Unknown,
604 ))
605 }
606 }
607
608 #[cfg(any(
609 feature = "pdfium_future",
610 feature = "pdfium_7543",
611 feature = "pdfium_7350",
612 feature = "pdfium_7215",
613 feature = "pdfium_7123",
614 feature = "pdfium_6996"
615 ))]
616 #[inline]
618 pub fn is_inactive(&self) -> Result<bool, PdfiumError> {
619 self.is_active().map(|result| !result)
620 }
621
622 create_transform_setters!(
623 &mut Self,
624 Result<(), PdfiumError>,
625 "this [PdfPageObject]",
626 "this [PdfPageObject].",
627 "this [PdfPageObject],"
628 );
629
630 create_transform_getters!(
634 "this [PdfPageObject]",
635 "this [PdfPageObject].",
636 "this [PdfPageObject],"
637 );
638
639 }
642
643impl<'a> PdfiumLibraryBindingsAccessor<'a> for PdfPageObject<'a> {}
644
645#[cfg(feature = "thread_safe")]
646unsafe impl<'a> Send for PdfPageObject<'a> {}
647
648#[cfg(feature = "thread_safe")]
649unsafe impl<'a> Sync for PdfPageObject<'a> {}
650
651pub trait PdfPageObjectCommon<'a> {
653 fn has_transparency(&self) -> bool;
655
656 fn bounds(&self) -> Result<PdfQuadPoints, PdfiumError>;
663
664 #[inline]
666 fn width(&self) -> Result<PdfPoints, PdfiumError> {
667 Ok(self.bounds()?.width())
668 }
669
670 #[inline]
672 fn height(&self) -> Result<PdfPoints, PdfiumError> {
673 Ok(self.bounds()?.height())
674 }
675
676 #[inline]
678 fn is_inside_rect(&self, rect: &PdfRect) -> bool {
679 self.bounds()
680 .map(|bounds| bounds.to_rect().is_inside(rect))
681 .unwrap_or(false)
682 }
683
684 #[inline]
687 fn does_overlap_rect(&self, rect: &PdfRect) -> bool {
688 self.bounds()
689 .map(|bounds| bounds.to_rect().does_overlap(rect))
690 .unwrap_or(false)
691 }
692
693 fn transform_from(&mut self, other: &PdfPageObject) -> Result<(), PdfiumError>;
698
699 fn set_blend_mode(&mut self, blend_mode: PdfPageObjectBlendMode) -> Result<(), PdfiumError>;
703
704 fn fill_color(&self) -> Result<PdfColor, PdfiumError>;
706
707 fn set_fill_color(&mut self, fill_color: PdfColor) -> Result<(), PdfiumError>;
709
710 fn stroke_color(&self) -> Result<PdfColor, PdfiumError>;
712
713 fn set_stroke_color(&mut self, stroke_color: PdfColor) -> Result<(), PdfiumError>;
718
719 fn stroke_width(&self) -> Result<PdfPoints, PdfiumError>;
721
722 fn set_stroke_width(&mut self, stroke_width: PdfPoints) -> Result<(), PdfiumError>;
732
733 fn line_join(&self) -> Result<PdfPageObjectLineJoin, PdfiumError>;
736
737 fn set_line_join(&mut self, line_join: PdfPageObjectLineJoin) -> Result<(), PdfiumError>;
740
741 fn line_cap(&self) -> Result<PdfPageObjectLineCap, PdfiumError>;
744
745 fn set_line_cap(&mut self, line_cap: PdfPageObjectLineCap) -> Result<(), PdfiumError>;
748
749 fn dash_phase(&self) -> Result<PdfPoints, PdfiumError>;
765
766 fn set_dash_phase(&mut self, dash_phase: PdfPoints) -> Result<(), PdfiumError>;
782
783 fn dash_array(&self) -> Result<Vec<PdfPoints>, PdfiumError>;
799
800 fn set_dash_array(&mut self, array: &[PdfPoints], phase: PdfPoints) -> Result<(), PdfiumError>;
816
817 fn copy_to_page<'b>(
821 &mut self,
822 page: &mut PdfPage<'b>,
823 ) -> Result<PdfPageObject<'b>, PdfiumError>;
824
825 fn move_to_page(&mut self, page: &mut PdfPage) -> Result<(), PdfiumError>;
832
833 fn move_to_annotation(&mut self, annotation: &mut PdfPageAnnotation)
840 -> Result<(), PdfiumError>;
841}
842
843impl<'a, T> PdfPageObjectCommon<'a> for T
846where
847 T: PdfPageObjectPrivate<'a>,
848{
849 #[inline]
850 fn has_transparency(&self) -> bool {
851 self.has_transparency_impl()
852 }
853
854 #[inline]
855 fn bounds(&self) -> Result<PdfQuadPoints, PdfiumError> {
856 self.bounds_impl()
857 }
858
859 #[inline]
860 fn transform_from(&mut self, other: &PdfPageObject) -> Result<(), PdfiumError> {
861 self.reset_matrix_impl(other.matrix()?)
862 }
863
864 #[inline]
865 fn set_blend_mode(&mut self, blend_mode: PdfPageObjectBlendMode) -> Result<(), PdfiumError> {
866 unsafe {
867 self.bindings()
868 .FPDFPageObj_SetBlendMode(self.object_handle(), blend_mode.as_pdfium());
869 }
870
871 Ok(())
872 }
873
874 #[inline]
875 fn fill_color(&self) -> Result<PdfColor, PdfiumError> {
876 let mut r = 0;
877 let mut g = 0;
878 let mut b = 0;
879 let mut a = 0;
880
881 if self.bindings().is_true(unsafe {
882 self.bindings().FPDFPageObj_GetFillColor(
883 self.object_handle(),
884 &mut r,
885 &mut g,
886 &mut b,
887 &mut a,
888 )
889 }) {
890 Ok(PdfColor::new(
891 r.try_into()
892 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
893 g.try_into()
894 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
895 b.try_into()
896 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
897 a.try_into()
898 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
899 ))
900 } else {
901 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
902 }
903 }
904
905 #[inline]
906 fn set_fill_color(&mut self, fill_color: PdfColor) -> Result<(), PdfiumError> {
907 if self.bindings().is_true(unsafe {
908 self.bindings().FPDFPageObj_SetFillColor(
909 self.object_handle(),
910 fill_color.red() as c_uint,
911 fill_color.green() as c_uint,
912 fill_color.blue() as c_uint,
913 fill_color.alpha() as c_uint,
914 )
915 }) {
916 Ok(())
917 } else {
918 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
919 }
920 }
921
922 #[inline]
923 fn stroke_color(&self) -> Result<PdfColor, PdfiumError> {
924 let mut r = 0;
925 let mut g = 0;
926 let mut b = 0;
927 let mut a = 0;
928
929 if self.bindings().is_true(unsafe {
930 self.bindings().FPDFPageObj_GetStrokeColor(
931 self.object_handle(),
932 &mut r,
933 &mut g,
934 &mut b,
935 &mut a,
936 )
937 }) {
938 Ok(PdfColor::new(
939 r.try_into()
940 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
941 g.try_into()
942 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
943 b.try_into()
944 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
945 a.try_into()
946 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
947 ))
948 } else {
949 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
950 }
951 }
952
953 #[inline]
954 fn set_stroke_color(&mut self, stroke_color: PdfColor) -> Result<(), PdfiumError> {
955 if self.bindings().is_true(unsafe {
956 self.bindings().FPDFPageObj_SetStrokeColor(
957 self.object_handle(),
958 stroke_color.red() as c_uint,
959 stroke_color.green() as c_uint,
960 stroke_color.blue() as c_uint,
961 stroke_color.alpha() as c_uint,
962 )
963 }) {
964 Ok(())
965 } else {
966 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
967 }
968 }
969
970 #[inline]
971 fn stroke_width(&self) -> Result<PdfPoints, PdfiumError> {
972 let mut width = 0.0;
973
974 if self.bindings().is_true(unsafe {
975 self.bindings()
976 .FPDFPageObj_GetStrokeWidth(self.object_handle(), &mut width)
977 }) {
978 Ok(PdfPoints::new(width))
979 } else {
980 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
981 }
982 }
983
984 #[inline]
985 fn set_stroke_width(&mut self, stroke_width: PdfPoints) -> Result<(), PdfiumError> {
986 if self.bindings().is_true(unsafe {
987 self.bindings()
988 .FPDFPageObj_SetStrokeWidth(self.object_handle(), stroke_width.value)
989 }) {
990 Ok(())
991 } else {
992 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
993 }
994 }
995
996 #[inline]
997 fn line_join(&self) -> Result<PdfPageObjectLineJoin, PdfiumError> {
998 PdfPageObjectLineJoin::from_pdfium(unsafe {
999 self.bindings()
1000 .FPDFPageObj_GetLineJoin(self.object_handle())
1001 })
1002 .ok_or(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1003 }
1004
1005 #[inline]
1006 fn set_line_join(&mut self, line_join: PdfPageObjectLineJoin) -> Result<(), PdfiumError> {
1007 if self.bindings().is_true(unsafe {
1008 self.bindings()
1009 .FPDFPageObj_SetLineJoin(self.object_handle(), line_join.as_pdfium() as c_int)
1010 }) {
1011 Ok(())
1012 } else {
1013 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1014 }
1015 }
1016
1017 #[inline]
1018 fn line_cap(&self) -> Result<PdfPageObjectLineCap, PdfiumError> {
1019 PdfPageObjectLineCap::from_pdfium(unsafe {
1020 self.bindings().FPDFPageObj_GetLineCap(self.object_handle())
1021 })
1022 .ok_or(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1023 }
1024
1025 #[inline]
1026 fn set_line_cap(&mut self, line_cap: PdfPageObjectLineCap) -> Result<(), PdfiumError> {
1027 if self.bindings().is_true(unsafe {
1028 self.bindings()
1029 .FPDFPageObj_SetLineCap(self.object_handle(), line_cap.as_pdfium() as c_int)
1030 }) {
1031 Ok(())
1032 } else {
1033 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1034 }
1035 }
1036
1037 #[inline]
1038 fn dash_phase(&self) -> Result<PdfPoints, PdfiumError> {
1039 let mut phase = 0.0;
1040
1041 if self.bindings().is_true(unsafe {
1042 self.bindings()
1043 .FPDFPageObj_GetDashPhase(self.object_handle(), &mut phase)
1044 }) {
1045 Ok(PdfPoints::new(phase))
1046 } else {
1047 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1048 }
1049 }
1050
1051 #[inline]
1052 fn set_dash_phase(&mut self, dash_phase: PdfPoints) -> Result<(), PdfiumError> {
1053 if self.bindings().is_true(unsafe {
1054 self.bindings()
1055 .FPDFPageObj_SetDashPhase(self.object_handle(), dash_phase.value)
1056 }) {
1057 Ok(())
1058 } else {
1059 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1060 }
1061 }
1062
1063 #[inline]
1064 fn dash_array(&self) -> Result<Vec<PdfPoints>, PdfiumError> {
1065 let dash_count = unsafe {
1066 self.bindings()
1067 .FPDFPageObj_GetDashCount(self.object_handle())
1068 } as usize;
1069
1070 let mut dash_array = vec![0.0; dash_count];
1071
1072 if self.bindings().is_true(unsafe {
1073 self.bindings().FPDFPageObj_GetDashArray(
1074 self.object_handle(),
1075 dash_array.as_mut_ptr(),
1076 dash_count,
1077 )
1078 }) {
1079 Ok(dash_array
1080 .iter()
1081 .map(|dash| PdfPoints::new(*dash))
1082 .collect())
1083 } else {
1084 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1085 }
1086 }
1087
1088 fn set_dash_array(&mut self, array: &[PdfPoints], phase: PdfPoints) -> Result<(), PdfiumError> {
1089 let dash_array = array.iter().map(|dash| dash.value).collect::<Vec<_>>();
1090
1091 if self.bindings().is_true(unsafe {
1092 self.bindings().FPDFPageObj_SetDashArray(
1093 self.object_handle(),
1094 dash_array.as_ptr(),
1095 dash_array.len(),
1096 phase.value,
1097 )
1098 }) {
1099 Ok(())
1100 } else {
1101 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1102 }
1103 }
1104
1105 #[inline]
1106 fn copy_to_page<'b>(
1107 &mut self,
1108 page: &mut PdfPage<'b>,
1109 ) -> Result<PdfPageObject<'b>, PdfiumError> {
1110 self.copy_to_page_impl(page)
1111 }
1112
1113 fn move_to_page(&mut self, page: &mut PdfPage) -> Result<(), PdfiumError> {
1114 match self.ownership() {
1115 PdfPageObjectOwnership::Document(ownership) => {
1116 if ownership.document_handle() != page.document_handle() {
1117 return Err(PdfiumError::CannotMoveObjectAcrossDocuments);
1118 }
1119 }
1120 PdfPageObjectOwnership::Page(_) => self.remove_object_from_page()?,
1121 PdfPageObjectOwnership::AttachedAnnotation(_)
1122 | PdfPageObjectOwnership::UnattachedAnnotation(_) => {
1123 self.remove_object_from_annotation()?
1124 }
1125 PdfPageObjectOwnership::Unowned => {}
1126 }
1127
1128 self.add_object_to_page(page.objects_mut())
1129 }
1130
1131 fn move_to_annotation(
1132 &mut self,
1133 annotation: &mut PdfPageAnnotation,
1134 ) -> Result<(), PdfiumError> {
1135 match self.ownership() {
1136 PdfPageObjectOwnership::Document(ownership) => {
1137 let annotation_document_handle = match annotation.ownership() {
1138 PdfPageObjectOwnership::Document(ownership) => {
1139 Some(ownership.document_handle())
1140 }
1141 PdfPageObjectOwnership::Page(ownership) => Some(ownership.document_handle()),
1142 PdfPageObjectOwnership::AttachedAnnotation(ownership) => {
1143 Some(ownership.document_handle())
1144 }
1145 PdfPageObjectOwnership::UnattachedAnnotation(_)
1146 | PdfPageObjectOwnership::Unowned => None,
1147 };
1148
1149 if let Some(annotation_document_handle) = annotation_document_handle {
1150 if ownership.document_handle() != annotation_document_handle {
1151 return Err(PdfiumError::CannotMoveObjectAcrossDocuments);
1152 }
1153 }
1154 }
1155 PdfPageObjectOwnership::Page(_) => self.remove_object_from_page()?,
1156 PdfPageObjectOwnership::AttachedAnnotation(_)
1157 | PdfPageObjectOwnership::UnattachedAnnotation(_) => {
1158 self.remove_object_from_annotation()?
1159 }
1160 PdfPageObjectOwnership::Unowned => {}
1161 }
1162
1163 self.add_object_to_annotation(annotation.objects())
1164 }
1165}
1166
1167impl<'a> PdfPageObjectPrivate<'a> for PdfPageObject<'a> {
1168 #[inline]
1169 fn object_handle(&self) -> FPDF_PAGEOBJECT {
1170 self.unwrap_as_trait().object_handle()
1171 }
1172
1173 #[inline]
1174 fn ownership(&self) -> &PdfPageObjectOwnership {
1175 self.unwrap_as_trait().ownership()
1176 }
1177
1178 #[inline]
1179 fn set_ownership(&mut self, ownership: PdfPageObjectOwnership) {
1180 self.unwrap_as_trait_mut().set_ownership(ownership);
1181 }
1182
1183 #[inline]
1184 fn add_object_to_page(&mut self, page_objects: &mut PdfPageObjects) -> Result<(), PdfiumError> {
1185 self.unwrap_as_trait_mut().add_object_to_page(page_objects)
1186 }
1187
1188 #[cfg(any(feature = "pdfium_future", feature = "pdfium_7350"))]
1189 #[inline]
1190 fn insert_object_on_page(
1191 &mut self,
1192 page_objects: &mut PdfPageObjects,
1193 index: PdfPageObjectIndex,
1194 ) -> Result<(), PdfiumError> {
1195 self.unwrap_as_trait_mut()
1196 .insert_object_on_page(page_objects, index)
1197 }
1198
1199 #[inline]
1200 fn remove_object_from_page(&mut self) -> Result<(), PdfiumError> {
1201 self.unwrap_as_trait_mut().remove_object_from_page()
1202 }
1203
1204 #[inline]
1205 fn add_object_to_annotation(
1206 &mut self,
1207 annotation_objects: &PdfPageAnnotationObjects,
1208 ) -> Result<(), PdfiumError> {
1209 self.unwrap_as_trait_mut()
1210 .add_object_to_annotation(annotation_objects)
1211 }
1212
1213 #[inline]
1214 fn remove_object_from_annotation(&mut self) -> Result<(), PdfiumError> {
1215 self.unwrap_as_trait_mut().remove_object_from_annotation()
1216 }
1217
1218 #[inline]
1219 fn copy_to_page_impl<'b>(
1220 &mut self,
1221 page: &mut PdfPage<'b>,
1222 ) -> Result<PdfPageObject<'b>, PdfiumError> {
1223 self.unwrap_as_trait_mut().copy_to_page_impl(page)
1224 }
1225}
1226
1227impl<'a> From<PdfPageXObjectFormObject<'a>> for PdfPageObject<'a> {
1228 #[inline]
1229 fn from(object: PdfPageXObjectFormObject<'a>) -> Self {
1230 Self::XObjectForm(object)
1231 }
1232}
1233
1234impl<'a> From<PdfPageImageObject<'a>> for PdfPageObject<'a> {
1235 #[inline]
1236 fn from(object: PdfPageImageObject<'a>) -> Self {
1237 Self::Image(object)
1238 }
1239}
1240
1241impl<'a> From<PdfPagePathObject<'a>> for PdfPageObject<'a> {
1242 #[inline]
1243 fn from(object: PdfPagePathObject<'a>) -> Self {
1244 Self::Path(object)
1245 }
1246}
1247
1248impl<'a> From<PdfPageShadingObject<'a>> for PdfPageObject<'a> {
1249 #[inline]
1250 fn from(object: PdfPageShadingObject<'a>) -> Self {
1251 Self::Shading(object)
1252 }
1253}
1254
1255impl<'a> From<PdfPageTextObject<'a>> for PdfPageObject<'a> {
1256 #[inline]
1257 fn from(object: PdfPageTextObject<'a>) -> Self {
1258 Self::Text(object)
1259 }
1260}
1261
1262impl<'a> From<PdfPageUnsupportedObject<'a>> for PdfPageObject<'a> {
1263 #[inline]
1264 fn from(object: PdfPageUnsupportedObject<'a>) -> Self {
1265 Self::Unsupported(object)
1266 }
1267}
1268
1269impl<'a> Drop for PdfPageObject<'a> {
1270 #[inline]
1272 fn drop(&mut self) {
1273 if !self.ownership().is_owned() {
1284 unsafe {
1285 self.bindings().FPDFPageObj_Destroy(self.object_handle());
1286 }
1287 }
1288 }
1289}
1290
1291#[cfg(test)]
1292mod tests {
1293 use crate::prelude::*;
1294 use crate::utils::test::test_bind_to_pdfium;
1295
1296 #[test]
1297 fn test_apply_matrix() -> Result<(), PdfiumError> {
1298 let pdfium = test_bind_to_pdfium();
1299
1300 let mut document = pdfium.create_new_pdf()?;
1301
1302 let mut page = document
1303 .pages_mut()
1304 .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))?;
1319 object.flip_vertically()?;
1320 object.rotate_clockwise_degrees(45.0)?;
1321 object.scale(3.0, 4.0)?;
1322
1323 let previous_matrix = object.matrix()?;
1324
1325 object.apply_matrix(PdfMatrix::IDENTITY)?;
1328
1329 assert_eq!(previous_matrix, object.matrix()?);
1330
1331 Ok(())
1332 }
1333
1334 #[test]
1335 fn test_reset_matrix_to_identity() -> Result<(), PdfiumError> {
1336 let pdfium = test_bind_to_pdfium();
1337
1338 let mut document = pdfium.create_new_pdf()?;
1339
1340 let mut page = document
1341 .pages_mut()
1342 .create_page_at_start(PdfPagePaperSize::a4())?;
1343
1344 let font = document.fonts_mut().times_roman();
1345
1346 let mut object = page.objects_mut().create_text_object(
1347 PdfPoints::ZERO,
1348 PdfPoints::ZERO,
1349 "My new text object",
1350 font,
1351 PdfPoints::new(10.0),
1352 )?;
1353
1354 object.translate(PdfPoints::new(100.0), PdfPoints::new(100.0))?;
1357 object.flip_vertically()?;
1358 object.rotate_clockwise_degrees(45.0)?;
1359 object.scale(3.0, 4.0)?;
1360
1361 let previous_matrix = object.matrix()?;
1362
1363 object.reset_matrix_to_identity()?;
1367
1368 assert_ne!(previous_matrix, object.matrix()?);
1369 assert_eq!(object.matrix()?, PdfMatrix::IDENTITY);
1370
1371 Ok(())
1372 }
1373
1374 #[test]
1375 fn test_transform_captured_in_content_regeneration() -> Result<(), PdfiumError> {
1376 let pdfium = test_bind_to_pdfium();
1382
1383 let mut document = pdfium.create_new_pdf()?;
1384
1385 let x = PdfPoints::new(100.0);
1386 let y = PdfPoints::new(400.0);
1387
1388 let object_matrix_before_rotation = {
1389 let mut page = document
1390 .pages_mut()
1391 .create_page_at_start(PdfPagePaperSize::a4())?;
1392
1393 let font = document
1394 .fonts_mut()
1395 .new_built_in(PdfFontBuiltin::TimesRoman);
1396
1397 let mut object = page.objects_mut().create_text_object(
1398 x,
1399 y,
1400 "Hello world!",
1401 font,
1402 PdfPoints::new(20.0),
1403 )?;
1404
1405 let object_matrix_before_rotation = object.matrix()?;
1406
1407 object.rotate_clockwise_degrees(45.0)?;
1411
1412 object_matrix_before_rotation
1413 };
1414
1415 assert_eq!(
1421 object_matrix_before_rotation.rotate_clockwise_degrees(45.0)?,
1422 document.pages().first()?.objects().first()?.matrix()?
1423 );
1424
1425 Ok(())
1426 }
1427}