cursive_image/image/compatibility/
pdf.rs1use super::{
2 super::{format::*, image::Image, stream::*},
3 zlib::*,
4};
5
6use {
7 hayro::{
8 hayro_interpret::*,
9 hayro_syntax::{page::*, *},
10 *,
11 },
12 std::{fs::*, io, path::*, sync::*},
13};
14
15impl Image {
16 pub fn new_owned_from_pdf_file<PathT>(
22 path: PathT,
23 format: ImageFormat,
24 scale: f64,
25 compress: bool,
26 ) -> io::Result<Vec<Self>>
27 where
28 PathT: AsRef<Path>,
29 {
30 let mut images = Vec::default();
31
32 let pdf = read_pdf(path)?;
33 for page in pdf.pages().into_iter() {
34 let (width, height) = size(page, scale);
35 let data = render_page(page, format, scale)?;
36 let data = if compress { zlib(&data)? } else { data };
37 images.push(Self::new_owned(data, compress, format, (width, height)));
38 }
39
40 Ok(images)
41 }
42
43 pub fn new_stream_from_pdf_file<PathT>(path: PathT, format: ImageFormat, scale: f64) -> io::Result<Vec<Self>>
49 where
50 PathT: AsRef<Path>,
51 {
52 let mut images = Vec::default();
53
54 let path = path.as_ref();
55 let pdf = read_pdf(path)?;
56 for (index, page) in pdf.pages().into_iter().enumerate() {
57 let (width, height) = size(page, scale);
58 let stream = PdfPageImageStream::new(path.into(), index, format, scale);
59 images.push(Self::new_stream(stream, format, (width, height)));
60 }
61
62 Ok(images)
63 }
64}
65
66struct PdfPageImageStream {
71 path: PathBuf,
72 index: usize,
73 format: ImageFormat,
74 scale: f64,
75}
76
77impl PdfPageImageStream {
78 fn new(path: PathBuf, index: usize, format: ImageFormat, scale: f64) -> Self {
79 Self { path, index, format, scale }
80 }
81}
82
83impl ImageStream for PdfPageImageStream {
84 fn open(&self) -> io::Result<(Box<dyn io::Read>, bool)> {
85 let pdf = read_pdf(&self.path)?;
87 let page = pdf.pages().get(self.index).ok_or_else(|| io::Error::other("PDF missing page"))?;
88 let data = render_page(page, self.format, self.scale)?;
89 Ok((Box::new(io::Cursor::new(data)), false))
90 }
91}
92
93fn read_pdf<PathT>(path: PathT) -> io::Result<Pdf>
96where
97 PathT: AsRef<Path>,
98{
99 let data = read(path.as_ref())?;
100 Ok(Pdf::new(Arc::new(data)).map_err(|_| io::Error::other("PDF parsing error"))?)
101}
102
103fn render_page(page: &Page, format: ImageFormat, scale: f64) -> io::Result<Vec<u8>> {
104 let interpreter_settings = InterpreterSettings::default();
105
106 let mut render_settings = RenderSettings::default();
107 let scale = scale as f32;
108 render_settings.x_scale = scale;
109 render_settings.y_scale = scale;
110
111 let pixmap = render(page, &interpreter_settings, &render_settings);
112
113 Ok(match format {
114 ImageFormat::PNG => pixmap.into_png()?,
115 ImageFormat::RGBA => bytemuck::cast_slice(&pixmap.take()).into(),
117 _ => return Err(io::Error::other("unsupported format")),
118 })
119}
120
121fn size(page: &Page, scale: f64) -> (usize, usize) {
122 let scale = scale as f32;
123 let (width, height) = page.render_dimensions();
124 ((width * scale).round() as usize, (height * scale).round() as usize)
125}