mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-24 10:18:13 +08:00
Fix gradient transformation (#588)
* Fix with perfect circle * Actually fix rotated gradient * Gradient transform & fix on rotated canvas * Cleanup & remove logging
This commit is contained in:
committed by
Keavon Chambers
parent
bbe94e35cb
commit
c7e80180c2
@@ -32,6 +32,10 @@ pub struct ShapeLayer {
|
||||
impl LayerData for ShapeLayer {
|
||||
fn render(&mut self, svg: &mut String, svg_defs: &mut String, transforms: &mut Vec<DAffine2>, view_mode: ViewMode) {
|
||||
let mut path = self.path.clone();
|
||||
|
||||
let kurbo::Rect { x0, y0, x1, y1 } = path.bounding_box();
|
||||
let layer_bounds = [(x0, y0).into(), (x1, y1).into()];
|
||||
|
||||
let transform = self.transform(transforms, view_mode);
|
||||
let inverse = transform.inverse();
|
||||
if !inverse.is_finite() {
|
||||
@@ -40,12 +44,20 @@ impl LayerData for ShapeLayer {
|
||||
}
|
||||
path.apply_affine(glam_to_kurbo(transform));
|
||||
|
||||
let kurbo::Rect { x0, y0, x1, y1 } = path.bounding_box();
|
||||
let transformed_bounds = [(x0, y0).into(), (x1, y1).into()];
|
||||
|
||||
let _ = writeln!(svg, r#"<g transform="matrix("#);
|
||||
inverse.to_cols_array().iter().enumerate().for_each(|(i, entry)| {
|
||||
let _ = svg.write_str(&(entry.to_string() + if i == 5 { "" } else { "," }));
|
||||
});
|
||||
let _ = svg.write_str(r#")">"#);
|
||||
let _ = write!(svg, r#"<path d="{}" {} />"#, path.to_svg(), self.style.render(view_mode, svg_defs));
|
||||
let _ = write!(
|
||||
svg,
|
||||
r#"<path d="{}" {} />"#,
|
||||
path.to_svg(),
|
||||
self.style.render(view_mode, svg_defs, transform, layer_bounds, transformed_bounds)
|
||||
);
|
||||
let _ = svg.write_str("</g>");
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,11 @@ impl Gradient {
|
||||
}
|
||||
|
||||
/// Adds the gradient def with the uuid specified
|
||||
fn render_defs(&self, svg_defs: &mut String) {
|
||||
fn render_defs(&self, svg_defs: &mut String, multiplied_transform: DAffine2, bounds: [DVec2; 2], transformed_bounds: [DVec2; 2]) {
|
||||
let bound_transform = DAffine2::from_scale_angle_translation(bounds[1] - bounds[0], 0., bounds[0]);
|
||||
let transformed_bound_transform = DAffine2::from_scale_angle_translation(transformed_bounds[1] - transformed_bounds[0], 0., transformed_bounds[0]);
|
||||
let updated_transform = multiplied_transform * bound_transform;
|
||||
|
||||
let positions = self
|
||||
.positions
|
||||
.iter()
|
||||
@@ -69,11 +73,13 @@ impl Gradient {
|
||||
.map(|(position, color)| format!(r##"<stop offset="{}" stop-color="#{}" />"##, position, color.rgba_hex()))
|
||||
.collect::<String>();
|
||||
|
||||
let start = self.transform.inverse().transform_point2(self.start);
|
||||
let end = self.transform.inverse().transform_point2(self.end);
|
||||
let mod_gradient = transformed_bound_transform.inverse();
|
||||
let mod_points = mod_gradient.inverse() * transformed_bound_transform.inverse() * updated_transform;
|
||||
|
||||
let transform = self
|
||||
.transform
|
||||
let start = mod_points.transform_point2(self.start);
|
||||
let end = mod_points.transform_point2(self.end);
|
||||
|
||||
let transform = mod_gradient
|
||||
.to_cols_array()
|
||||
.iter()
|
||||
.enumerate()
|
||||
@@ -122,12 +128,12 @@ impl Fill {
|
||||
}
|
||||
|
||||
/// Renders the fill, adding necessary defs.
|
||||
pub fn render(&self, svg_defs: &mut String) -> String {
|
||||
pub fn render(&self, svg_defs: &mut String, multiplied_transform: DAffine2, bounds: [DVec2; 2], transformed_bounds: [DVec2; 2]) -> String {
|
||||
match self {
|
||||
Self::None => r#" fill="none""#.to_string(),
|
||||
Self::Solid(color) => format!(r##" fill="#{}"{}"##, color.rgb_hex(), format_opacity("fill", color.a())),
|
||||
Self::LinearGradient(gradient) => {
|
||||
gradient.render_defs(svg_defs);
|
||||
gradient.render_defs(svg_defs, multiplied_transform, bounds, transformed_bounds);
|
||||
format!(r##" fill="url('#{}')""##, gradient.uuid)
|
||||
}
|
||||
}
|
||||
@@ -430,10 +436,10 @@ impl PathStyle {
|
||||
self.stroke = None;
|
||||
}
|
||||
|
||||
pub fn render(&self, view_mode: ViewMode, svg_defs: &mut String) -> String {
|
||||
pub fn render(&self, view_mode: ViewMode, svg_defs: &mut String, multiplied_transform: DAffine2, bounds: [DVec2; 2], transformed_bounds: [DVec2; 2]) -> String {
|
||||
let fill_attribute = match (view_mode, &self.fill) {
|
||||
(ViewMode::Outline, _) => Fill::None.render(svg_defs),
|
||||
(_, fill) => fill.render(svg_defs),
|
||||
(ViewMode::Outline, _) => Fill::None.render(svg_defs, multiplied_transform, bounds, transformed_bounds),
|
||||
(_, fill) => fill.render(svg_defs, multiplied_transform, bounds, transformed_bounds),
|
||||
};
|
||||
let stroke_attribute = match (view_mode, &self.stroke) {
|
||||
(ViewMode::Outline, _) => Stroke::new(LAYER_OUTLINE_STROKE_COLOR, LAYER_OUTLINE_STROKE_WIDTH).render(),
|
||||
|
||||
@@ -63,9 +63,20 @@ impl LayerData for TextLayer {
|
||||
} else {
|
||||
let mut path = self.to_bez_path();
|
||||
|
||||
let kurbo::Rect { x0, y0, x1, y1 } = path.bounding_box();
|
||||
let bounds = [(x0, y0).into(), (x1, y1).into()];
|
||||
|
||||
path.apply_affine(glam_to_kurbo(transform));
|
||||
|
||||
let _ = write!(svg, r#"<path d="{}" {} />"#, path.to_svg(), self.style.render(view_mode, svg_defs));
|
||||
let kurbo::Rect { x0, y0, x1, y1 } = path.bounding_box();
|
||||
let transformed_bounds = [(x0, y0).into(), (x1, y1).into()];
|
||||
|
||||
let _ = write!(
|
||||
svg,
|
||||
r#"<path d="{}" {} />"#,
|
||||
path.to_svg(),
|
||||
self.style.render(view_mode, svg_defs, transform, bounds, transformed_bounds)
|
||||
);
|
||||
}
|
||||
let _ = svg.write_str("</g>");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user