use std::path;
use base64;
use svgdom;
use tree;
use tree::prelude::*;
use super::prelude::*;
pub fn convert(
node: &svgdom::Node,
opt: &Options,
mut parent: tree::Node,
) {
let ref attrs = node.attributes();
let transform = attrs.get_transform(AId::Transform).unwrap_or_default();
let view_box = tree::ViewBox {
rect: super::convert_rect(attrs),
aspect: super::convert_aspect(attrs),
};
let href = match attrs.get_value(("xlink", AId::Href)) {
Some(&AValue::String(ref s)) => s,
_ => {
warn!("The 'image' element lacks '{}' attribute. Skipped.", "xlink:href");
return;
}
};
if let Some((data, format)) = get_href_data(href, opt.path.as_ref()) {
parent.append_kind(tree::NodeKind::Image(tree::Image {
id: node.id().clone(),
transform,
view_box,
data,
format,
}));
}
}
fn get_href_data(
href: &str,
path: Option<&path::PathBuf>,
) -> Option<(tree::ImageData, tree::ImageFormat)> {
if href.starts_with("data:image/") {
if let Some(idx) = href.find(',') {
let start_idx = 11; let format = match &href[start_idx..idx] {
"jpg;base64" | "jpeg;base64" => {
tree::ImageFormat::JPEG
}
"png;base64" => {
tree::ImageFormat::PNG
}
"svg+xml;base64" => {
tree::ImageFormat::SVG
}
_ => {
return None;
}
};
let base_data = &href[(idx + 1)..];
let conf = base64::Config::new(
base64::CharacterSet::Standard,
true,
true,
base64::LineWrap::NoWrap,
);
if let Ok(data) = base64::decode_config(base_data, conf) {
return Some((tree::ImageData::Raw(data.to_owned()), format));
}
}
warn!("Invalid xlink:href content.");
} else {
let path = match path {
Some(path) => path.parent().unwrap().join(href),
None => path::PathBuf::from(href),
};
if path.exists() {
if let Some(format) = get_image_format(&path) {
return Some((tree::ImageData::Path(path.to_owned()), format));
} else {
warn!("'{}' is not a PNG, JPEG or SVG(Z) image.", href);
}
} else {
warn!("Linked file does not exist: '{}'.", href);
}
}
None
}
fn file_extension(path: &path::Path) -> Option<&str> {
if let Some(ext) = path.extension() {
ext.to_str()
} else {
None
}
}
fn get_image_format(path: &path::Path) -> Option<tree::ImageFormat> {
use std::fs;
use std::io::Read;
let ext = file_extension(path)?.to_lowercase();
if ext == "svg" || ext == "svgz" {
return Some(tree::ImageFormat::SVG);
}
let mut file = fs::File::open(path).ok()?;
let mut d = Vec::new();
d.resize(8, 0);
file.read_exact(&mut d).ok()?;
if d.starts_with(b"\x89PNG\r\n\x1a\n") {
Some(tree::ImageFormat::PNG)
} else if d.starts_with(&[0xff, 0xd8, 0xff]) {
Some(tree::ImageFormat::JPEG)
} else {
None
}
}