use crate::{Document, DocumentExt, FontKey, FontRegistry};
use lightweight_pdf_layout::{LayoutWarning, LayoutWarningKind};
use wasm_bindgen::prelude::*;
fn to_js_error(err: impl std::fmt::Display) -> JsError {
JsError::new(&err.to_string())
}
#[derive(serde::Serialize)]
struct WasmWarning {
page: usize,
kind: &'static str,
hint: String,
}
impl From<&LayoutWarning> for WasmWarning {
fn from(w: &LayoutWarning) -> Self {
let kind = match w.kind {
LayoutWarningKind::TextClipped => "text_clipped",
LayoutWarningKind::ContentOverflow => "content_overflow",
LayoutWarningKind::ForcedPageBreak => "forced_page_break",
LayoutWarningKind::HeaderFooterOverflow => "header_footer_overflow",
LayoutWarningKind::MissingGlyph { .. } => "missing_glyph",
LayoutWarningKind::TableRowOverflow => "table_row_overflow",
LayoutWarningKind::MissingAltText => "missing_alt_text",
};
WasmWarning {
page: w.page,
kind,
hint: w.element_hint.clone(),
}
}
}
#[wasm_bindgen]
pub struct RenderResult {
bytes: Vec<u8>,
warnings: Vec<WasmWarning>,
}
#[wasm_bindgen]
impl RenderResult {
#[wasm_bindgen(getter)]
pub fn bytes(&self) -> Vec<u8> {
self.bytes.clone()
}
#[wasm_bindgen(getter)]
pub fn warnings(&self) -> Result<JsValue, JsError> {
serde_wasm_bindgen::to_value(&self.warnings).map_err(to_js_error)
}
}
#[wasm_bindgen]
pub struct LightweightPdf {
fonts: FontRegistry,
}
impl Default for LightweightPdf {
fn default() -> Self {
Self::new()
}
}
#[wasm_bindgen]
impl LightweightPdf {
#[wasm_bindgen(constructor)]
pub fn new() -> LightweightPdf {
LightweightPdf {
fonts: FontRegistry::empty(),
}
}
#[cfg(feature = "default-fonts")]
#[wasm_bindgen(js_name = withDefaultFonts)]
pub fn with_default_fonts() -> Result<LightweightPdf, JsError> {
Ok(LightweightPdf {
fonts: FontRegistry::with_defaults().map_err(to_js_error)?,
})
}
#[wasm_bindgen(js_name = registerFont)]
pub fn register_font(&mut self, key: &str, bytes: &[u8]) -> Result<(), JsError> {
let key = FontKey(Box::leak(key.to_string().into_boxed_str()));
self.fonts.register(key, bytes).map_err(to_js_error)
}
pub fn render(&self, document_json: &str) -> Result<Vec<u8>, JsError> {
let doc = Document::from_json(document_json).map_err(to_js_error)?;
doc.render_with_fonts(&self.fonts).map_err(to_js_error)
}
#[wasm_bindgen(js_name = renderWithDiagnostics)]
pub fn render_with_diagnostics(&self, document_json: &str) -> Result<RenderResult, JsError> {
let doc = Document::from_json(document_json).map_err(to_js_error)?;
let (bytes, warnings) = doc.render_with_fonts_and_diagnostics(&self.fonts).map_err(to_js_error)?;
Ok(RenderResult {
bytes,
warnings: warnings.iter().map(WasmWarning::from).collect(),
})
}
#[wasm_bindgen(js_name = renderTemplate)]
pub fn render_template(&self, template_json: &str, data_json: &str, allow_missing: bool) -> Result<Vec<u8>, JsError> {
let on_missing = if allow_missing {
crate::MissingPlaceholder::Empty
} else {
crate::MissingPlaceholder::Error
};
let doc = Document::from_template(template_json, data_json, on_missing).map_err(to_js_error)?;
doc.render_with_fonts(&self.fonts).map_err(to_js_error)
}
}