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::{aligned_bgr_to_rgba, bgra_to_rgba, rgba_to_bgra},
31 image_025::{DynamicImage, EncodableLayout, GrayImage, RgbaImage},
32};
33
34#[cfg(feature = "image_024")]
35use {
36 crate::pdf::bitmap::PdfBitmapFormat,
37 crate::utils::pixels::{aligned_bgr_to_rgba, bgra_to_rgba, rgba_to_bgra},
38 image_024::{DynamicImage, EncodableLayout, GrayImage, RgbaImage},
39};
40
41#[cfg(feature = "image_023")]
42use {
43 crate::pdf::bitmap::PdfBitmapFormat,
44 crate::utils::pixels::{aligned_bgr_to_rgba, bgra_to_rgba, rgba_to_bgra},
45 image_023::{DynamicImage, EncodableLayout, GenericImageView, GrayImage, RgbaImage},
46};
47
48#[cfg(doc)]
49use {crate::pdf::document::page::object::PdfPageObjectType, crate::pdf::document::page::PdfPage};
50
51pub struct PdfPageImageObject<'a> {
69 object_handle: FPDF_PAGEOBJECT,
70 ownership: PdfPageObjectOwnership,
71 bindings: &'a dyn PdfiumLibraryBindings,
72}
73
74impl<'a> PdfPageImageObject<'a> {
75 #[inline]
76 pub(crate) fn from_pdfium(
77 object_handle: FPDF_PAGEOBJECT,
78 ownership: PdfPageObjectOwnership,
79 bindings: &'a dyn PdfiumLibraryBindings,
80 ) -> Self {
81 PdfPageImageObject {
82 object_handle,
83 ownership,
84 bindings,
85 }
86 }
87
88 #[cfg(feature = "image_api")]
100 #[inline]
101 pub fn new(document: &PdfDocument<'a>, image: &DynamicImage) -> Result<Self, PdfiumError> {
102 let mut result = Self::new_from_handle(document.handle(), document.bindings());
103
104 if let Ok(result) = result.as_mut() {
105 result.set_image(image)?;
106 }
107
108 result
109 }
110
111 #[cfg(not(feature = "image_api"))]
122 pub fn new(document: &PdfDocument<'a>) -> Result<Self, PdfiumError> {
123 Self::new_from_handle(document.handle(), document.bindings())
124 }
125
126 #[cfg(not(target_arch = "wasm32"))]
138 pub fn new_from_jpeg_file(
139 document: &PdfDocument<'a>,
140 path: &(impl AsRef<Path> + ?Sized),
141 ) -> Result<Self, PdfiumError> {
142 Self::new_from_jpeg_reader(document, File::open(path).map_err(PdfiumError::IoError)?)
143 }
144
145 #[cfg(not(target_arch = "wasm32"))]
161 pub fn new_from_jpeg_reader<R: Read + Seek>(
162 document: &PdfDocument<'a>,
163 reader: R,
164 ) -> Result<Self, PdfiumError> {
165 let object = Self::new_from_handle(document.handle(), document.bindings())?;
166
167 let mut reader = get_pdfium_file_accessor_from_reader(reader);
168
169 let result = document.bindings().FPDFImageObj_LoadJpegFileInline(
170 std::ptr::null_mut(),
171 0,
172 object.object_handle(),
173 reader.as_fpdf_file_access_mut_ptr(),
174 );
175
176 if object.bindings.is_true(result) {
177 Ok(object)
178 } else {
179 Err(PdfiumError::PdfiumLibraryInternalError(
180 PdfiumInternalError::Unknown,
181 ))
182 }
183 }
184
185 pub(crate) fn new_from_handle(
188 document: FPDF_DOCUMENT,
189 bindings: &'a dyn PdfiumLibraryBindings,
190 ) -> Result<Self, PdfiumError> {
191 let handle = bindings.FPDFPageObj_NewImageObj(document);
192
193 if handle.is_null() {
194 Err(PdfiumError::PdfiumLibraryInternalError(
195 PdfiumInternalError::Unknown,
196 ))
197 } else {
198 Ok(PdfPageImageObject {
199 object_handle: handle,
200 ownership: PdfPageObjectOwnership::unowned(),
201 bindings,
202 })
203 }
204 }
205
206 #[cfg(feature = "image_api")]
213 pub fn new_with_width(
214 document: &PdfDocument<'a>,
215 image: &DynamicImage,
216 width: PdfPoints,
217 ) -> Result<Self, PdfiumError> {
218 let aspect_ratio = image.height() as f32 / image.width() as f32;
219
220 let height = width * aspect_ratio;
221
222 Self::new_with_size(document, image, width, height)
223 }
224
225 #[cfg(feature = "image_api")]
232 pub fn new_with_height(
233 document: &PdfDocument<'a>,
234 image: &DynamicImage,
235 height: PdfPoints,
236 ) -> Result<Self, PdfiumError> {
237 let aspect_ratio = image.height() as f32 / image.width() as f32;
238
239 let width = height / aspect_ratio;
240
241 Self::new_with_size(document, image, width, height)
242 }
243
244 #[cfg(feature = "image_api")]
250 #[inline]
251 pub fn new_with_size(
252 document: &PdfDocument<'a>,
253 image: &DynamicImage,
254 width: PdfPoints,
255 height: PdfPoints,
256 ) -> Result<Self, PdfiumError> {
257 let mut result = Self::new(document, image)?;
258
259 result.scale(width.value, height.value)?;
260
261 Ok(result)
262 }
263
264 pub fn get_raw_bitmap(&self) -> Result<PdfBitmap, PdfiumError> {
268 Ok(PdfBitmap::from_pdfium(
269 self.bindings().FPDFImageObj_GetBitmap(self.object_handle()),
270 self.bindings(),
271 ))
272 }
273
274 #[cfg(feature = "image_api")]
280 #[inline]
281 pub fn get_raw_image(&self) -> Result<DynamicImage, PdfiumError> {
282 self.get_image_from_bitmap(&self.get_raw_bitmap()?)
283 }
284
285 #[inline]
289 pub fn get_processed_bitmap(&self, document: &PdfDocument) -> Result<PdfBitmap, PdfiumError> {
290 let (width, height) = self.get_current_width_and_height_from_metadata()?;
291
292 self.get_processed_bitmap_with_size(document, width, height)
293 }
294
295 #[cfg(feature = "image_api")]
301 #[inline]
302 pub fn get_processed_image(&self, document: &PdfDocument) -> Result<DynamicImage, PdfiumError> {
303 let (width, height) = self.get_current_width_and_height_from_metadata()?;
304
305 self.get_processed_image_with_size(document, width, height)
306 }
307
308 #[inline]
314 pub fn get_processed_bitmap_with_width(
315 &self,
316 document: &PdfDocument,
317 width: Pixels,
318 ) -> Result<PdfBitmap, PdfiumError> {
319 let (current_width, current_height) = self.get_current_width_and_height_from_metadata()?;
320
321 let aspect_ratio = current_width as f32 / current_height as f32;
322
323 self.get_processed_bitmap_with_size(
324 document,
325 width,
326 ((width as f32 * aspect_ratio) as u32)
327 .try_into()
328 .map_err(|_| PdfiumError::ImageSizeOutOfBounds)?,
329 )
330 }
331
332 #[cfg(feature = "image_api")]
340 #[inline]
341 pub fn get_processed_image_with_width(
342 &self,
343 document: &PdfDocument,
344 width: Pixels,
345 ) -> Result<DynamicImage, PdfiumError> {
346 let (current_width, current_height) = self.get_current_width_and_height_from_metadata()?;
347
348 let aspect_ratio = current_width as f32 / current_height as f32;
349
350 self.get_processed_image_with_size(
351 document,
352 width,
353 ((width as f32 * aspect_ratio) as u32)
354 .try_into()
355 .map_err(|_| PdfiumError::ImageSizeOutOfBounds)?,
356 )
357 }
358
359 #[inline]
365 pub fn get_processed_bitmap_with_height(
366 &self,
367 document: &PdfDocument,
368 height: Pixels,
369 ) -> Result<PdfBitmap, PdfiumError> {
370 let (current_width, current_height) = self.get_current_width_and_height_from_metadata()?;
371
372 let aspect_ratio = current_width as f32 / current_height as f32;
373
374 self.get_processed_bitmap_with_size(
375 document,
376 ((height as f32 / aspect_ratio) as u32)
377 .try_into()
378 .map_err(|_| PdfiumError::ImageSizeOutOfBounds)?,
379 height,
380 )
381 }
382
383 #[cfg(feature = "image_api")]
391 #[inline]
392 pub fn get_processed_image_with_height(
393 &self,
394 document: &PdfDocument,
395 height: Pixels,
396 ) -> Result<DynamicImage, PdfiumError> {
397 let (current_width, current_height) = self.get_current_width_and_height_from_metadata()?;
398
399 let aspect_ratio = current_width as f32 / current_height as f32;
400
401 self.get_processed_image_with_size(
402 document,
403 ((height as f32 / aspect_ratio) as u32)
404 .try_into()
405 .map_err(|_| PdfiumError::ImageSizeOutOfBounds)?,
406 height,
407 )
408 }
409
410 pub fn get_processed_bitmap_with_size(
417 &self,
418 document: &PdfDocument,
419 width: Pixels,
420 height: Pixels,
421 ) -> Result<PdfBitmap, PdfiumError> {
422 let mut matrix = self.matrix()?;
439
440 let original_matrix = matrix; if matrix.a() < 0f32 {
445 matrix.set_a(-matrix.a());
446 self.reset_matrix_impl(matrix)?;
447 }
448
449 if matrix.d() < 0f32 {
450 matrix.set_d(-matrix.d());
451 self.reset_matrix_impl(matrix)?;
452 }
453
454 let page_handle = match self.ownership() {
455 PdfPageObjectOwnership::Page(ownership) => Some(ownership.page_handle()),
456 PdfPageObjectOwnership::AttachedAnnotation(ownership) => Some(ownership.page_handle()),
457 _ => None,
458 };
459
460 let bitmap_handle = match page_handle {
461 Some(page_handle) => self.bindings().FPDFImageObj_GetRenderedBitmap(
462 document.handle(),
463 page_handle,
464 self.object_handle(),
465 ),
466 None => self.bindings.FPDFImageObj_GetRenderedBitmap(
467 document.handle(),
468 std::ptr::null_mut::<fpdf_page_t__>(),
469 self.object_handle(),
470 ),
471 };
472
473 if bitmap_handle.is_null() {
474 self.reset_matrix_impl(original_matrix)?;
478 return Err(PdfiumError::PdfiumLibraryInternalError(
479 PdfiumInternalError::Unknown,
480 ));
481 }
482
483 let result = PdfBitmap::from_pdfium(bitmap_handle, self.bindings());
484
485 if width == result.width() && height == result.height() {
486 self.reset_matrix_impl(original_matrix)?;
490
491 Ok(result)
492 } else {
493 self.transform_impl(
498 width as PdfMatrixValue / result.width() as PdfMatrixValue,
499 0.0,
500 0.0,
501 height as PdfMatrixValue / result.height() as PdfMatrixValue,
502 0.0,
503 0.0,
504 )?;
505
506 let result = PdfBitmap::from_pdfium(
509 match page_handle {
510 Some(page_handle) => self.bindings().FPDFImageObj_GetRenderedBitmap(
511 document.handle(),
512 page_handle,
513 self.object_handle(),
514 ),
515 None => self.bindings.FPDFImageObj_GetRenderedBitmap(
516 document.handle(),
517 std::ptr::null_mut::<fpdf_page_t__>(),
518 self.object_handle(),
519 ),
520 },
521 self.bindings,
522 );
523
524 self.reset_matrix_impl(original_matrix)?;
527
528 Ok(result)
529 }
530 }
531
532 #[cfg(feature = "image_api")]
541 #[inline]
542 pub fn get_processed_image_with_size(
543 &self,
544 document: &PdfDocument,
545 width: Pixels,
546 height: Pixels,
547 ) -> Result<DynamicImage, PdfiumError> {
548 self.get_processed_bitmap_with_size(document, width, height)
549 .and_then(|bitmap| self.get_image_from_bitmap(&bitmap))
550 }
551
552 #[cfg(feature = "image_api")]
553 pub(crate) fn get_image_from_bitmap(
554 &self,
555 bitmap: &PdfBitmap,
556 ) -> Result<DynamicImage, PdfiumError> {
557 let handle = *bitmap.handle();
558
559 let width = self.bindings.FPDFBitmap_GetWidth(handle);
560
561 let height = self.bindings.FPDFBitmap_GetHeight(handle);
562
563 let stride = self.bindings.FPDFBitmap_GetStride(handle);
564
565 let format =
566 PdfBitmapFormat::from_pdfium(self.bindings.FPDFBitmap_GetFormat(handle) as u32)?;
567
568 #[cfg(not(target_arch = "wasm32"))]
569 let buffer = self.bindings.FPDFBitmap_GetBuffer_as_slice(handle);
570
571 #[cfg(target_arch = "wasm32")]
572 let buffer_vec = self.bindings.FPDFBitmap_GetBuffer_as_vec(handle);
573 #[cfg(target_arch = "wasm32")]
574 let buffer = buffer_vec.as_slice();
575
576 match format {
577 #[allow(deprecated)]
578 PdfBitmapFormat::BGRA | PdfBitmapFormat::BRGx | PdfBitmapFormat::BGRx => {
579 RgbaImage::from_raw(width as u32, height as u32, bgra_to_rgba(buffer))
580 .map(DynamicImage::ImageRgba8)
581 }
582 PdfBitmapFormat::BGR => RgbaImage::from_raw(
583 width as u32,
584 height as u32,
585 aligned_bgr_to_rgba(buffer, width as usize, stride as usize),
586 )
587 .map(DynamicImage::ImageRgba8),
588 PdfBitmapFormat::Gray => {
589 GrayImage::from_raw(width as u32, height as u32, buffer.to_vec())
590 .map(DynamicImage::ImageLuma8)
591 }
592 }
593 .ok_or(PdfiumError::ImageError)
594 }
595
596 pub(crate) fn get_current_width_and_height_from_metadata(
598 &self,
599 ) -> Result<(Pixels, Pixels), PdfiumError> {
600 let width = self.get_raw_metadata().and_then(|metadata| {
601 metadata
602 .width
603 .try_into()
604 .map_err(|_| PdfiumError::ImageSizeOutOfBounds)
605 })?;
606
607 let height = self.get_raw_metadata().and_then(|metadata| {
608 metadata
609 .height
610 .try_into()
611 .map_err(|_| PdfiumError::ImageSizeOutOfBounds)
612 })?;
613
614 Ok((width, height))
615 }
616
617 #[cfg(feature = "image_api")]
621 pub fn set_image(&mut self, image: &DynamicImage) -> Result<(), PdfiumError> {
622 let width: Pixels = image
623 .width()
624 .try_into()
625 .map_err(|_| PdfiumError::ImageSizeOutOfBounds)?;
626
627 let height: Pixels = image
628 .height()
629 .try_into()
630 .map_err(|_| PdfiumError::ImageSizeOutOfBounds)?;
631
632 let bitmap = PdfBitmap::empty(width, height, PdfBitmapFormat::BGRA, self.bindings)?;
633
634 let buffer = if let Some(image) = image.as_rgba8() {
635 rgba_to_bgra(image.as_bytes())
638 } else {
639 let image = image.to_rgba8();
642
643 rgba_to_bgra(image.as_bytes())
644 };
645
646 if !self
647 .bindings
648 .FPDFBitmap_SetBuffer(*bitmap.handle(), buffer.as_slice())
649 {
650 return Err(PdfiumError::PdfiumLibraryInternalError(
651 PdfiumInternalError::Unknown,
652 ));
653 }
654
655 self.set_bitmap(&bitmap)
656 }
657
658 pub fn set_bitmap(&mut self, bitmap: &PdfBitmap) -> Result<(), PdfiumError> {
660 if self
661 .bindings
662 .is_true(self.bindings().FPDFImageObj_SetBitmap(
663 std::ptr::null_mut::<FPDF_PAGE>(),
664 0,
665 self.object_handle(),
666 *bitmap.handle(),
667 ))
668 {
669 Ok(())
670 } else {
671 Err(PdfiumError::PdfiumLibraryInternalError(
672 PdfiumInternalError::Unknown,
673 ))
674 }
675 }
676
677 pub(crate) fn get_raw_metadata(&self) -> Result<FPDF_IMAGEOBJ_METADATA, PdfiumError> {
679 let mut metadata = FPDF_IMAGEOBJ_METADATA {
680 width: 0,
681 height: 0,
682 horizontal_dpi: 0.0,
683 vertical_dpi: 0.0,
684 bits_per_pixel: 0,
685 colorspace: 0,
686 marked_content_id: 0,
687 };
688
689 let page_handle = match self.ownership() {
690 PdfPageObjectOwnership::Page(ownership) => Some(ownership.page_handle()),
691 PdfPageObjectOwnership::AttachedAnnotation(ownership) => Some(ownership.page_handle()),
692 _ => None,
693 };
694
695 let result = self.bindings().FPDFImageObj_GetImageMetadata(
696 self.object_handle(),
697 match page_handle {
698 Some(page_handle) => page_handle,
699 None => std::ptr::null_mut::<fpdf_page_t__>(),
700 },
701 &mut metadata,
702 );
703
704 if self.bindings().is_true(result) {
705 Ok(metadata)
706 } else {
707 Err(PdfiumError::PdfiumLibraryInternalError(
708 PdfiumInternalError::Unknown,
709 ))
710 }
711 }
712
713 #[inline]
717 pub fn horizontal_dpi(&self) -> Result<f32, PdfiumError> {
718 self.get_raw_metadata()
719 .map(|metadata| metadata.horizontal_dpi)
720 }
721
722 #[inline]
726 pub fn vertical_dpi(&self) -> Result<f32, PdfiumError> {
727 self.get_raw_metadata()
728 .map(|metadata| metadata.vertical_dpi)
729 }
730
731 #[inline]
735 pub fn bits_per_pixel(&self) -> Result<u8, PdfiumError> {
736 self.get_raw_metadata()
737 .map(|metadata| metadata.bits_per_pixel as u8)
738 }
739
740 #[inline]
744 pub fn color_space(&self) -> Result<PdfColorSpace, PdfiumError> {
745 self.get_raw_metadata()
746 .and_then(|metadata| PdfColorSpace::from_pdfium(metadata.colorspace as u32))
747 }
748
749 #[inline]
751 pub fn filters(&self) -> PdfPageImageObjectFilters {
752 PdfPageImageObjectFilters::new(self)
753 }
754
755 create_transform_setters!(
756 &mut Self,
757 Result<(), PdfiumError>,
758 "this [PdfPageImageObject]",
759 "this [PdfPageImageObject].",
760 "this [PdfPageImageObject],"
761 );
762
763 create_transform_getters!(
767 "this [PdfPageImageObject]",
768 "this [PdfPageImageObject].",
769 "this [PdfPageImageObject],"
770 );
771
772 }
775
776impl<'a> PdfPageObjectPrivate<'a> for PdfPageImageObject<'a> {
777 #[inline]
778 fn object_handle(&self) -> FPDF_PAGEOBJECT {
779 self.object_handle
780 }
781
782 #[inline]
783 fn ownership(&self) -> &PdfPageObjectOwnership {
784 &self.ownership
785 }
786
787 #[inline]
788 fn set_ownership(&mut self, ownership: PdfPageObjectOwnership) {
789 self.ownership = ownership;
790 }
791
792 #[inline]
793 fn bindings(&self) -> &dyn PdfiumLibraryBindings {
794 self.bindings
795 }
796
797 #[inline]
798 fn is_copyable_impl(&self) -> bool {
799 self.filters().is_empty()
802 }
803
804 #[inline]
805 fn try_copy_impl<'b>(
806 &self,
807 document: FPDF_DOCUMENT,
808 bindings: &'b dyn PdfiumLibraryBindings,
809 ) -> Result<PdfPageObject<'b>, PdfiumError> {
810 if !self.filters().is_empty() {
811 return Err(PdfiumError::ImageObjectFiltersNotCopyable);
814 }
815
816 let mut copy = PdfPageImageObject::new_from_handle(document, bindings)?;
817
818 copy.set_bitmap(&self.get_raw_bitmap()?)?;
819 copy.reset_matrix(self.matrix()?)?;
820
821 Ok(PdfPageObject::Image(copy))
822 }
823}
824
825pub type PdfPageImageObjectFilterIndex = usize;
828
829pub struct PdfPageImageObjectFilters<'a> {
831 object: &'a PdfPageImageObject<'a>,
832}
833
834impl<'a> PdfPageImageObjectFilters<'a> {
835 #[inline]
836 pub(crate) fn new(object: &'a PdfPageImageObject<'a>) -> Self {
837 PdfPageImageObjectFilters { object }
838 }
839
840 pub fn len(&self) -> usize {
842 self.object
843 .bindings()
844 .FPDFImageObj_GetImageFilterCount(self.object.object_handle()) as usize
845 }
846
847 #[inline]
849 pub fn is_empty(&self) -> bool {
850 self.len() == 0
851 }
852
853 #[inline]
855 pub fn as_range(&self) -> Range<PdfPageImageObjectFilterIndex> {
856 0..self.len()
857 }
858
859 #[inline]
861 pub fn as_range_inclusive(&self) -> RangeInclusive<PdfPageImageObjectFilterIndex> {
862 if self.is_empty() {
863 0..=0
864 } else {
865 0..=(self.len() - 1)
866 }
867 }
868
869 pub fn get(
871 &self,
872 index: PdfPageImageObjectFilterIndex,
873 ) -> Result<PdfPageImageObjectFilter, PdfiumError> {
874 if index >= self.len() {
875 return Err(PdfiumError::ImageObjectFilterIndexOutOfBounds);
876 }
877
878 let buffer_length = self.object.bindings().FPDFImageObj_GetImageFilter(
888 self.object.object_handle(),
889 index as c_int,
890 std::ptr::null_mut(),
891 0,
892 );
893
894 if buffer_length == 0 {
895 return Err(PdfiumError::ImageObjectFilterIndexInBoundsButFilterUndefined);
898 }
899
900 let mut buffer = create_byte_buffer(buffer_length as usize);
901
902 let result = self.object.bindings().FPDFImageObj_GetImageFilter(
903 self.object.object_handle(),
904 index as c_int,
905 buffer.as_mut_ptr() as *mut c_void,
906 buffer_length,
907 );
908
909 assert_eq!(result, buffer_length);
910
911 Ok(PdfPageImageObjectFilter::new(
912 String::from_utf8(buffer)
913 .map(|str| str.trim_end_matches(char::from(0)).to_owned())
916 .unwrap_or_default(),
917 ))
918 }
919
920 #[inline]
923 pub fn iter(&self) -> PdfPageImageObjectFiltersIterator {
924 PdfPageImageObjectFiltersIterator::new(self)
925 }
926}
927
928pub struct PdfPageImageObjectFilter {
930 name: String,
931}
932
933impl PdfPageImageObjectFilter {
934 #[inline]
935 pub(crate) fn new(name: String) -> Self {
936 PdfPageImageObjectFilter { name }
937 }
938
939 pub fn name(&self) -> &str {
941 self.name.as_str()
942 }
943}
944
945pub struct PdfPageImageObjectFiltersIterator<'a> {
948 filters: &'a PdfPageImageObjectFilters<'a>,
949 next_index: PdfPageImageObjectFilterIndex,
950}
951
952impl<'a> PdfPageImageObjectFiltersIterator<'a> {
953 #[inline]
954 pub(crate) fn new(filters: &'a PdfPageImageObjectFilters<'a>) -> Self {
955 PdfPageImageObjectFiltersIterator {
956 filters,
957 next_index: 0,
958 }
959 }
960}
961
962impl<'a> Iterator for PdfPageImageObjectFiltersIterator<'a> {
963 type Item = PdfPageImageObjectFilter;
964
965 fn next(&mut self) -> Option<Self::Item> {
966 let next = self.filters.get(self.next_index);
967
968 self.next_index += 1;
969
970 next.ok()
971 }
972}
973
974#[cfg(test)]
975mod tests {
976 use crate::prelude::*;
977 use crate::utils::test::test_bind_to_pdfium;
978
979 #[test]
980 fn test_page_image_object_retains_format() -> Result<(), PdfiumError> {
981 let pdfium = test_bind_to_pdfium();
985
986 let image = pdfium
987 .load_pdf_from_file("./test/path-test.pdf", None)?
988 .pages()
989 .get(0)?
990 .render_with_config(&PdfRenderConfig::new().set_target_width(1000))?
991 .as_image();
992
993 let mut document = pdfium.create_new_pdf()?;
994
995 let mut page = document
996 .pages_mut()
997 .create_page_at_end(PdfPagePaperSize::a4())?;
998
999 let object = page.objects_mut().create_image_object(
1000 PdfPoints::new(100.0),
1001 PdfPoints::new(100.0),
1002 &image,
1003 Some(PdfPoints::new(image.width() as f32)),
1004 Some(PdfPoints::new(image.height() as f32)),
1005 )?;
1006
1007 let raw_image = object.as_image_object().unwrap().get_raw_image()?;
1015
1016 let processed_image = object
1021 .as_image_object()
1022 .unwrap()
1023 .get_processed_image(&document)?;
1024
1025 assert!(compare_equality_of_byte_arrays(
1030 image.as_bytes(),
1031 raw_image.into_rgba8().as_raw().as_slice()
1032 ));
1033
1034 assert!(compare_equality_of_byte_arrays(
1035 image.as_bytes(),
1036 processed_image.into_rgba8().as_raw().as_slice()
1037 ));
1038
1039 Ok(())
1040 }
1041
1042 fn compare_equality_of_byte_arrays(a: &[u8], b: &[u8]) -> bool {
1043 if a.len() != b.len() {
1044 return false;
1045 }
1046
1047 for index in 0..a.len() {
1048 if a[index] != b[index] {
1049 return false;
1050 }
1051 }
1052
1053 true
1054 }
1055}