mirror of
https://github.com/typst/typst
synced 2025-05-13 12:36:23 +08:00
Enhance PDF crate API 🚀
This commit is contained in:
parent
6b8da16be8
commit
da60261376
133
src/pdf.rs
133
src/pdf.rs
@ -4,10 +4,12 @@ use std::fmt;
|
|||||||
use std::io::{self, Write, Cursor};
|
use std::io::{self, Write, Cursor};
|
||||||
use crate::doc::Document;
|
use crate::doc::Document;
|
||||||
use pdf::{PdfWriter, Id, Rect, Version, Trailer};
|
use pdf::{PdfWriter, Id, Rect, Version, Trailer};
|
||||||
use pdf::doc::{DocumentCatalog, PageTree, Page, PageData, Resource, Content};
|
use pdf::doc::{Catalog, PageTree, Page, Resource, Content};
|
||||||
use pdf::text::Text;
|
use pdf::text::Text;
|
||||||
use pdf::font::{Type0Font, CMapEncoding, CIDFont, CIDFontType, CIDSystemInfo,
|
use pdf::font::{
|
||||||
WidthRecord, FontDescriptor, EmbeddedFont, GlyphUnit};
|
Type0Font, CMapEncoding, CIDFont, CIDFontType, CIDSystemInfo,
|
||||||
|
WidthRecord, FontDescriptor, FontFlags, EmbeddedFont, GlyphUnit
|
||||||
|
};
|
||||||
use opentype::{OpenTypeReader, tables};
|
use opentype::{OpenTypeReader, tables};
|
||||||
|
|
||||||
|
|
||||||
@ -52,18 +54,6 @@ impl fmt::Display for PdfWritingError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Shortcut macro to create bitflags from bools.
|
|
||||||
macro_rules! flags {
|
|
||||||
($($bit:expr => $value:expr),*) => {{
|
|
||||||
let mut flags = 0;
|
|
||||||
$(
|
|
||||||
flags |= if $value { 1 << ($bit - 1) } else { 0 };
|
|
||||||
)*
|
|
||||||
flags
|
|
||||||
}};
|
|
||||||
($($bit:expr => $value:expr,)*) => (flags!($($bit => $value),*));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Keeps track of the document while letting the pdf writer
|
/// Keeps track of the document while letting the pdf writer
|
||||||
/// generate the _PDF_.
|
/// generate the _PDF_.
|
||||||
struct PdfCreator<'a, W: Write> {
|
struct PdfCreator<'a, W: Write> {
|
||||||
@ -140,9 +130,7 @@ impl<'a, W: Write> PdfCreator<'a, W> {
|
|||||||
self.writer.write_xref_table()?;
|
self.writer.write_xref_table()?;
|
||||||
|
|
||||||
// Trailer
|
// Trailer
|
||||||
self.writer.write_trailer(&Trailer {
|
self.writer.write_trailer(&Trailer::new(self.offsets.catalog))?;
|
||||||
root: self.offsets.catalog,
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(self.writer.written())
|
Ok(self.writer.written())
|
||||||
}
|
}
|
||||||
@ -150,19 +138,13 @@ impl<'a, W: Write> PdfCreator<'a, W> {
|
|||||||
/// Write the document catalog, page tree and pages.
|
/// Write the document catalog, page tree and pages.
|
||||||
fn write_pages(&mut self) -> PdfResult<()> {
|
fn write_pages(&mut self) -> PdfResult<()> {
|
||||||
// The document catalog
|
// The document catalog
|
||||||
self.writer.write_obj(self.offsets.catalog, &DocumentCatalog {
|
self.writer.write_obj(self.offsets.catalog, &Catalog::new(self.offsets.page_tree))?;
|
||||||
page_tree: self.offsets.page_tree,
|
|
||||||
})?;
|
|
||||||
|
|
||||||
// Root page tree
|
// Root page tree
|
||||||
self.writer.write_obj(self.offsets.page_tree, &PageTree {
|
self.writer.write_obj(self.offsets.page_tree, PageTree::new()
|
||||||
parent: None,
|
.kids(self.offsets.pages.0 ..= self.offsets.pages.1)
|
||||||
kids: (self.offsets.pages.0 ..= self.offsets.pages.1).collect(),
|
.resource(Resource::Font { nr: 1, id: self.offsets.fonts.0 })
|
||||||
data: PageData {
|
)?;
|
||||||
resources: Some(vec![Resource::Font { nr: 1, id: self.offsets.fonts.0 }]),
|
|
||||||
.. PageData::none()
|
|
||||||
},
|
|
||||||
})?;
|
|
||||||
|
|
||||||
// The page objects
|
// The page objects
|
||||||
let mut id = self.offsets.pages.0;
|
let mut id = self.offsets.pages.0;
|
||||||
@ -170,15 +152,10 @@ impl<'a, W: Write> PdfCreator<'a, W> {
|
|||||||
let width = page.size[0].to_points();
|
let width = page.size[0].to_points();
|
||||||
let height = page.size[1].to_points();
|
let height = page.size[1].to_points();
|
||||||
|
|
||||||
let contents = (self.offsets.contents.0 ..= self.offsets.contents.1).collect();
|
self.writer.write_obj(id, Page::new(self.offsets.page_tree)
|
||||||
self.writer.write_obj(id, &Page {
|
.media_box(Rect::new(0.0, 0.0, width, height))
|
||||||
parent: self.offsets.page_tree,
|
.contents(self.offsets.contents.0 ..= self.offsets.contents.1)
|
||||||
data: PageData {
|
)?;
|
||||||
media_box: Some(Rect::new(0.0, 0.0, width, height)),
|
|
||||||
contents: Some(contents),
|
|
||||||
.. PageData::none()
|
|
||||||
},
|
|
||||||
})?;
|
|
||||||
|
|
||||||
id += 1;
|
id += 1;
|
||||||
}
|
}
|
||||||
@ -216,54 +193,50 @@ impl<'a, W: Write> PdfCreator<'a, W> {
|
|||||||
let base_font = font_data.name.post_script_name.as_ref()
|
let base_font = font_data.name.post_script_name.as_ref()
|
||||||
.unwrap_or(&self.doc.font);
|
.unwrap_or(&self.doc.font);
|
||||||
|
|
||||||
self.writer.write_obj(id, &Type0Font {
|
self.writer.write_obj(id, &Type0Font::new(
|
||||||
base_font: base_font.clone(),
|
base_font.clone(),
|
||||||
encoding: CMapEncoding::Predefined("Identity-H".to_owned()),
|
CMapEncoding::Predefined("Identity-H".to_owned()),
|
||||||
descendant_font: id + 1,
|
id + 1
|
||||||
to_unicode: None,
|
)).unwrap();
|
||||||
}).unwrap();
|
|
||||||
|
|
||||||
self.writer.write_obj(id + 1, &CIDFont {
|
self.writer.write_obj(id + 1,
|
||||||
subtype: CIDFontType::Type2,
|
CIDFont::new(
|
||||||
base_font: base_font.clone(),
|
CIDFontType::Type2,
|
||||||
cid_system_info: CIDSystemInfo {
|
base_font.clone(),
|
||||||
registry: "(Adobe)".to_owned(),
|
CIDSystemInfo::new("(Adobe)", "(Identity)", 0),
|
||||||
ordering: "(Identity)".to_owned(),
|
id + 2,
|
||||||
supplement: 0,
|
).widths(vec![
|
||||||
},
|
WidthRecord::start(0, font_data.hmtx.metrics.iter().map(|m| convert(m.advance_width))
|
||||||
font_descriptor: id + 2,
|
)])
|
||||||
widths: Some(vec![WidthRecord::Start(0,
|
).unwrap();
|
||||||
font_data.hmtx.metrics.iter()
|
|
||||||
.map(|m| convert(m.advance_width))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
)]),
|
|
||||||
cid_to_gid_map: Some(CMapEncoding::Predefined("Identity".to_owned())),
|
|
||||||
}).unwrap();
|
|
||||||
|
|
||||||
self.writer.write_obj(id + 2, &FontDescriptor {
|
let mut flags = FontFlags::empty();
|
||||||
font_name: base_font.clone(),
|
flags.set(FontFlags::FIXED_PITCH, font_data.post.is_fixed_pitch);
|
||||||
flags: flags!(
|
flags.set(FontFlags::SERIF, base_font.contains("Serif"));
|
||||||
1 => font_data.post.is_fixed_pitch,
|
flags.insert(FontFlags::SYMBOLIC);
|
||||||
2 => base_font.contains("Serif"),
|
flags.set(FontFlags::ITALIC, (font_data.head.mac_style & 1) != 0);
|
||||||
3 => true, 4 => false, 6 => false,
|
flags.insert(FontFlags::SMALL_CAP);
|
||||||
7 => (font_data.head.mac_style & 1) != 0,
|
|
||||||
17 => false, 18 => true, 19 => false,
|
self.writer.write_obj(id + 2,
|
||||||
),
|
FontDescriptor::new(
|
||||||
found_bbox: Rect::new(
|
base_font.clone(),
|
||||||
|
flags,
|
||||||
|
font_data.post.italic_angle.to_f32(),
|
||||||
|
)
|
||||||
|
.font_bbox(Rect::new(
|
||||||
convert(font_data.head.x_min),
|
convert(font_data.head.x_min),
|
||||||
convert(font_data.head.y_min),
|
convert(font_data.head.y_min),
|
||||||
convert(font_data.head.x_max),
|
convert(font_data.head.x_max),
|
||||||
convert(font_data.head.y_max)
|
convert(font_data.head.y_max)
|
||||||
),
|
))
|
||||||
italic_angle: font_data.post.italic_angle.to_f32(),
|
.ascent(convert(font_data.os2.s_typo_ascender))
|
||||||
ascent: convert(font_data.os2.s_typo_ascender),
|
.descent(convert(font_data.os2.s_typo_descender))
|
||||||
descent: convert(font_data.os2.s_typo_descender),
|
.cap_height(convert(font_data.os2.s_cap_height
|
||||||
cap_height: convert(font_data.os2.s_cap_height
|
.unwrap_or(font_data.os2.s_typo_ascender)))
|
||||||
.unwrap_or(font_data.os2.s_typo_ascender)),
|
.stem_v((10.0 + 220.0 * (font_data.os2.us_weight_class as f32
|
||||||
stem_v: (10.0 + 220.0 *
|
- 50.0) / 900.0) as GlyphUnit)
|
||||||
(font_data.os2.us_weight_class as f32 - 50.0) / 900.0) as GlyphUnit,
|
.font_file_3(id + 3)
|
||||||
font_file_3: Some(id + 3),
|
).unwrap();
|
||||||
}).unwrap();
|
|
||||||
|
|
||||||
self.writer.write_obj(id + 3, &EmbeddedFont::OpenType(&font_data.data)).unwrap();
|
self.writer.write_obj(id + 3, &EmbeddedFont::OpenType(&font_data.data)).unwrap();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user