use super::layer_info::LayerData; use super::style::ViewMode; use crate::intersection::{intersect_quad_bez_path, Quad}; use crate::LayerId; use glam::{DAffine2, DMat2, DVec2}; use kurbo::{Affine, BezPath, Shape as KurboShape}; use serde::{Deserialize, Serialize}; use std::fmt::Write; fn glam_to_kurbo(transform: DAffine2) -> Affine { Affine::new(transform.to_cols_array()) } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] pub struct ImageLayer { pub mime: String, pub image_data: Vec, #[serde(skip)] pub blob_url: Option, #[serde(skip)] pub dimensions: DVec2, } impl LayerData for ImageLayer { fn render(&mut self, svg: &mut String, _svg_defs: &mut String, transforms: &mut Vec, view_mode: ViewMode) { let transform = self.transform(transforms, view_mode); let inverse = transform.inverse(); if !inverse.is_finite() { let _ = write!(svg, ""); return; } let _ = writeln!(svg, r#""#); let svg_transform = transform .to_cols_array() .iter() .enumerate() .map(|(i, entry)| entry.to_string() + if i == 5 { "" } else { "," }) .collect::(); let _ = write!( svg, r#""#, self.dimensions.x, self.dimensions.y, svg_transform, self.blob_url.as_ref().unwrap_or(&String::new()) ); let _ = svg.write_str(""); } fn bounding_box(&self, transform: glam::DAffine2) -> Option<[DVec2; 2]> { let mut path = self.bounds(); if transform.matrix2 == DMat2::ZERO { return None; } path.apply_affine(glam_to_kurbo(transform)); let kurbo::Rect { x0, y0, x1, y1 } = path.bounding_box(); Some([(x0, y0).into(), (x1, y1).into()]) } fn intersects_quad(&self, quad: Quad, path: &mut Vec, intersections: &mut Vec>) { if intersect_quad_bez_path(quad, &self.bounds(), true) { intersections.push(path.clone()); } } } impl ImageLayer { pub fn new(mime: String, image_data: Vec) -> Self { let blob_url = None; let dimensions = DVec2::ONE; Self { mime, image_data, blob_url, dimensions, } } pub fn transform(&self, transforms: &[DAffine2], mode: ViewMode) -> DAffine2 { let start = match mode { ViewMode::Outline => 0, _ => (transforms.len() as i32 - 1).max(0) as usize, }; transforms.iter().skip(start).cloned().reduce(|a, b| a * b).unwrap_or(DAffine2::IDENTITY) } fn bounds(&self) -> BezPath { kurbo::Rect::from_origin_size(kurbo::Point::ZERO, kurbo::Size::new(self.dimensions.x, self.dimensions.y)).to_path(0.) } }