use std::hash::{Hash, Hasher};
use std::sync::Arc;
use hayro_syntax::page::Page;
use hayro_syntax::{LoadPdfError, Pdf};
use crate::foundations::Bytes;
#[derive(Clone, Hash)]
pub struct PdfDocument(Arc<DocumentRepr>);
struct DocumentRepr {
pdf: Arc<Pdf>,
data: Bytes,
}
impl PdfDocument {
#[comemo::memoize]
#[typst_macros::time(name = "load pdf document")]
pub fn new(data: Bytes) -> Result<PdfDocument, LoadPdfError> {
let pdf = Arc::new(Pdf::new(Arc::new(data.clone()))?);
Ok(Self(Arc::new(DocumentRepr { data, pdf })))
}
pub fn pdf(&self) -> &Arc<Pdf> {
&self.0.pdf
}
pub fn num_pages(&self) -> usize {
self.0.pdf.pages().len()
}
}
impl Hash for DocumentRepr {
fn hash<H: Hasher>(&self, state: &mut H) {
self.data.hash(state);
}
}
#[derive(Clone, Hash)]
pub struct PdfImage(Arc<ImageRepr>);
struct ImageRepr {
document: PdfDocument,
page_index: usize,
width: f32,
height: f32,
}
impl PdfImage {
#[comemo::memoize]
pub fn new(document: PdfDocument, page_index: usize) -> Option<PdfImage> {
let (width, height) = document.0.pdf.pages().get(page_index)?.render_dimensions();
Some(Self(Arc::new(ImageRepr { document, page_index, width, height })))
}
pub fn document(&self) -> &PdfDocument {
&self.0.document
}
pub fn page(&self) -> &Page<'_> {
&self.document().pdf().pages()[self.0.page_index]
}
pub fn width(&self) -> f32 {
self.0.width
}
pub fn height(&self) -> f32 {
self.0.height
}
pub fn page_index(&self) -> usize {
self.0.page_index
}
}
impl Hash for ImageRepr {
fn hash<H: Hasher>(&self, state: &mut H) {
self.document.hash(state);
self.page_index.hash(state);
}
}