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::ops::{Range, RangeInclusive};
21use std::os::raw::{c_int, c_void};
22
23#[cfg(not(target_arch = "wasm32"))]
24use {
25 crate::utils::files::get_pdfium_file_accessor_from_reader,
26 std::fs::File,
27 std::io::{Read, Seek},
28 std::path::Path,
29};
30
31#[cfg(any(feature = "image_latest", feature = "image_025"))]
32use {
33 crate::pdf::bitmap::PdfBitmapFormat,
34 crate::utils::pixels::{
35 aligned_bgr_to_rgba, aligned_grayscale_to_unaligned, bgra_to_rgba, rgba_to_bgra,
36 },
37 image_025::{DynamicImage, EncodableLayout, GrayImage, RgbaImage},
38};
39
40#[cfg(feature = "image_024")]
41use {
42 crate::pdf::bitmap::PdfBitmapFormat,
43 crate::utils::pixels::{aligned_bgr_to_rgba, aligned_grayscale, bgra_to_rgba, rgba_to_bgra},
44 image_024::{DynamicImage, EncodableLayout, GrayImage, RgbaImage},
45};
46
47#[cfg(feature = "image_023")]
48use {
49 crate::pdf::bitmap::PdfBitmapFormat,
50 crate::utils::pixels::{aligned_bgr_to_rgba, aligned_grayscale, bgra_to_rgba, rgba_to_bgra},
51 image_023::{DynamicImage, EncodableLayout, GenericImageView, GrayImage, RgbaImage},
52};
53
54#[cfg(doc)]
55use {
56 crate::pdf::document::page::object::PdfPageObjectType,
57 crate::pdf::document::page::objects::common::PdfPageObjectsCommon,
58 crate::pdf::document::page::PdfPage,
59};
60
61pub struct PdfPageImageObject<'a> {
79 object_handle: FPDF_PAGEOBJECT,
80 ownership: PdfPageObjectOwnership,
81 bindings: &'a dyn PdfiumLibraryBindings,
82}
83
84impl<'a> PdfPageImageObject<'a> {
85 #[inline]
86 pub(crate) fn from_pdfium(
87 object_handle: FPDF_PAGEOBJECT,
88 ownership: PdfPageObjectOwnership,
89 bindings: &'a dyn PdfiumLibraryBindings,
90 ) -> Self {
91 PdfPageImageObject {
92 object_handle,
93 ownership,
94 bindings,
95 }
96 }
97
98 #[cfg(feature = "image_api")]
110 #[inline]
111 pub fn new(document: &PdfDocument<'a>, image: &DynamicImage) -> Result<Self, PdfiumError> {
112 let mut result = Self::new_from_handle(document.handle(), document.bindings());
113
114 if let Ok(result) = result.as_mut() {
115 result.set_image(image)?;
116 }
117
118 result
119 }
120
121 #[cfg(not(feature = "image_api"))]
132 pub fn new(document: &PdfDocument<'a>) -> Result<Self, PdfiumError> {
133 Self::new_from_handle(document.handle(), document.bindings())
134 }
135
136 #[cfg(not(target_arch = "wasm32"))]
148 pub fn new_from_jpeg_file(
149 document: &PdfDocument<'a>,
150 path: &(impl AsRef<Path> + ?Sized),
151 ) -> Result<Self, PdfiumError> {
152 Self::new_from_jpeg_reader(document, File::open(path).map_err(PdfiumError::IoError)?)
153 }
154
155 #[cfg(not(target_arch = "wasm32"))]
171 pub fn new_from_jpeg_reader<R: Read + Seek>(
172 document: &PdfDocument<'a>,
173 reader: R,
174 ) -> Result<Self, PdfiumError> {
175 let object = Self::new_from_handle(document.handle(), document.bindings())?;
176
177 let mut reader = get_pdfium_file_accessor_from_reader(reader);
178
179 let result = document.bindings().FPDFImageObj_LoadJpegFileInline(
180 std::ptr::null_mut(),
181 0,
182 object.object_handle(),
183 reader.as_fpdf_file_access_mut_ptr(),
184 );
185
186 if object.bindings.is_true(result) {
187 Ok(object)
188 } else {
189 Err(PdfiumError::PdfiumLibraryInternalError(
190 PdfiumInternalError::Unknown,
191 ))
192 }
193 }
194
195 pub(crate) fn new_from_handle(
198 document: FPDF_DOCUMENT,
199 bindings: &'a dyn PdfiumLibraryBindings,
200 ) -> Result<Self, PdfiumError> {
201 let handle = bindings.FPDFPageObj_NewImageObj(document);
202
203 if handle.is_null() {
204 Err(PdfiumError::PdfiumLibraryInternalError(
205 PdfiumInternalError::Unknown,
206 ))
207 } else {
208 Ok(PdfPageImageObject {
209 object_handle: handle,
210 ownership: PdfPageObjectOwnership::unowned(),
211 bindings,
212 })
213 }
214 }
215
216 #[cfg(feature = "image_api")]
223 pub fn new_with_width(
224 document: &PdfDocument<'a>,
225 image: &DynamicImage,
226 width: PdfPoints,
227 ) -> Result<Self, PdfiumError> {
228 let aspect_ratio = image.height() as f32 / image.width() as f32;
229
230 let height = width * aspect_ratio;
231
232 Self::new_with_size(document, image, width, height)
233 }
234
235 #[cfg(feature = "image_api")]
242 pub fn new_with_height(
243 document: &PdfDocument<'a>,
244 image: &DynamicImage,
245 height: PdfPoints,
246 ) -> Result<Self, PdfiumError> {
247 let aspect_ratio = image.height() as f32 / image.width() as f32;
248
249 let width = height / aspect_ratio;
250
251 Self::new_with_size(document, image, width, height)
252 }
253
254 #[cfg(feature = "image_api")]
260 #[inline]
261 pub fn new_with_size(
262 document: &PdfDocument<'a>,
263 image: &DynamicImage,
264 width: PdfPoints,
265 height: PdfPoints,
266 ) -> Result<Self, PdfiumError> {
267 let mut result = Self::new(document, image)?;
268
269 result.scale(width.value, height.value)?;
270
271 Ok(result)
272 }
273
274 pub fn get_raw_bitmap(&self) -> Result<PdfBitmap, PdfiumError> {
278 Ok(PdfBitmap::from_pdfium(
279 self.bindings().FPDFImageObj_GetBitmap(self.object_handle()),
280 self.bindings(),
281 ))
282 }
283
284 #[cfg(feature = "image_api")]
290 #[inline]
291 pub fn get_raw_image(&self) -> Result<DynamicImage, PdfiumError> {
292 self.get_image_from_bitmap(&self.get_raw_bitmap()?)
293 }
294
295 #[inline]
299 pub fn get_processed_bitmap(&self, document: &PdfDocument) -> Result<PdfBitmap, PdfiumError> {
300 let (width, height) = self.get_current_width_and_height_from_metadata()?;
301
302 self.get_processed_bitmap_with_size(document, width, height)
303 }
304
305 #[cfg(feature = "image_api")]
311 #[inline]
312 pub fn get_processed_image(&self, document: &PdfDocument) -> Result<DynamicImage, PdfiumError> {
313 let (width, height) = self.get_current_width_and_height_from_metadata()?;
314
315 self.get_processed_image_with_size(document, width, height)
316 }
317
318 #[inline]
324 pub fn get_processed_bitmap_with_width(
325 &self,
326 document: &PdfDocument,
327 width: Pixels,
328 ) -> Result<PdfBitmap, PdfiumError> {
329 let (current_width, current_height) = self.get_current_width_and_height_from_metadata()?;
330
331 let aspect_ratio = current_width as f32 / current_height as f32;
332
333 self.get_processed_bitmap_with_size(
334 document,
335 width,
336 ((width as f32 / aspect_ratio) as u32)
337 .try_into()
338 .map_err(|_| PdfiumError::ImageSizeOutOfBounds)?,
339 )
340 }
341
342 #[cfg(feature = "image_api")]
350 #[inline]
351 pub fn get_processed_image_with_width(
352 &self,
353 document: &PdfDocument,
354 width: Pixels,
355 ) -> Result<DynamicImage, PdfiumError> {
356 let (current_width, current_height) = self.get_current_width_and_height_from_metadata()?;
357
358 let aspect_ratio = current_width as f32 / current_height as f32;
359
360 self.get_processed_image_with_size(
361 document,
362 width,
363 ((width as f32 / aspect_ratio) as u32)
364 .try_into()
365 .map_err(|_| PdfiumError::ImageSizeOutOfBounds)?,
366 )
367 }
368
369 #[inline]
375 pub fn get_processed_bitmap_with_height(
376 &self,
377 document: &PdfDocument,
378 height: Pixels,
379 ) -> Result<PdfBitmap, PdfiumError> {
380 let (current_width, current_height) = self.get_current_width_and_height_from_metadata()?;
381
382 let aspect_ratio = current_width as f32 / current_height as f32;
383
384 self.get_processed_bitmap_with_size(
385 document,
386 ((height as f32 * aspect_ratio) as u32)
387 .try_into()
388 .map_err(|_| PdfiumError::ImageSizeOutOfBounds)?,
389 height,
390 )
391 }
392
393 #[cfg(feature = "image_api")]
401 #[inline]
402 pub fn get_processed_image_with_height(
403 &self,
404 document: &PdfDocument,
405 height: Pixels,
406 ) -> Result<DynamicImage, PdfiumError> {
407 let (current_width, current_height) = self.get_current_width_and_height_from_metadata()?;
408
409 let aspect_ratio = current_width as f32 / current_height as f32;
410
411 self.get_processed_image_with_size(
412 document,
413 ((height as f32 * aspect_ratio) as u32)
414 .try_into()
415 .map_err(|_| PdfiumError::ImageSizeOutOfBounds)?,
416 height,
417 )
418 }
419
420 pub fn get_processed_bitmap_with_size(
427 &self,
428 document: &PdfDocument,
429 width: Pixels,
430 height: Pixels,
431 ) -> Result<PdfBitmap, PdfiumError> {
432 let mut matrix = self.matrix()?;
449
450 let original_matrix = matrix; if matrix.a() < 0f32 {
455 matrix.set_a(-matrix.a());
456 self.reset_matrix_impl(matrix)?;
457 }
458
459 if matrix.d() < 0f32 {
460 matrix.set_d(-matrix.d());
461 self.reset_matrix_impl(matrix)?;
462 }
463
464 let page_handle = match self.ownership() {
465 PdfPageObjectOwnership::Page(ownership) => Some(ownership.page_handle()),
466 PdfPageObjectOwnership::AttachedAnnotation(ownership) => Some(ownership.page_handle()),
467 _ => None,
468 };
469
470 let bitmap_handle = match page_handle {
471 Some(page_handle) => self.bindings().FPDFImageObj_GetRenderedBitmap(
472 document.handle(),
473 page_handle,
474 self.object_handle(),
475 ),
476 None => self.bindings.FPDFImageObj_GetRenderedBitmap(
477 document.handle(),
478 std::ptr::null_mut::<fpdf_page_t__>(),
479 self.object_handle(),
480 ),
481 };
482
483 if bitmap_handle.is_null() {
484 self.reset_matrix_impl(original_matrix)?;
488 return Err(PdfiumError::PdfiumLibraryInternalError(
489 PdfiumInternalError::Unknown,
490 ));
491 }
492
493 let result = PdfBitmap::from_pdfium(bitmap_handle, self.bindings());
494
495 if width == result.width() && height == result.height() {
496 self.reset_matrix_impl(original_matrix)?;
500
501 Ok(result)
502 } else {
503 self.transform_impl(
508 width as PdfMatrixValue / result.width() as PdfMatrixValue,
509 0.0,
510 0.0,
511 height as PdfMatrixValue / result.height() as PdfMatrixValue,
512 0.0,
513 0.0,
514 )?;
515
516 let result = PdfBitmap::from_pdfium(
519 match page_handle {
520 Some(page_handle) => self.bindings().FPDFImageObj_GetRenderedBitmap(
521 document.handle(),
522 page_handle,
523 self.object_handle(),
524 ),
525 None => self.bindings.FPDFImageObj_GetRenderedBitmap(
526 document.handle(),
527 std::ptr::null_mut::<fpdf_page_t__>(),
528 self.object_handle(),
529 ),
530 },
531 self.bindings,
532 );
533
534 self.reset_matrix_impl(original_matrix)?;
537
538 Ok(result)
539 }
540 }
541
542 #[cfg(feature = "image_api")]
551 #[inline]
552 pub fn get_processed_image_with_size(
553 &self,
554 document: &PdfDocument,
555 width: Pixels,
556 height: Pixels,
557 ) -> Result<DynamicImage, PdfiumError> {
558 self.get_processed_bitmap_with_size(document, width, height)
559 .and_then(|bitmap| self.get_image_from_bitmap(&bitmap))
560 }
561
562 #[cfg(feature = "image_api")]
563 pub(crate) fn get_image_from_bitmap(
564 &self,
565 bitmap: &PdfBitmap,
566 ) -> Result<DynamicImage, PdfiumError> {
567 let handle = *bitmap.handle();
568
569 let width = self.bindings.FPDFBitmap_GetWidth(handle);
570
571 let height = self.bindings.FPDFBitmap_GetHeight(handle);
572
573 let stride = self.bindings.FPDFBitmap_GetStride(handle);
574
575 let format =
576 PdfBitmapFormat::from_pdfium(self.bindings.FPDFBitmap_GetFormat(handle) as u32)?;
577
578 #[cfg(not(target_arch = "wasm32"))]
579 let buffer = self.bindings.FPDFBitmap_GetBuffer_as_slice(handle);
580
581 #[cfg(target_arch = "wasm32")]
582 let buffer_vec = self.bindings.FPDFBitmap_GetBuffer_as_vec(handle);
583 #[cfg(target_arch = "wasm32")]
584 let buffer = buffer_vec.as_slice();
585
586 match format {
587 #[allow(deprecated)]
588 PdfBitmapFormat::BGRA | PdfBitmapFormat::BRGx | PdfBitmapFormat::BGRx => {
589 RgbaImage::from_raw(width as u32, height as u32, bgra_to_rgba(buffer))
590 .map(DynamicImage::ImageRgba8)
591 }
592 PdfBitmapFormat::BGR => RgbaImage::from_raw(
593 width as u32,
594 height as u32,
595 aligned_bgr_to_rgba(buffer, width as usize, stride as usize),
596 )
597 .map(DynamicImage::ImageRgba8),
598 PdfBitmapFormat::Gray => GrayImage::from_raw(
599 width as u32,
600 height as u32,
601 aligned_grayscale_to_unaligned(buffer, width as usize, stride as usize),
602 )
603 .map(DynamicImage::ImageLuma8),
604 }
605 .ok_or(PdfiumError::ImageError)
606 }
607
608 pub(crate) fn get_current_width_and_height_from_metadata(
610 &self,
611 ) -> Result<(Pixels, Pixels), PdfiumError> {
612 let width = self.get_raw_metadata().and_then(|metadata| {
613 metadata
614 .width
615 .try_into()
616 .map_err(|_| PdfiumError::ImageSizeOutOfBounds)
617 })?;
618
619 let height = self.get_raw_metadata().and_then(|metadata| {
620 metadata
621 .height
622 .try_into()
623 .map_err(|_| PdfiumError::ImageSizeOutOfBounds)
624 })?;
625
626 Ok((width, height))
627 }
628
629 #[inline]
633 pub fn width(&self) -> Result<Pixels, PdfiumError> {
634 self.get_current_width_and_height_from_metadata()
635 .map(|(width, _height)| width)
636 }
637
638 #[inline]
642 pub fn height(&self) -> Result<Pixels, PdfiumError> {
643 self.get_current_width_and_height_from_metadata()
644 .map(|(_width, height)| height)
645 }
646
647 #[cfg(feature = "image_api")]
651 pub fn set_image(&mut self, image: &DynamicImage) -> Result<(), PdfiumError> {
652 let width: Pixels = image
653 .width()
654 .try_into()
655 .map_err(|_| PdfiumError::ImageSizeOutOfBounds)?;
656
657 let height: Pixels = image
658 .height()
659 .try_into()
660 .map_err(|_| PdfiumError::ImageSizeOutOfBounds)?;
661
662 let bitmap = PdfBitmap::empty(width, height, PdfBitmapFormat::BGRA, self.bindings)?;
663
664 let buffer = if let Some(image) = image.as_rgba8() {
665 rgba_to_bgra(image.as_bytes())
668 } else {
669 let image = image.to_rgba8();
672
673 rgba_to_bgra(image.as_bytes())
674 };
675
676 if !self
677 .bindings
678 .FPDFBitmap_SetBuffer(*bitmap.handle(), buffer.as_slice())
679 {
680 return Err(PdfiumError::PdfiumLibraryInternalError(
681 PdfiumInternalError::Unknown,
682 ));
683 }
684
685 self.set_bitmap(&bitmap)
686 }
687
688 pub fn set_bitmap(&mut self, bitmap: &PdfBitmap) -> Result<(), PdfiumError> {
690 if self
691 .bindings
692 .is_true(self.bindings().FPDFImageObj_SetBitmap(
693 std::ptr::null_mut::<FPDF_PAGE>(),
694 0,
695 self.object_handle(),
696 *bitmap.handle(),
697 ))
698 {
699 Ok(())
700 } else {
701 Err(PdfiumError::PdfiumLibraryInternalError(
702 PdfiumInternalError::Unknown,
703 ))
704 }
705 }
706
707 pub(crate) fn get_raw_metadata(&self) -> Result<FPDF_IMAGEOBJ_METADATA, PdfiumError> {
709 let mut metadata = FPDF_IMAGEOBJ_METADATA {
710 width: 0,
711 height: 0,
712 horizontal_dpi: 0.0,
713 vertical_dpi: 0.0,
714 bits_per_pixel: 0,
715 colorspace: 0,
716 marked_content_id: 0,
717 };
718
719 let page_handle = match self.ownership() {
720 PdfPageObjectOwnership::Page(ownership) => Some(ownership.page_handle()),
721 PdfPageObjectOwnership::AttachedAnnotation(ownership) => Some(ownership.page_handle()),
722 _ => None,
723 };
724
725 let result = self.bindings().FPDFImageObj_GetImageMetadata(
726 self.object_handle(),
727 match page_handle {
728 Some(page_handle) => page_handle,
729 None => std::ptr::null_mut::<fpdf_page_t__>(),
730 },
731 &mut metadata,
732 );
733
734 if self.bindings().is_true(result) {
735 Ok(metadata)
736 } else {
737 Err(PdfiumError::PdfiumLibraryInternalError(
738 PdfiumInternalError::Unknown,
739 ))
740 }
741 }
742
743 #[inline]
747 pub fn horizontal_dpi(&self) -> Result<f32, PdfiumError> {
748 self.get_raw_metadata()
749 .map(|metadata| metadata.horizontal_dpi)
750 }
751
752 #[inline]
756 pub fn vertical_dpi(&self) -> Result<f32, PdfiumError> {
757 self.get_raw_metadata()
758 .map(|metadata| metadata.vertical_dpi)
759 }
760
761 #[inline]
765 pub fn bits_per_pixel(&self) -> Result<u8, PdfiumError> {
766 self.get_raw_metadata()
767 .map(|metadata| metadata.bits_per_pixel as u8)
768 }
769
770 #[inline]
774 pub fn color_space(&self) -> Result<PdfColorSpace, PdfiumError> {
775 self.get_raw_metadata()
776 .and_then(|metadata| PdfColorSpace::from_pdfium(metadata.colorspace as u32))
777 }
778
779 #[inline]
781 pub fn filters(&self) -> PdfPageImageObjectFilters {
782 PdfPageImageObjectFilters::new(self)
783 }
784
785 create_transform_setters!(
786 &mut Self,
787 Result<(), PdfiumError>,
788 "this [PdfPageImageObject]",
789 "this [PdfPageImageObject].",
790 "this [PdfPageImageObject],"
791 );
792
793 create_transform_getters!(
797 "this [PdfPageImageObject]",
798 "this [PdfPageImageObject].",
799 "this [PdfPageImageObject],"
800 );
801
802 }
805
806impl<'a> PdfPageObjectPrivate<'a> for PdfPageImageObject<'a> {
807 #[inline]
808 fn object_handle(&self) -> FPDF_PAGEOBJECT {
809 self.object_handle
810 }
811
812 #[inline]
813 fn ownership(&self) -> &PdfPageObjectOwnership {
814 &self.ownership
815 }
816
817 #[inline]
818 fn set_ownership(&mut self, ownership: PdfPageObjectOwnership) {
819 self.ownership = ownership;
820 }
821
822 #[inline]
823 fn bindings(&self) -> &dyn PdfiumLibraryBindings {
824 self.bindings
825 }
826
827 #[inline]
828 fn is_copyable_impl(&self) -> bool {
829 self.filters().is_empty()
832 }
833
834 #[inline]
835 fn try_copy_impl<'b>(
836 &self,
837 document: FPDF_DOCUMENT,
838 bindings: &'b dyn PdfiumLibraryBindings,
839 ) -> Result<PdfPageObject<'b>, PdfiumError> {
840 if !self.filters().is_empty() {
841 return Err(PdfiumError::ImageObjectFiltersNotCopyable);
844 }
845
846 let mut copy = PdfPageImageObject::new_from_handle(document, bindings)?;
847
848 copy.set_bitmap(&self.get_raw_bitmap()?)?;
849 copy.reset_matrix(self.matrix()?)?;
850
851 Ok(PdfPageObject::Image(copy))
852 }
853}
854
855pub type PdfPageImageObjectFilterIndex = usize;
858
859pub struct PdfPageImageObjectFilters<'a> {
861 object: &'a PdfPageImageObject<'a>,
862}
863
864impl<'a> PdfPageImageObjectFilters<'a> {
865 #[inline]
866 pub(crate) fn new(object: &'a PdfPageImageObject<'a>) -> Self {
867 PdfPageImageObjectFilters { object }
868 }
869
870 pub fn len(&self) -> usize {
872 self.object
873 .bindings()
874 .FPDFImageObj_GetImageFilterCount(self.object.object_handle()) as usize
875 }
876
877 #[inline]
879 pub fn is_empty(&self) -> bool {
880 self.len() == 0
881 }
882
883 #[inline]
885 pub fn as_range(&self) -> Range<PdfPageImageObjectFilterIndex> {
886 0..self.len()
887 }
888
889 #[inline]
891 pub fn as_range_inclusive(&self) -> RangeInclusive<PdfPageImageObjectFilterIndex> {
892 if self.is_empty() {
893 0..=0
894 } else {
895 0..=(self.len() - 1)
896 }
897 }
898
899 pub fn get(
901 &self,
902 index: PdfPageImageObjectFilterIndex,
903 ) -> Result<PdfPageImageObjectFilter, PdfiumError> {
904 if index >= self.len() {
905 return Err(PdfiumError::ImageObjectFilterIndexOutOfBounds);
906 }
907
908 let buffer_length = self.object.bindings().FPDFImageObj_GetImageFilter(
918 self.object.object_handle(),
919 index as c_int,
920 std::ptr::null_mut(),
921 0,
922 );
923
924 if buffer_length == 0 {
925 return Err(PdfiumError::ImageObjectFilterIndexInBoundsButFilterUndefined);
928 }
929
930 let mut buffer = create_byte_buffer(buffer_length as usize);
931
932 let result = self.object.bindings().FPDFImageObj_GetImageFilter(
933 self.object.object_handle(),
934 index as c_int,
935 buffer.as_mut_ptr() as *mut c_void,
936 buffer_length,
937 );
938
939 assert_eq!(result, buffer_length);
940
941 Ok(PdfPageImageObjectFilter::new(
942 String::from_utf8(buffer)
943 .map(|str| str.trim_end_matches(char::from(0)).to_owned())
946 .unwrap_or_default(),
947 ))
948 }
949
950 #[inline]
953 pub fn iter(&self) -> PdfPageImageObjectFiltersIterator {
954 PdfPageImageObjectFiltersIterator::new(self)
955 }
956}
957
958pub struct PdfPageImageObjectFilter {
960 name: String,
961}
962
963impl PdfPageImageObjectFilter {
964 #[inline]
965 pub(crate) fn new(name: String) -> Self {
966 PdfPageImageObjectFilter { name }
967 }
968
969 pub fn name(&self) -> &str {
971 self.name.as_str()
972 }
973}
974
975pub struct PdfPageImageObjectFiltersIterator<'a> {
978 filters: &'a PdfPageImageObjectFilters<'a>,
979 next_index: PdfPageImageObjectFilterIndex,
980}
981
982impl<'a> PdfPageImageObjectFiltersIterator<'a> {
983 #[inline]
984 pub(crate) fn new(filters: &'a PdfPageImageObjectFilters<'a>) -> Self {
985 PdfPageImageObjectFiltersIterator {
986 filters,
987 next_index: 0,
988 }
989 }
990}
991
992impl<'a> Iterator for PdfPageImageObjectFiltersIterator<'a> {
993 type Item = PdfPageImageObjectFilter;
994
995 fn next(&mut self) -> Option<Self::Item> {
996 let next = self.filters.get(self.next_index);
997
998 self.next_index += 1;
999
1000 next.ok()
1001 }
1002}
1003
1004#[cfg(test)]
1005mod tests {
1006 use super::*;
1007 use crate::prelude::*;
1008 use crate::utils::test::test_bind_to_pdfium;
1009
1010 #[test]
1011 fn test_page_image_object_retains_format() -> Result<(), PdfiumError> {
1012 let pdfium = test_bind_to_pdfium();
1016
1017 let image = pdfium
1018 .load_pdf_from_file("./test/path-test.pdf", None)?
1019 .pages()
1020 .get(0)?
1021 .render_with_config(&PdfRenderConfig::new().set_target_width(1000))?
1022 .as_image();
1023
1024 let mut document = pdfium.create_new_pdf()?;
1025
1026 let mut page = document
1027 .pages_mut()
1028 .create_page_at_end(PdfPagePaperSize::a4())?;
1029
1030 let object = page.objects_mut().create_image_object(
1031 PdfPoints::new(100.0),
1032 PdfPoints::new(100.0),
1033 &image,
1034 Some(PdfPoints::new(image.width() as f32)),
1035 Some(PdfPoints::new(image.height() as f32)),
1036 )?;
1037
1038 let raw_image = object.as_image_object().unwrap().get_raw_image()?;
1046
1047 let processed_image = object
1052 .as_image_object()
1053 .unwrap()
1054 .get_processed_image(&document)?;
1055
1056 assert!(compare_equality_of_byte_arrays(
1061 image.as_bytes(),
1062 raw_image.into_rgba8().as_raw().as_slice()
1063 ));
1064
1065 assert!(compare_equality_of_byte_arrays(
1066 image.as_bytes(),
1067 processed_image.into_rgba8().as_raw().as_slice()
1068 ));
1069
1070 Ok(())
1071 }
1072
1073 fn compare_equality_of_byte_arrays(a: &[u8], b: &[u8]) -> bool {
1074 if a.len() != b.len() {
1075 return false;
1076 }
1077
1078 for index in 0..a.len() {
1079 if a[index] != b[index] {
1080 return false;
1081 }
1082 }
1083
1084 true
1085 }
1086
1087 #[test]
1088 fn test_image_scaling_keeps_aspect_ratio() -> Result<(), PdfiumError> {
1089 let pdfium = test_bind_to_pdfium();
1090
1091 let mut document = pdfium.create_new_pdf()?;
1092
1093 let mut page = document
1094 .pages_mut()
1095 .create_page_at_end(PdfPagePaperSize::a4())?;
1096
1097 let image = DynamicImage::new_rgb8(100, 200);
1098
1099 let object = page.objects_mut().create_image_object(
1100 PdfPoints::new(0.0),
1101 PdfPoints::new(0.0),
1102 &image,
1103 Some(PdfPoints::new(image.width() as f32)),
1104 Some(PdfPoints::new(image.height() as f32)),
1105 )?;
1106
1107 let image_object = object.as_image_object().unwrap();
1108
1109 assert_eq!(
1110 image_object
1111 .get_processed_bitmap_with_width(&document, 50)?
1112 .height(),
1113 100
1114 );
1115 assert_eq!(
1116 image_object
1117 .get_processed_image_with_width(&document, 50)?
1118 .height(),
1119 100
1120 );
1121 assert_eq!(
1122 image_object
1123 .get_processed_bitmap_with_height(&document, 50)?
1124 .width(),
1125 25
1126 );
1127 assert_eq!(
1128 image_object
1129 .get_processed_image_with_height(&document, 50)?
1130 .width(),
1131 25
1132 );
1133
1134 Ok(())
1135 }
1136}