mirror of
https://github.com/typst/typst
synced 2025-07-27 22:37:54 +08:00
Compare commits
13 Commits
5dcb1def0c
...
e4cdaadcfb
Author | SHA1 | Date | |
---|---|---|---|
|
e4cdaadcfb | ||
|
77c25aed74 | ||
|
e71057536b | ||
|
2f72a1f197 | ||
|
62eab1dc9f | ||
|
7791162455 | ||
|
24d68ba61c | ||
|
34d26dc64b | ||
|
62daf7d3ef | ||
|
d9fb17edb3 | ||
|
b790c6d59c | ||
|
b1c79b50d4 | ||
|
4629ede020 |
17
Cargo.lock
generated
17
Cargo.lock
generated
@ -967,7 +967,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "hayro"
|
name = "hayro"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/LaurenzV/hayro?rev=2b63dc8#2b63dc85b9447a815cc5b40c16338841c3780f7e"
|
source = "git+https://github.com/LaurenzV/hayro?rev=d651e18#d651e188a747c188db2e206733eaf17e8f622a5d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"hayro-interpret",
|
"hayro-interpret",
|
||||||
@ -980,7 +980,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "hayro-font"
|
name = "hayro-font"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/LaurenzV/hayro?rev=2b63dc8#2b63dc85b9447a815cc5b40c16338841c3780f7e"
|
source = "git+https://github.com/LaurenzV/hayro?rev=d651e18#d651e188a747c188db2e206733eaf17e8f622a5d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"phf",
|
"phf",
|
||||||
@ -989,7 +989,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "hayro-interpret"
|
name = "hayro-interpret"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/LaurenzV/hayro?rev=2b63dc8#2b63dc85b9447a815cc5b40c16338841c3780f7e"
|
source = "git+https://github.com/LaurenzV/hayro?rev=d651e18#d651e188a747c188db2e206733eaf17e8f622a5d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.1",
|
"bitflags 2.9.1",
|
||||||
"hayro-font",
|
"hayro-font",
|
||||||
@ -1006,7 +1006,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "hayro-syntax"
|
name = "hayro-syntax"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
source = "git+https://github.com/LaurenzV/hayro?rev=2b63dc8#2b63dc85b9447a815cc5b40c16338841c3780f7e"
|
source = "git+https://github.com/LaurenzV/hayro?rev=d651e18#d651e188a747c188db2e206733eaf17e8f622a5d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"flate2",
|
"flate2",
|
||||||
"kurbo",
|
"kurbo",
|
||||||
@ -1019,7 +1019,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "hayro-write"
|
name = "hayro-write"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/LaurenzV/hayro?rev=2b63dc8#2b63dc85b9447a815cc5b40c16338841c3780f7e"
|
source = "git+https://github.com/LaurenzV/hayro?rev=d651e18#d651e188a747c188db2e206733eaf17e8f622a5d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"flate2",
|
"flate2",
|
||||||
"hayro-syntax",
|
"hayro-syntax",
|
||||||
@ -1430,7 +1430,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "krilla"
|
name = "krilla"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "git+https://github.com/LaurenzV/krilla?rev=1668ac2#1668ac2e64dc85572e6c62a2399e85acd39b619d"
|
source = "git+https://github.com/LaurenzV/krilla/?rev=2da9d6c#2da9d6c6cb6a6baa6379592c72ae4eb7e16aa7b4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
@ -1460,7 +1460,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "krilla-svg"
|
name = "krilla-svg"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/LaurenzV/krilla?rev=1668ac2#1668ac2e64dc85572e6c62a2399e85acd39b619d"
|
source = "git+https://github.com/LaurenzV/krilla/?rev=2da9d6c#2da9d6c6cb6a6baa6379592c72ae4eb7e16aa7b4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"flate2",
|
"flate2",
|
||||||
"fontdb",
|
"fontdb",
|
||||||
@ -2926,6 +2926,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "typst-assets"
|
name = "typst-assets"
|
||||||
version = "0.13.1"
|
version = "0.13.1"
|
||||||
|
source = "git+https://github.com/LaurenzV/typst-assets?rev=d89cc82#d89cc821f84a5667714491019c0b64087b2608bd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typst-cli"
|
name = "typst-cli"
|
||||||
@ -2975,7 +2976,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "typst-dev-assets"
|
name = "typst-dev-assets"
|
||||||
version = "0.13.1"
|
version = "0.13.1"
|
||||||
source = "git+https://github.com/typst/typst-dev-assets?rev=bfa947f#bfa947f3433d7d13a995168c40ae788a2ebfe648"
|
source = "git+https://github.com/LaurenzV/typst-dev-assets?rev=180c145#180c145cf810c8b2a7ed77355b351f3aed07d0c6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typst-docs"
|
name = "typst-docs"
|
||||||
|
12
Cargo.toml
12
Cargo.toml
@ -32,8 +32,8 @@ typst-svg = { path = "crates/typst-svg", version = "0.13.1" }
|
|||||||
typst-syntax = { path = "crates/typst-syntax", version = "0.13.1" }
|
typst-syntax = { path = "crates/typst-syntax", version = "0.13.1" }
|
||||||
typst-timing = { path = "crates/typst-timing", version = "0.13.1" }
|
typst-timing = { path = "crates/typst-timing", version = "0.13.1" }
|
||||||
typst-utils = { path = "crates/typst-utils", version = "0.13.1" }
|
typst-utils = { path = "crates/typst-utils", version = "0.13.1" }
|
||||||
typst-assets = { path = "../typst-assets" }
|
typst-assets = { git = "https://github.com/LaurenzV/typst-assets", rev = "d89cc82" }
|
||||||
typst-dev-assets = { git = "https://github.com/typst/typst-dev-assets", rev = "bfa947f" }
|
typst-dev-assets = { git = "https://github.com/LaurenzV/typst-dev-assets", rev = "180c145" }
|
||||||
arrayvec = "0.7.4"
|
arrayvec = "0.7.4"
|
||||||
az = "1.2"
|
az = "1.2"
|
||||||
base64 = "0.22"
|
base64 = "0.22"
|
||||||
@ -61,8 +61,8 @@ fontdb = { version = "0.23", default-features = false }
|
|||||||
fs_extra = "1.3"
|
fs_extra = "1.3"
|
||||||
glidesort = "0.1.2"
|
glidesort = "0.1.2"
|
||||||
hayagriva = "0.8.1"
|
hayagriva = "0.8.1"
|
||||||
hayro-syntax = { git = "https://github.com/LaurenzV/hayro", rev = "2b63dc8" }
|
hayro-syntax = { git = "https://github.com/LaurenzV/hayro", rev = "d651e18" }
|
||||||
hayro = { git = "https://github.com/LaurenzV/hayro", rev = "2b63dc8" }
|
hayro = { git = "https://github.com/LaurenzV/hayro", rev = "d651e18" }
|
||||||
heck = "0.5"
|
heck = "0.5"
|
||||||
hypher = "0.1.4"
|
hypher = "0.1.4"
|
||||||
icu_properties = { version = "1.4", features = ["serde"] }
|
icu_properties = { version = "1.4", features = ["serde"] }
|
||||||
@ -75,8 +75,8 @@ image = { version = "0.25.5", default-features = false, features = ["png", "jpeg
|
|||||||
indexmap = { version = "2", features = ["serde"] }
|
indexmap = { version = "2", features = ["serde"] }
|
||||||
infer = { version = "0.19.0", default-features = false }
|
infer = { version = "0.19.0", default-features = false }
|
||||||
kamadak-exif = "0.6"
|
kamadak-exif = "0.6"
|
||||||
krilla = { git = "https://github.com/LaurenzV/krilla", rev = "1668ac2", default-features = false, features = ["raster-images", "comemo", "rayon", "pdf"] }
|
krilla = { git = "https://github.com/LaurenzV/krilla/", rev = "2da9d6c", default-features = false, features = ["raster-images", "comemo", "rayon", "pdf"] }
|
||||||
krilla-svg = { git = "https://github.com/LaurenzV/krilla", rev = "1668ac2" }
|
krilla-svg = { git = "https://github.com/LaurenzV/krilla/", rev = "2da9d6c"}
|
||||||
kurbo = "0.11"
|
kurbo = "0.11"
|
||||||
libfuzzer-sys = "0.4"
|
libfuzzer-sys = "0.4"
|
||||||
lipsum = "0.9"
|
lipsum = "0.9"
|
||||||
|
@ -174,7 +174,10 @@ typst help watch
|
|||||||
```
|
```
|
||||||
|
|
||||||
If you prefer an integrated IDE-like experience with autocompletion and instant
|
If you prefer an integrated IDE-like experience with autocompletion and instant
|
||||||
preview, you can also check out [Typst's free web app][app].
|
preview, you can also check out our [free web app][app]. Alternatively, there is
|
||||||
|
a community-created language server called
|
||||||
|
[Tinymist](https://myriad-dreamin.github.io/tinymist/) which is integrated into
|
||||||
|
various editor extensions.
|
||||||
|
|
||||||
## Community
|
## Community
|
||||||
The main places where the community gathers are our [Forum][forum] and our
|
The main places where the community gathers are our [Forum][forum] and our
|
||||||
|
@ -797,7 +797,9 @@ impl Color {
|
|||||||
components
|
components
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the constructor function for this color's space:
|
/// Returns the constructor function for this color's space.
|
||||||
|
///
|
||||||
|
/// Returns one of:
|
||||||
/// - [`luma`]($color.luma)
|
/// - [`luma`]($color.luma)
|
||||||
/// - [`oklab`]($color.oklab)
|
/// - [`oklab`]($color.oklab)
|
||||||
/// - [`oklch`]($color.oklch)
|
/// - [`oklch`]($color.oklch)
|
||||||
|
@ -15,6 +15,7 @@ use std::fmt::{self, Debug, Formatter};
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use ecow::EcoString;
|
use ecow::EcoString;
|
||||||
|
use hayro_syntax::LoadPdfError;
|
||||||
use typst_library::{Feature, World};
|
use typst_library::{Feature, World};
|
||||||
use typst_syntax::{Span, Spanned};
|
use typst_syntax::{Span, Spanned};
|
||||||
use typst_utils::LazyHash;
|
use typst_utils::LazyHash;
|
||||||
@ -272,9 +273,27 @@ impl Packed<ImageElem> {
|
|||||||
),
|
),
|
||||||
ImageFormat::Vector(VectorFormat::Pdf) => {
|
ImageFormat::Vector(VectorFormat::Pdf) => {
|
||||||
if engine.world.library().features.is_enabled(Feature::PdfEmbedding) {
|
if engine.world.library().features.is_enabled(Feature::PdfEmbedding) {
|
||||||
let document =
|
let document = match PdfDocument::new(loaded.data.clone()) {
|
||||||
PdfDocument::new(loaded.data.clone(), engine.world.clone())
|
Ok(doc) => doc,
|
||||||
.within(loaded)?;
|
Err(e) => match e {
|
||||||
|
LoadPdfError::Encryption => {
|
||||||
|
bail!(
|
||||||
|
span,
|
||||||
|
"the PDF is encrypted or password-protected";
|
||||||
|
hint: "such PDFs are currently not supported";
|
||||||
|
hint: "preprocess the PDF to remove the encryption"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
LoadPdfError::Invalid => {
|
||||||
|
bail!(
|
||||||
|
span,
|
||||||
|
"the PDF could not be loaded";
|
||||||
|
hint: "perhaps the PDF file is malformed"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
let page_num = self.page.get(styles);
|
let page_num = self.page.get(styles);
|
||||||
|
|
||||||
if page_num == 0 {
|
if page_num == 0 {
|
||||||
@ -285,16 +304,18 @@ impl Packed<ImageElem> {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
// The user provides the page number start from 1, further down the pipeline,
|
// The user provides the page number start from 1, but further down the pipeline,
|
||||||
// page numbers are 0-based.
|
// page numbers are 0-based.
|
||||||
let page_idx = page_num - 1;
|
let page_idx = page_num - 1;
|
||||||
let num_pages = document.len();
|
let num_pages = document.len();
|
||||||
|
|
||||||
let Some(pdf_image) = PdfImage::new(document, page_idx) else {
|
let Some(pdf_image) = PdfImage::new(document, page_idx) else {
|
||||||
|
let pages = if num_pages == 1 { "page" } else { "pages" };
|
||||||
|
|
||||||
bail!(
|
bail!(
|
||||||
span,
|
span,
|
||||||
"page {page_num} doesn't exist";
|
"page {page_num} doesn't exist";
|
||||||
hint: "the document only has {num_pages} pages"
|
hint: "the document only has {num_pages} {pages}"
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,13 +1,10 @@
|
|||||||
use crate::diag::LoadResult;
|
|
||||||
use crate::foundations::Bytes;
|
|
||||||
use crate::text::{FontStretch, FontStyle, FontVariant, FontWeight};
|
|
||||||
use crate::World;
|
|
||||||
use comemo::Tracked;
|
|
||||||
use hayro_syntax::page::Page;
|
|
||||||
use hayro_syntax::Pdf;
|
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use typst_library::text::FontInfo;
|
|
||||||
|
use hayro_syntax::page::Page;
|
||||||
|
use hayro_syntax::{LoadPdfError, Pdf};
|
||||||
|
|
||||||
|
use crate::foundations::Bytes;
|
||||||
|
|
||||||
struct DocumentRepr {
|
struct DocumentRepr {
|
||||||
pdf: Arc<Pdf>,
|
pdf: Arc<Pdf>,
|
||||||
@ -29,24 +26,24 @@ impl PdfDocument {
|
|||||||
/// Load a PDF document.
|
/// Load a PDF document.
|
||||||
#[comemo::memoize]
|
#[comemo::memoize]
|
||||||
#[typst_macros::time(name = "load pdf document")]
|
#[typst_macros::time(name = "load pdf document")]
|
||||||
pub fn new(data: Bytes, world: Tracked<dyn World + '_>) -> LoadResult<PdfDocument> {
|
pub fn new(data: Bytes) -> Result<PdfDocument, LoadPdfError> {
|
||||||
// TODO: Remove unwraps
|
let pdf = Arc::new(Pdf::new(Arc::new(data.clone()))?);
|
||||||
let pdf = Arc::new(Pdf::new(Arc::new(data.clone())).unwrap());
|
let standard_fonts = get_standard_fonts();
|
||||||
let standard_fonts = get_standard_fonts(world.clone());
|
|
||||||
|
|
||||||
Ok(Self(Arc::new(DocumentRepr { data, pdf, standard_fonts })))
|
Ok(Self(Arc::new(DocumentRepr { data, pdf, standard_fonts })))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the number of pages in the PDF.
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.0.pdf.pages().len()
|
self.0.pdf.pages().len()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ImageRepr {
|
struct ImageRepr {
|
||||||
pub document: PdfDocument,
|
document: PdfDocument,
|
||||||
pub page_index: usize,
|
page_index: usize,
|
||||||
pub width: f32,
|
width: f32,
|
||||||
pub height: f32,
|
height: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for ImageRepr {
|
impl Hash for ImageRepr {
|
||||||
@ -56,16 +53,16 @@ impl Hash for ImageRepr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A page of a PDF file.
|
/// A specific page of a PDF acting as an image.
|
||||||
#[derive(Clone, Hash)]
|
#[derive(Clone, Hash)]
|
||||||
pub struct PdfImage(Arc<ImageRepr>);
|
pub struct PdfImage(Arc<ImageRepr>);
|
||||||
|
|
||||||
impl PdfImage {
|
impl PdfImage {
|
||||||
/// Create a new PDF image. Returns `None` if the page index is not valid.
|
/// Create a new PDF image.
|
||||||
|
///
|
||||||
|
/// Returns `None` if the page index is not valid.
|
||||||
#[comemo::memoize]
|
#[comemo::memoize]
|
||||||
pub fn new(document: PdfDocument, page: usize) -> Option<PdfImage> {
|
pub fn new(document: PdfDocument, page: usize) -> Option<PdfImage> {
|
||||||
// TODO: Don't allow loading if pdf-embedding feature is disabled.
|
|
||||||
// TODO: Remove Unwrap
|
|
||||||
let dimensions = document.0.pdf.pages().get(page)?.render_dimensions();
|
let dimensions = document.0.pdf.pages().get(page)?.render_dimensions();
|
||||||
|
|
||||||
Some(Self(Arc::new(ImageRepr {
|
Some(Self(Arc::new(ImageRepr {
|
||||||
@ -76,110 +73,93 @@ impl PdfImage {
|
|||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the PDF page of the image.
|
||||||
pub fn page(&self) -> &Page {
|
pub fn page(&self) -> &Page {
|
||||||
&self.0.document.0.pdf.pages()[self.0.page_index]
|
&self.pdf().pages()[self.0.page_index]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the underlying PDF document.
|
||||||
pub fn pdf(&self) -> &Arc<Pdf> {
|
pub fn pdf(&self) -> &Arc<Pdf> {
|
||||||
&self.0.document.0.pdf
|
&self.0.document.0.pdf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the width of the image.
|
||||||
pub fn width(&self) -> f32 {
|
pub fn width(&self) -> f32 {
|
||||||
self.0.width
|
self.0.width
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the embedded standard fonts of the image.
|
||||||
pub fn standard_fonts(&self) -> &Arc<StandardFonts> {
|
pub fn standard_fonts(&self) -> &Arc<StandardFonts> {
|
||||||
&self.0.document.0.standard_fonts
|
&self.0.document.0.standard_fonts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the height of the image.
|
||||||
pub fn height(&self) -> f32 {
|
pub fn height(&self) -> f32 {
|
||||||
self.0.height
|
self.0.height
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn data(&self) -> &Bytes {
|
/// Returns the page index of the image.
|
||||||
&self.0.document.0.data
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn page_index(&self) -> usize {
|
pub fn page_index(&self) -> usize {
|
||||||
self.0.page_index
|
self.0.page_index
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the underlying Typst PDF document.
|
||||||
pub fn document(&self) -> &PdfDocument {
|
pub fn document(&self) -> &PdfDocument {
|
||||||
&self.0.document
|
&self.0.document
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[comemo::memoize]
|
#[comemo::memoize]
|
||||||
fn get_standard_fonts(world: Tracked<dyn World + '_>) -> Arc<StandardFonts> {
|
fn get_standard_fonts() -> Arc<StandardFonts> {
|
||||||
let book = world.book();
|
|
||||||
|
|
||||||
let get_font = |name: &str, fallback_name: Option<&str>, variant: FontVariant| {
|
|
||||||
book.select(name, variant)
|
|
||||||
.or_else(|| {
|
|
||||||
if let Some(fallback_name) = fallback_name {
|
|
||||||
book.select(fallback_name, variant)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.or_else(|| book.select_fallback(None, variant, "A"))
|
|
||||||
.and_then(|i| world.font(i))
|
|
||||||
.map(|font| (font.data().clone(), font.index()))
|
|
||||||
};
|
|
||||||
|
|
||||||
let normal_variant = FontVariant::new(
|
|
||||||
FontStyle::Normal,
|
|
||||||
FontWeight::default(),
|
|
||||||
FontStretch::default(),
|
|
||||||
);
|
|
||||||
let bold_variant =
|
|
||||||
FontVariant::new(FontStyle::Normal, FontWeight::BOLD, FontStretch::default());
|
|
||||||
let italic_variant = FontVariant::new(
|
|
||||||
FontStyle::Italic,
|
|
||||||
FontWeight::default(),
|
|
||||||
FontStretch::default(),
|
|
||||||
);
|
|
||||||
let bold_italic_variant =
|
|
||||||
FontVariant::new(FontStyle::Italic, FontWeight::BOLD, FontStretch::default());
|
|
||||||
|
|
||||||
let helvetica = VariantFont {
|
let helvetica = VariantFont {
|
||||||
normal: get_font("helvetica", Some("liberation sans"), normal_variant),
|
normal: Bytes::new(typst_assets::pdf::SANS),
|
||||||
bold: get_font("helvetica", Some("liberation sans"), bold_variant),
|
bold: Bytes::new(typst_assets::pdf::SANS_BOLD),
|
||||||
italic: get_font("helvetica", Some("liberation sans"), italic_variant),
|
italic: Bytes::new(typst_assets::pdf::SANS_ITALIC),
|
||||||
bold_italic: get_font("helvetica", Some("liberation sans"), bold_italic_variant),
|
bold_italic: Bytes::new(typst_assets::pdf::SANS_BOLD_ITALIC),
|
||||||
};
|
};
|
||||||
|
|
||||||
let courier = VariantFont {
|
let courier = VariantFont {
|
||||||
normal: get_font("courier", Some("liberation mono"), normal_variant),
|
normal: Bytes::new(typst_assets::pdf::FIXED),
|
||||||
bold: get_font("courier", Some("liberation mono"), bold_variant),
|
bold: Bytes::new(typst_assets::pdf::FIXED_BOLD),
|
||||||
italic: get_font("courier", Some("liberation mono"), italic_variant),
|
italic: Bytes::new(typst_assets::pdf::FIXED_ITALIC),
|
||||||
bold_italic: get_font("courier", Some("liberation mono"), bold_italic_variant),
|
bold_italic: Bytes::new(typst_assets::pdf::FIXED_BOLD_ITALIC),
|
||||||
};
|
};
|
||||||
|
|
||||||
let times = VariantFont {
|
let times = VariantFont {
|
||||||
normal: get_font("times", Some("liberation serif"), normal_variant),
|
normal: Bytes::new(typst_assets::pdf::SERIF),
|
||||||
bold: get_font("times", Some("liberation serif"), bold_variant),
|
bold: Bytes::new(typst_assets::pdf::SERIF_BOLD),
|
||||||
italic: get_font("times", Some("liberation serif"), italic_variant),
|
italic: Bytes::new(typst_assets::pdf::SERIF_ITALIC),
|
||||||
bold_italic: get_font("times", Some("liberation serif"), bold_italic_variant),
|
bold_italic: Bytes::new(typst_assets::pdf::SERIF_BOLD_ITALIC),
|
||||||
};
|
};
|
||||||
|
|
||||||
let symbol = Some(Bytes::new(typst_assets::pdf::SYMBOL));
|
let symbol = Bytes::new(typst_assets::pdf::SYMBOL);
|
||||||
let zapf_dingbats = Some(Bytes::new(typst_assets::pdf::DING_BATS));
|
let zapf_dingbats = Bytes::new(typst_assets::pdf::DING_BATS);
|
||||||
|
|
||||||
Arc::new(StandardFonts { helvetica, courier, times, symbol, zapf_dingbats })
|
Arc::new(StandardFonts { helvetica, courier, times, symbol, zapf_dingbats })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A PDF font with multiple variants.
|
||||||
pub struct VariantFont {
|
pub struct VariantFont {
|
||||||
pub normal: Option<(Bytes, u32)>,
|
/// The normal variant.
|
||||||
pub bold: Option<(Bytes, u32)>,
|
pub normal: Bytes,
|
||||||
pub italic: Option<(Bytes, u32)>,
|
/// The bold variant.
|
||||||
pub bold_italic: Option<(Bytes, u32)>,
|
pub bold: Bytes,
|
||||||
|
/// The italic variant.
|
||||||
|
pub italic: Bytes,
|
||||||
|
/// The bold-italic variant.
|
||||||
|
pub bold_italic: Bytes,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A structure holding the raw data of all PDF standard fonts.
|
||||||
pub struct StandardFonts {
|
pub struct StandardFonts {
|
||||||
|
/// The data for the `Helvetica` font family.
|
||||||
pub helvetica: VariantFont,
|
pub helvetica: VariantFont,
|
||||||
|
/// The data for the `Courier` font family.
|
||||||
pub courier: VariantFont,
|
pub courier: VariantFont,
|
||||||
|
/// The data for the `Times` font family.
|
||||||
pub times: VariantFont,
|
pub times: VariantFont,
|
||||||
pub symbol: Option<Bytes>,
|
/// The data for the `Symbol` font family.
|
||||||
pub zapf_dingbats: Option<Bytes>,
|
pub symbol: Bytes,
|
||||||
|
/// The data for the `Zapf Dingbats` font family.
|
||||||
|
pub zapf_dingbats: Bytes,
|
||||||
}
|
}
|
||||||
|
@ -124,15 +124,13 @@ fn build_pdf_texture(pdf: &PdfImage, w: u32, h: u32) -> Option<sk::Pixmap> {
|
|||||||
StandardFont::TimesBold => sf.times.bold.clone(),
|
StandardFont::TimesBold => sf.times.bold.clone(),
|
||||||
StandardFont::TimesItalic => sf.times.italic.clone(),
|
StandardFont::TimesItalic => sf.times.italic.clone(),
|
||||||
StandardFont::TimesBoldItalic => sf.times.bold_italic.clone(),
|
StandardFont::TimesBoldItalic => sf.times.bold_italic.clone(),
|
||||||
StandardFont::ZapfDingBats => sf.zapf_dingbats.clone().map(|d| (d, 0)),
|
StandardFont::ZapfDingBats => sf.zapf_dingbats.clone(),
|
||||||
StandardFont::Symbol => sf.symbol.clone().map(|d| (d, 0)),
|
StandardFont::Symbol => sf.symbol.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
bytes.map(|d| {
|
let font_data: Arc<dyn AsRef<[u8]> + Send + Sync> = Arc::new(bytes.clone());
|
||||||
let font_data: Arc<dyn AsRef<[u8]> + Send + Sync> = Arc::new(d.0.clone());
|
|
||||||
|
|
||||||
(font_data, d.1)
|
Some((font_data, 0))
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let interpreter_settings = InterpreterSettings {
|
let interpreter_settings = InterpreterSettings {
|
||||||
|
@ -116,15 +116,13 @@ fn pdf_to_png(pdf: &PdfImage, w: u32, h: u32) -> Vec<u8> {
|
|||||||
StandardFont::TimesBold => sf.times.bold.clone(),
|
StandardFont::TimesBold => sf.times.bold.clone(),
|
||||||
StandardFont::TimesItalic => sf.times.italic.clone(),
|
StandardFont::TimesItalic => sf.times.italic.clone(),
|
||||||
StandardFont::TimesBoldItalic => sf.times.bold_italic.clone(),
|
StandardFont::TimesBoldItalic => sf.times.bold_italic.clone(),
|
||||||
StandardFont::ZapfDingBats => sf.zapf_dingbats.clone().map(|d| (d, 0)),
|
StandardFont::ZapfDingBats => sf.zapf_dingbats.clone(),
|
||||||
StandardFont::Symbol => sf.symbol.clone().map(|d| (d, 0)),
|
StandardFont::Symbol => sf.symbol.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
bytes.map(|d| {
|
let font_data: Arc<dyn AsRef<[u8]> + Send + Sync> = Arc::new(bytes.clone());
|
||||||
let font_data: Arc<dyn AsRef<[u8]> + Send + Sync> = Arc::new(d.0.clone());
|
|
||||||
|
|
||||||
(font_data, d.1)
|
Some((font_data, 0))
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let interpreter_settings = InterpreterSettings {
|
let interpreter_settings = InterpreterSettings {
|
||||||
|
@ -242,7 +242,7 @@ fn category_page(resolver: &dyn Resolver, category: Category) -> PageModel {
|
|||||||
items.push(CategoryItem {
|
items.push(CategoryItem {
|
||||||
name: group.name.clone(),
|
name: group.name.clone(),
|
||||||
route: subpage.route.clone(),
|
route: subpage.route.clone(),
|
||||||
oneliner: oneliner(docs).into(),
|
oneliner: oneliner(docs),
|
||||||
code: true,
|
code: true,
|
||||||
});
|
});
|
||||||
children.push(subpage);
|
children.push(subpage);
|
||||||
@ -296,7 +296,7 @@ fn category_page(resolver: &dyn Resolver, category: Category) -> PageModel {
|
|||||||
items.push(CategoryItem {
|
items.push(CategoryItem {
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
route: subpage.route.clone(),
|
route: subpage.route.clone(),
|
||||||
oneliner: oneliner(func.docs().unwrap_or_default()).into(),
|
oneliner: oneliner(func.docs().unwrap_or_default()),
|
||||||
code: true,
|
code: true,
|
||||||
});
|
});
|
||||||
children.push(subpage);
|
children.push(subpage);
|
||||||
@ -306,7 +306,7 @@ fn category_page(resolver: &dyn Resolver, category: Category) -> PageModel {
|
|||||||
items.push(CategoryItem {
|
items.push(CategoryItem {
|
||||||
name: ty.short_name().into(),
|
name: ty.short_name().into(),
|
||||||
route: subpage.route.clone(),
|
route: subpage.route.clone(),
|
||||||
oneliner: oneliner(ty.docs()).into(),
|
oneliner: oneliner(ty.docs()),
|
||||||
code: true,
|
code: true,
|
||||||
});
|
});
|
||||||
children.push(subpage);
|
children.push(subpage);
|
||||||
@ -637,7 +637,7 @@ fn group_page(
|
|||||||
let item = CategoryItem {
|
let item = CategoryItem {
|
||||||
name: group.name.clone(),
|
name: group.name.clone(),
|
||||||
route: model.route.clone(),
|
route: model.route.clone(),
|
||||||
oneliner: oneliner(&group.details).into(),
|
oneliner: oneliner(&group.details),
|
||||||
code: false,
|
code: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -772,8 +772,24 @@ pub fn urlify(title: &str) -> EcoString {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Extract the first line of documentation.
|
/// Extract the first line of documentation.
|
||||||
fn oneliner(docs: &str) -> &str {
|
fn oneliner(docs: &str) -> EcoString {
|
||||||
docs.lines().next().unwrap_or_default()
|
let paragraph = docs.split("\n\n").next().unwrap_or_default();
|
||||||
|
let mut depth = 0;
|
||||||
|
let mut period = false;
|
||||||
|
let mut end = paragraph.len();
|
||||||
|
for (i, c) in paragraph.char_indices() {
|
||||||
|
match c {
|
||||||
|
'(' | '[' | '{' => depth += 1,
|
||||||
|
')' | ']' | '}' => depth -= 1,
|
||||||
|
'.' if depth == 0 => period = true,
|
||||||
|
c if period && c.is_whitespace() && !docs[..i].ends_with("e.g.") => {
|
||||||
|
end = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => period = false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EcoString::from(&docs[..end]).replace("\r\n", " ").replace("\n", " ")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The order of types in the documentation.
|
/// The order of types in the documentation.
|
||||||
|
@ -86,7 +86,7 @@ pub struct FuncModel {
|
|||||||
pub name: EcoString,
|
pub name: EcoString,
|
||||||
pub title: &'static str,
|
pub title: &'static str,
|
||||||
pub keywords: &'static [&'static str],
|
pub keywords: &'static [&'static str],
|
||||||
pub oneliner: &'static str,
|
pub oneliner: EcoString,
|
||||||
pub element: bool,
|
pub element: bool,
|
||||||
pub contextual: bool,
|
pub contextual: bool,
|
||||||
pub deprecation: Option<&'static str>,
|
pub deprecation: Option<&'static str>,
|
||||||
@ -139,7 +139,7 @@ pub struct TypeModel {
|
|||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
pub title: &'static str,
|
pub title: &'static str,
|
||||||
pub keywords: &'static [&'static str],
|
pub keywords: &'static [&'static str],
|
||||||
pub oneliner: &'static str,
|
pub oneliner: EcoString,
|
||||||
pub details: Html,
|
pub details: Html,
|
||||||
pub constructor: Option<FuncModel>,
|
pub constructor: Option<FuncModel>,
|
||||||
pub scope: Vec<FuncModel>,
|
pub scope: Vec<FuncModel>,
|
||||||
|
@ -127,6 +127,10 @@
|
|||||||
checks = self'.checks;
|
checks = self'.checks;
|
||||||
inputsFrom = [ typst ];
|
inputsFrom = [ typst ];
|
||||||
|
|
||||||
|
buildInputs = with pkgs; [
|
||||||
|
rust-analyzer
|
||||||
|
];
|
||||||
|
|
||||||
packages = [
|
packages = [
|
||||||
# A script for quickly running tests.
|
# A script for quickly running tests.
|
||||||
# See https://github.com/typst/typst/blob/main/tests/README.md#making-an-alias
|
# See https://github.com/typst/typst/blob/main/tests/README.md#making-an-alias
|
||||||
|
BIN
tests/ref/image-pdf-multiple-pages.png
Normal file
BIN
tests/ref/image-pdf-multiple-pages.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.4 KiB |
BIN
tests/ref/image-pdf.png
Normal file
BIN
tests/ref/image-pdf.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.9 KiB |
@ -198,7 +198,7 @@ fn library() -> Library {
|
|||||||
// exactly 100pt wide. Page height is unbounded and font size is 10pt so
|
// exactly 100pt wide. Page height is unbounded and font size is 10pt so
|
||||||
// that it multiplies to nice round numbers.
|
// that it multiplies to nice round numbers.
|
||||||
let mut lib = Library::builder()
|
let mut lib = Library::builder()
|
||||||
.with_features([Feature::Html].into_iter().collect())
|
.with_features([Feature::Html, Feature::PdfEmbedding].into_iter().collect())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Hook up helpers into the global scope.
|
// Hook up helpers into the global scope.
|
||||||
|
@ -258,7 +258,7 @@ A #box(image("/assets/images/tiger.jpg", height: 1cm, width: 80%)) B
|
|||||||
--- image-png-but-pixmap-format ---
|
--- image-png-but-pixmap-format ---
|
||||||
#image(
|
#image(
|
||||||
read("/assets/images/tiger.jpg", encoding: none),
|
read("/assets/images/tiger.jpg", encoding: none),
|
||||||
// Error: 11-18 expected "png", "jpg", "gif", "webp", dictionary, "svg", or auto
|
// Error: 11-18 expected "png", "jpg", "gif", "webp", dictionary, "svg", "pdf", or auto
|
||||||
format: "rgba8",
|
format: "rgba8",
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -289,3 +289,16 @@ A #box(image("/assets/images/tiger.jpg", height: 1cm, width: 80%)) B
|
|||||||
..rotations.map(v => raw(str(v), lang: "typc")),
|
..rotations.map(v => raw(str(v), lang: "typc")),
|
||||||
..rotations.map(rotated)
|
..rotations.map(rotated)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
--- image-pdf ---
|
||||||
|
#image("/assets/images/matplotlib.pdf")
|
||||||
|
|
||||||
|
--- image-pdf-invalid-page ---
|
||||||
|
// Error: 2-49 page 2 doesn't exist
|
||||||
|
// Hint: 2-49 the document only has 1 page
|
||||||
|
#image("/assets/images/matplotlib.pdf", page: 2)
|
||||||
|
|
||||||
|
--- image-pdf-multiple-pages ---
|
||||||
|
#image("/assets/images/diagrams.pdf", page: 1)
|
||||||
|
#image("/assets/images/diagrams.pdf", page: 3)
|
||||||
|
#image("/assets/images/diagrams.pdf", page: 2)
|
Loading…
x
Reference in New Issue
Block a user