1use crate::bindgen::{
5 fpdf_page_t__, FPDF_DOCUMENT, FPDF_IMAGEOBJ_METADATA, FPDF_PAGE, FPDF_PAGEOBJECT,
6};
7use crate::bindings::PdfiumLibraryBindings;
8use crate::error::{PdfiumError, PdfiumInternalError};
9use crate::pdf::bitmap::PdfBitmap;
10use crate::pdf::bitmap::Pixels;
11use crate::pdf::color_space::PdfColorSpace;
12use crate::pdf::document::page::object::private::internal::PdfPageObjectPrivate;
13use crate::pdf::document::page::object::{PdfPageObject, PdfPageObjectOwnership};
14use crate::pdf::document::PdfDocument;
15use crate::pdf::matrix::{PdfMatrix, PdfMatrixValue};
16use crate::pdf::points::PdfPoints;
17use crate::utils::mem::create_byte_buffer;
18use crate::{create_transform_getters, create_transform_setters};
19use std::convert::TryInto;
20use std::io::{Read, Seek};
21use std::ops::{Range, RangeInclusive};
22use std::os::raw::{c_int, c_void};
23
24#[cfg(not(target_arch = "wasm32"))]
25use {crate::utils::files::get_pdfium_file_accessor_from_reader, std::fs::File, std::path::Path};
26
27#[cfg(any(feature = "image_latest", feature = "image_025"))]
28use {
29 crate::pdf::bitmap::PdfBitmapFormat,
30 crate::utils::pixels::{
31 aligned_bgr_to_rgba, aligned_grayscale_to_unaligned, bgra_to_rgba, rgba_to_bgra,
32 },
33 image_025::{DynamicImage, EncodableLayout, GrayImage, RgbaImage},
34};
35
36#[cfg(feature = "image_024")]
37use {
38 crate::pdf::bitmap::PdfBitmapFormat,
39 crate::utils::pixels::{aligned_bgr_to_rgba, aligned_grayscale, bgra_to_rgba, rgba_to_bgra},
40 image_024::{DynamicImage, EncodableLayout, GrayImage, RgbaImage},
41};
42
43#[cfg(feature = "image_023")]
44use {
45 crate::pdf::bitmap::PdfBitmapFormat,
46 crate::utils::pixels::{aligned_bgr_to_rgba, aligned_grayscale, bgra_to_rgba, rgba_to_bgra},
47 image_023::{DynamicImage, EncodableLayout, GenericImageView, GrayImage, RgbaImage},
48};
49
50#[cfg(doc)]
51use {crate::pdf::document::page::object::PdfPageObjectType, crate::pdf::document::page::PdfPage};
52
53pub struct PdfPageImageObject<'a> {
71 object_handle: FPDF_PAGEOBJECT,
72 ownership: PdfPageObjectOwnership,
73 bindings: &'a dyn PdfiumLibraryBindings,
74}
75
76impl<'a> PdfPageImageObject<'a> {
77 #[inline]
78 pub(crate) fn from_pdfium(
79 object_handle: FPDF_PAGEOBJECT,
80 ownership: PdfPageObjectOwnership,
81 bindings: &'a dyn PdfiumLibraryBindings,
82 ) -> Self {
83 PdfPageImageObject {
84 object_handle,
85 ownership,
86 bindings,
87 }
88 }
89
90 #[cfg(feature = "image_api")]
102 #[inline]
103 pub fn new(document: &PdfDocument<'a>, image: &DynamicImage) -> Result<Self, PdfiumError> {
104 let mut result = Self::new_from_handle(document.handle(), document.bindings());
105
106 if let Ok(result) = result.as_mut() {
107 result.set_image(image)?;
108 }
109
110 result
111 }
112
113 #[cfg(not(feature = "image_api"))]
124 pub fn new(document: &PdfDocument<'a>) -> Result<Self, PdfiumError> {
125 Self::new_from_handle(document.handle(), document.bindings())
126 }
127
128 #[cfg(not(target_arch = "wasm32"))]
140 pub fn new_from_jpeg_file(
141 document: &PdfDocument<'a>,
142 path: &(impl AsRef<Path> + ?Sized),
143 ) -> Result<Self, PdfiumError> {
144 Self::new_from_jpeg_reader(document, File::open(path).map_err(PdfiumError::IoError)?)
145 }
146
147 #[cfg(not(target_arch = "wasm32"))]
163 pub fn new_from_jpeg_reader<R: Read + Seek>(
164 document: &PdfDocument<'a>,
165 reader: R,
166 ) -> Result<Self, PdfiumError> {
167 let object = Self::new_from_handle(document.handle(), document.bindings())?;
168
169 let mut reader = get_pdfium_file_accessor_from_reader(reader);
170
171 let result = document.bindings().FPDFImageObj_LoadJpegFileInline(
172 std::ptr::null_mut(),
173 0,
174 object.object_handle(),
175 reader.as_fpdf_file_access_mut_ptr(),
176 );
177
178 if object.bindings.is_true(result) {
179 Ok(object)
180 } else {
181 Err(PdfiumError::PdfiumLibraryInternalError(
182 PdfiumInternalError::Unknown,
183 ))
184 }
185 }
186
187 pub(crate) fn new_from_handle(
190 document: FPDF_DOCUMENT,
191 bindings: &'a dyn PdfiumLibraryBindings,
192 ) -> Result<Self, PdfiumError> {
193 let handle = bindings.FPDFPageObj_NewImageObj(document);
194
195 if handle.is_null() {
196 Err(PdfiumError::PdfiumLibraryInternalError(
197 PdfiumInternalError::Unknown,
198 ))
199 } else {
200 Ok(PdfPageImageObject {
201 object_handle: handle,
202 ownership: PdfPageObjectOwnership::unowned(),
203 bindings,
204 })
205 }
206 }
207
208 #[cfg(feature = "image_api")]
215 pub fn new_with_width(
216 document: &PdfDocument<'a>,
217 image: &DynamicImage,
218 width: PdfPoints,
219 ) -> Result<Self, PdfiumError> {
220 let aspect_ratio = image.height() as f32 / image.width() as f32;
221
222 let height = width * aspect_ratio;
223
224 Self::new_with_size(document, image, width, height)
225 }
226
227 #[cfg(feature = "image_api")]
234 pub fn new_with_height(
235 document: &PdfDocument<'a>,
236 image: &DynamicImage,
237 height: PdfPoints,
238 ) -> Result<Self, PdfiumError> {
239 let aspect_ratio = image.height() as f32 / image.width() as f32;
240
241 let width = height / aspect_ratio;
242
243 Self::new_with_size(document, image, width, height)
244 }
245
246 #[cfg(feature = "image_api")]
252 #[inline]
253 pub fn new_with_size(
254 document: &PdfDocument<'a>,
255 image: &DynamicImage,
256 width: PdfPoints,
257 height: PdfPoints,
258 ) -> Result<Self, PdfiumError> {
259 let mut result = Self::new(document, image)?;
260
261 result.scale(width.value, height.value)?;
262
263 Ok(result)
264 }
265
266 pub fn get_raw_bitmap(&self) -> Result<PdfBitmap, PdfiumError> {
270 Ok(PdfBitmap::from_pdfium(
271 self.bindings().FPDFImageObj_GetBitmap(self.object_handle()),
272 self.bindings(),
273 ))
274 }
275
276 #[cfg(feature = "image_api")]
282 #[inline]
283 pub fn get_raw_image(&self) -> Result<DynamicImage, PdfiumError> {
284 self.get_image_from_bitmap(&self.get_raw_bitmap()?)
285 }
286
287 #[inline]
291 pub fn get_processed_bitmap(&self, document: &PdfDocument) -> Result<PdfBitmap, PdfiumError> {
292 let (width, height) = self.get_current_width_and_height_from_metadata()?;
293
294 self.get_processed_bitmap_with_size(document, width, height)
295 }
296
297 #[cfg(feature = "image_api")]
303 #[inline]
304 pub fn get_processed_image(&self, document: &PdfDocument) -> Result<DynamicImage, PdfiumError> {
305 let (width, height) = self.get_current_width_and_height_from_metadata()?;
306
307 self.get_processed_image_with_size(document, width, height)
308 }
309
310 #[inline]
316 pub fn get_processed_bitmap_with_width(
317 &self,
318 document: &PdfDocument,
319 width: Pixels,
320 ) -> Result<PdfBitmap, PdfiumError> {
321 let (current_width, current_height) = self.get_current_width_and_height_from_metadata()?;
322
323 let aspect_ratio = current_width as f32 / current_height as f32;
324
325 self.get_processed_bitmap_with_size(
326 document,
327 width,
328 ((width as f32 / aspect_ratio) as u32)
329 .try_into()
330 .map_err(|_| PdfiumError::ImageSizeOutOfBounds)?,
331 )
332 }
333
334 #[cfg(feature = "image_api")]
342 #[inline]
343 pub fn get_processed_image_with_width(
344 &self,
345 document: &PdfDocument,
346 width: Pixels,
347 ) -> Result<DynamicImage, PdfiumError> {
348 let (current_width, current_height) = self.get_current_width_and_height_from_metadata()?;
349
350 let aspect_ratio = current_width as f32 / current_height as f32;
351
352 self.get_processed_image_with_size(
353 document,
354 width,
355 ((width as f32 / aspect_ratio) as u32)
356 .try_into()
357 .map_err(|_| PdfiumError::ImageSizeOutOfBounds)?,
358 )
359 }
360
361 #[inline]
367 pub fn get_processed_bitmap_with_height(
368 &self,
369 document: &PdfDocument,
370 height: Pixels,
371 ) -> Result<PdfBitmap, PdfiumError> {
372 let (current_width, current_height) = self.get_current_width_and_height_from_metadata()?;
373
374 let aspect_ratio = current_width as f32 / current_height as f32;
375
376 self.get_processed_bitmap_with_size(
377 document,
378 ((height as f32 * aspect_ratio) as u32)
379 .try_into()
380 .map_err(|_| PdfiumError::ImageSizeOutOfBounds)?,
381 height,
382 )
383 }
384
385 #[cfg(feature = "image_api")]
393 #[inline]
394 pub fn get_processed_image_with_height(
395 &self,
396 document: &PdfDocument,
397 height: Pixels,
398 ) -> Result<DynamicImage, PdfiumError> {
399 let (current_width, current_height) = self.get_current_width_and_height_from_metadata()?;
400
401 let aspect_ratio = current_width as f32 / current_height as f32;
402
403 self.get_processed_image_with_size(
404 document,
405 ((height as f32 * aspect_ratio) as u32)
406 .try_into()
407 .map_err(|_| PdfiumError::ImageSizeOutOfBounds)?,
408 height,
409 )
410 }
411
412 pub fn get_processed_bitmap_with_size(
419 &self,
420 document: &PdfDocument,
421 width: Pixels,
422 height: Pixels,
423 ) -> Result<PdfBitmap, PdfiumError> {
424 let mut matrix = self.matrix()?;
441
442 let original_matrix = matrix; if matrix.a() < 0f32 {
447 matrix.set_a(-matrix.a());
448 self.reset_matrix_impl(matrix)?;
449 }
450
451 if matrix.d() < 0f32 {
452 matrix.set_d(-matrix.d());
453 self.reset_matrix_impl(matrix)?;
454 }
455
456 let page_handle = match self.ownership() {
457 PdfPageObjectOwnership::Page(ownership) => Some(ownership.page_handle()),
458 PdfPageObjectOwnership::AttachedAnnotation(ownership) => Some(ownership.page_handle()),
459 _ => None,
460 };
461
462 let bitmap_handle = match page_handle {
463 Some(page_handle) => self.bindings().FPDFImageObj_GetRenderedBitmap(
464 document.handle(),
465 page_handle,
466 self.object_handle(),
467 ),
468 None => self.bindings.FPDFImageObj_GetRenderedBitmap(
469 document.handle(),
470 std::ptr::null_mut::<fpdf_page_t__>(),
471 self.object_handle(),
472 ),
473 };
474
475 if bitmap_handle.is_null() {
476 self.reset_matrix_impl(original_matrix)?;
480 return Err(PdfiumError::PdfiumLibraryInternalError(
481 PdfiumInternalError::Unknown,
482 ));
483 }
484
485 let result = PdfBitmap::from_pdfium(bitmap_handle, self.bindings());
486
487 if width == result.width() && height == result.height() {
488 self.reset_matrix_impl(original_matrix)?;
492
493 Ok(result)
494 } else {
495 self.transform_impl(
500 width as PdfMatrixValue / result.width() as PdfMatrixValue,
501 0.0,
502 0.0,
503 height as PdfMatrixValue / result.height() as PdfMatrixValue,
504 0.0,
505 0.0,
506 )?;
507
508 let result = PdfBitmap::from_pdfium(
511 match page_handle {
512 Some(page_handle) => self.bindings().FPDFImageObj_GetRenderedBitmap(
513 document.handle(),
514 page_handle,
515 self.object_handle(),
516 ),
517 None => self.bindings.FPDFImageObj_GetRenderedBitmap(
518 document.handle(),
519 std::ptr::null_mut::<fpdf_page_t__>(),
520 self.object_handle(),
521 ),
522 },
523 self.bindings,
524 );
525
526 self.reset_matrix_impl(original_matrix)?;
529
530 Ok(result)
531 }
532 }
533
534 #[cfg(feature = "image_api")]
543 #[inline]
544 pub fn get_processed_image_with_size(
545 &self,
546 document: &PdfDocument,
547 width: Pixels,
548 height: Pixels,
549 ) -> Result<DynamicImage, PdfiumError> {
550 self.get_processed_bitmap_with_size(document, width, height)
551 .and_then(|bitmap| self.get_image_from_bitmap(&bitmap))
552 }
553
554 #[cfg(feature = "image_api")]
555 pub(crate) fn get_image_from_bitmap(
556 &self,
557 bitmap: &PdfBitmap,
558 ) -> Result<DynamicImage, PdfiumError> {
559 let handle = *bitmap.handle();
560
561 let width = self.bindings.FPDFBitmap_GetWidth(handle);
562
563 let height = self.bindings.FPDFBitmap_GetHeight(handle);
564
565 let stride = self.bindings.FPDFBitmap_GetStride(handle);
566
567 let format =
568 PdfBitmapFormat::from_pdfium(self.bindings.FPDFBitmap_GetFormat(handle) as u32)?;
569
570 #[cfg(not(target_arch = "wasm32"))]
571 let buffer = self.bindings.FPDFBitmap_GetBuffer_as_slice(handle);
572
573 #[cfg(target_arch = "wasm32")]
574 let buffer_vec = self.bindings.FPDFBitmap_GetBuffer_as_vec(handle);
575 #[cfg(target_arch = "wasm32")]
576 let buffer = buffer_vec.as_slice();
577
578 match format {
579 #[allow(deprecated)]
580 PdfBitmapFormat::BGRA | PdfBitmapFormat::BRGx | PdfBitmapFormat::BGRx => {
581 RgbaImage::from_raw(width as u32, height as u32, bgra_to_rgba(buffer))
582 .map(DynamicImage::ImageRgba8)
583 }
584 PdfBitmapFormat::BGR => RgbaImage::from_raw(
585 width as u32,
586 height as u32,
587 aligned_bgr_to_rgba(buffer, width as usize, stride as usize),
588 )
589 .map(DynamicImage::ImageRgba8),
590 PdfBitmapFormat::Gray => GrayImage::from_raw(
591 width as u32,
592 height as u32,
593 aligned_grayscale_to_unaligned(buffer, width as usize, stride as usize),
594 )
595 .map(DynamicImage::ImageLuma8),
596 }
597 .ok_or(PdfiumError::ImageError)
598 }
599
600 pub(crate) fn get_current_width_and_height_from_metadata(
602 &self,
603 ) -> Result<(Pixels, Pixels), PdfiumError> {
604 let width = self.get_raw_metadata().and_then(|metadata| {
605 metadata
606 .width
607 .try_into()
608 .map_err(|_| PdfiumError::ImageSizeOutOfBounds)
609 })?;
610
611 let height = self.get_raw_metadata().and_then(|metadata| {
612 metadata
613 .height
614 .try_into()
615 .map_err(|_| PdfiumError::ImageSizeOutOfBounds)
616 })?;
617
618 Ok((width, height))
619 }
620
621 #[inline]
625 pub fn width(&self) -> Result<Pixels, PdfiumError> {
626 self.get_current_width_and_height_from_metadata()
627 .map(|(width, _height)| width)
628 }
629
630 #[inline]
634 pub fn height(&self) -> Result<Pixels, PdfiumError> {
635 self.get_current_width_and_height_from_metadata()
636 .map(|(_width, height)| height)
637 }
638
639 #[cfg(feature = "image_api")]
643 pub fn set_image(&mut self, image: &DynamicImage) -> Result<(), PdfiumError> {
644 let width: Pixels = image
645 .width()
646 .try_into()
647 .map_err(|_| PdfiumError::ImageSizeOutOfBounds)?;
648
649 let height: Pixels = image
650 .height()
651 .try_into()
652 .map_err(|_| PdfiumError::ImageSizeOutOfBounds)?;
653
654 let bitmap = PdfBitmap::empty(width, height, PdfBitmapFormat::BGRA, self.bindings)?;
655
656 let buffer = if let Some(image) = image.as_rgba8() {
657 rgba_to_bgra(image.as_bytes())
660 } else {
661 let image = image.to_rgba8();
664
665 rgba_to_bgra(image.as_bytes())
666 };
667
668 if !self
669 .bindings
670 .FPDFBitmap_SetBuffer(*bitmap.handle(), buffer.as_slice())
671 {
672 return Err(PdfiumError::PdfiumLibraryInternalError(
673 PdfiumInternalError::Unknown,
674 ));
675 }
676
677 self.set_bitmap(&bitmap)
678 }
679
680 pub fn set_bitmap(&mut self, bitmap: &PdfBitmap) -> Result<(), PdfiumError> {
682 if self
683 .bindings
684 .is_true(self.bindings().FPDFImageObj_SetBitmap(
685 std::ptr::null_mut::<FPDF_PAGE>(),
686 0,
687 self.object_handle(),
688 *bitmap.handle(),
689 ))
690 {
691 Ok(())
692 } else {
693 Err(PdfiumError::PdfiumLibraryInternalError(
694 PdfiumInternalError::Unknown,
695 ))
696 }
697 }
698
699 pub(crate) fn get_raw_metadata(&self) -> Result<FPDF_IMAGEOBJ_METADATA, PdfiumError> {
701 let mut metadata = FPDF_IMAGEOBJ_METADATA {
702 width: 0,
703 height: 0,
704 horizontal_dpi: 0.0,
705 vertical_dpi: 0.0,
706 bits_per_pixel: 0,
707 colorspace: 0,
708 marked_content_id: 0,
709 };
710
711 let page_handle = match self.ownership() {
712 PdfPageObjectOwnership::Page(ownership) => Some(ownership.page_handle()),
713 PdfPageObjectOwnership::AttachedAnnotation(ownership) => Some(ownership.page_handle()),
714 _ => None,
715 };
716
717 let result = self.bindings().FPDFImageObj_GetImageMetadata(
718 self.object_handle(),
719 match page_handle {
720 Some(page_handle) => page_handle,
721 None => std::ptr::null_mut::<fpdf_page_t__>(),
722 },
723 &mut metadata,
724 );
725
726 if self.bindings().is_true(result) {
727 Ok(metadata)
728 } else {
729 Err(PdfiumError::PdfiumLibraryInternalError(
730 PdfiumInternalError::Unknown,
731 ))
732 }
733 }
734
735 #[inline]
739 pub fn horizontal_dpi(&self) -> Result<f32, PdfiumError> {
740 self.get_raw_metadata()
741 .map(|metadata| metadata.horizontal_dpi)
742 }
743
744 #[inline]
748 pub fn vertical_dpi(&self) -> Result<f32, PdfiumError> {
749 self.get_raw_metadata()
750 .map(|metadata| metadata.vertical_dpi)
751 }
752
753 #[inline]
757 pub fn bits_per_pixel(&self) -> Result<u8, PdfiumError> {
758 self.get_raw_metadata()
759 .map(|metadata| metadata.bits_per_pixel as u8)
760 }
761
762 #[inline]
766 pub fn color_space(&self) -> Result<PdfColorSpace, PdfiumError> {
767 self.get_raw_metadata()
768 .and_then(|metadata| PdfColorSpace::from_pdfium(metadata.colorspace as u32))
769 }
770
771 #[inline]
773 pub fn filters(&self) -> PdfPageImageObjectFilters {
774 PdfPageImageObjectFilters::new(self)
775 }
776
777 create_transform_setters!(
778 &mut Self,
779 Result<(), PdfiumError>,
780 "this [PdfPageImageObject]",
781 "this [PdfPageImageObject].",
782 "this [PdfPageImageObject],"
783 );
784
785 create_transform_getters!(
789 "this [PdfPageImageObject]",
790 "this [PdfPageImageObject].",
791 "this [PdfPageImageObject],"
792 );
793
794 }
797
798impl<'a> PdfPageObjectPrivate<'a> for PdfPageImageObject<'a> {
799 #[inline]
800 fn object_handle(&self) -> FPDF_PAGEOBJECT {
801 self.object_handle
802 }
803
804 #[inline]
805 fn ownership(&self) -> &PdfPageObjectOwnership {
806 &self.ownership
807 }
808
809 #[inline]
810 fn set_ownership(&mut self, ownership: PdfPageObjectOwnership) {
811 self.ownership = ownership;
812 }
813
814 #[inline]
815 fn bindings(&self) -> &dyn PdfiumLibraryBindings {
816 self.bindings
817 }
818
819 #[inline]
820 fn is_copyable_impl(&self) -> bool {
821 self.filters().is_empty()
824 }
825
826 #[inline]
827 fn try_copy_impl<'b>(
828 &self,
829 document: FPDF_DOCUMENT,
830 bindings: &'b dyn PdfiumLibraryBindings,
831 ) -> Result<PdfPageObject<'b>, PdfiumError> {
832 if !self.filters().is_empty() {
833 return Err(PdfiumError::ImageObjectFiltersNotCopyable);
836 }
837
838 let mut copy = PdfPageImageObject::new_from_handle(document, bindings)?;
839
840 copy.set_bitmap(&self.get_raw_bitmap()?)?;
841 copy.reset_matrix(self.matrix()?)?;
842
843 Ok(PdfPageObject::Image(copy))
844 }
845}
846
847pub type PdfPageImageObjectFilterIndex = usize;
850
851pub struct PdfPageImageObjectFilters<'a> {
853 object: &'a PdfPageImageObject<'a>,
854}
855
856impl<'a> PdfPageImageObjectFilters<'a> {
857 #[inline]
858 pub(crate) fn new(object: &'a PdfPageImageObject<'a>) -> Self {
859 PdfPageImageObjectFilters { object }
860 }
861
862 pub fn len(&self) -> usize {
864 self.object
865 .bindings()
866 .FPDFImageObj_GetImageFilterCount(self.object.object_handle()) as usize
867 }
868
869 #[inline]
871 pub fn is_empty(&self) -> bool {
872 self.len() == 0
873 }
874
875 #[inline]
877 pub fn as_range(&self) -> Range<PdfPageImageObjectFilterIndex> {
878 0..self.len()
879 }
880
881 #[inline]
883 pub fn as_range_inclusive(&self) -> RangeInclusive<PdfPageImageObjectFilterIndex> {
884 if self.is_empty() {
885 0..=0
886 } else {
887 0..=(self.len() - 1)
888 }
889 }
890
891 pub fn get(
893 &self,
894 index: PdfPageImageObjectFilterIndex,
895 ) -> Result<PdfPageImageObjectFilter, PdfiumError> {
896 if index >= self.len() {
897 return Err(PdfiumError::ImageObjectFilterIndexOutOfBounds);
898 }
899
900 let buffer_length = self.object.bindings().FPDFImageObj_GetImageFilter(
910 self.object.object_handle(),
911 index as c_int,
912 std::ptr::null_mut(),
913 0,
914 );
915
916 if buffer_length == 0 {
917 return Err(PdfiumError::ImageObjectFilterIndexInBoundsButFilterUndefined);
920 }
921
922 let mut buffer = create_byte_buffer(buffer_length as usize);
923
924 let result = self.object.bindings().FPDFImageObj_GetImageFilter(
925 self.object.object_handle(),
926 index as c_int,
927 buffer.as_mut_ptr() as *mut c_void,
928 buffer_length,
929 );
930
931 assert_eq!(result, buffer_length);
932
933 Ok(PdfPageImageObjectFilter::new(
934 String::from_utf8(buffer)
935 .map(|str| str.trim_end_matches(char::from(0)).to_owned())
938 .unwrap_or_default(),
939 ))
940 }
941
942 #[inline]
945 pub fn iter(&self) -> PdfPageImageObjectFiltersIterator {
946 PdfPageImageObjectFiltersIterator::new(self)
947 }
948}
949
950pub struct PdfPageImageObjectFilter {
952 name: String,
953}
954
955impl PdfPageImageObjectFilter {
956 #[inline]
957 pub(crate) fn new(name: String) -> Self {
958 PdfPageImageObjectFilter { name }
959 }
960
961 pub fn name(&self) -> &str {
963 self.name.as_str()
964 }
965}
966
967pub struct PdfPageImageObjectFiltersIterator<'a> {
970 filters: &'a PdfPageImageObjectFilters<'a>,
971 next_index: PdfPageImageObjectFilterIndex,
972}
973
974impl<'a> PdfPageImageObjectFiltersIterator<'a> {
975 #[inline]
976 pub(crate) fn new(filters: &'a PdfPageImageObjectFilters<'a>) -> Self {
977 PdfPageImageObjectFiltersIterator {
978 filters,
979 next_index: 0,
980 }
981 }
982}
983
984impl<'a> Iterator for PdfPageImageObjectFiltersIterator<'a> {
985 type Item = PdfPageImageObjectFilter;
986
987 fn next(&mut self) -> Option<Self::Item> {
988 let next = self.filters.get(self.next_index);
989
990 self.next_index += 1;
991
992 next.ok()
993 }
994}
995
996#[cfg(test)]
997mod tests {
998 use super::*;
999 use crate::prelude::*;
1000 use crate::utils::test::test_bind_to_pdfium;
1001
1002 #[test]
1003 fn test_page_image_object_retains_format() -> Result<(), PdfiumError> {
1004 let pdfium = test_bind_to_pdfium();
1008
1009 let image = pdfium
1010 .load_pdf_from_file("./test/path-test.pdf", None)?
1011 .pages()
1012 .get(0)?
1013 .render_with_config(&PdfRenderConfig::new().set_target_width(1000))?
1014 .as_image();
1015
1016 let mut document = pdfium.create_new_pdf()?;
1017
1018 let mut page = document
1019 .pages_mut()
1020 .create_page_at_end(PdfPagePaperSize::a4())?;
1021
1022 let object = page.objects_mut().create_image_object(
1023 PdfPoints::new(100.0),
1024 PdfPoints::new(100.0),
1025 &image,
1026 Some(PdfPoints::new(image.width() as f32)),
1027 Some(PdfPoints::new(image.height() as f32)),
1028 )?;
1029
1030 let raw_image = object.as_image_object().unwrap().get_raw_image()?;
1038
1039 let processed_image = object
1044 .as_image_object()
1045 .unwrap()
1046 .get_processed_image(&document)?;
1047
1048 assert!(compare_equality_of_byte_arrays(
1053 image.as_bytes(),
1054 raw_image.into_rgba8().as_raw().as_slice()
1055 ));
1056
1057 assert!(compare_equality_of_byte_arrays(
1058 image.as_bytes(),
1059 processed_image.into_rgba8().as_raw().as_slice()
1060 ));
1061
1062 Ok(())
1063 }
1064
1065 fn compare_equality_of_byte_arrays(a: &[u8], b: &[u8]) -> bool {
1066 if a.len() != b.len() {
1067 return false;
1068 }
1069
1070 for index in 0..a.len() {
1071 if a[index] != b[index] {
1072 return false;
1073 }
1074 }
1075
1076 true
1077 }
1078
1079 #[test]
1080 fn test_image_scaling_keeps_aspect_ratio() -> Result<(), PdfiumError> {
1081 let pdfium = test_bind_to_pdfium();
1082
1083 let mut document = pdfium.create_new_pdf()?;
1084
1085 let mut page = document
1086 .pages_mut()
1087 .create_page_at_end(PdfPagePaperSize::a4())?;
1088
1089 let image = DynamicImage::new_rgb8(100, 200);
1090
1091 let object = page.objects_mut().create_image_object(
1092 PdfPoints::new(0.0),
1093 PdfPoints::new(0.0),
1094 &image,
1095 Some(PdfPoints::new(image.width() as f32)),
1096 Some(PdfPoints::new(image.height() as f32)),
1097 )?;
1098
1099 let image_object = object.as_image_object().unwrap();
1100
1101 assert_eq!(
1102 image_object
1103 .get_processed_bitmap_with_width(&document, 50)?
1104 .height(),
1105 100
1106 );
1107 assert_eq!(
1108 image_object
1109 .get_processed_image_with_width(&document, 50)?
1110 .height(),
1111 100
1112 );
1113 assert_eq!(
1114 image_object
1115 .get_processed_bitmap_with_height(&document, 50)?
1116 .width(),
1117 25
1118 );
1119 assert_eq!(
1120 image_object
1121 .get_processed_image_with_height(&document, 50)?
1122 .width(),
1123 25
1124 );
1125
1126 Ok(())
1127 }
1128}