1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
use crate::core::assets::protocol::{AssetLoadResult, AssetProtocol};
use std::str::from_utf8;
use svg::{
    node::element::tag::{Type, SVG},
    parser::Event,
};

pub struct SvgImageAsset {
    bytes: Vec<u8>,
    width: usize,
    height: usize,
}

impl SvgImageAsset {
    pub fn bytes(&self) -> &[u8] {
        &self.bytes
    }

    pub fn width(&self) -> usize {
        self.width
    }

    pub fn height(&self) -> usize {
        self.height
    }
}

pub struct SvgImageAssetProtocol;

impl AssetProtocol for SvgImageAssetProtocol {
    fn name(&self) -> &str {
        "svg"
    }

    fn on_load(&mut self, data: Vec<u8>) -> AssetLoadResult {
        let content = from_utf8(&data).unwrap();
        let mut width = 0;
        let mut height = 0;
        for event in svg::read(&content).unwrap() {
            if let Event::Tag(SVG, Type::Start, attributes) = event {
                let mut iter = attributes.get("viewBox").unwrap().split_whitespace();
                let left = iter.next().unwrap().parse::<isize>().unwrap();
                let top = iter.next().unwrap().parse::<isize>().unwrap();
                let right = iter.next().unwrap().parse::<isize>().unwrap();
                let bottom = iter.next().unwrap().parse::<isize>().unwrap();
                width = (right - left) as usize;
                height = (bottom - top) as usize;
                break;
            }
        }
        let content = content.replace("width=\"100%\"", &format!("width=\"{}\"", width));
        let content = content.replace("height=\"100%\"", &format!("height=\"{}\"", height));
        AssetLoadResult::Data(Box::new(SvgImageAsset {
            bytes: content.into_bytes(),
            width,
            height,
        }))
    }
}