diff --git a/Cargo.lock b/Cargo.lock index fe1623ee..69da40f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4488,6 +4488,7 @@ dependencies = [ "typst-ts-canvas-exporter", "typst-ts-compiler", "typst-ts-core", + "typst-ts-pdf-exporter", "typst-ts-svg-exporter", "typst-ts-test-common", "wasm-bindgen", diff --git a/packages/compiler/Cargo.toml b/packages/compiler/Cargo.toml index 6d8b1e26..2b320f69 100644 --- a/packages/compiler/Cargo.toml +++ b/packages/compiler/Cargo.toml @@ -49,6 +49,7 @@ typst-ts-compiler = { version = "0.4.0-rc1", default-features = false, features typst-ts-ast-exporter.workspace = true typst-ts-canvas-exporter.workspace = true typst-ts-svg-exporter.workspace = true +typst-ts-pdf-exporter.workspace = true [dev-dependencies] wasm-bindgen-test.workspace = true diff --git a/packages/compiler/src/lib.rs b/packages/compiler/src/lib.rs index 00bee64f..83b685d4 100644 --- a/packages/compiler/src/lib.rs +++ b/packages/compiler/src/lib.rs @@ -10,7 +10,10 @@ use typst_ts_compiler::{ vfs::browser::ProxyAccessModel, world::WorldSnapshot, }; -use typst_ts_core::{cache::FontInfoCache, error::prelude::*, Exporter, FontLoader, FontSlot}; +use typst_ts_core::{ + cache::FontInfoCache, error::prelude::*, DynExporter, Exporter, FontLoader, FontSlot, + TypstDocument, +}; use wasm_bindgen::prelude::*; use crate::utils::console_log; @@ -194,26 +197,28 @@ impl TypstCompiler { } pub fn get_artifact(&mut self, fmt: String) -> Result, JsValue> { - if fmt != "vector" { - return Err(error_once!("Unsupported fmt", format: fmt).into()); - } - - let ir_exporter = typst_ts_core::exporter_builtins::VecExporter::new( - typst_ts_svg_exporter::SvgModuleExporter::default(), - ); + let vec_exporter: DynExporter> = match fmt.as_str() { + "vector" => Box::new(typst_ts_core::exporter_builtins::VecExporter::new( + typst_ts_svg_exporter::SvgModuleExporter::default(), + )), + "pdf" => Box::::default(), + _ => { + return Err(error_once!("Unsupported fmt", format: fmt).into()); + } + }; let doc = self.compiler.compile().map_err(|e| format!("{e:?}"))?; - let artifact_bytes = ir_exporter + let artifact_bytes = vec_exporter .export(self.compiler.world(), doc) .map_err(|e| format!("{e:?}"))?; Ok(artifact_bytes) } - pub fn compile(&mut self, main_file_path: String) -> Result, JsValue> { + pub fn compile(&mut self, main_file_path: String, fmt: String) -> Result, JsValue> { self.compiler .set_entry_file(Path::new(&main_file_path).to_owned()); - self.get_artifact("vector".into()) + self.get_artifact(fmt) } } diff --git a/packages/typst.ts/examples/compiler.html b/packages/typst.ts/examples/compiler.html index 189295ca..4ed97a8e 100644 --- a/packages/typst.ts/examples/compiler.html +++ b/packages/typst.ts/examples/compiler.html @@ -24,36 +24,54 @@ document.ready(() => { const terminalContent = document.getElementById('terminal-content'); - terminalContent.innerHTML = 'Compiling...'; + terminalContent.innerHTML = 'Downloading font assets...'; - const runCompile = async () => { + const runCompile = async fmt => { const begin = performance.now(); compilerPlugin.reset(); - const ast = await compilerPlugin.getAst('corpus/skyzh-cv/main.typ'); - const end = performance.now(); - const rounded = Math.round((end - begin) * 1000) / 1000; - const compileInfo = `--- - Compiled in ${rounded}ms`; + if (fmt === 'ast') { + const ast = await compilerPlugin.getAst('corpus/skyzh-cv/main.typ'); + const end = performance.now(); + const rounded = Math.round((end - begin) * 1000) / 1000; - terminalContent.innerHTML = [compileInfo, ast].join('\n'); + const compileInfo = `--- +Compiled to AST in ${rounded}ms`; + + terminalContent.innerHTML = [compileInfo, ast].join('\n'); + } else if (fmt === 'pdf') { + const pdfData = await compilerPlugin.compile({ + mainFilePath: 'corpus/skyzh-cv/main.typ', + format: 'pdf', + }); + const end = performance.now(); + const rounded = Math.round((end - begin) * 1000) / 1000; + + const compileInfo = `Compiled to PDF in ${rounded}ms`; + + terminalContent.innerHTML = compileInfo; + console.log(pdfData); + var pdfFile = new Blob([pdfData], { type: 'application/pdf' }); + + // Create element with tag + const link = document.createElement('a'); + + // Add file content in the object URL + link.href = URL.createObjectURL(pdfFile); + + // Add file name + link.target = '_blank'; + + // Add click event to tag to save file. + link.click(); + URL.revokeObjectURL(link.href); + } }; let compilerPlugin = window.TypstCompileModule.createTypstCompiler(); compilerPlugin .init({ beforeBuild: [ - window.TypstCompileModule.preloadRemoteFonts([ - 'http://localhost:20810/assets/fonts/LinLibertine_R.ttf', - 'http://localhost:20810/assets/fonts/LinLibertine_RB.ttf', - 'http://localhost:20810/assets/fonts/LinLibertine_RBI.ttf', - 'http://localhost:20810/assets/fonts/LinLibertine_RI.ttf', - 'http://localhost:20810/assets/fonts/NewCMMath-Book.otf', - 'http://localhost:20810/assets/fonts/NewCMMath-Regular.otf', - ]), - // window.TypstCompileModule.preloadSystemFonts({ - // byFamily: ['Segoe UI Symbol'], - // }), window.TypstCompileModule.withAccessModel( new window.TypstCompileModule.FetchAccessModel('http://localhost:20810'), ), @@ -63,9 +81,12 @@ }) .then(() => { document.getElementById('compile-button').addEventListener('click', () => { - runCompile(); + runCompile('ast'); + }); + document.getElementById('compile-to-pdf-button').addEventListener('click', () => { + runCompile('pdf'); }); - return runCompile(); + return runCompile('ast'); }); }); @@ -107,7 +128,12 @@ } .terminal pre { - font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace; + font-family: + SFMono-Regular, + Consolas, + Liberation Mono, + Menlo, + monospace; color: white; padding: 0 1rem 1rem; margin: 0; @@ -133,7 +159,8 @@
- + +
hello world
diff --git a/packages/typst.ts/src/compiler.mts b/packages/typst.ts/src/compiler.mts index f9da6e56..203d6114 100644 --- a/packages/typst.ts/src/compiler.mts +++ b/packages/typst.ts/src/compiler.mts @@ -8,6 +8,7 @@ import { LazyWasmModule } from './wasm.mjs'; export interface CompileOptions { mainFilePath: string; + format: 'vector' | 'pdf'; } /** @@ -137,7 +138,7 @@ class TypstCompilerDriver { compile(options: CompileOptions): Promise { return new Promise(resolve => { - resolve(this.compiler.compile(options.mainFilePath)); + resolve(this.compiler.compile(options.mainFilePath, options.format || 'vector')); }); }