1#![doc = include_str!("../README.md")]
2#![allow(clippy::doc_nested_refdefs)]
3#![allow(dead_code)]
5#![allow(deprecated)]
6
7mod bindgen {
8 #![allow(non_upper_case_globals)]
9 #![allow(non_camel_case_types)]
10 #![allow(non_snake_case)]
11 #![allow(dead_code)]
12
13 include!("bindgen/pdfium_7678.rs");
14
15 pub(crate) type size_t = usize;
16}
17
18mod bindings;
19mod error;
20mod font_provider;
21mod pdf;
22mod pdfium;
23mod utils;
24
25pub mod prelude {
37 pub use crate::{
38 bindings::*,
39 error::*,
40 font_provider::FontDescriptor,
41 pdf::bitmap::*,
43 pdf::color::*,
44 pdf::color_space::*,
45 pdf::document::fonts::*,
47 pdf::document::metadata::*,
48 pdf::document::page::annotation::attachment_points::*,
50 pdf::document::page::annotation::circle::*,
51 pdf::document::page::annotation::free_text::*,
52 pdf::document::page::annotation::highlight::*,
53 pdf::document::page::annotation::ink::*,
54 pdf::document::page::annotation::link::*,
55 pdf::document::page::annotation::objects::*,
56 pdf::document::page::annotation::square::*,
57 pdf::document::page::annotation::squiggly::*,
58 pdf::document::page::annotation::stamp::*,
59 pdf::document::page::annotation::strikeout::*,
60 pdf::document::page::annotation::text::*,
61 pdf::document::page::annotation::underline::*,
62 pdf::document::page::annotation::unsupported::*,
63 pdf::document::page::annotation::{PdfPageAnnotation, PdfPageAnnotationCommon, PdfPageAnnotationType},
64 pdf::document::page::annotations::*,
65 pdf::document::page::boundaries::*,
67 pdf::document::page::extraction::*,
68 pdf::document::page::links::*,
69 pdf::document::page::object::content_mark::*,
71 pdf::document::page::object::content_marks::*,
72 pdf::document::page::object::group::*,
73 pdf::document::page::object::image::*,
74 pdf::document::page::object::path::*,
75 pdf::document::page::object::shading::*,
76 pdf::document::page::object::text::*,
77 pdf::document::page::object::unsupported::*,
78 pdf::document::page::object::x_object_form::*,
79 pdf::document::page::object::{
80 PdfPageObject, PdfPageObjectBlendMode, PdfPageObjectCommon, PdfPageObjectLineCap, PdfPageObjectLineJoin,
81 PdfPageObjectType,
82 },
83 pdf::document::page::objects::common::*,
84 pdf::document::page::objects::*,
85 pdf::document::page::paragraph::*,
86 pdf::document::page::render_config::*,
87 pdf::document::page::size::*,
88 pdf::document::page::struct_element::*,
89 pdf::document::page::struct_tree::*,
90 pdf::document::page::text::char::*,
92 pdf::document::page::text::chars::*,
93 pdf::document::page::text::search::*,
94 pdf::document::page::text::segment::*,
95 pdf::document::page::text::segments::*,
96 pdf::document::page::text::*,
97 pdf::document::page::{PdfPage, PdfPageContentRegenerationStrategy, PdfPageOrientation, PdfPageRenderRotation},
98 pdf::document::pages::*,
99 pdf::document::permissions::*,
100 pdf::document::{PdfDocument, PdfDocumentVersion},
101 pdf::font::glyph::*,
103 pdf::font::glyphs::*,
104 pdf::font::*,
105 pdf::link::*,
106 pdf::matrix::*,
107 pdf::path::clip_path::*,
108 pdf::path::segment::*,
109 pdf::path::segments::*,
110 pdf::points::*,
111 pdf::quad_points::*,
112 pdf::rect::*,
113 pdfium::*,
115 };
116}
117
118#[cfg(test)]
119mod tests {
120 use crate::prelude::*;
121 use crate::utils::test::{test_bind_to_pdfium, test_fixture_path};
122 use image_025::ImageFormat;
123 use std::fs::File;
124 use std::path::Path;
125
126 #[test]
127 #[cfg(not(pdfium_use_static))]
128 fn test_readme_example() -> Result<(), PdfiumError> {
129 fn export_pdf_to_jpegs(path: &impl AsRef<Path>, password: Option<&str>) -> Result<(), PdfiumError> {
132 let pdfium = Pdfium;
133
134 let document = pdfium.load_pdf_from_file(path, password)?;
135
136 let render_config = PdfRenderConfig::new()
137 .set_target_width(2000)
138 .set_maximum_height(2000)
139 .rotate_if_landscape(PdfPageRenderRotation::Degrees90, true);
140
141 for (index, page) in document.pages().iter().enumerate() {
142 page.render_with_config(&render_config)?
143 .as_image()?
144 .into_rgb8()
145 .save_with_format(format!("test-page-{}.jpg", index), ImageFormat::Jpeg)
146 .map_err(|_| PdfiumError::ImageError)?;
147 }
148
149 Ok(())
150 }
151
152 export_pdf_to_jpegs(&test_fixture_path("export-test.pdf"), None)
153 }
154
155 #[test]
156 #[cfg(not(pdfium_use_static))]
157 fn test_dynamic_bindings() -> Result<(), PdfiumError> {
158 let pdfium = Pdfium;
159
160 let document = pdfium.load_pdf_from_file(&test_fixture_path("form-test.pdf"), None)?;
161
162 let render_config = PdfRenderConfig::new()
163 .set_target_width(2000)
164 .set_maximum_height(2000)
165 .rotate_if_landscape(PdfPageRenderRotation::Degrees90, true)
166 .render_form_data(true)
167 .render_annotations(true);
168
169 for (index, page) in document.pages().iter().enumerate() {
170 let result = page
171 .render_with_config(&render_config)?
172 .as_image()?
173 .into_rgb8()
174 .save_with_format(format!("form-test-page-{}.jpg", index), ImageFormat::Jpeg);
175
176 assert!(result.is_ok());
177 }
178
179 Ok(())
180 }
181
182 #[test]
183 #[cfg(pdfium_use_static)]
184 fn test_static_bindings() {
185 Pdfium::bind_to_statically_linked_library().unwrap();
188 }
189
190 #[test]
191 fn test_reader_lifetime() -> Result<(), PdfiumError> {
192 let pdfium = test_bind_to_pdfium();
196
197 let filenames = ["form-test.pdf", "annotations-test.pdf"];
198
199 for filename in filenames {
200 let path = test_fixture_path(filename);
201 let page_count = {
202 let reader = File::open(&path).map_err(PdfiumError::IoError)?;
203
204 let document = pdfium.load_pdf_from_reader(reader, None)?;
205
206 document.pages().len()
207
208 };
210
211 println!("{} has {} pages", path.display(), page_count);
212 }
213
214 Ok(())
215 }
216
217 #[test]
218 #[cfg(not(pdfium_use_static))]
219 fn test_custom_font_paths_with_text_rendering() -> Result<(), PdfiumError> {
220 let config = PdfiumConfig::new().set_user_font_paths(vec!["/usr/share/fonts/truetype/".to_string()]);
222
223 let bindings = Pdfium::bind_to_library(Pdfium::pdfium_platform_library_name_at_path("./"))
224 .or_else(|_| Pdfium::bind_to_system_library());
225
226 match bindings {
227 Ok(bindings) => {
228 let pdfium = Pdfium::new_with_config(bindings, &config);
229
230 let mut document = pdfium.create_new_pdf()?;
232 let mut page = document.pages_mut().create_page_at_end(PdfPagePaperSize::a4())?;
233
234 let font = document.fonts_mut().helvetica();
236 let _text_obj = page.objects_mut().create_text_object(
237 PdfPoints::new(100.0),
238 PdfPoints::new(700.0),
239 "Testing custom font paths",
240 font,
241 PdfPoints::new(12.0),
242 )?;
243
244 assert!(page.objects().iter().count() > 0);
246
247 Ok(())
248 }
249 Err(PdfiumError::PdfiumLibraryBindingsAlreadyInitialized) => {
250 Ok(())
252 }
253 Err(e) => Err(e),
254 }
255 }
256
257 #[test]
258 #[cfg(not(pdfium_use_static))]
259 fn test_empty_font_paths() -> Result<(), PdfiumError> {
260 let config = PdfiumConfig::new(); let bindings = Pdfium::bind_to_library(Pdfium::pdfium_platform_library_name_at_path("./"))
263 .or_else(|_| Pdfium::bind_to_system_library());
264
265 match bindings {
266 Ok(bindings) => {
267 let pdfium = Pdfium::new_with_config(bindings, &config);
268 let document = pdfium.create_new_pdf()?;
269 assert_eq!(document.pages().len(), 0);
270 Ok(())
271 }
272 Err(PdfiumError::PdfiumLibraryBindingsAlreadyInitialized) => Ok(()),
273 Err(e) => Err(e),
274 }
275 }
276
277 #[test]
278 #[cfg(not(pdfium_use_static))]
279 fn test_font_paths_with_null_bytes() -> Result<(), PdfiumError> {
280 let config = PdfiumConfig::new().set_user_font_paths(vec![
282 "/usr/share\0/fonts".to_string(), "/usr/share/fonts/truetype/".to_string(), ]);
285
286 let bindings = Pdfium::bind_to_library(Pdfium::pdfium_platform_library_name_at_path("./"))
287 .or_else(|_| Pdfium::bind_to_system_library());
288
289 match bindings {
290 Ok(bindings) => {
291 let pdfium = Pdfium::new_with_config(bindings, &config);
293 let document = pdfium.create_new_pdf()?;
294 assert_eq!(document.pages().len(), 0);
295 Ok(())
296 }
297 Err(PdfiumError::PdfiumLibraryBindingsAlreadyInitialized) => Ok(()),
298 Err(e) => Err(e),
299 }
300 }
301
302 #[test]
303 #[cfg(not(pdfium_use_static))]
304 fn test_font_paths_nonexistent() -> Result<(), PdfiumError> {
305 let config = PdfiumConfig::new().set_user_font_paths(vec![
307 "/this/path/does/not/exist".to_string(),
308 "/another/fake/path".to_string(),
309 ]);
310
311 let bindings = Pdfium::bind_to_library(Pdfium::pdfium_platform_library_name_at_path("./"))
312 .or_else(|_| Pdfium::bind_to_system_library());
313
314 match bindings {
315 Ok(bindings) => {
316 let pdfium = Pdfium::new_with_config(bindings, &config);
318 let document = pdfium.create_new_pdf()?;
319 assert_eq!(document.pages().len(), 0);
320 Ok(())
321 }
322 Err(PdfiumError::PdfiumLibraryBindingsAlreadyInitialized) => Ok(()),
323 Err(e) => Err(e),
324 }
325 }
326
327 #[test]
328 #[cfg(not(pdfium_use_static))]
329 fn test_default_config_uses_simple_initialization() -> Result<(), PdfiumError> {
330 let config = PdfiumConfig::new(); let bindings = Pdfium::bind_to_library(Pdfium::pdfium_platform_library_name_at_path("./"))
337 .or_else(|_| Pdfium::bind_to_system_library());
338
339 match bindings {
340 Ok(bindings) => {
341 let pdfium = Pdfium::new_with_config(bindings, &config);
342 let document = pdfium.create_new_pdf()?;
343 assert_eq!(document.pages().len(), 0);
344 Ok(())
345 }
346 Err(PdfiumError::PdfiumLibraryBindingsAlreadyInitialized) => Ok(()),
347 Err(e) => Err(e),
348 }
349 }
350}