diff --git a/crates/typst-pdf/src/convert.rs b/crates/typst-pdf/src/convert.rs index c5d11c04f..ef29a3ccf 100644 --- a/crates/typst-pdf/src/convert.rs +++ b/crates/typst-pdf/src/convert.rs @@ -1,5 +1,15 @@ use std::collections::{BTreeMap, HashMap, HashSet}; +use crate::embed::embed_files; +use crate::image::handle_image; +use crate::link::handle_link; +use crate::metadata::build_metadata; +use crate::outline::build_outline; +use crate::page::PageLabelExt; +use crate::shape::handle_shape; +use crate::text::handle_text; +use crate::util::{convert_path, display_font, AbsExt, TransformExt}; +use crate::PdfOptions; use krilla::annotation::Annotation; use krilla::configure::{Configuration, PdfVersion, ValidationError}; use krilla::destination::{NamedDestination, XyzDestination}; @@ -19,16 +29,6 @@ use typst_library::text::{Font, Lang}; use typst_library::visualize::{Geometry, Paint}; use typst_syntax::Span; -use crate::image::handle_image; -use crate::link::handle_link; -use crate::metadata::build_metadata; -use crate::outline::build_outline; -use crate::page::PageLabelExt; -use crate::shape::handle_shape; -use crate::text::handle_text; -use crate::util::{convert_path, display_font, AbsExt, TransformExt}; -use crate::PdfOptions; - pub fn convert( typst_document: &PagedDocument, options: &PdfOptions, @@ -53,6 +53,7 @@ pub fn convert( ); convert_pages(&mut gc, &mut document)?; + embed_files(&typst_document, &mut document)?; document.set_outline(build_outline(&gc)); document.set_metadata(build_metadata(&gc)); diff --git a/crates/typst-pdf/src/embed.rs b/crates/typst-pdf/src/embed.rs new file mode 100644 index 000000000..b2152d7ae --- /dev/null +++ b/crates/typst-pdf/src/embed.rs @@ -0,0 +1,52 @@ +use krilla::embed::{AssociationKind, EmbeddedFile}; +use krilla::Document; +use std::sync::Arc; +use typst_library::diag::{bail, SourceResult}; +use typst_library::foundations::{NativeElement, StyleChain}; +use typst_library::layout::PagedDocument; +use typst_library::pdf::{EmbedElem, EmbeddedFileRelationship}; +use typst_syntax::Span; + +pub(crate) fn embed_files( + typst_doc: &PagedDocument, + document: &mut Document, +) -> SourceResult<()> { + let elements = typst_doc.introspector.query(&EmbedElem::elem().select()); + + for elem in &elements { + let embed = elem.to_packed::().unwrap(); + let derived_path = &embed.path.derived; + let path = derived_path.to_string(); + let mime_type = + embed.mime_type(StyleChain::default()).clone().map(|s| s.to_string()); + let description = embed + .description(StyleChain::default()) + .clone() + .map(|s| s.to_string()); + let association_kind = match embed.relationship(StyleChain::default()) { + None => AssociationKind::Unspecified, + Some(e) => match e { + EmbeddedFileRelationship::Source => AssociationKind::Source, + EmbeddedFileRelationship::Data => AssociationKind::Data, + EmbeddedFileRelationship::Alternative => AssociationKind::Alternative, + EmbeddedFileRelationship::Supplement => AssociationKind::Supplement, + }, + }; + let data: Arc + Send + Sync> = Arc::new(embed.data.clone()); + + let file = EmbeddedFile { + path, + mime_type, + description, + association_kind, + data: data.into(), + compress: true, + }; + + if document.embed_file(file).is_none() { + bail!(Span::detached(), "attempted to embed file {derived_path} twice"); + } + } + + Ok(()) +} diff --git a/crates/typst-pdf/src/lib.rs b/crates/typst-pdf/src/lib.rs index 43df44943..171a05786 100644 --- a/crates/typst-pdf/src/lib.rs +++ b/crates/typst-pdf/src/lib.rs @@ -1,6 +1,7 @@ //! Exporting Typst documents to PDF. mod convert; +mod embed; mod image; mod link; mod metadata;