1use crate::bindgen::{
5 FPDF_ANNOT, FPDF_CONVERT_FILL_TO_STROKE, FPDF_DWORD, FPDF_GRAYSCALE, FPDF_LCD_TEXT, FPDF_NO_NATIVETEXT,
6 FPDF_PRINTING, FPDF_RENDER_FORCEHALFTONE, FPDF_RENDER_LIMITEDIMAGECACHE, FPDF_RENDER_NO_SMOOTHIMAGE,
7 FPDF_RENDER_NO_SMOOTHPATH, FPDF_RENDER_NO_SMOOTHTEXT, FPDF_REVERSE_BYTE_ORDER, FS_MATRIX, FS_RECTF,
8};
9use crate::create_transform_setters;
10use crate::error::PdfiumError;
11use crate::pdf::bitmap::{PdfBitmap, PdfBitmapFormat, Pixels};
12use crate::pdf::color::PdfColor;
13use crate::pdf::document::page::PdfPageOrientation::{Landscape, Portrait};
14use crate::pdf::document::page::{PdfPage, PdfPageOrientation, PdfPageRenderRotation};
15use crate::pdf::matrix::{PdfMatrix, PdfMatrixValue};
16use crate::pdf::points::PdfPoints;
17use std::os::raw::c_int;
18
19#[deprecated(
22 since = "0.7.12",
23 note = "This struct has been renamed to better reflect its purpose. Use the PdfRenderConfig struct instead."
24)]
25#[doc(hidden)]
26pub struct PdfBitmapConfig {}
27
28#[allow(deprecated)]
29impl PdfBitmapConfig {
30 #[deprecated(
32 since = "0.7.12",
33 note = "This struct has been renamed to better reflect its purpose. Use the PdfRenderConfig::new() function instead."
34 )]
35 #[inline]
36 #[doc(hidden)]
37 #[allow(clippy::new_ret_no_self)]
38 pub fn new() -> PdfRenderConfig {
39 PdfRenderConfig::new()
40 }
41
42 #[deprecated(
43 since = "0.7.12",
44 note = "This struct has been renamed to better reflect its purpose. Use the PdfRenderConfig::default() function instead."
45 )]
46 #[inline]
47 #[doc(hidden)]
48 #[allow(clippy::should_implement_trait)]
49 pub fn default() -> PdfRenderConfig {
50 PdfRenderConfig::default()
51 }
52}
53
54pub struct PdfRenderConfig {
68 use_auto_scaling: bool,
69 fixed_width: Option<Pixels>,
70 fixed_height: Option<Pixels>,
71 target_width: Option<Pixels>,
72 target_height: Option<Pixels>,
73 scale_width_factor: Option<f32>,
74 scale_height_factor: Option<f32>,
75 maximum_width: Option<Pixels>,
76 maximum_height: Option<Pixels>,
77 portrait_rotation: PdfPageRenderRotation,
78 portrait_rotation_do_rotate_constraints: bool,
79 landscape_rotation: PdfPageRenderRotation,
80 landscape_rotation_do_rotate_constraints: bool,
81 format: PdfBitmapFormat,
82 do_clear_bitmap_before_rendering: bool,
83 clear_color: PdfColor,
84 do_render_form_data: bool,
85 transformation_matrix: PdfMatrix,
86 clip_rect: Option<(Pixels, Pixels, Pixels, Pixels)>,
87
88 do_set_flag_render_annotations: bool,
90 do_set_flag_use_lcd_text_rendering: bool,
91 do_set_flag_no_native_text: bool,
92 do_set_flag_grayscale: bool,
93 do_set_flag_render_limited_image_cache: bool,
94 do_set_flag_render_force_half_tone: bool,
95 do_set_flag_render_for_printing: bool,
96 do_set_flag_render_no_smooth_text: bool,
97 do_set_flag_render_no_smooth_image: bool,
98 do_set_flag_render_no_smooth_path: bool,
99 do_set_flag_reverse_byte_order: bool,
100 do_set_flag_convert_fill_to_stroke: bool,
101}
102
103impl PdfRenderConfig {
104 pub fn new() -> Self {
106 PdfRenderConfig {
107 use_auto_scaling: true,
108 fixed_width: None,
109 fixed_height: None,
110 target_width: None,
111 target_height: None,
112 scale_width_factor: None,
113 scale_height_factor: None,
114 maximum_width: None,
115 maximum_height: None,
116 portrait_rotation: PdfPageRenderRotation::None,
117 portrait_rotation_do_rotate_constraints: false,
118 landscape_rotation: PdfPageRenderRotation::None,
119 landscape_rotation_do_rotate_constraints: false,
120 format: PdfBitmapFormat::default(),
121 do_clear_bitmap_before_rendering: true,
122 clear_color: PdfColor::WHITE,
123 do_render_form_data: true,
124 transformation_matrix: PdfMatrix::IDENTITY,
125 clip_rect: None,
126 do_set_flag_render_annotations: true,
127 do_set_flag_use_lcd_text_rendering: false,
128 do_set_flag_no_native_text: false,
129 do_set_flag_grayscale: false,
130 do_set_flag_render_limited_image_cache: false,
131 do_set_flag_render_force_half_tone: false,
132 do_set_flag_render_for_printing: false,
133 do_set_flag_render_no_smooth_text: false,
134 do_set_flag_render_no_smooth_image: false,
135 do_set_flag_render_no_smooth_path: false,
136 do_set_flag_convert_fill_to_stroke: false,
137
138 do_set_flag_reverse_byte_order: true,
139 }
140 }
141
142 #[inline]
155 pub fn thumbnail(self, size: Pixels) -> Self {
156 self.set_target_size(size, size)
157 .set_maximum_width(size)
158 .set_maximum_height(size)
159 .rotate(PdfPageRenderRotation::None, false)
160 .use_print_quality(false)
161 .set_image_smoothing(false)
162 .render_annotations(false)
163 .render_form_data(false)
164 }
165
166 #[inline]
172 pub fn set_fixed_size_to_bitmap(self, bitmap: &PdfBitmap) -> Self {
173 self.set_fixed_size(bitmap.width(), bitmap.height())
174 }
175
176 #[inline]
181 pub fn set_fixed_size(self, width: Pixels, height: Pixels) -> Self {
182 self.set_fixed_width(width).set_fixed_height(height)
183 }
184
185 #[inline]
188 pub fn set_fixed_width(mut self, width: Pixels) -> Self {
189 self.use_auto_scaling = false;
190 self.fixed_width = Some(width);
191
192 self
193 }
194
195 #[inline]
198 pub fn set_fixed_height(mut self, height: Pixels) -> Self {
199 self.use_auto_scaling = false;
200 self.fixed_height = Some(height);
201
202 self
203 }
204
205 #[inline]
210 pub fn set_target_size(self, width: Pixels, height: Pixels) -> Self {
211 self.set_target_width(width).set_target_height(height)
212 }
213
214 #[inline]
220 pub fn set_target_width(mut self, width: Pixels) -> Self {
221 self.use_auto_scaling = true;
222 self.target_width = Some(width);
223
224 self
225 }
226
227 #[inline]
233 pub fn set_target_height(mut self, height: Pixels) -> Self {
234 self.use_auto_scaling = true;
235 self.target_height = Some(height);
236
237 self
238 }
239
240 #[inline]
247 pub fn scale_page_to_bitmap(self, bitmap: &PdfBitmap) -> Self {
248 self.scale_page_to_display_size(bitmap.width(), bitmap.height())
249 }
250
251 #[inline]
259 pub fn scale_page_to_display_size(mut self, width: Pixels, height: Pixels) -> Self {
260 self.scale_width_factor = None;
261 self.scale_height_factor = None;
262
263 self.set_target_width(width)
264 .set_maximum_width(width)
265 .set_maximum_height(height)
266 .rotate_if_landscape(PdfPageRenderRotation::Degrees90, true)
267 }
268
269 #[inline]
274 pub fn scale_page_by_factor(self, scale: f32) -> Self {
275 let result = self.scale_page_width_by_factor(scale);
276
277 result.scale_page_height_by_factor(scale)
278 }
279
280 #[inline]
286 pub fn scale_page_width_by_factor(mut self, scale: f32) -> Self {
287 self.scale_width_factor = Some(scale);
288
289 self
290 }
291
292 #[inline]
298 pub fn scale_page_height_by_factor(mut self, scale: f32) -> Self {
299 self.scale_height_factor = Some(scale);
300
301 self
302 }
303
304 #[inline]
306 pub fn set_maximum_width(mut self, width: Pixels) -> Self {
307 self.maximum_width = Some(width);
308
309 self
310 }
311
312 #[inline]
314 pub fn set_maximum_height(mut self, height: Pixels) -> Self {
315 self.maximum_height = Some(height);
316
317 self
318 }
319
320 #[inline]
327 pub fn rotate(self, rotation: PdfPageRenderRotation, do_rotate_constraints: bool) -> Self {
328 self.rotate_if_portrait(rotation, do_rotate_constraints)
329 .rotate_if_landscape(rotation, do_rotate_constraints)
330 }
331
332 #[deprecated(
342 since = "0.7.12",
343 note = "This function has been renamed to correct a typo. Use the PdfRenderConfig::rotate_if_portrait() function instead."
344 )]
345 #[doc(hidden)]
346 #[inline]
347 pub fn rotate_if_portait(self, rotation: PdfPageRenderRotation, do_rotate_constraints: bool) -> Self {
348 self.rotate_if_portrait(rotation, do_rotate_constraints)
349 }
350
351 #[inline]
359 pub fn rotate_if_portrait(mut self, rotation: PdfPageRenderRotation, do_rotate_constraints: bool) -> Self {
360 self.portrait_rotation = rotation;
361
362 if rotation == PdfPageRenderRotation::Degrees90 || rotation == PdfPageRenderRotation::Degrees270 {
363 self.portrait_rotation_do_rotate_constraints = do_rotate_constraints;
364 }
365
366 self
367 }
368
369 #[inline]
377 pub fn rotate_if_landscape(mut self, rotation: PdfPageRenderRotation, do_rotate_constraints: bool) -> Self {
378 self.landscape_rotation = rotation;
379
380 if rotation == PdfPageRenderRotation::Degrees90 || rotation == PdfPageRenderRotation::Degrees270 {
381 self.landscape_rotation_do_rotate_constraints = do_rotate_constraints;
382 }
383
384 self
385 }
386
387 #[inline]
390 pub fn set_format(mut self, format: PdfBitmapFormat) -> Self {
391 self.format = format;
392
393 self
394 }
395
396 #[inline]
400 pub fn clear_before_rendering(mut self, do_clear: bool) -> Self {
401 self.do_clear_bitmap_before_rendering = do_clear;
402
403 self
404 }
405
406 #[inline]
410 pub fn set_clear_color(mut self, color: PdfColor) -> Self {
411 self.clear_color = color;
412
413 self
414 }
415
416 #[inline]
423 pub fn render_form_data(mut self, do_render: bool) -> Self {
424 self.do_render_form_data = do_render;
425
426 self
427 }
428
429 #[inline]
432 pub fn render_annotations(mut self, do_render: bool) -> Self {
433 self.do_set_flag_render_annotations = do_render;
434
435 self
436 }
437
438 #[inline]
443 pub fn use_lcd_text_rendering(mut self, do_set_flag: bool) -> Self {
444 self.do_set_flag_use_lcd_text_rendering = do_set_flag;
445
446 self
447 }
448
449 #[inline]
454 pub fn disable_native_text_rendering(mut self, do_set_flag: bool) -> Self {
455 self.do_set_flag_no_native_text = do_set_flag;
456
457 self
458 }
459
460 #[inline]
463 pub fn use_grayscale_rendering(mut self, do_set_flag: bool) -> Self {
464 self.do_set_flag_grayscale = do_set_flag;
465
466 self
467 }
468
469 #[inline]
473 pub fn limit_render_image_cache_size(mut self, do_set_flag: bool) -> Self {
474 self.do_set_flag_render_limited_image_cache = do_set_flag;
475
476 self
477 }
478
479 #[inline]
483 pub fn force_half_tone(mut self, do_set_flag: bool) -> Self {
484 self.do_set_flag_render_force_half_tone = do_set_flag;
485
486 self
487 }
488
489 #[inline]
496 pub fn use_print_quality(mut self, do_set_flag: bool) -> Self {
497 self.do_set_flag_render_for_printing = do_set_flag;
498
499 self
500 }
501
502 #[inline]
508 pub fn set_text_smoothing(mut self, do_set_flag: bool) -> Self {
509 self.do_set_flag_render_no_smooth_text = !do_set_flag;
510
511 self
512 }
513
514 #[inline]
517 pub fn set_image_smoothing(mut self, do_set_flag: bool) -> Self {
518 self.do_set_flag_render_no_smooth_image = !do_set_flag;
519
520 self
521 }
522
523 #[inline]
526 pub fn set_path_smoothing(mut self, do_set_flag: bool) -> Self {
527 self.do_set_flag_render_no_smooth_path = !do_set_flag;
528
529 self
530 }
531
532 #[inline]
540 pub fn set_reverse_byte_order(mut self, do_set_flag: bool) -> Self {
541 self.do_set_flag_reverse_byte_order = do_set_flag;
542
543 self
544 }
545
546 #[inline]
549 pub fn render_fills_as_strokes(mut self, do_set_flag: bool) -> Self {
550 self.do_set_flag_convert_fill_to_stroke = do_set_flag;
551
552 self
553 }
554
555 create_transform_setters!(
556 Self,
557 Result<Self, PdfiumError>,
558 "the [PdfPage] during rendering",
559 "the [PdfPage] during rendering.",
560 "the [PdfPage] during rendering,",
561 "Pdfium's rendering pipeline supports _either_ rendering with form data _or_ rendering with
562 a custom transformation matrix, but not both at the same time. Applying any transformation
563 automatically disables rendering of form data. If you must render form data while simultaneously
564 applying transformations, consider using the [PdfPage::flatten()] function to flatten the
565 form elements and form data into the containing page."
566 );
567
568 fn transform_impl(
569 mut self,
570 a: PdfMatrixValue,
571 b: PdfMatrixValue,
572 c: PdfMatrixValue,
573 d: PdfMatrixValue,
574 e: PdfMatrixValue,
575 f: PdfMatrixValue,
576 ) -> Result<Self, PdfiumError> {
577 let result = self.transformation_matrix.multiply(PdfMatrix::new(a, b, c, d, e, f));
578
579 if result.determinant() == 0.0 {
580 Err(PdfiumError::InvalidTransformationMatrix)
581 } else {
582 self.transformation_matrix = result;
583 self.do_render_form_data = false;
584
585 Ok(self)
586 }
587 }
588
589 fn reset_matrix_impl(mut self, matrix: PdfMatrix) -> Result<Self, PdfiumError> {
590 self.transformation_matrix = matrix;
591
592 Ok(self)
593 }
594
595 #[inline]
605 pub fn clip(mut self, left: Pixels, top: Pixels, right: Pixels, bottom: Pixels) -> Self {
606 self.clip_rect = Some((left, top, right, bottom));
607 self.do_render_form_data = false;
608
609 self
610 }
611
612 #[inline]
615 pub(crate) fn apply_to_page(&self, page: &PdfPage) -> PdfPageRenderSettings {
616 let source_width = page.width();
617
618 let source_height = page.height();
619
620 let source_orientation = PdfPageOrientation::from_width_and_height(source_width, source_height);
621
622 let (target_rotation, do_rotate_constraints) = self.compute_target_rotation(source_orientation);
623
624 let (output_width, output_height, width_scale, height_scale) =
625 self.compute_output_dimensions(source_width, source_height, do_rotate_constraints);
626
627 let render_flags = self.compute_render_flags();
628
629 let transformation_matrix =
630 self.compute_transformation_matrix(target_rotation, source_width, source_height, width_scale, height_scale);
631
632 PdfPageRenderSettings {
633 width: output_width,
634 height: output_height,
635 format: self.format.as_pdfium() as c_int,
636 rotate: target_rotation.as_pdfium(),
637 do_clear_bitmap_before_rendering: self.do_clear_bitmap_before_rendering,
638 clear_color: self.clear_color.as_pdfium_color(),
639 do_render_form_data: self.do_render_form_data,
640 form_field_highlight: None,
641 matrix: transformation_matrix.unwrap_or(PdfMatrix::IDENTITY).as_pdfium(),
642 clipping: self.compute_clipping_rect(output_width, output_height),
643 render_flags: render_flags as c_int,
644 is_reversed_byte_order_flag_set: self.do_set_flag_reverse_byte_order,
645 }
646 }
647
648 fn compute_target_rotation(&self, source_orientation: PdfPageOrientation) -> (PdfPageRenderRotation, bool) {
652 if source_orientation == Portrait && self.portrait_rotation != PdfPageRenderRotation::None {
653 (self.portrait_rotation, self.portrait_rotation_do_rotate_constraints)
654 } else if source_orientation == Landscape && self.landscape_rotation != PdfPageRenderRotation::None {
655 (self.landscape_rotation, self.landscape_rotation_do_rotate_constraints)
656 } else {
657 (PdfPageRenderRotation::None, false)
658 }
659 }
660
661 fn compute_output_dimensions(
665 &self,
666 source_width: PdfPoints,
667 source_height: PdfPoints,
668 do_rotate_constraints: bool,
669 ) -> (c_int, c_int, f32, f32) {
670 if !self.use_auto_scaling {
671 return (
672 self.fixed_width.unwrap_or(0) as c_int,
673 self.fixed_height.unwrap_or(0) as c_int,
674 self.scale_width_factor.unwrap_or(1.0),
675 self.scale_height_factor.unwrap_or(1.0),
676 );
677 }
678
679 let width_scale = if let Some(scale) = self.scale_width_factor {
680 Some(scale)
681 } else {
682 self.target_width.map(|target| (target as f32) / source_width.value)
683 };
684
685 let height_scale = if let Some(scale) = self.scale_height_factor {
686 Some(scale)
687 } else {
688 self.target_height.map(|target| (target as f32) / source_height.value)
689 };
690
691 let (do_maintain_aspect_ratio, mut width_scale, mut height_scale) = match (width_scale, height_scale) {
692 (Some(width_scale), Some(height_scale)) => (width_scale == height_scale, width_scale, height_scale),
693 (Some(width_scale), None) => (true, width_scale, width_scale),
694 (None, Some(height_scale)) => (true, height_scale, height_scale),
695 (None, None) => (false, 1.0, 1.0),
696 };
697
698 let (source_width, source_height, width_constraint, height_constraint) = if do_rotate_constraints {
699 (source_height, source_width, self.maximum_height, self.maximum_width)
700 } else {
701 (source_width, source_height, self.maximum_width, self.maximum_height)
702 };
703
704 if let Some(maximum) = width_constraint {
705 let maximum = maximum as f32;
706
707 if source_width.value * width_scale > maximum {
708 width_scale = maximum / source_width.value;
709
710 if do_maintain_aspect_ratio {
711 height_scale = width_scale;
712 }
713 }
714 }
715
716 if let Some(maximum) = height_constraint {
717 let maximum = maximum as f32;
718
719 if source_height.value * height_scale > maximum {
720 height_scale = maximum / source_height.value;
721
722 if do_maintain_aspect_ratio {
723 width_scale = height_scale;
724 }
725 }
726 }
727
728 (
729 (source_width.value * width_scale).round() as c_int,
730 (source_height.value * height_scale).round() as c_int,
731 width_scale,
732 height_scale,
733 )
734 }
735
736 fn compute_render_flags(&self) -> u32 {
739 let mut render_flags = 0;
740
741 if self.do_set_flag_render_annotations {
742 render_flags |= FPDF_ANNOT;
743 }
744
745 if self.do_set_flag_use_lcd_text_rendering {
746 render_flags |= FPDF_LCD_TEXT;
747 }
748
749 if self.do_set_flag_no_native_text {
750 render_flags |= FPDF_NO_NATIVETEXT;
751 }
752
753 if self.do_set_flag_grayscale {
754 render_flags |= FPDF_GRAYSCALE;
755 }
756
757 if self.do_set_flag_render_limited_image_cache {
758 render_flags |= FPDF_RENDER_LIMITEDIMAGECACHE;
759 }
760
761 if self.do_set_flag_render_force_half_tone {
762 render_flags |= FPDF_RENDER_FORCEHALFTONE;
763 }
764
765 if self.do_set_flag_render_for_printing {
766 render_flags |= FPDF_PRINTING;
767 }
768
769 if self.do_set_flag_render_no_smooth_text {
770 render_flags |= FPDF_RENDER_NO_SMOOTHTEXT;
771 }
772
773 if self.do_set_flag_render_no_smooth_image {
774 render_flags |= FPDF_RENDER_NO_SMOOTHIMAGE;
775 }
776
777 if self.do_set_flag_render_no_smooth_path {
778 render_flags |= FPDF_RENDER_NO_SMOOTHPATH;
779 }
780
781 if self.do_set_flag_reverse_byte_order {
782 render_flags |= FPDF_REVERSE_BYTE_ORDER;
783 }
784
785 if self.do_set_flag_convert_fill_to_stroke {
786 render_flags |= FPDF_CONVERT_FILL_TO_STROKE;
787 }
788
789 render_flags
790 }
791
792 fn compute_transformation_matrix(
796 &self,
797 target_rotation: PdfPageRenderRotation,
798 source_width: PdfPoints,
799 source_height: PdfPoints,
800 width_scale: f32,
801 height_scale: f32,
802 ) -> Result<PdfMatrix, PdfiumError> {
803 if self.do_render_form_data {
804 return Ok(PdfMatrix::identity());
805 }
806
807 let result = if target_rotation != PdfPageRenderRotation::None {
808 let (delta_x, delta_y) = match target_rotation {
809 PdfPageRenderRotation::None => unreachable!(),
810 PdfPageRenderRotation::Degrees90 => (PdfPoints::ZERO, -source_width),
811 PdfPageRenderRotation::Degrees180 => (-source_width, -source_height),
812 PdfPageRenderRotation::Degrees270 => (-source_height, PdfPoints::ZERO),
813 };
814
815 self.transformation_matrix
816 .translate(delta_x, delta_y)
817 .and_then(|result| result.rotate_clockwise_degrees(target_rotation.as_degrees()))
818 } else {
819 Ok(self.transformation_matrix)
820 };
821
822 result.and_then(|result| result.scale(width_scale, height_scale))
823 }
824
825 fn compute_clipping_rect(&self, output_width: c_int, output_height: c_int) -> FS_RECTF {
828 if let Some((left, top, right, bottom)) = self.clip_rect {
829 FS_RECTF {
830 left: left as f32,
831 top: top as f32,
832 right: right as f32,
833 bottom: bottom as f32,
834 }
835 } else {
836 FS_RECTF {
837 left: 0.0,
838 top: 0.0,
839 right: output_width as f32,
840 bottom: output_height as f32,
841 }
842 }
843 }
844}
845
846impl Default for PdfRenderConfig {
847 #[inline]
848 fn default() -> Self {
849 PdfRenderConfig::new()
850 }
851}
852
853#[derive(Debug, Clone)]
856pub(crate) struct PdfPageRenderSettings {
857 pub(crate) width: c_int,
858 pub(crate) height: c_int,
859 pub(crate) format: c_int,
860 pub(crate) rotate: c_int,
861 pub(crate) do_clear_bitmap_before_rendering: bool,
862 pub(crate) clear_color: FPDF_DWORD,
863 pub(crate) do_render_form_data: bool,
864 pub(crate) form_field_highlight: Option<Vec<(c_int, (FPDF_DWORD, u8))>>,
865 pub(crate) matrix: FS_MATRIX,
866 pub(crate) clipping: FS_RECTF,
867 pub(crate) render_flags: c_int,
868 pub(crate) is_reversed_byte_order_flag_set: bool,
869}
870
871#[cfg(test)]
872mod tests {
873 use crate::prelude::*;
874 use crate::utils::test::test_bind_to_pdfium;
875
876 #[test]
877 fn test_fixed_size_render_config() -> Result<(), PdfiumError> {
878 let render_settings = get_render_settings_from_config(PdfRenderConfig::new().set_fixed_size(2000, 2000))?;
879
880 assert_eq!(render_settings.width, 2000);
881 assert_eq!(render_settings.height, 2000);
882
883 let render_settings = get_render_settings_from_config(
884 PdfRenderConfig::new()
885 .set_fixed_size(2000, 2000)
886 .scale_page_by_factor(5.0),
887 )?;
888
889 assert_eq!(render_settings.width, 2000);
890 assert_eq!(render_settings.height, 2000);
891
892 Ok(())
893 }
894
895 #[test]
896 fn test_target_size_render_config() -> Result<(), PdfiumError> {
897 let render_settings =
898 get_render_settings_from_config(PdfRenderConfig::new().scale_page_to_display_size(2000, 2000))?;
899
900 assert_eq!(render_settings.width, 1414);
901 assert_eq!(render_settings.height, 2000);
902
903 let render_settings = get_render_settings_from_config(
904 PdfRenderConfig::new()
905 .set_target_size(2000, 2000)
906 .scale_page_by_factor(5.0),
907 )?;
908
909 assert_eq!(render_settings.width, 2976);
910 assert_eq!(render_settings.height, 4209);
911
912 Ok(())
913 }
914
915 fn get_render_settings_from_config(config: PdfRenderConfig) -> Result<PdfPageRenderSettings, PdfiumError> {
916 let pdfium = test_bind_to_pdfium();
917
918 let mut document = pdfium.create_new_pdf()?;
919 let page = document
920 .pages_mut()
921 .create_page_at_start(PdfPagePaperSize::Portrait(PdfPagePaperStandardSize::A4))?;
922
923 Ok(config.apply_to_page(&page))
924 }
925}