Extract typst-pdf
crate
This commit is contained in:
parent
80b4ca4c04
commit
46846a337e
35
Cargo.lock
generated
35
Cargo.lock
generated
@ -2892,22 +2892,17 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
name = "typst"
|
||||
version = "0.9.0"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bitflags 2.4.1",
|
||||
"bytemuck",
|
||||
"comemo",
|
||||
"ecow",
|
||||
"flate2",
|
||||
"fontdb",
|
||||
"image",
|
||||
"indexmap 2.0.2",
|
||||
"kurbo",
|
||||
"lasso",
|
||||
"log",
|
||||
"miniz_oxide",
|
||||
"once_cell",
|
||||
"palette",
|
||||
"pdf-writer",
|
||||
"regex",
|
||||
"roxmltree",
|
||||
"rustybuzz",
|
||||
@ -2915,22 +2910,16 @@ dependencies = [
|
||||
"siphasher",
|
||||
"smallvec",
|
||||
"stacker",
|
||||
"subsetter",
|
||||
"svg2pdf",
|
||||
"time",
|
||||
"toml",
|
||||
"tracing",
|
||||
"ttf-parser",
|
||||
"typst-macros",
|
||||
"typst-syntax",
|
||||
"unicode-ident",
|
||||
"unicode-math-class",
|
||||
"unicode-properties",
|
||||
"unicode-segmentation",
|
||||
"unscanny",
|
||||
"usvg",
|
||||
"wasmi",
|
||||
"xmp-writer",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2971,6 +2960,7 @@ dependencies = [
|
||||
"tracing-subscriber",
|
||||
"typst",
|
||||
"typst-library",
|
||||
"typst-pdf",
|
||||
"typst-render",
|
||||
"typst-svg",
|
||||
"ureq",
|
||||
@ -3062,6 +3052,28 @@ dependencies = [
|
||||
"syn 2.0.38",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typst-pdf"
|
||||
version = "0.9.0"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bytemuck",
|
||||
"comemo",
|
||||
"ecow",
|
||||
"image",
|
||||
"miniz_oxide",
|
||||
"once_cell",
|
||||
"pdf-writer",
|
||||
"subsetter",
|
||||
"svg2pdf",
|
||||
"tracing",
|
||||
"ttf-parser",
|
||||
"typst",
|
||||
"unicode-properties",
|
||||
"unscanny",
|
||||
"xmp-writer",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typst-render"
|
||||
version = "0.9.0"
|
||||
@ -3124,6 +3136,7 @@ dependencies = [
|
||||
"ttf-parser",
|
||||
"typst",
|
||||
"typst-library",
|
||||
"typst-pdf",
|
||||
"typst-render",
|
||||
"typst-svg",
|
||||
"unscanny",
|
||||
|
@ -17,8 +17,12 @@ keywords = ["typst"]
|
||||
|
||||
[workspace.dependencies]
|
||||
typst = { path = "crates/typst" }
|
||||
typst-cli = { path = "crates/typst-cli" }
|
||||
typst-docs = { path = "crates/typst-docs" }
|
||||
typst-ide = { path = "crates/typst-ide" }
|
||||
typst-library = { path = "crates/typst-library" }
|
||||
typst-macros = { path = "crates/typst-macros" }
|
||||
typst-pdf = { path = "crates/typst-pdf" }
|
||||
typst-render = { path = "crates/typst-render" }
|
||||
typst-svg = { path = "crates/typst-svg" }
|
||||
typst-syntax = { path = "crates/typst-syntax" }
|
||||
@ -86,6 +90,7 @@ serde_json = "1"
|
||||
serde_yaml = "0.9"
|
||||
siphasher = "0.3"
|
||||
smallvec = { version = "1.11.1", features = ["union", "const_generics", "const_new"] }
|
||||
stacker = "0.1.15"
|
||||
subsetter = "0.1.1"
|
||||
svg2pdf = "0.9"
|
||||
syn = { version = "2", features = ["full", "extra-traits"] }
|
||||
|
@ -22,6 +22,7 @@ doc = false
|
||||
[dependencies]
|
||||
typst = { workspace = true }
|
||||
typst-library = { workspace = true }
|
||||
typst-pdf = { workspace = true }
|
||||
typst-render = { workspace = true }
|
||||
typst-svg = { workspace = true }
|
||||
chrono = { workspace = true }
|
||||
|
@ -153,7 +153,7 @@ fn export_pdf(
|
||||
world: &SystemWorld,
|
||||
) -> StrResult<()> {
|
||||
let ident = world.input().to_string_lossy();
|
||||
let buffer = typst::export::pdf(document, Some(&ident), now());
|
||||
let buffer = typst_pdf::pdf(document, Some(&ident), now());
|
||||
let output = command.output();
|
||||
fs::write(output, buffer)
|
||||
.map_err(|err| eco_format!("failed to write PDF file ({err})"))?;
|
||||
|
@ -2,7 +2,7 @@ use std::str::FromStr;
|
||||
|
||||
use chinese_number::{ChineseCase, ChineseCountMethod, ChineseVariant, NumberToChinese};
|
||||
use ecow::EcoVec;
|
||||
use typst::export::{PdfPageLabel, PdfPageLabelStyle};
|
||||
use typst::doc::{PdfPageLabel, PdfPageLabelStyle};
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::text::Case;
|
||||
|
34
crates/typst-pdf/Cargo.toml
Normal file
34
crates/typst-pdf/Cargo.toml
Normal file
@ -0,0 +1,34 @@
|
||||
[package]
|
||||
name = "typst-pdf"
|
||||
description = "PDF exporter for Typst."
|
||||
version.workspace = true
|
||||
rust-version.workspace = true
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
license.workspace = true
|
||||
categories.workspace = true
|
||||
keywords.workspace = true
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
typst = { workspace = true }
|
||||
base64 = { workspace = true }
|
||||
bytemuck = { workspace = true }
|
||||
comemo = { workspace = true }
|
||||
ecow = { workspace = true}
|
||||
image = { workspace = true }
|
||||
miniz_oxide = { workspace = true }
|
||||
once_cell = { workspace = true }
|
||||
pdf-writer = { workspace = true }
|
||||
subsetter = { workspace = true }
|
||||
svg2pdf = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
ttf-parser = { workspace = true }
|
||||
unicode-properties = { workspace = true }
|
||||
unscanny = { workspace = true }
|
||||
xmp-writer = { workspace = true }
|
@ -1,10 +1,10 @@
|
||||
use once_cell::sync::Lazy;
|
||||
use pdf_writer::types::DeviceNSubtype;
|
||||
use pdf_writer::{writers, Chunk, Dict, Filter, Name, Ref};
|
||||
use typst::geom::{Color, ColorSpace, Paint};
|
||||
|
||||
use super::page::{PageContext, Transforms};
|
||||
use crate::export::pdf::deflate;
|
||||
use crate::geom::{Color, ColorSpace, Paint};
|
||||
use crate::deflate;
|
||||
use crate::page::{PageContext, Transforms};
|
||||
|
||||
// The names of the color spaces.
|
||||
pub const SRGB: Name<'static> = Name(b"srgb");
|
@ -5,11 +5,11 @@ use ecow::{eco_format, EcoString};
|
||||
use pdf_writer::types::{CidFontType, FontFlags, SystemInfo, UnicodeCmap};
|
||||
use pdf_writer::{Filter, Finish, Name, Rect, Str};
|
||||
use ttf_parser::{name_id, GlyphId, Tag};
|
||||
use typst::font::Font;
|
||||
use typst::util::SliceExt;
|
||||
use unicode_properties::{GeneralCategory, UnicodeGeneralCategory};
|
||||
|
||||
use super::{deflate, EmExt, PdfContext};
|
||||
use crate::font::Font;
|
||||
use crate::util::SliceExt;
|
||||
use crate::{deflate, EmExt, PdfContext};
|
||||
|
||||
const CFF: Tag = Tag::from_bytes(b"CFF ");
|
||||
const CFF2: Tag = Tag::from_bytes(b"CFF2");
|
||||
@ -187,7 +187,7 @@ fn subset_font(font: &Font, glyphs: &[u16]) -> Arc<Vec<u8>> {
|
||||
fn subset_tag(glyphs: &BTreeMap<u16, EcoString>) -> EcoString {
|
||||
const LEN: usize = 6;
|
||||
const BASE: u128 = 26;
|
||||
let mut hash = crate::util::hash128(&glyphs);
|
||||
let mut hash = typst::util::hash128(&glyphs);
|
||||
let mut letter = [b'A'; LEN];
|
||||
for l in letter.iter_mut() {
|
||||
*l = b'A' + (hash % BASE) as u8;
|
@ -6,16 +6,15 @@ use pdf_writer::types::FunctionShadingType;
|
||||
use pdf_writer::writers::StreamShadingType;
|
||||
use pdf_writer::{types::ColorSpaceOperand, Name};
|
||||
use pdf_writer::{Filter, Finish, Ref};
|
||||
|
||||
use super::color::{ColorSpaceExt, PaintEncode, QuantizedColor};
|
||||
use super::page::{PageContext, Transforms};
|
||||
use super::{AbsExt, PdfContext};
|
||||
use crate::export::pdf::deflate;
|
||||
use crate::geom::{
|
||||
use typst::geom::{
|
||||
Abs, Angle, Color, ColorSpace, ConicGradient, Gradient, Numeric, Point, Quadrant,
|
||||
Ratio, Relative, Transform, WeightedColor,
|
||||
};
|
||||
|
||||
use crate::color::{ColorSpaceExt, PaintEncode, QuantizedColor};
|
||||
use crate::page::{PageContext, Transforms};
|
||||
use crate::{deflate, AbsExt, PdfContext};
|
||||
|
||||
/// A unique-transform-aspect-ratio combination that will be encoded into the
|
||||
/// PDF.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
@ -4,10 +4,10 @@ use std::sync::Arc;
|
||||
|
||||
use image::{DynamicImage, GenericImageView, Rgba};
|
||||
use pdf_writer::{Chunk, Filter, Finish, Ref};
|
||||
use typst::geom::ColorSpace;
|
||||
use typst::image::{ImageKind, RasterFormat, RasterImage, SvgImage};
|
||||
|
||||
use super::{deflate, PdfContext};
|
||||
use crate::geom::ColorSpace;
|
||||
use crate::image::{ImageKind, RasterFormat, RasterImage, SvgImage};
|
||||
use crate::{deflate, PdfContext};
|
||||
|
||||
/// Embed all used images into the PDF.
|
||||
#[tracing::instrument(skip_all)]
|
@ -8,31 +8,26 @@ mod image;
|
||||
mod outline;
|
||||
mod page;
|
||||
|
||||
pub use self::color::{ColorEncode, ColorSpaces};
|
||||
pub use self::page::{PdfPageLabel, PdfPageLabelStyle};
|
||||
|
||||
use std::cmp::Eq;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::hash::Hash;
|
||||
use std::num::NonZeroUsize;
|
||||
|
||||
use base64::Engine;
|
||||
use ecow::{eco_format, EcoString};
|
||||
use pdf_writer::types::Direction;
|
||||
use pdf_writer::writers::PageLabel;
|
||||
use pdf_writer::{Finish, Name, Pdf, Ref, TextStr};
|
||||
use typst::doc::{Document, Lang};
|
||||
use typst::eval::Datetime;
|
||||
use typst::font::Font;
|
||||
use typst::geom::{Abs, Dir, Em};
|
||||
use typst::image::Image;
|
||||
use typst::model::Introspector;
|
||||
use xmp_writer::{DateTime, LangId, RenditionClass, Timezone, XmpWriter};
|
||||
|
||||
use self::gradient::PdfGradient;
|
||||
use self::page::Page;
|
||||
use crate::doc::{Document, Lang};
|
||||
use crate::eval::Datetime;
|
||||
use crate::font::Font;
|
||||
use crate::geom::{Abs, Dir, Em};
|
||||
use crate::image::Image;
|
||||
use crate::model::Introspector;
|
||||
|
||||
use extg::ExtGState;
|
||||
use crate::color::ColorSpaces;
|
||||
use crate::extg::ExtGState;
|
||||
use crate::gradient::PdfGradient;
|
||||
use crate::page::Page;
|
||||
|
||||
/// Export a document into a PDF file.
|
||||
///
|
||||
@ -161,7 +156,7 @@ fn write_catalog(ctx: &mut PdfContext, ident: Option<&str>, timestamp: Option<Da
|
||||
let outline_root_id = outline::write_outline(ctx);
|
||||
|
||||
// Write the page labels.
|
||||
let page_labels = write_page_labels(ctx);
|
||||
let page_labels = page::write_page_labels(ctx);
|
||||
|
||||
// Write the document information.
|
||||
let mut info = ctx.pdf.document_info(ctx.alloc.bump());
|
||||
@ -256,55 +251,6 @@ fn write_catalog(ctx: &mut PdfContext, ident: Option<&str>, timestamp: Option<Da
|
||||
}
|
||||
}
|
||||
|
||||
/// Write the page labels.
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn write_page_labels(ctx: &mut PdfContext) -> Vec<(NonZeroUsize, Ref)> {
|
||||
let mut result = vec![];
|
||||
let mut prev: Option<&PdfPageLabel> = None;
|
||||
|
||||
for (i, page) in ctx.pages.iter().enumerate() {
|
||||
let nr = NonZeroUsize::new(1 + i).unwrap();
|
||||
let Some(label) = &page.label else { continue };
|
||||
|
||||
// Don't create a label if neither style nor prefix are specified.
|
||||
if label.prefix.is_none() && label.style.is_none() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(pre) = prev {
|
||||
if label.prefix == pre.prefix
|
||||
&& label.style == pre.style
|
||||
&& label.offset == pre.offset.map(|n| n.saturating_add(1))
|
||||
{
|
||||
prev = Some(label);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let id = ctx.alloc.bump();
|
||||
let mut entry = ctx.pdf.indirect(id).start::<PageLabel>();
|
||||
|
||||
// Only add what is actually provided. Don't add empty prefix string if
|
||||
// it wasn't given for example.
|
||||
if let Some(prefix) = &label.prefix {
|
||||
entry.prefix(TextStr(prefix));
|
||||
}
|
||||
|
||||
if let Some(style) = label.style {
|
||||
entry.style(style.into());
|
||||
}
|
||||
|
||||
if let Some(offset) = label.offset {
|
||||
entry.offset(offset.get() as i32);
|
||||
}
|
||||
|
||||
result.push((nr, id));
|
||||
prev = Some(label);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Compress data with the DEFLATE algorithm.
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn deflate(data: &[u8]) -> Vec<u8> {
|
||||
@ -315,7 +261,7 @@ fn deflate(data: &[u8]) -> Vec<u8> {
|
||||
/// Create a base64-encoded hash of the value.
|
||||
fn hash_base64<T: Hash>(value: &T) -> String {
|
||||
base64::engine::general_purpose::STANDARD
|
||||
.encode(crate::util::hash128(value).to_be_bytes())
|
||||
.encode(typst::util::hash128(value).to_be_bytes())
|
||||
}
|
||||
|
||||
/// Converts a datetime to a pdf-writer date.
|
@ -1,10 +1,11 @@
|
||||
use std::num::NonZeroUsize;
|
||||
|
||||
use pdf_writer::{Finish, Ref, TextStr};
|
||||
use typst::eval::item;
|
||||
use typst::geom::{Abs, Smart};
|
||||
use typst::model::Content;
|
||||
|
||||
use super::{AbsExt, PdfContext};
|
||||
use crate::geom::{Abs, Smart};
|
||||
use crate::model::Content;
|
||||
use crate::{AbsExt, PdfContext};
|
||||
|
||||
/// Construct the outline for the document.
|
||||
#[tracing::instrument(skip_all)]
|
@ -1,24 +1,27 @@
|
||||
use std::num::NonZeroUsize;
|
||||
use std::sync::Arc;
|
||||
|
||||
use ecow::{eco_format, EcoString};
|
||||
use ecow::eco_format;
|
||||
use pdf_writer::types::{
|
||||
ActionType, AnnotationType, ColorSpaceOperand, LineCapStyle, LineJoinStyle,
|
||||
NumberingStyle,
|
||||
};
|
||||
use pdf_writer::{Content, Filter, Finish, Name, Rect, Ref, Str};
|
||||
|
||||
use super::color::PaintEncode;
|
||||
use super::extg::ExtGState;
|
||||
use super::{deflate, AbsExt, EmExt, PdfContext};
|
||||
use crate::doc::{Destination, Frame, FrameItem, GroupItem, Meta, TextItem};
|
||||
use crate::eval::Repr;
|
||||
use crate::font::Font;
|
||||
use crate::geom::{
|
||||
use pdf_writer::writers::PageLabel;
|
||||
use pdf_writer::{Content, Filter, Finish, Name, Rect, Ref, Str, TextStr};
|
||||
use typst::doc::{
|
||||
Destination, Frame, FrameItem, GroupItem, Meta, PdfPageLabel, PdfPageLabelStyle,
|
||||
TextItem,
|
||||
};
|
||||
use typst::font::Font;
|
||||
use typst::geom::{
|
||||
self, Abs, Em, FixedStroke, Geometry, LineCap, LineJoin, Numeric, Paint, Point,
|
||||
Ratio, Shape, Size, Transform,
|
||||
};
|
||||
use crate::image::Image;
|
||||
use typst::image::Image;
|
||||
|
||||
use crate::color::PaintEncode;
|
||||
use crate::extg::ExtGState;
|
||||
use crate::{deflate, AbsExt, EmExt, PdfContext};
|
||||
|
||||
/// Construct page objects.
|
||||
#[tracing::instrument(skip_all)]
|
||||
@ -189,6 +192,55 @@ fn write_page(ctx: &mut PdfContext, i: usize) {
|
||||
ctx.pdf.stream(content_id, &data).filter(Filter::FlateDecode);
|
||||
}
|
||||
|
||||
/// Write the page labels.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn write_page_labels(ctx: &mut PdfContext) -> Vec<(NonZeroUsize, Ref)> {
|
||||
let mut result = vec![];
|
||||
let mut prev: Option<&PdfPageLabel> = None;
|
||||
|
||||
for (i, page) in ctx.pages.iter().enumerate() {
|
||||
let nr = NonZeroUsize::new(1 + i).unwrap();
|
||||
let Some(label) = &page.label else { continue };
|
||||
|
||||
// Don't create a label if neither style nor prefix are specified.
|
||||
if label.prefix.is_none() && label.style.is_none() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(pre) = prev {
|
||||
if label.prefix == pre.prefix
|
||||
&& label.style == pre.style
|
||||
&& label.offset == pre.offset.map(|n| n.saturating_add(1))
|
||||
{
|
||||
prev = Some(label);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let id = ctx.alloc.bump();
|
||||
let mut entry = ctx.pdf.indirect(id).start::<PageLabel>();
|
||||
|
||||
// Only add what is actually provided. Don't add empty prefix string if
|
||||
// it wasn't given for example.
|
||||
if let Some(prefix) = &label.prefix {
|
||||
entry.prefix(TextStr(prefix));
|
||||
}
|
||||
|
||||
if let Some(style) = label.style {
|
||||
entry.style(to_pdf_numbering_style(style));
|
||||
}
|
||||
|
||||
if let Some(offset) = label.offset {
|
||||
entry.offset(offset.get() as i32);
|
||||
}
|
||||
|
||||
result.push((nr, id));
|
||||
prev = Some(label);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Memoized version of [`deflate`] specialized for a page's content stream.
|
||||
#[comemo::memoize]
|
||||
fn deflate_content(content: &[u8]) -> Arc<Vec<u8>> {
|
||||
@ -401,10 +453,10 @@ impl PageContext<'_, '_> {
|
||||
|
||||
self.content.set_line_width(thickness.to_f32());
|
||||
if self.state.stroke.as_ref().map(|s| &s.line_cap) != Some(line_cap) {
|
||||
self.content.set_line_cap(line_cap.into());
|
||||
self.content.set_line_cap(to_pdf_line_cap(*line_cap));
|
||||
}
|
||||
if self.state.stroke.as_ref().map(|s| &s.line_join) != Some(line_join) {
|
||||
self.content.set_line_join(line_join.into());
|
||||
self.content.set_line_join(to_pdf_line_join(*line_join));
|
||||
}
|
||||
if self.state.stroke.as_ref().map(|s| &s.dash_pattern) != Some(dash_pattern) {
|
||||
if let Some(pattern) = dash_pattern {
|
||||
@ -680,73 +732,28 @@ fn write_link(ctx: &mut PageContext, pos: Point, dest: &Destination, size: Size)
|
||||
ctx.links.push((dest.clone(), rect));
|
||||
}
|
||||
|
||||
impl From<&LineCap> for LineCapStyle {
|
||||
fn from(line_cap: &LineCap) -> Self {
|
||||
match line_cap {
|
||||
LineCap::Butt => LineCapStyle::ButtCap,
|
||||
LineCap::Round => LineCapStyle::RoundCap,
|
||||
LineCap::Square => LineCapStyle::ProjectingSquareCap,
|
||||
}
|
||||
fn to_pdf_line_cap(cap: LineCap) -> LineCapStyle {
|
||||
match cap {
|
||||
LineCap::Butt => LineCapStyle::ButtCap,
|
||||
LineCap::Round => LineCapStyle::RoundCap,
|
||||
LineCap::Square => LineCapStyle::ProjectingSquareCap,
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&LineJoin> for LineJoinStyle {
|
||||
fn from(line_join: &LineJoin) -> Self {
|
||||
match line_join {
|
||||
LineJoin::Miter => LineJoinStyle::MiterJoin,
|
||||
LineJoin::Round => LineJoinStyle::RoundJoin,
|
||||
LineJoin::Bevel => LineJoinStyle::BevelJoin,
|
||||
}
|
||||
fn to_pdf_line_join(join: LineJoin) -> LineJoinStyle {
|
||||
match join {
|
||||
LineJoin::Miter => LineJoinStyle::MiterJoin,
|
||||
LineJoin::Round => LineJoinStyle::RoundJoin,
|
||||
LineJoin::Bevel => LineJoinStyle::BevelJoin,
|
||||
}
|
||||
}
|
||||
|
||||
/// Specification for a PDF page label.
|
||||
#[derive(Debug, Clone, PartialEq, Hash, Default)]
|
||||
pub struct PdfPageLabel {
|
||||
/// Can be any string or none. Will always be prepended to the numbering style.
|
||||
pub prefix: Option<EcoString>,
|
||||
/// Based on the numbering pattern.
|
||||
///
|
||||
/// If `None` or numbering is a function, the field will be empty.
|
||||
pub style: Option<PdfPageLabelStyle>,
|
||||
/// Offset for the page label start.
|
||||
///
|
||||
/// Describes where to start counting from when setting a style.
|
||||
/// (Has to be greater or equal than 1)
|
||||
pub offset: Option<NonZeroUsize>,
|
||||
}
|
||||
|
||||
impl Repr for PdfPageLabel {
|
||||
fn repr(&self) -> EcoString {
|
||||
eco_format!("{self:?}")
|
||||
}
|
||||
}
|
||||
|
||||
/// A PDF page label number style.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum PdfPageLabelStyle {
|
||||
/// Decimal arabic numerals (1, 2, 3).
|
||||
Arabic,
|
||||
/// Lowercase roman numerals (i, ii, iii).
|
||||
LowerRoman,
|
||||
/// Uppercase roman numerals (I, II, III).
|
||||
UpperRoman,
|
||||
/// Lowercase letters (`a` to `z` for the first 26 pages,
|
||||
/// `aa` to `zz` and so on for the next).
|
||||
LowerAlpha,
|
||||
/// Uppercase letters (`A` to `Z` for the first 26 pages,
|
||||
/// `AA` to `ZZ` and so on for the next).
|
||||
UpperAlpha,
|
||||
}
|
||||
|
||||
impl From<PdfPageLabelStyle> for NumberingStyle {
|
||||
fn from(value: PdfPageLabelStyle) -> Self {
|
||||
match value {
|
||||
PdfPageLabelStyle::Arabic => Self::Arabic,
|
||||
PdfPageLabelStyle::LowerRoman => Self::LowerRoman,
|
||||
PdfPageLabelStyle::UpperRoman => Self::UpperRoman,
|
||||
PdfPageLabelStyle::LowerAlpha => Self::LowerAlpha,
|
||||
PdfPageLabelStyle::UpperAlpha => Self::UpperAlpha,
|
||||
}
|
||||
fn to_pdf_numbering_style(style: PdfPageLabelStyle) -> NumberingStyle {
|
||||
match style {
|
||||
PdfPageLabelStyle::Arabic => NumberingStyle::Arabic,
|
||||
PdfPageLabelStyle::LowerRoman => NumberingStyle::LowerRoman,
|
||||
PdfPageLabelStyle::UpperRoman => NumberingStyle::UpperRoman,
|
||||
PdfPageLabelStyle::LowerAlpha => NumberingStyle::LowerAlpha,
|
||||
PdfPageLabelStyle::UpperAlpha => NumberingStyle::UpperAlpha,
|
||||
}
|
||||
}
|
@ -18,42 +18,31 @@ bench = false
|
||||
[dependencies]
|
||||
typst-macros = { workspace = true }
|
||||
typst-syntax = { workspace = true }
|
||||
base64 = { workspace = true }
|
||||
bitflags = { workspace = true }
|
||||
bytemuck = { workspace = true }
|
||||
comemo = { workspace = true }
|
||||
ecow = { workspace = true}
|
||||
flate2 = { workspace = true }
|
||||
fontdb = { workspace = true }
|
||||
image = { workspace = true }
|
||||
indexmap = { workspace = true }
|
||||
kurbo = { workspace = true }
|
||||
lasso = { workspace = true }
|
||||
log = { workspace = true }
|
||||
miniz_oxide = { workspace = true }
|
||||
once_cell = { workspace = true }
|
||||
palette = { workspace = true }
|
||||
pdf-writer = { workspace = true }
|
||||
regex = { workspace = true }
|
||||
roxmltree = { workspace = true }
|
||||
rustybuzz = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
siphasher = { workspace = true }
|
||||
smallvec = { workspace = true }
|
||||
subsetter = { workspace = true }
|
||||
svg2pdf = { workspace = true }
|
||||
time = { workspace = true }
|
||||
toml = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
ttf-parser = { workspace = true }
|
||||
unicode-ident = { workspace = true }
|
||||
unicode-math-class = { workspace = true }
|
||||
unicode-properties = { workspace = true }
|
||||
unicode-segmentation = { workspace = true }
|
||||
unscanny = { workspace = true }
|
||||
usvg = { workspace = true }
|
||||
wasmi = { workspace = true }
|
||||
xmp-writer = { workspace = true }
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
stacker = "0.1.15"
|
||||
stacker = { workspace = true }
|
||||
|
@ -9,7 +9,6 @@ use std::sync::Arc;
|
||||
use ecow::{eco_format, EcoString};
|
||||
|
||||
use crate::eval::{cast, dict, ty, Datetime, Dict, Repr, Value};
|
||||
use crate::export::PdfPageLabel;
|
||||
use crate::font::Font;
|
||||
use crate::geom::{
|
||||
self, styled_rect, Abs, Axes, Color, Corners, Dir, Em, FixedAlign, FixedStroke,
|
||||
@ -835,6 +834,45 @@ impl From<Position> for Dict {
|
||||
}
|
||||
}
|
||||
|
||||
/// Specification for a PDF page label.
|
||||
#[derive(Debug, Clone, PartialEq, Hash, Default)]
|
||||
pub struct PdfPageLabel {
|
||||
/// Can be any string or none. Will always be prepended to the numbering style.
|
||||
pub prefix: Option<EcoString>,
|
||||
/// Based on the numbering pattern.
|
||||
///
|
||||
/// If `None` or numbering is a function, the field will be empty.
|
||||
pub style: Option<PdfPageLabelStyle>,
|
||||
/// Offset for the page label start.
|
||||
///
|
||||
/// Describes where to start counting from when setting a style.
|
||||
/// (Has to be greater or equal than 1)
|
||||
pub offset: Option<NonZeroUsize>,
|
||||
}
|
||||
|
||||
impl Repr for PdfPageLabel {
|
||||
fn repr(&self) -> EcoString {
|
||||
eco_format!("{self:?}")
|
||||
}
|
||||
}
|
||||
|
||||
/// A PDF page label number style.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum PdfPageLabelStyle {
|
||||
/// Decimal arabic numerals (1, 2, 3).
|
||||
Arabic,
|
||||
/// Lowercase roman numerals (i, ii, iii).
|
||||
LowerRoman,
|
||||
/// Uppercase roman numerals (I, II, III).
|
||||
UpperRoman,
|
||||
/// Lowercase letters (`a` to `z` for the first 26 pages,
|
||||
/// `aa` to `zz` and so on for the next).
|
||||
LowerAlpha,
|
||||
/// Uppercase letters (`A` to `Z` for the first 26 pages,
|
||||
/// `AA` to `ZZ` and so on for the next).
|
||||
UpperAlpha,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -167,8 +167,13 @@ pub fn set_lang_items(items: LangItems) {
|
||||
}
|
||||
|
||||
/// Access a lang item.
|
||||
macro_rules! item {
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! __item {
|
||||
($name:ident) => {
|
||||
$crate::eval::LANG_ITEMS.get().unwrap().$name
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(inline)]
|
||||
pub use crate::__item as item;
|
||||
|
@ -55,7 +55,7 @@ pub use self::fields::fields_on;
|
||||
pub use self::func::{
|
||||
func, CapturesVisitor, Func, NativeFunc, NativeFuncData, ParamInfo,
|
||||
};
|
||||
pub use self::library::{set_lang_items, LangItems, Library};
|
||||
pub use self::library::{item, set_lang_items, LangItems, Library};
|
||||
pub use self::methods::mutable_methods_on;
|
||||
pub use self::module::Module;
|
||||
pub use self::none::NoneValue;
|
||||
|
@ -6,6 +6,7 @@ use ecow::eco_format;
|
||||
|
||||
use super::{format_str, IntoValue, Regex, Repr, Value};
|
||||
use crate::diag::{bail, StrResult};
|
||||
use crate::eval::item;
|
||||
use crate::geom::{Align, Length, Numeric, Rel, Smart, Stroke};
|
||||
use Value::*;
|
||||
|
||||
|
@ -17,7 +17,7 @@ use super::{
|
||||
Version,
|
||||
};
|
||||
use crate::diag::StrResult;
|
||||
use crate::eval::Datetime;
|
||||
use crate::eval::{item, Datetime};
|
||||
use crate::geom::{Abs, Angle, Color, Em, Fr, Gradient, Length, Ratio, Rel};
|
||||
use crate::model::{Label, Styles};
|
||||
use crate::syntax::{ast, Span};
|
||||
|
@ -1,5 +0,0 @@
|
||||
//! Exporting into external formats.
|
||||
|
||||
mod pdf;
|
||||
|
||||
pub use self::pdf::{pdf, PdfPageLabel, PdfPageLabelStyle};
|
@ -1,4 +1,5 @@
|
||||
use super::*;
|
||||
use crate::eval::item;
|
||||
|
||||
/// Where to [align]($align) something along an axis.
|
||||
///
|
||||
|
@ -1,4 +1,5 @@
|
||||
use super::*;
|
||||
use crate::eval::item;
|
||||
|
||||
/// A length that is relative to the font size.
|
||||
///
|
||||
|
@ -43,7 +43,6 @@ pub mod util;
|
||||
pub mod eval;
|
||||
pub mod diag;
|
||||
pub mod doc;
|
||||
pub mod export;
|
||||
pub mod font;
|
||||
pub mod geom;
|
||||
pub mod image;
|
||||
|
@ -7,6 +7,7 @@ use super::{
|
||||
};
|
||||
use crate::diag::SourceResult;
|
||||
use crate::doc::Meta;
|
||||
use crate::eval::item;
|
||||
use crate::util::hash128;
|
||||
|
||||
/// Whether the target is affected by show rules in the given style chain.
|
||||
|
@ -8,8 +8,8 @@ use smallvec::SmallVec;
|
||||
use super::{Content, Element, Label, Locatable, Location};
|
||||
use crate::diag::{bail, StrResult};
|
||||
use crate::eval::{
|
||||
cast, func, scope, ty, CastInfo, Dict, FromValue, Func, Reflect, Regex, Repr, Str,
|
||||
Symbol, Type, Value,
|
||||
cast, func, item, scope, ty, CastInfo, Dict, FromValue, Func, Reflect, Regex, Repr,
|
||||
Str, Symbol, Type, Value,
|
||||
};
|
||||
use crate::util::pretty_array_like;
|
||||
|
||||
|
@ -9,6 +9,7 @@ publish = false
|
||||
[dev-dependencies]
|
||||
typst = { workspace = true }
|
||||
typst-library = { workspace = true }
|
||||
typst-pdf = { workspace = true }
|
||||
typst-render = { workspace = true }
|
||||
typst-svg = { workspace = true }
|
||||
clap = { workspace = true }
|
||||
|
@ -420,7 +420,7 @@ fn test(
|
||||
let document = Document { pages: frames, ..Default::default() };
|
||||
if compare_ever {
|
||||
if let Some(pdf_path) = pdf_path {
|
||||
let pdf_data = typst::export::pdf(
|
||||
let pdf_data = typst_pdf::pdf(
|
||||
&document,
|
||||
Some(&format!("typst-test: {}", name.display())),
|
||||
world.today(Some(0)),
|
||||
|
Loading…
x
Reference in New Issue
Block a user