1pub mod content_mark;
4pub mod group;
5pub mod image;
6pub mod ownership;
7pub mod path;
8pub(crate) mod private; pub mod shading;
10pub mod text;
11pub mod unsupported;
12pub mod x_object_form;
13
14use crate::bindgen::{
15 FPDF_LINECAP_BUTT, FPDF_LINECAP_PROJECTING_SQUARE, FPDF_LINECAP_ROUND, FPDF_LINEJOIN_BEVEL,
16 FPDF_LINEJOIN_MITER, FPDF_LINEJOIN_ROUND, FPDF_PAGEOBJECT, FPDF_PAGEOBJ_FORM,
17 FPDF_PAGEOBJ_IMAGE, FPDF_PAGEOBJ_PATH, FPDF_PAGEOBJ_SHADING, FPDF_PAGEOBJ_TEXT,
18 FPDF_PAGEOBJ_UNKNOWN,
19};
20use crate::bindings::PdfiumLibraryBindings;
21use crate::error::PdfiumError;
22use crate::pdf::color::PdfColor;
23use crate::pdf::document::page::annotation::objects::PdfPageAnnotationObjects;
24use crate::pdf::document::page::annotation::private::internal::PdfPageAnnotationPrivate;
25use crate::pdf::document::page::annotation::{PdfPageAnnotation, PdfPageAnnotationCommon};
26use crate::pdf::document::page::object::image::PdfPageImageObject;
27use crate::pdf::document::page::object::path::PdfPagePathObject;
28use crate::pdf::document::page::object::private::internal::PdfPageObjectPrivate;
29use crate::pdf::document::page::object::shading::PdfPageShadingObject;
30use crate::pdf::document::page::object::text::PdfPageTextObject;
31use crate::pdf::document::page::object::unsupported::PdfPageUnsupportedObject;
32use crate::pdf::document::page::object::x_object_form::PdfPageXObjectFormObject;
33use crate::pdf::document::page::objects::PdfPageObjects;
34use crate::pdf::document::page::{PdfPage, PdfPageObjectOwnership};
35use crate::pdf::matrix::{PdfMatrix, PdfMatrixValue};
36use crate::pdf::path::clip_path::PdfClipPath;
37use crate::pdf::points::PdfPoints;
38use crate::pdf::quad_points::PdfQuadPoints;
39use crate::pdf::rect::PdfRect;
40use crate::pdfium::PdfiumLibraryBindingsAccessor;
41use crate::{create_transform_getters, create_transform_setters};
42use std::convert::TryInto;
43use std::os::raw::{c_int, c_uint};
44
45#[cfg(any(
46 feature = "pdfium_future",
47 feature = "pdfium_8125",
48 feature = "pdfium_7881",
49 feature = "pdfium_7763",
50 feature = "pdfium_7543",
51 feature = "pdfium_7350"
52))]
53use crate::pdf::document::page::objects::common::PdfPageObjectIndex;
54
55#[cfg(any(
56 feature = "pdfium_future",
57 feature = "pdfium_8125",
58 feature = "pdfium_7881",
59 feature = "pdfium_7763",
60 feature = "pdfium_7543",
61 feature = "pdfium_7350",
62 feature = "pdfium_7215",
63 feature = "pdfium_7123",
64 feature = "pdfium_6996"
65))]
66use crate::error::PdfiumInternalError;
67
68#[cfg(doc)]
69use crate::pdf::document::PdfDocument;
70
71#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Eq, Hash)]
78pub enum PdfPageObjectType {
79 Unsupported = FPDF_PAGEOBJ_UNKNOWN as isize,
81
82 Text = FPDF_PAGEOBJ_TEXT as isize,
84
85 Path = FPDF_PAGEOBJ_PATH as isize,
87
88 Image = FPDF_PAGEOBJ_IMAGE as isize,
90
91 Shading = FPDF_PAGEOBJ_SHADING as isize,
94
95 XObjectForm = FPDF_PAGEOBJ_FORM as isize,
102}
103
104impl PdfPageObjectType {
105 pub(crate) fn from_pdfium(value: u32) -> Result<PdfPageObjectType, PdfiumError> {
106 match value {
107 FPDF_PAGEOBJ_UNKNOWN => Ok(PdfPageObjectType::Unsupported),
108 FPDF_PAGEOBJ_TEXT => Ok(PdfPageObjectType::Text),
109 FPDF_PAGEOBJ_PATH => Ok(PdfPageObjectType::Path),
110 FPDF_PAGEOBJ_IMAGE => Ok(PdfPageObjectType::Image),
111 FPDF_PAGEOBJ_SHADING => Ok(PdfPageObjectType::Shading),
112 FPDF_PAGEOBJ_FORM => Ok(PdfPageObjectType::XObjectForm),
113 _ => Err(PdfiumError::UnknownPdfPageObjectType),
114 }
115 }
116}
117
118#[derive(Debug, Copy, Clone, PartialEq)]
127pub enum PdfPageObjectBlendMode {
128 Normal,
130
131 Multiply,
137
138 Screen,
146
147 Overlay,
152
153 Darken,
156
157 Lighten,
160
161 ColorDodge,
164
165 ColorBurn,
168
169 HardLight,
172
173 SoftLight,
176
177 Difference,
180
181 Exclusion,
184
185 HSLColor,
188
189 HSLHue,
192
193 HSLLuminosity,
196
197 HSLSaturation,
200}
201
202impl PdfPageObjectBlendMode {
203 pub(crate) fn as_pdfium(&self) -> &str {
204 match self {
205 PdfPageObjectBlendMode::HSLColor => "Color",
206 PdfPageObjectBlendMode::ColorBurn => "ColorBurn",
207 PdfPageObjectBlendMode::ColorDodge => "ColorDodge",
208 PdfPageObjectBlendMode::Darken => "Darken",
209 PdfPageObjectBlendMode::Difference => "Difference",
210 PdfPageObjectBlendMode::Exclusion => "Exclusion",
211 PdfPageObjectBlendMode::HardLight => "HardLight",
212 PdfPageObjectBlendMode::HSLHue => "Hue",
213 PdfPageObjectBlendMode::Lighten => "Lighten",
214 PdfPageObjectBlendMode::HSLLuminosity => "Luminosity",
215 PdfPageObjectBlendMode::Multiply => "Multiply",
216 PdfPageObjectBlendMode::Normal => "Normal",
217 PdfPageObjectBlendMode::Overlay => "Overlay",
218 PdfPageObjectBlendMode::HSLSaturation => "Saturation",
219 PdfPageObjectBlendMode::Screen => "Screen",
220 PdfPageObjectBlendMode::SoftLight => "SoftLight",
221 }
222 }
223}
224
225#[derive(Debug, Copy, Clone, PartialEq)]
233pub enum PdfPageObjectLineJoin {
234 Miter = FPDF_LINEJOIN_MITER as isize,
238
239 Round = FPDF_LINEJOIN_ROUND as isize,
244
245 Bevel = FPDF_LINEJOIN_BEVEL as isize,
248}
249
250impl PdfPageObjectLineJoin {
251 pub(crate) fn from_pdfium(value: c_int) -> Option<Self> {
252 match value as u32 {
253 FPDF_LINEJOIN_MITER => Some(Self::Miter),
254 FPDF_LINEJOIN_ROUND => Some(Self::Round),
255 FPDF_LINEJOIN_BEVEL => Some(Self::Bevel),
256 _ => None,
257 }
258 }
259
260 pub(crate) fn as_pdfium(&self) -> u32 {
261 match self {
262 PdfPageObjectLineJoin::Miter => FPDF_LINEJOIN_MITER,
263 PdfPageObjectLineJoin::Round => FPDF_LINEJOIN_ROUND,
264 PdfPageObjectLineJoin::Bevel => FPDF_LINEJOIN_BEVEL,
265 }
266 }
267}
268
269#[derive(Debug, Copy, Clone, PartialEq)]
274pub enum PdfPageObjectLineCap {
275 Butt = FPDF_LINECAP_BUTT as isize,
278
279 Round = FPDF_LINECAP_ROUND as isize,
282
283 Square = FPDF_LINECAP_PROJECTING_SQUARE as isize,
286}
287
288impl PdfPageObjectLineCap {
289 pub(crate) fn from_pdfium(value: c_int) -> Option<Self> {
290 match value as u32 {
291 FPDF_LINECAP_BUTT => Some(Self::Butt),
292 FPDF_LINECAP_ROUND => Some(Self::Round),
293 FPDF_LINECAP_PROJECTING_SQUARE => Some(Self::Square),
294 _ => None,
295 }
296 }
297
298 pub(crate) fn as_pdfium(&self) -> u32 {
299 match self {
300 PdfPageObjectLineCap::Butt => FPDF_LINECAP_BUTT,
301 PdfPageObjectLineCap::Round => FPDF_LINECAP_ROUND,
302 PdfPageObjectLineCap::Square => FPDF_LINECAP_PROJECTING_SQUARE,
303 }
304 }
305}
306
307pub enum PdfPageObject<'a> {
309 Text(PdfPageTextObject<'a>),
311
312 Path(PdfPagePathObject<'a>),
314
315 Image(PdfPageImageObject<'a>),
317
318 Shading(PdfPageShadingObject<'a>),
321
322 XObjectForm(PdfPageXObjectFormObject<'a>),
329
330 Unsupported(PdfPageUnsupportedObject<'a>),
336}
337
338impl<'a> PdfPageObject<'a> {
339 pub(crate) fn from_pdfium(
340 object_handle: FPDF_PAGEOBJECT,
341 ownership: PdfPageObjectOwnership,
342 bindings: &'a dyn PdfiumLibraryBindings,
343 ) -> Self {
344 match PdfPageObjectType::from_pdfium(
345 unsafe { bindings.FPDFPageObj_GetType(object_handle) } as u32
346 )
347 .unwrap_or(PdfPageObjectType::Unsupported)
348 {
349 PdfPageObjectType::Unsupported => PdfPageObject::Unsupported(
350 PdfPageUnsupportedObject::from_pdfium(object_handle, ownership),
351 ),
352 PdfPageObjectType::Text => {
353 PdfPageObject::Text(PdfPageTextObject::from_pdfium(object_handle, ownership))
354 }
355 PdfPageObjectType::Path => {
356 PdfPageObject::Path(PdfPagePathObject::from_pdfium(object_handle, ownership))
357 }
358 PdfPageObjectType::Image => {
359 PdfPageObject::Image(PdfPageImageObject::from_pdfium(object_handle, ownership))
360 }
361 PdfPageObjectType::Shading => {
362 PdfPageObject::Shading(PdfPageShadingObject::from_pdfium(object_handle, ownership))
363 }
364 PdfPageObjectType::XObjectForm => PdfPageObject::XObjectForm(
365 PdfPageXObjectFormObject::from_pdfium(object_handle, ownership),
366 ),
367 }
368 }
369
370 #[inline]
371 pub(crate) fn unwrap_as_trait(&self) -> &dyn PdfPageObjectPrivate<'a> {
372 match self {
373 PdfPageObject::Text(object) => object,
374 PdfPageObject::Path(object) => object,
375 PdfPageObject::Image(object) => object,
376 PdfPageObject::Shading(object) => object,
377 PdfPageObject::XObjectForm(object) => object,
378 PdfPageObject::Unsupported(object) => object,
379 }
380 }
381
382 #[inline]
383 pub(crate) fn unwrap_as_trait_mut(&mut self) -> &mut dyn PdfPageObjectPrivate<'a> {
384 match self {
385 PdfPageObject::Text(object) => object,
386 PdfPageObject::Path(object) => object,
387 PdfPageObject::Image(object) => object,
388 PdfPageObject::Shading(object) => object,
389 PdfPageObject::XObjectForm(object) => object,
390 PdfPageObject::Unsupported(object) => object,
391 }
392 }
393
394 #[inline]
401 pub fn object_type(&self) -> PdfPageObjectType {
402 match self {
403 PdfPageObject::Text(_) => PdfPageObjectType::Text,
404 PdfPageObject::Path(_) => PdfPageObjectType::Path,
405 PdfPageObject::Image(_) => PdfPageObjectType::Image,
406 PdfPageObject::Shading(_) => PdfPageObjectType::Shading,
407 PdfPageObject::XObjectForm(_) => PdfPageObjectType::XObjectForm,
408 PdfPageObject::Unsupported(_) => PdfPageObjectType::Unsupported,
409 }
410 }
411
412 #[inline]
418 pub fn is_supported(&self) -> bool {
419 !self.is_unsupported()
420 }
421
422 #[inline]
428 pub fn is_unsupported(&self) -> bool {
429 self.object_type() == PdfPageObjectType::Unsupported
430 }
431
432 #[inline]
435 pub fn as_text_object(&self) -> Option<&PdfPageTextObject<'_>> {
436 match self {
437 PdfPageObject::Text(object) => Some(object),
438 _ => None,
439 }
440 }
441
442 #[inline]
445 pub fn as_text_object_mut(&mut self) -> Option<&mut PdfPageTextObject<'a>> {
446 match self {
447 PdfPageObject::Text(object) => Some(object),
448 _ => None,
449 }
450 }
451
452 #[inline]
455 pub fn as_path_object(&self) -> Option<&PdfPagePathObject<'_>> {
456 match self {
457 PdfPageObject::Path(object) => Some(object),
458 _ => None,
459 }
460 }
461
462 #[inline]
465 pub fn as_path_object_mut(&mut self) -> Option<&mut PdfPagePathObject<'a>> {
466 match self {
467 PdfPageObject::Path(object) => Some(object),
468 _ => None,
469 }
470 }
471
472 #[inline]
475 pub fn as_image_object(&self) -> Option<&PdfPageImageObject<'_>> {
476 match self {
477 PdfPageObject::Image(object) => Some(object),
478 _ => None,
479 }
480 }
481
482 #[inline]
485 pub fn as_image_object_mut(&mut self) -> Option<&mut PdfPageImageObject<'a>> {
486 match self {
487 PdfPageObject::Image(object) => Some(object),
488 _ => None,
489 }
490 }
491
492 #[inline]
495 pub fn as_shading_object(&self) -> Option<&PdfPageShadingObject<'_>> {
496 match self {
497 PdfPageObject::Shading(object) => Some(object),
498 _ => None,
499 }
500 }
501
502 #[inline]
505 pub fn as_shading_object_mut(&mut self) -> Option<&mut PdfPageShadingObject<'a>> {
506 match self {
507 PdfPageObject::Shading(object) => Some(object),
508 _ => None,
509 }
510 }
511
512 #[inline]
515 pub fn as_x_object_form_object(&self) -> Option<&PdfPageXObjectFormObject<'_>> {
516 match self {
517 PdfPageObject::XObjectForm(object) => Some(object),
518 _ => None,
519 }
520 }
521
522 #[inline]
525 pub fn as_x_object_form_object_mut(&mut self) -> Option<&mut PdfPageXObjectFormObject<'a>> {
526 match self {
527 PdfPageObject::XObjectForm(object) => Some(object),
528 _ => None,
529 }
530 }
531
532 pub fn get_clip_path(&self) -> Option<PdfClipPath<'_>> {
534 let path_handle = unsafe {
535 self.bindings()
536 .FPDFPageObj_GetClipPath(self.object_handle())
537 };
538
539 if path_handle.is_null() {
540 return None;
541 }
542
543 return Some(PdfClipPath::from_pdfium(
544 path_handle,
545 self.ownership().clone(),
546 ));
547 }
548
549 #[cfg(any(
550 feature = "pdfium_future",
551 feature = "pdfium_8125",
552 feature = "pdfium_7881",
553 feature = "pdfium_7763",
554 feature = "pdfium_7543",
555 feature = "pdfium_7350",
556 feature = "pdfium_7215",
557 feature = "pdfium_7123",
558 feature = "pdfium_6996"
559 ))]
560 pub fn set_active(&mut self) -> Result<(), PdfiumError> {
563 if self.bindings().is_true(unsafe {
564 self.bindings()
565 .FPDFPageObj_SetIsActive(self.object_handle(), self.bindings().TRUE())
566 }) {
567 Ok(())
568 } else {
569 Err(PdfiumError::PdfiumLibraryInternalError(
570 PdfiumInternalError::Unknown,
571 ))
572 }
573 }
574
575 #[cfg(any(
576 feature = "pdfium_future",
577 feature = "pdfium_8125",
578 feature = "pdfium_7881",
579 feature = "pdfium_7763",
580 feature = "pdfium_7543",
581 feature = "pdfium_7350",
582 feature = "pdfium_7215",
583 feature = "pdfium_7123",
584 feature = "pdfium_6996"
585 ))]
586 pub fn is_active(&self) -> Result<bool, PdfiumError> {
588 let mut result = self.bindings().FALSE();
589
590 if self.bindings().is_true(unsafe {
591 self.bindings()
592 .FPDFPageObj_GetIsActive(self.object_handle(), &mut result)
593 }) {
594 Ok(self.bindings().is_true(result))
595 } else {
596 Err(PdfiumError::PdfiumLibraryInternalError(
597 PdfiumInternalError::Unknown,
598 ))
599 }
600 }
601
602 #[cfg(any(
603 feature = "pdfium_future",
604 feature = "pdfium_8125",
605 feature = "pdfium_7881",
606 feature = "pdfium_7763",
607 feature = "pdfium_7543",
608 feature = "pdfium_7350",
609 feature = "pdfium_7215",
610 feature = "pdfium_7123",
611 feature = "pdfium_6996"
612 ))]
613 pub fn set_inactive(&mut self) -> Result<(), PdfiumError> {
616 if self.bindings().is_true(unsafe {
617 self.bindings()
618 .FPDFPageObj_SetIsActive(self.object_handle(), self.bindings().FALSE())
619 }) {
620 Ok(())
621 } else {
622 Err(PdfiumError::PdfiumLibraryInternalError(
623 PdfiumInternalError::Unknown,
624 ))
625 }
626 }
627
628 #[cfg(any(
629 feature = "pdfium_future",
630 feature = "pdfium_8125",
631 feature = "pdfium_7881",
632 feature = "pdfium_7763",
633 feature = "pdfium_7543",
634 feature = "pdfium_7350",
635 feature = "pdfium_7215",
636 feature = "pdfium_7123",
637 feature = "pdfium_6996"
638 ))]
639 #[inline]
641 pub fn is_inactive(&self) -> Result<bool, PdfiumError> {
642 self.is_active().map(|result| !result)
643 }
644
645 create_transform_setters!(
646 &mut Self,
647 Result<(), PdfiumError>,
648 "this [PdfPageObject]",
649 "this [PdfPageObject].",
650 "this [PdfPageObject],"
651 );
652
653 create_transform_getters!(
657 "this [PdfPageObject]",
658 "this [PdfPageObject].",
659 "this [PdfPageObject],"
660 );
661
662 }
665
666impl<'a> PdfiumLibraryBindingsAccessor<'a> for PdfPageObject<'a> {}
667
668#[cfg(feature = "thread_safe")]
669unsafe impl<'a> Send for PdfPageObject<'a> {}
670
671#[cfg(feature = "thread_safe")]
672unsafe impl<'a> Sync for PdfPageObject<'a> {}
673
674pub trait PdfPageObjectCommon<'a> {
676 fn has_transparency(&self) -> bool;
678
679 fn bounds(&self) -> Result<PdfQuadPoints, PdfiumError>;
686
687 #[inline]
689 fn width(&self) -> Result<PdfPoints, PdfiumError> {
690 Ok(self.bounds()?.width())
691 }
692
693 #[inline]
695 fn height(&self) -> Result<PdfPoints, PdfiumError> {
696 Ok(self.bounds()?.height())
697 }
698
699 #[inline]
701 fn is_inside_rect(&self, rect: &PdfRect) -> bool {
702 self.bounds()
703 .map(|bounds| bounds.to_rect().is_inside(rect))
704 .unwrap_or(false)
705 }
706
707 #[inline]
710 fn does_overlap_rect(&self, rect: &PdfRect) -> bool {
711 self.bounds()
712 .map(|bounds| bounds.to_rect().does_overlap(rect))
713 .unwrap_or(false)
714 }
715
716 fn transform_from(&mut self, other: &PdfPageObject) -> Result<(), PdfiumError>;
721
722 fn set_blend_mode(&mut self, blend_mode: PdfPageObjectBlendMode) -> Result<(), PdfiumError>;
726
727 fn fill_color(&self) -> Result<PdfColor, PdfiumError>;
729
730 fn set_fill_color(&mut self, fill_color: PdfColor) -> Result<(), PdfiumError>;
732
733 fn stroke_color(&self) -> Result<PdfColor, PdfiumError>;
735
736 fn set_stroke_color(&mut self, stroke_color: PdfColor) -> Result<(), PdfiumError>;
741
742 fn stroke_width(&self) -> Result<PdfPoints, PdfiumError>;
744
745 fn set_stroke_width(&mut self, stroke_width: PdfPoints) -> Result<(), PdfiumError>;
755
756 fn line_join(&self) -> Result<PdfPageObjectLineJoin, PdfiumError>;
759
760 fn set_line_join(&mut self, line_join: PdfPageObjectLineJoin) -> Result<(), PdfiumError>;
763
764 fn line_cap(&self) -> Result<PdfPageObjectLineCap, PdfiumError>;
767
768 fn set_line_cap(&mut self, line_cap: PdfPageObjectLineCap) -> Result<(), PdfiumError>;
771
772 fn dash_phase(&self) -> Result<PdfPoints, PdfiumError>;
788
789 fn set_dash_phase(&mut self, dash_phase: PdfPoints) -> Result<(), PdfiumError>;
805
806 fn dash_array(&self) -> Result<Vec<PdfPoints>, PdfiumError>;
822
823 fn set_dash_array(&mut self, array: &[PdfPoints], phase: PdfPoints) -> Result<(), PdfiumError>;
839
840 fn copy_to_page<'b>(
844 &mut self,
845 page: &mut PdfPage<'b>,
846 ) -> Result<PdfPageObject<'b>, PdfiumError>;
847
848 fn move_to_page(&mut self, page: &mut PdfPage) -> Result<(), PdfiumError>;
855
856 fn move_to_annotation(&mut self, annotation: &mut PdfPageAnnotation)
863 -> Result<(), PdfiumError>;
864}
865
866impl<'a, T> PdfPageObjectCommon<'a> for T
869where
870 T: PdfPageObjectPrivate<'a>,
871{
872 #[inline]
873 fn has_transparency(&self) -> bool {
874 self.has_transparency_impl()
875 }
876
877 #[inline]
878 fn bounds(&self) -> Result<PdfQuadPoints, PdfiumError> {
879 self.bounds_impl()
880 }
881
882 #[inline]
883 fn transform_from(&mut self, other: &PdfPageObject) -> Result<(), PdfiumError> {
884 self.reset_matrix_impl(other.matrix()?)
885 }
886
887 #[inline]
888 fn set_blend_mode(&mut self, blend_mode: PdfPageObjectBlendMode) -> Result<(), PdfiumError> {
889 unsafe {
890 self.bindings()
891 .FPDFPageObj_SetBlendMode(self.object_handle(), blend_mode.as_pdfium());
892 }
893
894 Ok(())
895 }
896
897 #[inline]
898 fn fill_color(&self) -> Result<PdfColor, PdfiumError> {
899 let mut r = 0;
900 let mut g = 0;
901 let mut b = 0;
902 let mut a = 0;
903
904 if self.bindings().is_true(unsafe {
905 self.bindings().FPDFPageObj_GetFillColor(
906 self.object_handle(),
907 &mut r,
908 &mut g,
909 &mut b,
910 &mut a,
911 )
912 }) {
913 Ok(PdfColor::new(
914 r.try_into()
915 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
916 g.try_into()
917 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
918 b.try_into()
919 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
920 a.try_into()
921 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
922 ))
923 } else {
924 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
925 }
926 }
927
928 #[inline]
929 fn set_fill_color(&mut self, fill_color: PdfColor) -> Result<(), PdfiumError> {
930 if self.bindings().is_true(unsafe {
931 self.bindings().FPDFPageObj_SetFillColor(
932 self.object_handle(),
933 fill_color.red() as c_uint,
934 fill_color.green() as c_uint,
935 fill_color.blue() as c_uint,
936 fill_color.alpha() as c_uint,
937 )
938 }) {
939 Ok(())
940 } else {
941 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
942 }
943 }
944
945 #[inline]
946 fn stroke_color(&self) -> Result<PdfColor, PdfiumError> {
947 let mut r = 0;
948 let mut g = 0;
949 let mut b = 0;
950 let mut a = 0;
951
952 if self.bindings().is_true(unsafe {
953 self.bindings().FPDFPageObj_GetStrokeColor(
954 self.object_handle(),
955 &mut r,
956 &mut g,
957 &mut b,
958 &mut a,
959 )
960 }) {
961 Ok(PdfColor::new(
962 r.try_into()
963 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
964 g.try_into()
965 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
966 b.try_into()
967 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
968 a.try_into()
969 .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
970 ))
971 } else {
972 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
973 }
974 }
975
976 #[inline]
977 fn set_stroke_color(&mut self, stroke_color: PdfColor) -> Result<(), PdfiumError> {
978 if self.bindings().is_true(unsafe {
979 self.bindings().FPDFPageObj_SetStrokeColor(
980 self.object_handle(),
981 stroke_color.red() as c_uint,
982 stroke_color.green() as c_uint,
983 stroke_color.blue() as c_uint,
984 stroke_color.alpha() as c_uint,
985 )
986 }) {
987 Ok(())
988 } else {
989 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
990 }
991 }
992
993 #[inline]
994 fn stroke_width(&self) -> Result<PdfPoints, PdfiumError> {
995 let mut width = 0.0;
996
997 if self.bindings().is_true(unsafe {
998 self.bindings()
999 .FPDFPageObj_GetStrokeWidth(self.object_handle(), &mut width)
1000 }) {
1001 Ok(PdfPoints::new(width))
1002 } else {
1003 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1004 }
1005 }
1006
1007 #[inline]
1008 fn set_stroke_width(&mut self, stroke_width: PdfPoints) -> Result<(), PdfiumError> {
1009 if self.bindings().is_true(unsafe {
1010 self.bindings()
1011 .FPDFPageObj_SetStrokeWidth(self.object_handle(), stroke_width.value)
1012 }) {
1013 Ok(())
1014 } else {
1015 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1016 }
1017 }
1018
1019 #[inline]
1020 fn line_join(&self) -> Result<PdfPageObjectLineJoin, PdfiumError> {
1021 PdfPageObjectLineJoin::from_pdfium(unsafe {
1022 self.bindings()
1023 .FPDFPageObj_GetLineJoin(self.object_handle())
1024 })
1025 .ok_or(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1026 }
1027
1028 #[inline]
1029 fn set_line_join(&mut self, line_join: PdfPageObjectLineJoin) -> Result<(), PdfiumError> {
1030 if self.bindings().is_true(unsafe {
1031 self.bindings()
1032 .FPDFPageObj_SetLineJoin(self.object_handle(), line_join.as_pdfium() as c_int)
1033 }) {
1034 Ok(())
1035 } else {
1036 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1037 }
1038 }
1039
1040 #[inline]
1041 fn line_cap(&self) -> Result<PdfPageObjectLineCap, PdfiumError> {
1042 PdfPageObjectLineCap::from_pdfium(unsafe {
1043 self.bindings().FPDFPageObj_GetLineCap(self.object_handle())
1044 })
1045 .ok_or(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1046 }
1047
1048 #[inline]
1049 fn set_line_cap(&mut self, line_cap: PdfPageObjectLineCap) -> Result<(), PdfiumError> {
1050 if self.bindings().is_true(unsafe {
1051 self.bindings()
1052 .FPDFPageObj_SetLineCap(self.object_handle(), line_cap.as_pdfium() as c_int)
1053 }) {
1054 Ok(())
1055 } else {
1056 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1057 }
1058 }
1059
1060 #[inline]
1061 fn dash_phase(&self) -> Result<PdfPoints, PdfiumError> {
1062 let mut phase = 0.0;
1063
1064 if self.bindings().is_true(unsafe {
1065 self.bindings()
1066 .FPDFPageObj_GetDashPhase(self.object_handle(), &mut phase)
1067 }) {
1068 Ok(PdfPoints::new(phase))
1069 } else {
1070 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1071 }
1072 }
1073
1074 #[inline]
1075 fn set_dash_phase(&mut self, dash_phase: PdfPoints) -> Result<(), PdfiumError> {
1076 if self.bindings().is_true(unsafe {
1077 self.bindings()
1078 .FPDFPageObj_SetDashPhase(self.object_handle(), dash_phase.value)
1079 }) {
1080 Ok(())
1081 } else {
1082 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1083 }
1084 }
1085
1086 #[inline]
1087 fn dash_array(&self) -> Result<Vec<PdfPoints>, PdfiumError> {
1088 let dash_count = unsafe {
1089 self.bindings()
1090 .FPDFPageObj_GetDashCount(self.object_handle())
1091 } as usize;
1092
1093 let mut dash_array = vec![0.0; dash_count];
1094
1095 if self.bindings().is_true(unsafe {
1096 self.bindings().FPDFPageObj_GetDashArray(
1097 self.object_handle(),
1098 dash_array.as_mut_ptr(),
1099 dash_count,
1100 )
1101 }) {
1102 Ok(dash_array
1103 .iter()
1104 .map(|dash| PdfPoints::new(*dash))
1105 .collect())
1106 } else {
1107 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1108 }
1109 }
1110
1111 fn set_dash_array(&mut self, array: &[PdfPoints], phase: PdfPoints) -> Result<(), PdfiumError> {
1112 let dash_array = array.iter().map(|dash| dash.value).collect::<Vec<_>>();
1113
1114 if self.bindings().is_true(unsafe {
1115 self.bindings().FPDFPageObj_SetDashArray(
1116 self.object_handle(),
1117 dash_array.as_ptr(),
1118 dash_array.len(),
1119 phase.value,
1120 )
1121 }) {
1122 Ok(())
1123 } else {
1124 Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
1125 }
1126 }
1127
1128 #[inline]
1129 fn copy_to_page<'b>(
1130 &mut self,
1131 page: &mut PdfPage<'b>,
1132 ) -> Result<PdfPageObject<'b>, PdfiumError> {
1133 self.copy_to_page_impl(page)
1134 }
1135
1136 fn move_to_page(&mut self, page: &mut PdfPage) -> Result<(), PdfiumError> {
1137 match self.ownership() {
1138 PdfPageObjectOwnership::Document(ownership) => {
1139 if ownership.document_handle() != page.document_handle() {
1140 return Err(PdfiumError::CannotMoveObjectAcrossDocuments);
1141 }
1142 }
1143 PdfPageObjectOwnership::Page(_) => self.remove_object_from_page()?,
1144 PdfPageObjectOwnership::AttachedAnnotation(_)
1145 | PdfPageObjectOwnership::UnattachedAnnotation(_) => {
1146 self.remove_object_from_annotation()?
1147 }
1148 PdfPageObjectOwnership::Unowned => {}
1149 }
1150
1151 self.add_object_to_page(page.objects_mut())
1152 }
1153
1154 fn move_to_annotation(
1155 &mut self,
1156 annotation: &mut PdfPageAnnotation,
1157 ) -> Result<(), PdfiumError> {
1158 match self.ownership() {
1159 PdfPageObjectOwnership::Document(ownership) => {
1160 let annotation_document_handle = match annotation.ownership() {
1161 PdfPageObjectOwnership::Document(ownership) => {
1162 Some(ownership.document_handle())
1163 }
1164 PdfPageObjectOwnership::Page(ownership) => Some(ownership.document_handle()),
1165 PdfPageObjectOwnership::AttachedAnnotation(ownership) => {
1166 Some(ownership.document_handle())
1167 }
1168 PdfPageObjectOwnership::UnattachedAnnotation(_)
1169 | PdfPageObjectOwnership::Unowned => None,
1170 };
1171
1172 if let Some(annotation_document_handle) = annotation_document_handle {
1173 if ownership.document_handle() != annotation_document_handle {
1174 return Err(PdfiumError::CannotMoveObjectAcrossDocuments);
1175 }
1176 }
1177 }
1178 PdfPageObjectOwnership::Page(_) => self.remove_object_from_page()?,
1179 PdfPageObjectOwnership::AttachedAnnotation(_)
1180 | PdfPageObjectOwnership::UnattachedAnnotation(_) => {
1181 self.remove_object_from_annotation()?
1182 }
1183 PdfPageObjectOwnership::Unowned => {}
1184 }
1185
1186 self.add_object_to_annotation(annotation.objects())
1187 }
1188}
1189
1190impl<'a> PdfPageObjectPrivate<'a> for PdfPageObject<'a> {
1191 #[inline]
1192 fn object_handle(&self) -> FPDF_PAGEOBJECT {
1193 self.unwrap_as_trait().object_handle()
1194 }
1195
1196 #[inline]
1197 fn ownership(&self) -> &PdfPageObjectOwnership {
1198 self.unwrap_as_trait().ownership()
1199 }
1200
1201 #[inline]
1202 fn set_ownership(&mut self, ownership: PdfPageObjectOwnership) {
1203 self.unwrap_as_trait_mut().set_ownership(ownership);
1204 }
1205
1206 #[inline]
1207 fn add_object_to_page(&mut self, page_objects: &mut PdfPageObjects) -> Result<(), PdfiumError> {
1208 self.unwrap_as_trait_mut().add_object_to_page(page_objects)
1209 }
1210
1211 #[cfg(any(
1212 feature = "pdfium_future",
1213 feature = "pdfium_8125",
1214 feature = "pdfium_7881",
1215 feature = "pdfium_7763",
1216 feature = "pdfium_7543",
1217 feature = "pdfium_7350"
1218 ))]
1219 #[inline]
1220 fn insert_object_on_page(
1221 &mut self,
1222 page_objects: &mut PdfPageObjects,
1223 index: PdfPageObjectIndex,
1224 ) -> Result<(), PdfiumError> {
1225 self.unwrap_as_trait_mut()
1226 .insert_object_on_page(page_objects, index)
1227 }
1228
1229 #[inline]
1230 fn remove_object_from_page(&mut self) -> Result<(), PdfiumError> {
1231 self.unwrap_as_trait_mut().remove_object_from_page()
1232 }
1233
1234 #[inline]
1235 fn add_object_to_annotation(
1236 &mut self,
1237 annotation_objects: &PdfPageAnnotationObjects,
1238 ) -> Result<(), PdfiumError> {
1239 self.unwrap_as_trait_mut()
1240 .add_object_to_annotation(annotation_objects)
1241 }
1242
1243 #[inline]
1244 fn remove_object_from_annotation(&mut self) -> Result<(), PdfiumError> {
1245 self.unwrap_as_trait_mut().remove_object_from_annotation()
1246 }
1247
1248 #[inline]
1249 fn copy_to_page_impl<'b>(
1250 &mut self,
1251 page: &mut PdfPage<'b>,
1252 ) -> Result<PdfPageObject<'b>, PdfiumError> {
1253 self.unwrap_as_trait_mut().copy_to_page_impl(page)
1254 }
1255}
1256
1257impl<'a> From<PdfPageXObjectFormObject<'a>> for PdfPageObject<'a> {
1258 #[inline]
1259 fn from(object: PdfPageXObjectFormObject<'a>) -> Self {
1260 Self::XObjectForm(object)
1261 }
1262}
1263
1264impl<'a> From<PdfPageImageObject<'a>> for PdfPageObject<'a> {
1265 #[inline]
1266 fn from(object: PdfPageImageObject<'a>) -> Self {
1267 Self::Image(object)
1268 }
1269}
1270
1271impl<'a> From<PdfPagePathObject<'a>> for PdfPageObject<'a> {
1272 #[inline]
1273 fn from(object: PdfPagePathObject<'a>) -> Self {
1274 Self::Path(object)
1275 }
1276}
1277
1278impl<'a> From<PdfPageShadingObject<'a>> for PdfPageObject<'a> {
1279 #[inline]
1280 fn from(object: PdfPageShadingObject<'a>) -> Self {
1281 Self::Shading(object)
1282 }
1283}
1284
1285impl<'a> From<PdfPageTextObject<'a>> for PdfPageObject<'a> {
1286 #[inline]
1287 fn from(object: PdfPageTextObject<'a>) -> Self {
1288 Self::Text(object)
1289 }
1290}
1291
1292impl<'a> From<PdfPageUnsupportedObject<'a>> for PdfPageObject<'a> {
1293 #[inline]
1294 fn from(object: PdfPageUnsupportedObject<'a>) -> Self {
1295 Self::Unsupported(object)
1296 }
1297}
1298
1299#[cfg(test)]
1300mod tests {
1301 use crate::prelude::*;
1302 use crate::utils::test::test_bind_to_pdfium;
1303
1304 #[test]
1305 fn test_apply_matrix() -> Result<(), PdfiumError> {
1306 let pdfium = test_bind_to_pdfium();
1307
1308 let mut document = pdfium.create_new_pdf()?;
1309
1310 let mut page = document
1311 .pages_mut()
1312 .create_page_at_start(PdfPagePaperSize::a4())?;
1313
1314 let font = document.fonts_mut().times_roman();
1315
1316 let mut object = page.objects_mut().create_text_object(
1317 PdfPoints::ZERO,
1318 PdfPoints::ZERO,
1319 "My new text object",
1320 font,
1321 PdfPoints::new(10.0),
1322 )?;
1323
1324 object.translate(PdfPoints::new(100.0), PdfPoints::new(100.0))?;
1327 object.flip_vertically()?;
1328 object.rotate_clockwise_degrees(45.0)?;
1329 object.scale(3.0, 4.0)?;
1330
1331 let previous_matrix = object.matrix()?;
1332
1333 object.apply_matrix(PdfMatrix::IDENTITY)?;
1336
1337 assert_eq!(previous_matrix, object.matrix()?);
1338
1339 Ok(())
1340 }
1341
1342 #[test]
1343 fn test_reset_matrix_to_identity() -> Result<(), PdfiumError> {
1344 let pdfium = test_bind_to_pdfium();
1345
1346 let mut document = pdfium.create_new_pdf()?;
1347
1348 let mut page = document
1349 .pages_mut()
1350 .create_page_at_start(PdfPagePaperSize::a4())?;
1351
1352 let font = document.fonts_mut().times_roman();
1353
1354 let mut object = page.objects_mut().create_text_object(
1355 PdfPoints::ZERO,
1356 PdfPoints::ZERO,
1357 "My new text object",
1358 font,
1359 PdfPoints::new(10.0),
1360 )?;
1361
1362 object.translate(PdfPoints::new(100.0), PdfPoints::new(100.0))?;
1365 object.flip_vertically()?;
1366 object.rotate_clockwise_degrees(45.0)?;
1367 object.scale(3.0, 4.0)?;
1368
1369 let previous_matrix = object.matrix()?;
1370
1371 object.reset_matrix_to_identity()?;
1375
1376 assert_ne!(previous_matrix, object.matrix()?);
1377 assert_eq!(object.matrix()?, PdfMatrix::IDENTITY);
1378
1379 Ok(())
1380 }
1381
1382 #[test]
1383 fn test_transform_captured_in_content_regeneration() -> Result<(), PdfiumError> {
1384 let pdfium = test_bind_to_pdfium();
1390
1391 let mut document = pdfium.create_new_pdf()?;
1392
1393 let x = PdfPoints::new(100.0);
1394 let y = PdfPoints::new(400.0);
1395
1396 let object_matrix_before_rotation = {
1397 let mut page = document
1398 .pages_mut()
1399 .create_page_at_start(PdfPagePaperSize::a4())?;
1400
1401 let font = document
1402 .fonts_mut()
1403 .new_built_in(PdfFontBuiltin::TimesRoman);
1404
1405 let mut object = page.objects_mut().create_text_object(
1406 x,
1407 y,
1408 "Hello world!",
1409 font,
1410 PdfPoints::new(20.0),
1411 )?;
1412
1413 let object_matrix_before_rotation = object.matrix()?;
1414
1415 object.rotate_clockwise_degrees(45.0)?;
1419
1420 object_matrix_before_rotation
1421 };
1422
1423 assert_eq!(
1429 object_matrix_before_rotation.rotate_clockwise_degrees(45.0)?,
1430 document.pages().first()?.objects().first()?.matrix()?
1431 );
1432
1433 Ok(())
1434 }
1435}