diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
index a3552a09cc..a9afe37f89 100644
--- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
+++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
@@ -36,11 +36,10 @@
+
All
-
-
..\..\ImageSharp.ruleset
diff --git a/src/ImageSharp.Drawing/Paths/DrawPathCollection.cs b/src/ImageSharp.Drawing/Paths/DrawPathCollection.cs
new file mode 100644
index 0000000000..5cb499415f
--- /dev/null
+++ b/src/ImageSharp.Drawing/Paths/DrawPathCollection.cs
@@ -0,0 +1,115 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ using Drawing;
+ using Drawing.Brushes;
+ using Drawing.Pens;
+ using ImageSharp.PixelFormats;
+ using SixLabors.Shapes;
+
+ ///
+ /// Extension methods for the type.
+ ///
+ public static partial class ImageExtensions
+ {
+ ///
+ /// Draws the outline of the polygon with the provided pen.
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The pen.
+ /// The paths.
+ /// The options.
+ /// The .
+ public static Image Draw(this Image source, IPen pen, IPathCollection paths, GraphicsOptions options)
+ where TPixel : struct, IPixel
+ {
+ foreach (IPath path in paths)
+ {
+ source.Draw(pen, new ShapePath(path), options);
+ }
+
+ return source;
+ }
+
+ ///
+ /// Draws the outline of the polygon with the provided pen.
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The pen.
+ /// The paths.
+ /// The .
+ public static Image Draw(this Image source, IPen pen, IPathCollection paths)
+ where TPixel : struct, IPixel
+ {
+ return source.Draw(pen, paths, GraphicsOptions.Default);
+ }
+
+ ///
+ /// Draws the outline of the polygon with the provided brush at the provided thickness.
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The brush.
+ /// The thickness.
+ /// The shapes.
+ /// The options.
+ /// The .
+ public static Image Draw(this Image source, IBrush brush, float thickness, IPathCollection paths, GraphicsOptions options)
+ where TPixel : struct, IPixel
+ {
+ return source.Draw(new Pen(brush, thickness), paths, options);
+ }
+
+ ///
+ /// Draws the outline of the polygon with the provided brush at the provided thickness.
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The brush.
+ /// The thickness.
+ /// The paths.
+ /// The .
+ public static Image Draw(this Image source, IBrush brush, float thickness, IPathCollection paths)
+ where TPixel : struct, IPixel
+ {
+ return source.Draw(new Pen(brush, thickness), paths);
+ }
+
+ ///
+ /// Draws the outline of the polygon with the provided brush at the provided thickness.
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The color.
+ /// The thickness.
+ /// The paths.
+ /// The options.
+ /// The .
+ public static Image Draw(this Image source, TPixel color, float thickness, IPathCollection paths, GraphicsOptions options)
+ where TPixel : struct, IPixel
+ {
+ return source.Draw(new SolidBrush(color), thickness, paths, options);
+ }
+
+ ///
+ /// Draws the outline of the polygon with the provided brush at the provided thickness.
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The color.
+ /// The thickness.
+ /// The paths.
+ /// The .
+ public static Image Draw(this Image source, TPixel color, float thickness, IPathCollection paths)
+ where TPixel : struct, IPixel
+ {
+ return source.Draw(new SolidBrush(color), thickness, paths);
+ }
+ }
+}
diff --git a/src/ImageSharp.Drawing/Paths/FillPathCollection.cs b/src/ImageSharp.Drawing/Paths/FillPathCollection.cs
new file mode 100644
index 0000000000..3ea9fb94b8
--- /dev/null
+++ b/src/ImageSharp.Drawing/Paths/FillPathCollection.cs
@@ -0,0 +1,81 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ using Drawing;
+ using Drawing.Brushes;
+ using ImageSharp.PixelFormats;
+ using SixLabors.Shapes;
+
+ ///
+ /// Extension methods for the type.
+ ///
+ public static partial class ImageExtensions
+ {
+ ///
+ /// Flood fills the image in the shape of the provided polygon with the specified brush..
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The brush.
+ /// The shapes.
+ /// The graphics options.
+ /// The .
+ public static Image Fill(this Image source, IBrush brush, IPathCollection paths, GraphicsOptions options)
+ where TPixel : struct, IPixel
+ {
+ foreach (IPath s in paths)
+ {
+ source.Fill(brush, s, options);
+ }
+
+ return source;
+ }
+
+ ///
+ /// Flood fills the image in the shape of the provided polygon with the specified brush.
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The brush.
+ /// The paths.
+ /// The .
+ public static Image Fill(this Image source, IBrush brush, IPathCollection paths)
+ where TPixel : struct, IPixel
+ {
+ return source.Fill(brush, paths, GraphicsOptions.Default);
+ }
+
+ ///
+ /// Flood fills the image in the shape of the provided polygon with the specified brush..
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The color.
+ /// The paths.
+ /// The options.
+ /// The .
+ public static Image Fill(this Image source, TPixel color, IPathCollection paths, GraphicsOptions options)
+ where TPixel : struct, IPixel
+ {
+ return source.Fill(new SolidBrush(color), paths, options);
+ }
+
+ ///
+ /// Flood fills the image in the shape of the provided polygon with the specified brush..
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The color.
+ /// The paths.
+ /// The .
+ public static Image Fill(this Image source, TPixel color, IPathCollection paths)
+ where TPixel : struct, IPixel
+ {
+ return source.Fill(new SolidBrush(color), paths);
+ }
+ }
+}
diff --git a/src/ImageSharp.Drawing/Text/DrawText.cs b/src/ImageSharp.Drawing/Text/DrawText.cs
index bd33289fa6..6bb87dcf5f 100644
--- a/src/ImageSharp.Drawing/Text/DrawText.cs
+++ b/src/ImageSharp.Drawing/Text/DrawText.cs
@@ -12,6 +12,7 @@ namespace ImageSharp
using Drawing.Pens;
using ImageSharp.PixelFormats;
using SixLabors.Fonts;
+ using SixLabors.Shapes;
///
/// Extension methods for the type.
@@ -167,43 +168,32 @@ namespace ImageSharp
public static Image DrawText(this Image source, string text, Font font, IBrush brush, IPen pen, Vector2 location, TextGraphicsOptions options)
where TPixel : struct, IPixel
{
- GlyphBuilder glyphBuilder = new GlyphBuilder(location);
-
- TextRenderer renderer = new TextRenderer(glyphBuilder);
-
Vector2 dpi = DefaultTextDpi;
if (options.UseImageResolution)
{
dpi = new Vector2((float)source.MetaData.HorizontalResolution, (float)source.MetaData.VerticalResolution);
}
- FontSpan style = new FontSpan(font, dpi)
+ var style = new FontSpan(font, dpi)
{
ApplyKerning = options.ApplyKerning,
TabWidth = options.TabWidth,
WrappingWidth = options.WrapTextWidth,
- Alignment = options.TextAlignment
+ HorizontalAlignment = options.HorizontalAlignment,
+ VerticalAlignment = options.VerticalAlignment
};
- renderer.RenderText(text, style);
-
- System.Collections.Generic.IEnumerable shapesToDraw = glyphBuilder.Paths;
+ IPathCollection glyphs = TextBuilder.GenerateGlyphs(text, style).Translate(location); // todo move to better API
- GraphicsOptions pathOptions = (GraphicsOptions)options;
+ var pathOptions = (GraphicsOptions)options;
if (brush != null)
{
- foreach (SixLabors.Shapes.IPath s in shapesToDraw)
- {
- source.Fill(brush, s, pathOptions);
- }
+ source.Fill(brush, glyphs, pathOptions);
}
if (pen != null)
{
- foreach (SixLabors.Shapes.IPath s in shapesToDraw)
- {
- source.Draw(pen, s, pathOptions);
- }
+ source.Draw(pen, glyphs, pathOptions);
}
return source;
diff --git a/src/ImageSharp.Drawing/Text/GlyphBuilder.cs b/src/ImageSharp.Drawing/Text/GlyphBuilder.cs
deleted file mode 100644
index 0033a608c3..0000000000
--- a/src/ImageSharp.Drawing/Text/GlyphBuilder.cs
+++ /dev/null
@@ -1,127 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp.Drawing
-{
- using System.Collections.Generic;
- using System.Numerics;
-
- using SixLabors.Fonts;
- using SixLabors.Shapes;
-
- ///
- /// rendering surface that Fonts can use to generate Shapes.
- ///
- internal class GlyphBuilder : IGlyphRenderer
- {
- private readonly PathBuilder builder = new PathBuilder();
- private readonly List paths = new List();
- private Vector2 currentPoint = default(Vector2);
-
- ///
- /// Initializes a new instance of the class.
- ///
- public GlyphBuilder()
- : this(Vector2.Zero)
- {
- // glyphs are renderd realative to bottom left so invert the Y axis to allow it to render on top left origin surface
- this.builder = new PathBuilder();
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The origin.
- public GlyphBuilder(Vector2 origin)
- {
- this.builder = new PathBuilder();
- this.builder.SetOrigin(origin);
- }
-
- ///
- /// Gets the paths that have been rendered by this.
- ///
- public IEnumerable Paths => this.paths;
-
- ///
- /// Begins the glyph.
- ///
- /// The offset that the glyph will be rendered at.
- void IGlyphRenderer.BeginGlyph(Vector2 location)
- {
- this.builder.Clear();
- }
-
- ///
- /// Begins the figure.
- ///
- void IGlyphRenderer.BeginFigure()
- {
- this.builder.StartFigure();
- }
-
- ///
- /// Draws a cubic bezier from the current point to the
- ///
- /// The second control point.
- /// The third control point.
- /// The point.
- void IGlyphRenderer.CubicBezierTo(Vector2 secondControlPoint, Vector2 thirdControlPoint, Vector2 point)
- {
- this.builder.AddBezier(this.currentPoint, secondControlPoint, thirdControlPoint, point);
- this.currentPoint = point;
- }
-
- ///
- /// Ends the glyph.
- ///
- void IGlyphRenderer.EndGlyph()
- {
- this.paths.Add(this.builder.Build());
- }
-
- ///
- /// Ends the figure.
- ///
- void IGlyphRenderer.EndFigure()
- {
- this.builder.CloseFigure();
- }
-
- ///
- /// Draws a line from the current point to the .
- ///
- /// The point.
- void IGlyphRenderer.LineTo(Vector2 point)
- {
- this.builder.AddLine(this.currentPoint, point);
- this.currentPoint = point;
- }
-
- ///
- /// Moves to current point to the supplied vector.
- ///
- /// The point.
- void IGlyphRenderer.MoveTo(Vector2 point)
- {
- this.builder.StartFigure();
- this.currentPoint = point;
- }
-
- ///
- /// Draws a quadratics bezier from the current point to the
- ///
- /// The second control point.
- /// The point.
- void IGlyphRenderer.QuadraticBezierTo(Vector2 secondControlPoint, Vector2 point)
- {
- Vector2 c1 = (((secondControlPoint - this.currentPoint) * 2) / 3) + this.currentPoint;
- Vector2 c2 = (((secondControlPoint - point) * 2) / 3) + point;
-
- this.builder.AddBezier(this.currentPoint, c1, c2, point);
- this.currentPoint = point;
- }
- }
-}
diff --git a/src/ImageSharp.Drawing/Text/TextGraphicsOptions.cs b/src/ImageSharp.Drawing/Text/TextGraphicsOptions.cs
index 388b39bcc5..593ac36d4f 100644
--- a/src/ImageSharp.Drawing/Text/TextGraphicsOptions.cs
+++ b/src/ImageSharp.Drawing/Text/TextGraphicsOptions.cs
@@ -33,7 +33,8 @@ namespace ImageSharp.Drawing
private float wrapTextWidth;
- private SixLabors.Fonts.TextAlignment? textAlignment;
+ private SixLabors.Fonts.HorizontalAlignment? horizontalAlignment;
+ private SixLabors.Fonts.VerticalAlignment? verticalAlignment;
///
/// Initializes a new instance of the struct.
@@ -45,7 +46,8 @@ namespace ImageSharp.Drawing
this.tabWidth = 4;
this.useImageResolution = false;
this.wrapTextWidth = 0;
- this.textAlignment = SixLabors.Fonts.TextAlignment.Left;
+ this.horizontalAlignment = HorizontalAlignment.Left;
+ this.verticalAlignment = VerticalAlignment.Top;
this.antialiasSubpixelDepth = 16;
this.blenderMode = PixelBlenderMode.Normal;
@@ -104,7 +106,12 @@ namespace ImageSharp.Drawing
/// defined by the location and width, if equals zero, and thus
/// wrapping disabled, then the alignment is relative to the drawing location.
///
- public TextAlignment TextAlignment { get => this.textAlignment ?? TextAlignment.Left; set => this.textAlignment = value; }
+ public HorizontalAlignment HorizontalAlignment { get => this.horizontalAlignment ?? HorizontalAlignment.Left; set => this.horizontalAlignment = value; }
+
+ ///
+ /// Gets or sets a value indicating how to align the text relative to the rendering space.
+ ///
+ public VerticalAlignment VerticalAlignment { get => this.verticalAlignment ?? VerticalAlignment.Top; set => this.verticalAlignment = value; }
///
/// Performs an implicit conversion from to .
diff --git a/tests/ImageSharp.Tests/Drawing/Text/GlyphBuilder.cs b/tests/ImageSharp.Tests/Drawing/Text/GlyphBuilder.cs
deleted file mode 100644
index 7f16f30bb8..0000000000
--- a/tests/ImageSharp.Tests/Drawing/Text/GlyphBuilder.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-
-namespace ImageSharp.Tests.Drawing.Text
-{
- using ImageSharp.Drawing;
- using SixLabors.Fonts;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Numerics;
- using System.Threading.Tasks;
- using Xunit;
-
- public class GlyphBuilderTests
- {
- [Fact]
- public void OriginUsed()
- {
- // Y axis is inverted as it expects to be drawing for bottom left
- GlyphBuilder fullBuilder = new GlyphBuilder(new System.Numerics.Vector2(10, 99));
- IGlyphRenderer builder = fullBuilder;
-
- builder.BeginGlyph(Vector2.Zero);
- builder.BeginFigure();
- builder.MoveTo(new Vector2(0, 0));
- builder.LineTo(new Vector2(0, 10)); // becomes 0, -10
-
- builder.CubicBezierTo(
- new Vector2(15, 15), // control point - will not be in the final point collection
- new Vector2(15, 10), // control point - will not be in the final point collection
- new Vector2(10, 10));// becomes 10, -10
-
- builder.QuadraticBezierTo(
- new Vector2(10, 5), // control point - will not be in the final point collection
- new Vector2(10, 0));
-
- builder.EndFigure();
- builder.EndGlyph();
-
- System.Collections.Immutable.ImmutableArray points = fullBuilder.Paths.Single().Flatten().Single().Points;
-
- Assert.Contains(new Vector2(10, 99), points);
- Assert.Contains(new Vector2(10, 109), points);
- Assert.Contains(new Vector2(20, 99), points);
- Assert.Contains(new Vector2(20, 109), points);
- }
-
- [Fact]
- public void EachGlypeCausesNewPath()
- {
- // Y axis is inverted as it expects to be drawing for bottom left
- GlyphBuilder fullBuilder = new GlyphBuilder();
- IGlyphRenderer builder = fullBuilder;
- for (int i = 0; i < 10; i++)
- {
- builder.BeginGlyph(Vector2.Zero);
- builder.BeginFigure();
- builder.MoveTo(new Vector2(0, 0));
- builder.LineTo(new Vector2(0, 10)); // becomes 0, -10
- builder.LineTo(new Vector2(10, 10));// becomes 10, -10
- builder.LineTo(new Vector2(10, 0));
- builder.EndFigure();
- builder.EndGlyph();
- }
-
- Assert.Equal(10, fullBuilder.Paths.Count());
- }
- }
-}