use std::collections::BTreeMap;
use svg2pdf::{usvg, ConversionOptions, PageOptions};
use crate::{
xobject::ExternalXObject, ColorSpace, DictItem, ExternalStream, PdfResources, PdfWarnMsg,
};
#[derive(Debug, Clone)]
pub struct Svg {}
impl Svg {
pub fn parse(
svg_string: &str,
warnings: &mut Vec<PdfWarnMsg>,
) -> Result<ExternalXObject, String> {
#[cfg(target_arch = "wasm32")]
let options = usvg::Options::default();
#[cfg(not(target_arch = "wasm32"))]
let mut options = usvg::Options::default();
#[cfg(not(target_arch = "wasm32"))]
{
options.fontdb_mut().load_system_fonts();
}
let dpi = 300.0;
let tree = usvg::Tree::from_str(svg_string, &usvg::Options { dpi, ..options })
.map_err(|err| format!("usvg parse: {err}"))?;
let mut co = ConversionOptions::default();
co.compress = false;
co.embed_text = false;
let po = PageOptions { dpi };
let pdf_bytes = svg2pdf::to_pdf(&tree, co, po)
.map_err(|err| format!("convert svg tree to pdf: {err}"))?;
let pdf = crate::deserialize::parse_pdf_from_bytes(
&pdf_bytes,
&crate::PdfParseOptions {
fail_on_error: false,
},
warnings,
)
.map_err(|err| format!("convert svg tree to pdf: parse pdf: {err}"))?;
let page = pdf
.pages
.get(0)
.ok_or_else(|| format!("convert svg tree to pdf: no page rendered"))?;
let stream = crate::serialize::translate_operations(
&page.ops,
&crate::serialize::prepare_fonts_for_serialization(&PdfResources::default(), &[], false, warnings).0,
&BTreeMap::new(),
true,
warnings,
);
let sx = 1.0 / page.media_box.width.0;
let sy = 1.0 / page.media_box.height.0;
let dict = [
("Type", DictItem::Name("XObject".into())),
("Subtype", DictItem::Name("Form".into())),
(
"ProcSet",
DictItem::Array(vec![
DictItem::Name("PDF".into()),
DictItem::Name("Text".into()),
DictItem::Name("ImageC".into()),
DictItem::Name("ImageB".into()),
]),
),
(
"Resources",
DictItem::Dict {
map: [(
"ColorSpace".to_string(),
DictItem::Name(ColorSpace::Rgb.as_string().into()),
)]
.into_iter()
.collect(),
},
),
(
"BBox",
DictItem::Array(vec![
DictItem::Real(0.0),
DictItem::Real(0.0),
DictItem::Real(page.media_box.width.0),
DictItem::Real(page.media_box.height.0),
]),
),
(
"Matrix",
DictItem::Array(vec![
DictItem::Real(sx),
DictItem::Real(0.0),
DictItem::Real(0.0),
DictItem::Real(sy),
DictItem::Real(0.0),
DictItem::Real(0.0),
]),
),
];
Ok(ExternalXObject {
stream: ExternalStream {
dict: dict.into_iter().map(|(k, v)| (k.to_string(), v)).collect(),
content: stream,
compress: false,
},
width: Some(page.media_box.width.into_px(dpi)),
height: Some(page.media_box.height.into_px(dpi)),
dpi: Some(dpi),
})
}
}