Skip to content

Commit

Permalink
Add basic SVG rendering functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
themkat committed Sep 1, 2024
1 parent 0289b46 commit 5ab1d59
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 6 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ tga = ["image/tga"]
gif = ["image/gif"]
bmp = ["image/bmp"]

svg = ["dep:resvg"]

obj = ["wavefront_obj"]
gltf = ["dep:gltf"]
stl = ["dep:stl_io"]
Expand All @@ -50,6 +52,7 @@ gltf = { version = "1", optional = true, features=["KHR_materials_ior", "KHR_mat
wavefront_obj = { version = "10", optional = true }
stl_io = { version = "0.8.2", optional = true }
image = { version = "0.24", optional = true, default-features = false}
resvg = { version = "0.43.0", optional = true }
pcd-rs = { version = "0.10", optional = true, features = ["derive"] }
data-url = {version = "0.3", optional = true }
serde = {version= "1", optional = true, features = ["derive", "rc"] }
Expand Down
16 changes: 10 additions & 6 deletions src/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,16 +133,20 @@ use std::path::{Path, PathBuf};
impl Deserialize for crate::Texture2D {
fn deserialize(path: impl AsRef<std::path::Path>, raw_assets: &mut RawAssets) -> Result<Self> {
let path = raw_assets.match_path(path.as_ref())?;
let extension = path
.extension()
.map(|e| e.to_str().unwrap())
.unwrap_or("image")
.to_string();
#[allow(unused_variables)]
let bytes = raw_assets.get(&path)?;

#[cfg(not(feature = "image"))]
return Err(Error::FeatureMissing(
path.extension()
.map(|e| e.to_str().unwrap())
.unwrap_or("image")
.to_string(),
));
return Err(Error::FeatureMissing(extension));

if cfg!(feature = "svg") && "svg" == extension {
return img::deserialize_svg(path, bytes);
}

#[cfg(feature = "image")]
img::deserialize_img(path, bytes)
Expand Down
56 changes: 56 additions & 0 deletions src/io/img.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,45 @@ pub fn deserialize_img(path: impl AsRef<Path>, bytes: &[u8]) -> Result<Texture2D
})
}

#[cfg(feature = "svg")]
pub fn deserialize_svg(path: impl AsRef<Path>, bytes: &[u8]) -> Result<Texture2D> {
use cgmath::num_traits::ToPrimitive;

let name = path
.as_ref()
.to_str()
.filter(|s| !s.starts_with("data:"))
.unwrap_or("default")
.to_owned();
let tree = resvg::usvg::Tree::from_data(bytes, &resvg::usvg::Options::default())?;
// TODO: should we have more error checking here?
let (width, height) = (
tree.size().width().to_u32().unwrap(),
tree.size().height().to_u32().unwrap(),
);
let mut pixmap = resvg::tiny_skia::Pixmap::new(width, height).unwrap();
resvg::render(
&tree,
resvg::tiny_skia::Transform::default(),
&mut pixmap.as_mut(),
);

// process the data to our desired RGBAU8 format
let texture_data: Vec<[u8; 4]> = pixmap
.pixels()
.iter()
.map(|pixel| [pixel.red(), pixel.green(), pixel.blue(), pixel.alpha()])
.collect();

Ok(Texture2D {
name,
data: TextureData::RgbaU8(texture_data),
width,
height,
..Default::default()
})
}

pub fn serialize_img(tex: &Texture2D, path: &Path) -> Result<RawAssets> {
#![allow(unreachable_code)]
#![allow(unused_variables)]
Expand Down Expand Up @@ -266,4 +305,21 @@ mod test {
assert_eq!(tex.width, 1024);
assert_eq!(tex.height, 512);
}

#[cfg(feature = "svg")]
#[test]
pub fn svg() {
let tex: crate::Texture2D = crate::io::load_and_deserialize("test_data/test.svg").unwrap();
if let crate::TextureData::RgbaU8(data) = tex.data {
assert_eq!(data[0], [0, 0, 0, 0]);
assert_eq!(data[25036], [0, 51, 255, 255]);
assert_eq!(data[20062], [255, 0, 0, 255]);
assert_eq!(data[58095], [0, 255, 0, 255]);
} else {
panic!("Wrong texture data");
}

assert_eq!(tex.width, 320);
assert_eq!(tex.height, 240);
}
}
5 changes: 5 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,11 @@ pub enum Error {
#[cfg(feature = "image")]
#[error("error while parsing an image file")]
Image(#[from] image::ImageError),

#[cfg(feature = "svg")]
#[error("error while parsing svg file")]
Svg(#[from] resvg::usvg::Error),

#[cfg(feature = "obj")]
#[error("error while parsing an .obj file")]
Obj(#[from] wavefront_obj::ParseError),
Expand Down
10 changes: 10 additions & 0 deletions test_data/test.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 5ab1d59

Please sign in to comment.