typst_library/visualize/image/
pdf.rs

1use std::hash::{Hash, Hasher};
2use std::sync::Arc;
3
4use hayro_syntax::page::Page;
5use hayro_syntax::{LoadPdfError, Pdf};
6
7use crate::foundations::Bytes;
8
9/// A PDF document.
10#[derive(Clone, Hash)]
11pub struct PdfDocument(Arc<DocumentRepr>);
12
13/// The internal representation of a `PdfDocument`.
14struct DocumentRepr {
15    pdf: Arc<Pdf>,
16    data: Bytes,
17}
18
19impl PdfDocument {
20    /// Loads a PDF document.
21    #[comemo::memoize]
22    #[typst_macros::time(name = "load pdf document")]
23    pub fn new(data: Bytes) -> Result<PdfDocument, LoadPdfError> {
24        let pdf = Arc::new(Pdf::new(Arc::new(data.clone()))?);
25        Ok(Self(Arc::new(DocumentRepr { data, pdf })))
26    }
27
28    /// Returns the underlying PDF document.
29    pub fn pdf(&self) -> &Arc<Pdf> {
30        &self.0.pdf
31    }
32
33    /// Return the number of pages in the PDF.
34    pub fn num_pages(&self) -> usize {
35        self.0.pdf.pages().len()
36    }
37}
38
39impl Hash for DocumentRepr {
40    fn hash<H: Hasher>(&self, state: &mut H) {
41        self.data.hash(state);
42    }
43}
44
45/// A specific page of a PDF acting as an image.
46#[derive(Clone, Hash)]
47pub struct PdfImage(Arc<ImageRepr>);
48
49/// The internal representation of a `PdfImage`.
50struct ImageRepr {
51    document: PdfDocument,
52    page_index: usize,
53    width: f32,
54    height: f32,
55}
56
57impl PdfImage {
58    /// Creates a new PDF image.
59    ///
60    /// Returns `None` if the page index is not valid.
61    #[comemo::memoize]
62    pub fn new(document: PdfDocument, page_index: usize) -> Option<PdfImage> {
63        let (width, height) = document.0.pdf.pages().get(page_index)?.render_dimensions();
64        Some(Self(Arc::new(ImageRepr { document, page_index, width, height })))
65    }
66
67    /// Returns the underlying Typst PDF document.
68    pub fn document(&self) -> &PdfDocument {
69        &self.0.document
70    }
71
72    /// Returns the PDF page of the image.
73    pub fn page(&self) -> &Page<'_> {
74        &self.document().pdf().pages()[self.0.page_index]
75    }
76
77    /// Returns the width of the image.
78    pub fn width(&self) -> f32 {
79        self.0.width
80    }
81
82    /// Returns the height of the image.
83    pub fn height(&self) -> f32 {
84        self.0.height
85    }
86
87    /// Returns the page index of the image.
88    pub fn page_index(&self) -> usize {
89        self.0.page_index
90    }
91}
92
93impl Hash for ImageRepr {
94    fn hash<H: Hasher>(&self, state: &mut H) {
95        self.document.hash(state);
96        self.page_index.hash(state);
97    }
98}