From d1cd814ef8149cbac6e59c81e074aa59c930eed3 Mon Sep 17 00:00:00 2001 From: Birk Tjelmeland Date: Thu, 13 Apr 2023 16:05:56 +0200 Subject: Add support for more complex strokes (#505) --- src/export/render.rs | 54 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 3 deletions(-) (limited to 'src/export/render.rs') diff --git a/src/export/render.rs b/src/export/render.rs index 8cee3aa6..f3c72ba0 100644 --- a/src/export/render.rs +++ b/src/export/render.rs @@ -11,7 +11,8 @@ use usvg::{FitTo, NodeExt}; use crate::doc::{Frame, FrameItem, GroupItem, Meta, TextItem}; use crate::geom::{ - self, Abs, Color, Geometry, Paint, PathItem, Shape, Size, Stroke, Transform, + self, Abs, Color, Geometry, LineCap, LineJoin, Paint, PathItem, Shape, Size, Stroke, + Transform, }; use crate::image::{DecodedImage, Image}; @@ -392,9 +393,36 @@ fn render_shape( canvas.fill_path(&path, &paint, rule, ts, mask); } - if let Some(Stroke { paint, thickness }) = &shape.stroke { + if let Some(Stroke { + paint, + thickness, + line_cap, + line_join, + dash_pattern, + miter_limit, + }) = &shape.stroke + { + let dash = dash_pattern.as_ref().and_then(|pattern| { + // tiny-skia only allows dash patterns with an even number of elements, + // while pdf allows any number. + let len = if pattern.array.len() % 2 == 1 { + pattern.array.len() * 2 + } else { + pattern.array.len() + }; + let dash_array = + pattern.array.iter().map(|l| l.to_f32()).cycle().take(len).collect(); + + sk::StrokeDash::new(dash_array, pattern.phase.to_f32()) + }); let paint = paint.into(); - let stroke = sk::Stroke { width: thickness.to_f32(), ..Default::default() }; + let stroke = sk::Stroke { + width: thickness.to_f32(), + line_cap: line_cap.into(), + line_join: line_join.into(), + dash, + miter_limit: miter_limit.0 as f32, + }; canvas.stroke_path(&path, &paint, &stroke, ts, mask); } @@ -525,6 +553,26 @@ impl From for sk::Color { } } +impl From<&LineCap> for sk::LineCap { + fn from(line_cap: &LineCap) -> Self { + match line_cap { + LineCap::Butt => sk::LineCap::Butt, + LineCap::Round => sk::LineCap::Round, + LineCap::Square => sk::LineCap::Square, + } + } +} + +impl From<&LineJoin> for sk::LineJoin { + fn from(line_join: &LineJoin) -> Self { + match line_join { + LineJoin::Miter => sk::LineJoin::Miter, + LineJoin::Round => sk::LineJoin::Round, + LineJoin::Bevel => sk::LineJoin::Bevel, + } + } +} + /// Allows to build tiny-skia paths from glyph outlines. struct WrappedPathBuilder(sk::PathBuilder); -- cgit v1.2.3