use super::{
super::{format::*, image::Image, stream::*},
zlib::*,
};
use {
hayro::{
hayro_interpret::*,
hayro_syntax::{page::*, *},
*,
},
std::{fs::*, io, path::*, sync::*},
};
impl Image {
pub fn new_owned_from_pdf_file<PathT>(
path: PathT,
format: ImageFormat,
scale: f64,
compress: bool,
) -> io::Result<Vec<Self>>
where
PathT: AsRef<Path>,
{
let mut images = Vec::default();
let pdf = read_pdf(path)?;
for page in pdf.pages().into_iter() {
let (width, height) = size(page, scale);
let data = render_page(page, format, scale)?;
let data = if compress { zlib(&data)? } else { data };
images.push(Self::new_owned(data, compress, format, (width, height)));
}
Ok(images)
}
pub fn new_stream_from_pdf_file<PathT>(path: PathT, format: ImageFormat, scale: f64) -> io::Result<Vec<Self>>
where
PathT: AsRef<Path>,
{
let mut images = Vec::default();
let path = path.as_ref();
let pdf = read_pdf(path)?;
for (index, page) in pdf.pages().into_iter().enumerate() {
let (width, height) = size(page, scale);
let stream = PdfPageImageStream::new(path.into(), index, format, scale);
images.push(Self::new_stream(stream, format, (width, height)));
}
Ok(images)
}
}
struct PdfPageImageStream {
path: PathBuf,
index: usize,
format: ImageFormat,
scale: f64,
}
impl PdfPageImageStream {
fn new(path: PathBuf, index: usize, format: ImageFormat, scale: f64) -> Self {
Self { path, index, format, scale }
}
}
impl ImageStream for PdfPageImageStream {
fn open(&self) -> io::Result<(Box<dyn io::Read>, bool)> {
let pdf = read_pdf(&self.path)?;
let page = pdf.pages().get(self.index).ok_or_else(|| io::Error::other("PDF missing page"))?;
let data = render_page(page, self.format, self.scale)?;
Ok((Box::new(io::Cursor::new(data)), false))
}
}
fn read_pdf<PathT>(path: PathT) -> io::Result<Pdf>
where
PathT: AsRef<Path>,
{
let data = read(path.as_ref())?;
Ok(Pdf::new(Arc::new(data)).map_err(|_| io::Error::other("PDF parsing error"))?)
}
fn render_page(page: &Page, format: ImageFormat, scale: f64) -> io::Result<Vec<u8>> {
let interpreter_settings = InterpreterSettings::default();
let mut render_settings = RenderSettings::default();
let scale = scale as f32;
render_settings.x_scale = scale;
render_settings.y_scale = scale;
let pixmap = render(page, &interpreter_settings, &render_settings);
Ok(match format {
ImageFormat::PNG => pixmap.into_png()?,
ImageFormat::RGBA => bytemuck::cast_slice(&pixmap.take()).into(),
_ => return Err(io::Error::other("unsupported format")),
})
}
fn size(page: &Page, scale: f64) -> (usize, usize) {
let scale = scale as f32;
let (width, height) = page.render_dimensions();
((width * scale).round() as usize, (height * scale).round() as usize)
}