summaryrefslogtreecommitdiff
path: root/src/export
diff options
context:
space:
mode:
authorLaurenz Mädje <laurmaedje@gmail.com>2019-07-28 22:27:09 +0200
committerLaurenz Mädje <laurmaedje@gmail.com>2019-07-28 22:27:09 +0200
commitb96a7e0cf3c97463ecb746d859b675541a427774 (patch)
treedcbae7e29b84264c448ebf211dad5a31c3340715 /src/export
parent51faad45ad54e8db0009edb3b3b589059b051cb6 (diff)
Reuse font loader across compilations 🔋
Diffstat (limited to 'src/export')
-rw-r--r--src/export/pdf.rs54
1 files changed, 34 insertions, 20 deletions
diff --git a/src/export/pdf.rs b/src/export/pdf.rs
index aae62415..d01a9966 100644
--- a/src/export/pdf.rs
+++ b/src/export/pdf.rs
@@ -1,6 +1,6 @@
//! Exporting into _PDF_ documents.
-use std::collections::HashSet;
+use std::collections::{HashMap, HashSet};
use std::io::{self, Write};
use pdf::{PdfWriter, Ref, Rect, Version, Trailer, Content};
@@ -9,7 +9,7 @@ use pdf::font::{Type0Font, CIDFont, CIDFontType, CIDSystemInfo, FontDescriptor,
use pdf::font::{GlyphUnit, CMap, CMapEncoding, WidthRecord, FontStream};
use crate::doc::{Document, Page as DocPage, LayoutAction};
-use crate::font::{Font, FontError};
+use crate::font::{Font, FontLoader, FontError};
use crate::size::{Size, Size2D};
@@ -26,8 +26,9 @@ impl PdfExporter {
/// Export a typesetted document into a writer. Returns how many bytes were written.
#[inline]
- pub fn export<W: Write>(&self, document: &Document, target: W) -> PdfResult<usize> {
- let mut engine = PdfEngine::new(document, target)?;
+ pub fn export<W: Write>(&self, document: &Document, loader: &FontLoader, target: W)
+ -> PdfResult<usize> {
+ let mut engine = PdfEngine::new(document, loader, target)?;
engine.write()
}
}
@@ -38,6 +39,7 @@ struct PdfEngine<'d, W: Write> {
writer: PdfWriter<W>,
doc: &'d Document,
offsets: Offsets,
+ font_remap: HashMap<usize, usize>,
fonts: Vec<PdfFont>,
}
@@ -53,41 +55,53 @@ struct Offsets {
impl<'d, W: Write> PdfEngine<'d, W> {
/// Create a new _PDF_ engine.
- fn new(doc: &'d Document, target: W) -> PdfResult<PdfEngine<'d, W>> {
- // Calculate a unique id for all objects that will be written.
- let catalog = 1;
- let page_tree = catalog + 1;
- let pages = (page_tree + 1, page_tree + doc.pages.len() as Ref);
- let contents = (pages.1 + 1, pages.1 + doc.pages.len() as Ref);
- let fonts = (contents.1 + 1, contents.1 + 5 * doc.fonts.len() as Ref);
- let offsets = Offsets { catalog, page_tree, pages, contents, fonts };
-
+ fn new(doc: &'d Document, loader: &FontLoader, target: W) -> PdfResult<PdfEngine<'d, W>> {
// Create a subsetted PDF font for each font in the document.
+ let mut font_remap = HashMap::new();
let fonts = {
let mut font = 0usize;
- let mut chars = vec![HashSet::new(); doc.fonts.len()];
+ let mut chars = HashMap::new();
// Find out which characters are used for each font.
for page in &doc.pages {
for action in &page.actions {
match action {
- LayoutAction::WriteText(string) => chars[font].extend(string.chars()),
- LayoutAction::SetFont(id, _) => font = *id,
+ LayoutAction::WriteText(string) => {
+ chars.entry(font)
+ .or_insert_with(HashSet::new)
+ .extend(string.chars())
+ },
+ LayoutAction::SetFont(id, _) => {
+ font = *id;
+ let new_id = font_remap.len();
+ font_remap.entry(font).or_insert(new_id);
+ },
_ => {},
}
}
}
- doc.fonts.iter()
- .enumerate()
- .map(|(i, font)| PdfFont::new(font, &chars[i]))
+ // Collect the fonts into a vector in the order of the values in the remapping.
+ let mut order = font_remap.iter().map(|(&old, &new)| (old, new)).collect::<Vec<_>>();
+ order.sort_by_key(|&(_, new)| new);
+ order.into_iter()
+ .map(|(old, _)| PdfFont::new(&loader.get_with_index(old), &chars[&old]))
.collect::<PdfResult<Vec<_>>>()?
};
+ // Calculate a unique id for all objects that will be written.
+ let catalog = 1;
+ let page_tree = catalog + 1;
+ let pages = (page_tree + 1, page_tree + doc.pages.len() as Ref);
+ let contents = (pages.1 + 1, pages.1 + doc.pages.len() as Ref);
+ let font_offsets = (contents.1 + 1, contents.1 + 5 * fonts.len() as Ref);
+ let offsets = Offsets { catalog, page_tree, pages, contents, fonts: font_offsets };
+
Ok(PdfEngine {
writer: PdfWriter::new(target),
doc,
offsets,
+ font_remap,
fonts,
})
}
@@ -151,7 +165,7 @@ impl<'d, W: Write> PdfEngine<'d, W> {
for action in &page.actions {
match action {
LayoutAction::MoveAbsolute(pos) => next_pos = Some(*pos),
- LayoutAction::SetFont(id, size) => next_font = Some((*id, *size)),
+ LayoutAction::SetFont(id, size) => next_font = Some((self.font_remap[id], *size)),
LayoutAction::WriteText(string) => {
// Flush the font if it is different from the current.
if let Some((id, size)) = next_font {