use std::io::Cursor;
use std::path::{Path, PathBuf};
use anyhow::{Context, Result};
use image::io::Reader;
use image::{ImageFormat, RgbImage};
use image_compare::rgb_hybrid_compare;
use rusvid_core::holder::likes::color_like::ColorLike;
use rusvid_core::holder::likes::path_like::PathLike;
use rusvid_core::holder::likes::types_like::TypesLike;
use rusvid_core::holder::object::Object;
use rusvid_core::holder::stroke::Stroke;
use rusvid_core::holder::svg_holder::{SvgHolder, SvgItem};
use rusvid_core::holder::transform::{Transform, TransformLogic};
use rusvid_core::pixel::Pixel;
use rusvid_core::plane::Plane;
use rusvid_core::point::Point;
const DELTA: f64 = 0.00005;
const SIMPLE_PATH: &'static [u8] = include_bytes!("./data/simple_path.bmp");
const SIMPLE_TRANSFORM: &'static [u8] = include_bytes!("./data/simple_transform.bmp");
const SIMPLE_TRANSFORM_STROKE: &'static [u8] = include_bytes!("./data/simple_transform_stroke.bmp");
const SIMPLE_TRANSFORM_COLOR: &'static [u8] = include_bytes!("./data/simple_transform_color.bmp");
const SIMPLE_TRANSFORM_POSITION: &'static [u8] =
include_bytes!("./data/simple_transform_position.bmp");
const SIMPLE_TRANSFORM_MOVE: &'static [u8] = include_bytes!("./data/simple_transform_move.bmp");
const SIMPLE_TRANSFORM_COLOR_NONE: &'static [u8] =
include_bytes!("./data/simple_transform_color_none.bmp");
const SIMPLE_TRANSFORM_VISIBILITY: &'static [u8] =
include_bytes!("./data/simple_transform_visibility.bmp");
fn rebuild_snapshots<P: AsRef<Path>>(image: &RgbImage, name: P) -> Result<()> {
if option_env!("TEST_REBUILD").is_some() {
let mut path_buf = PathBuf::new();
path_buf.push(std::env::current_dir()?);
path_buf.push("./tests/data");
path_buf.push(name);
path_buf.set_extension("bmp");
image.save_with_format(path_buf, ImageFormat::Bmp)?
}
Ok(())
}
fn save_if_env(image: &RgbImage, name: &str) -> Result<()> {
if option_env!("TEST_SAVE").is_some() {
image.save_with_format(format!("{}.png", name), ImageFormat::Png)?;
}
Ok(())
}
fn test_image(image: RgbImage, snapshot: &[u8], name: &str) -> Result<()> {
let mut reader = Reader::new(Cursor::new(snapshot));
reader.set_format(ImageFormat::Bmp);
let test_image = reader.decode()?.to_rgb8();
let result = rgb_hybrid_compare(&image, &test_image)?;
save_if_env(&image, name)?;
assert!(
result.score > (1.0 - DELTA),
"score: {} (at {})",
result.score,
name
);
Ok(())
}
fn rebuild_and_test<P: AsRef<Path> + Clone>(plane: Plane, name: P, snapshot: &[u8]) -> Result<()> {
let image = plane.as_rgb_image()?;
let binding = name.clone();
let test_name = binding
.as_ref()
.to_str()
.context("Can't transform `P` to &str")?;
rebuild_snapshots(&image, name)?;
test_image(image, snapshot, test_name)
}
#[test]
fn simple_path() {
let mut svg = SvgHolder::new();
let triangle = SvgItem::new(
vec![
PathLike::Move(Point::new(100.0, 100.0)),
PathLike::Line(Point::new(150.0, 100.0)),
PathLike::Line(Point::new(120.0, 150.0)),
PathLike::Close,
],
Some(ColorLike::Color([0, 255, 100, 255].into())),
);
svg.add_item(triangle);
let heart = SvgItem::new(
vec![
PathLike::Move(Point::new(100.0, 100.0)),
PathLike::Line(Point::new(150.0, 50.0)),
PathLike::CurveTo(
Point::new(100.0, 25.0),
Point::new(169.0, 11.0),
Point::new(119.0, -13.0),
),
PathLike::CurveTo(
Point::new(50.0, 50.0),
Point::new(80.0, -13.0),
Point::new(30.0, 11.0),
),
PathLike::Close,
],
Some(ColorLike::Color([255, 0, 0, 255].into())),
);
svg.add_item(heart);
let object = Object::new(TypesLike::Svg(svg));
let plane = object.render(300, 300).unwrap();
rebuild_and_test(plane, "simple_path", SIMPLE_PATH).unwrap();
}
#[test]
fn simple_transform() {
let mut svg = SvgHolder::new();
let triangle_id = svg.add_item(SvgItem::new(
vec![
PathLike::Move(Point::new(100.0, 100.0)),
PathLike::Line(Point::new(150.0, 100.0)),
PathLike::Line(Point::new(120.0, 150.0)),
PathLike::Close,
],
Some(ColorLike::Color([0, 255, 120, 255].into())),
));
let heart_id = svg.add_item(SvgItem::new(
vec![
PathLike::Move(Point::new(100.0, 100.0)),
PathLike::Line(Point::new(150.0, 50.0)),
PathLike::CurveTo(
Point::new(100.0, 25.0),
Point::new(169.0, 11.0),
Point::new(119.0, -13.0),
),
PathLike::CurveTo(
Point::new(50.0, 50.0),
Point::new(80.0, -13.0),
Point::new(30.0, 11.0),
),
PathLike::Close,
],
Some(ColorLike::Color([200, 100, 20, 255].into())),
));
let mut object = Object::new(TypesLike::Svg(svg));
let plane = object.render(300, 300).unwrap();
rebuild_and_test(plane, "simple_transform", SIMPLE_TRANSFORM).unwrap();
object
.transform_by_id(
&triangle_id,
&Transform::Stroke(Some(Stroke {
paint: ColorLike::Color([100, 50, 120, 255].into()),
width: 1.75,
..Stroke::default()
})),
)
.unwrap();
let plane = object.render(300, 300).unwrap();
rebuild_and_test(plane, "simple_transform_stroke", SIMPLE_TRANSFORM_STROKE).unwrap();
object
.transform_by_id(
&heart_id,
&Transform::Color(Some(ColorLike::Color(Pixel::new(230, 57, 70, 255)))),
)
.unwrap();
let plane = object.render(300, 300).unwrap();
rebuild_and_test(plane, "simple_transform_color", SIMPLE_TRANSFORM_COLOR).unwrap();
object
.transform_by_id(&triangle_id, &Transform::Position(Point::new(200.0, 200.0)))
.unwrap();
let plane = object.render(300, 300).unwrap();
rebuild_and_test(
plane,
"simple_transform_position",
SIMPLE_TRANSFORM_POSITION,
)
.unwrap();
object
.transform_by_id(&heart_id, &Transform::Move(Point::new(50.0, 0.0)))
.unwrap();
let plane = object.render(300, 300).unwrap();
rebuild_and_test(plane, "simple_transform_move", SIMPLE_TRANSFORM_MOVE).unwrap();
object
.transform_by_id(&triangle_id, &Transform::Color(None))
.unwrap();
let plane = object.render(300, 300).unwrap();
rebuild_and_test(
plane,
"simple_transform_color_none",
SIMPLE_TRANSFORM_COLOR_NONE,
)
.unwrap();
object
.transform_by_id(&triangle_id, &Transform::Visibility(false))
.unwrap();
let plane = object.render(300, 300).unwrap();
rebuild_and_test(
plane,
"simple_transform_visibility",
SIMPLE_TRANSFORM_VISIBILITY,
)
.unwrap();
}