// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using SixLabors.ImageSharp.Drawing.PolygonGeometry; using SixLabors.ImageSharp.Drawing.Processing; using System; namespace SixLabors.ImageSharp.Drawing { /// /// Extensions to that allow the generation of outlines. /// public static class OutlinePathExtensions { private static readonly StrokeOptions DefaultOptions = new(); /// /// Generates an outline of the path. /// /// The path to outline /// The outline width. /// A new representing the outline. public static IPath GenerateOutline(this IPath path, float width) => GenerateOutline(path, width, DefaultOptions); /// /// Generates an outline of the path. /// /// The path to outline /// The outline width. /// The stroke geometry options. /// A new representing the outline. public static IPath GenerateOutline(this IPath path, float width, StrokeOptions strokeOptions) { if (width <= 0) { return Path.Empty; } return StrokedShapeGenerator.GenerateStrokedShapes(path, width, strokeOptions); } /// /// Generates an outline of the path with alternating on and off segments based on the pattern. /// /// The path to outline /// The outline width. /// The pattern made of multiples of the width. /// A new representing the outline. public static IPath GenerateOutline(this IPath path, float width, ReadOnlySpan pattern) => path.GenerateOutline(width, pattern, false); /// /// Generates an outline of the path with alternating on and off segments based on the pattern. /// /// The path to outline /// The outline width. /// The pattern made of multiples of the width. /// The stroke geometry options. /// A new representing the outline. public static IPath GenerateOutline(this IPath path, float width, ReadOnlySpan pattern, StrokeOptions strokeOptions) => GenerateOutline(path, width, pattern, false, strokeOptions); /// /// Generates an outline of the path with alternating on and off segments based on the pattern. /// /// The path to outline /// The outline width. /// The pattern made of multiples of the width. /// Whether the first item in the pattern is on or off. /// A new representing the outline. public static IPath GenerateOutline(this IPath path, float width, ReadOnlySpan pattern, bool startOff) => GenerateOutline(path, width, pattern, startOff, DefaultOptions); /// /// Generates an outline of the path with alternating on and off segments based on the pattern. /// /// The path to outline /// The outline width. /// The pattern made of multiples of the width. /// Whether the first item in the pattern is on or off. /// The stroke geometry options. /// A new representing the outline. public static IPath GenerateOutline( this IPath path, float width, ReadOnlySpan pattern, bool startOff, StrokeOptions strokeOptions) { if (width <= 0) { return Path.Empty; } if (pattern.Length < 2) { return path.GenerateOutline(width, strokeOptions); } IPath dashed = path.GenerateDashes(width, pattern, startOff); // GenerateDashes returns the original path when the pattern is degenerate // or when segmentation would exceed safety limits; stroke it as solid. if (ReferenceEquals(dashed, path)) { return path.GenerateOutline(width, strokeOptions); } if (dashed == Path.Empty) { return Path.Empty; } // Each dash segment is an open sub-path; stroke expansion and boolean merge // are handled by the generator. return StrokedShapeGenerator.GenerateStrokedShapes(dashed, width, strokeOptions); } } }