diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
index a3552a09c..13500b65a 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 000000000..877737653
--- /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, 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 000000000..3ea9fb94b
--- /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.Path.cs b/src/ImageSharp.Drawing/Text/DrawText.Path.cs
new file mode 100644
index 000000000..2bc23b64b
--- /dev/null
+++ b/src/ImageSharp.Drawing/Text/DrawText.Path.cs
@@ -0,0 +1,200 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ using System.Numerics;
+
+ using Drawing;
+ using Drawing.Brushes;
+ using Drawing.Pens;
+ using ImageSharp.PixelFormats;
+ using SixLabors.Fonts;
+ using SixLabors.Shapes;
+
+ ///
+ /// Extension methods for the type.
+ ///
+ public static partial class ImageExtensions
+ {
+ ///
+ /// Draws the text onto the the image filled via the brush.
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The text.
+ /// The font.
+ /// The color.
+ /// The path.
+ ///
+ /// The .
+ ///
+ public static Image DrawText(this Image source, string text, Font font, TPixel color, IPath path)
+ where TPixel : struct, IPixel
+ {
+ return source.DrawText(text, font, color, path, TextGraphicsOptions.Default);
+ }
+
+ ///
+ /// Draws the text onto the the image filled via the brush.
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The text.
+ /// The font.
+ /// The color.
+ /// The path.
+ /// The options.
+ ///
+ /// The .
+ ///
+ public static Image DrawText(this Image source, string text, Font font, TPixel color, IPath path, TextGraphicsOptions options)
+ where TPixel : struct, IPixel
+ {
+ return source.DrawText(text, font, Brushes.Solid(color), null, path, options);
+ }
+
+ ///
+ /// Draws the text onto the the image filled via the brush.
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The text.
+ /// The font.
+ /// The brush.
+ /// The location.
+ ///
+ /// The .
+ ///
+ public static Image DrawText(this Image source, string text, Font font, IBrush brush, IPath path)
+ where TPixel : struct, IPixel
+ {
+ return source.DrawText(text, font, brush, path, TextGraphicsOptions.Default);
+ }
+
+ ///
+ /// Draws the text onto the the image filled via the brush.
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The text.
+ /// The font.
+ /// The brush.
+ /// The path.
+ /// The options.
+ ///
+ /// The .
+ ///
+ public static Image DrawText(this Image source, string text, Font font, IBrush brush, IPath path, TextGraphicsOptions options)
+ where TPixel : struct, IPixel
+ {
+ return source.DrawText(text, font, brush, null, path, options);
+ }
+
+ ///
+ /// Draws the text onto the the image outlined via the pen.
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The text.
+ /// The font.
+ /// The pen.
+ /// The path.
+ ///
+ /// The .
+ ///
+ public static Image DrawText(this Image source, string text, Font font, IPen pen, IPath path)
+ where TPixel : struct, IPixel
+ {
+ return source.DrawText(text, font, pen, path, TextGraphicsOptions.Default);
+ }
+
+ ///
+ /// Draws the text onto the the image outlined via the pen.
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The text.
+ /// The font.
+ /// The pen.
+ /// The path.
+ /// The options.
+ ///
+ /// The .
+ ///
+ public static Image DrawText(this Image source, string text, Font font, IPen pen, IPath path, TextGraphicsOptions options)
+ where TPixel : struct, IPixel
+ {
+ return source.DrawText(text, font, null, pen, path, options);
+ }
+
+ ///
+ /// Draws the text onto the the image filled via the brush then outlined via the pen.
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The text.
+ /// The font.
+ /// The brush.
+ /// The pen.
+ /// The path.
+ ///
+ /// The .
+ ///
+ public static Image DrawText(this Image source, string text, Font font, IBrush brush, IPen pen, IPath path)
+ where TPixel : struct, IPixel
+ {
+ return source.DrawText(text, font, brush, pen, path, TextGraphicsOptions.Default);
+ }
+
+ ///
+ /// Draws the text onto the the image filled via the brush then outlined via the pen.
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The text.
+ /// The font.
+ /// The brush.
+ /// The pen.
+ /// The path.
+ /// The options.
+ ///
+ /// The .
+ ///
+ public static Image DrawText(this Image source, string text, Font font, IBrush brush, IPen pen, IPath path, TextGraphicsOptions options)
+ where TPixel : struct, IPixel
+ {
+ Vector2 dpi = DefaultTextDpi;
+ if (options.UseImageResolution)
+ {
+ dpi = new Vector2((float)source.MetaData.HorizontalResolution, (float)source.MetaData.VerticalResolution);
+ }
+
+ var style = new FontSpan(font, dpi)
+ {
+ ApplyKerning = options.ApplyKerning,
+ TabWidth = options.TabWidth,
+ WrappingWidth = options.WrapTextWidth,
+ HorizontalAlignment = options.HorizontalAlignment,
+ VerticalAlignment = options.VerticalAlignment
+ };
+
+ IPathCollection glyphs = TextBuilder.GenerateGlyphs(text, path, style);
+
+ var pathOptions = (GraphicsOptions)options;
+ if (brush != null)
+ {
+ source.Fill(brush, glyphs, pathOptions);
+ }
+
+ if (pen != null)
+ {
+ source.Draw(pen, glyphs, pathOptions);
+ }
+
+ return source;
+ }
+ }
+}
diff --git a/src/ImageSharp.Drawing/Text/DrawText.cs b/src/ImageSharp.Drawing/Text/DrawText.cs
index bd33289fa..3b0d3db41 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, location, style);
- 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 0033a608c..000000000
--- 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 388b39bcc..593ac36d4 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/Paths/FillPathCollection.cs b/tests/ImageSharp.Tests/Drawing/Paths/FillPathCollection.cs
new file mode 100644
index 000000000..e60ac0c13
--- /dev/null
+++ b/tests/ImageSharp.Tests/Drawing/Paths/FillPathCollection.cs
@@ -0,0 +1,131 @@
+
+namespace ImageSharp.Tests.Drawing.Paths
+{
+ using System;
+ using ImageSharp;
+ using ImageSharp.Drawing.Brushes;
+ using Xunit;
+ using ImageSharp.Drawing;
+ using System.Numerics;
+ using SixLabors.Shapes;
+ using ImageSharp.Drawing.Processors;
+ using ImageSharp.PixelFormats;
+
+ public class FillPathCollection : IDisposable
+ {
+ GraphicsOptions noneDefault = new GraphicsOptions();
+ Rgba32 color = Rgba32.HotPink;
+ SolidBrush brush = Brushes.Solid(Rgba32.HotPink);
+ IPath path1 = new SixLabors.Shapes.Path(new LinearLineSegment(new Vector2[] {
+ new Vector2(10,10),
+ new Vector2(20,10),
+ new Vector2(20,10),
+ new Vector2(30,10),
+ }));
+ IPath path2 = new SixLabors.Shapes.Path(new LinearLineSegment(new Vector2[] {
+ new Vector2(10,10),
+ new Vector2(20,10),
+ new Vector2(20,10),
+ new Vector2(30,10),
+ }));
+
+ IPathCollection pathCollection;
+
+ private ProcessorWatchingImage img;
+
+ public FillPathCollection()
+ {
+ this.pathCollection = new PathCollection(path1, path2);
+ this.img = new ProcessorWatchingImage(10, 10);
+ }
+
+ public void Dispose()
+ {
+ img.Dispose();
+ }
+
+ [Fact]
+ public void CorrectlySetsBrushAndPath()
+ {
+ img.Fill(brush, pathCollection);
+
+ Assert.Equal(2, img.ProcessorApplications.Count);
+ for (var i = 0; i < 2; i++)
+ {
+ FillRegionProcessor processor = Assert.IsType>(img.ProcessorApplications[i].processor);
+
+ Assert.Equal(GraphicsOptions.Default, processor.Options);
+
+ ShapeRegion region = Assert.IsType(processor.Region);
+
+ // path is converted to a polygon before filling
+ Polygon polygon = Assert.IsType(region.Shape);
+ LinearLineSegment segments = Assert.IsType(polygon.LineSegments[0]);
+
+ Assert.Equal(brush, processor.Brush);
+ }
+ }
+
+ [Fact]
+ public void CorrectlySetsBrushPathOptions()
+ {
+ img.Fill(brush, pathCollection, noneDefault);
+
+ Assert.Equal(2, img.ProcessorApplications.Count);
+ for (var i = 0; i < 2; i++)
+ {
+ FillRegionProcessor processor = Assert.IsType>(img.ProcessorApplications[i].processor);
+
+ Assert.Equal(noneDefault, processor.Options);
+
+ ShapeRegion region = Assert.IsType(processor.Region);
+ Polygon polygon = Assert.IsType(region.Shape);
+ LinearLineSegment segments = Assert.IsType(polygon.LineSegments[0]);
+
+ Assert.Equal(brush, processor.Brush);
+ }
+ }
+
+ [Fact]
+ public void CorrectlySetsColorAndPath()
+ {
+ img.Fill(color, pathCollection);
+
+ Assert.Equal(2, img.ProcessorApplications.Count);
+ for (var i = 0; i < 2; i++)
+ {
+ FillRegionProcessor processor = Assert.IsType>(img.ProcessorApplications[i].processor);
+
+ Assert.Equal(GraphicsOptions.Default, processor.Options);
+
+ ShapeRegion region = Assert.IsType(processor.Region);
+ Polygon polygon = Assert.IsType(region.Shape);
+ LinearLineSegment segments = Assert.IsType(polygon.LineSegments[0]);
+
+ SolidBrush brush = Assert.IsType>(processor.Brush);
+ Assert.Equal(color, brush.Color);
+ }
+ }
+
+ [Fact]
+ public void CorrectlySetsColorPathAndOptions()
+ {
+ img.Fill(color, pathCollection, noneDefault);
+
+ Assert.Equal(2, img.ProcessorApplications.Count);
+ for (var i = 0; i < 2; i++)
+ {
+ FillRegionProcessor processor = Assert.IsType>(img.ProcessorApplications[i].processor);
+
+ Assert.Equal(noneDefault, processor.Options);
+
+ ShapeRegion region = Assert.IsType(processor.Region);
+ Polygon polygon = Assert.IsType(region.Shape);
+ LinearLineSegment segments = Assert.IsType(polygon.LineSegments[0]);
+
+ SolidBrush brush = Assert.IsType>(processor.Brush);
+ Assert.Equal(color, brush.Color);
+ }
+ }
+ }
+}
diff --git a/tests/ImageSharp.Tests/Drawing/Text/DrawText.Path.cs b/tests/ImageSharp.Tests/Drawing/Text/DrawText.Path.cs
new file mode 100644
index 000000000..60fe44acd
--- /dev/null
+++ b/tests/ImageSharp.Tests/Drawing/Text/DrawText.Path.cs
@@ -0,0 +1,251 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Tests.Drawing.Text
+{
+ using System;
+ using System.Numerics;
+
+ using ImageSharp.Drawing;
+ using ImageSharp.Drawing.Brushes;
+ using ImageSharp.Drawing.Pens;
+ using ImageSharp.Drawing.Processors;
+ using ImageSharp.PixelFormats;
+ using ImageSharp.Tests.Drawing.Paths;
+
+ using SixLabors.Fonts;
+ using SixLabors.Shapes;
+
+ using Xunit;
+
+ public class DrawText_Path : IDisposable
+ {
+ Rgba32 color = Rgba32.HotPink;
+
+ SolidBrush brush = Brushes.Solid(Rgba32.HotPink);
+
+ IPath path = new SixLabors.Shapes.Path(
+ new LinearLineSegment(
+ new Vector2[] { new Vector2(10, 10), new Vector2(20, 10), new Vector2(20, 10), new Vector2(30, 10), }));
+
+ private ProcessorWatchingImage img;
+
+ private readonly FontCollection FontCollection;
+
+ private readonly Font Font;
+
+ public DrawText_Path()
+ {
+ this.FontCollection = new FontCollection();
+ this.Font = this.FontCollection.Install(TestFontUtilities.GetPath("SixLaborsSampleAB.woff"));
+ this.img = new ProcessorWatchingImage(10, 10);
+ }
+
+ public void Dispose()
+ {
+ this.img.Dispose();
+ }
+
+ [Fact]
+ public void FillsForEachACharachterWhenBrushSetAndNotPen()
+ {
+ this.img.DrawText(
+ "123",
+ this.Font,
+ Brushes.Solid(Rgba32.Red),
+ null,
+ path,
+ new TextGraphicsOptions(true));
+
+ Assert.NotEmpty(this.img.ProcessorApplications);
+ Assert.Equal(3, this.img.ProcessorApplications.Count); // 3 fills where applied
+ Assert.IsType>(this.img.ProcessorApplications[0].processor);
+ }
+
+ [Fact]
+ public void FillsForEachACharachterWhenBrushSetAndNotPenDefaultOptions()
+ {
+ this.img.DrawText("123", this.Font, Brushes.Solid(Rgba32.Red), null, path);
+
+ Assert.NotEmpty(this.img.ProcessorApplications);
+ Assert.Equal(3, this.img.ProcessorApplications.Count); // 3 fills where applied
+ Assert.IsType>(this.img.ProcessorApplications[0].processor);
+ }
+
+ [Fact]
+ public void FillsForEachACharachterWhenBrushSet()
+ {
+ this.img.DrawText("123", this.Font, Brushes.Solid(Rgba32.Red), path, new TextGraphicsOptions(true));
+
+ Assert.NotEmpty(this.img.ProcessorApplications);
+ Assert.Equal(3, this.img.ProcessorApplications.Count); // 3 fills where applied
+ Assert.IsType>(this.img.ProcessorApplications[0].processor);
+ }
+
+ [Fact]
+ public void FillsForEachACharachterWhenBrushSetDefaultOptions()
+ {
+ this.img.DrawText("123", this.Font, Brushes.Solid(Rgba32.Red), path);
+
+ Assert.NotEmpty(this.img.ProcessorApplications);
+ Assert.Equal(3, this.img.ProcessorApplications.Count); // 3 fills where applied
+ Assert.IsType>(this.img.ProcessorApplications[0].processor);
+ }
+
+ [Fact]
+ public void FillsForEachACharachterWhenColorSet()
+ {
+ this.img.DrawText("123", this.Font, Rgba32.Red, path, new TextGraphicsOptions(true));
+
+ Assert.NotEmpty(this.img.ProcessorApplications);
+ Assert.Equal(3, this.img.ProcessorApplications.Count);
+ FillRegionProcessor processor =
+ Assert.IsType>(this.img.ProcessorApplications[0].processor);
+
+ SolidBrush brush = Assert.IsType>(processor.Brush);
+ Assert.Equal(Rgba32.Red, brush.Color);
+ }
+
+ [Fact]
+ public void FillsForEachACharachterWhenColorSetDefaultOptions()
+ {
+ this.img.DrawText("123", this.Font, Rgba32.Red, path);
+
+ Assert.NotEmpty(this.img.ProcessorApplications);
+ Assert.Equal(3, this.img.ProcessorApplications.Count);
+ Assert.IsType>(this.img.ProcessorApplications[0].processor);
+ FillRegionProcessor processor =
+ Assert.IsType>(this.img.ProcessorApplications[0].processor);
+
+ SolidBrush brush = Assert.IsType>(processor.Brush);
+ Assert.Equal(Rgba32.Red, brush.Color);
+ }
+
+ [Fact]
+ public void DrawForEachACharachterWhenPenSetAndNotBrush()
+ {
+ this.img.DrawText(
+ "123",
+ this.Font,
+ null,
+ Pens.Dash(Rgba32.Red, 1),
+ path,
+ new TextGraphicsOptions(true));
+
+ Assert.NotEmpty(this.img.ProcessorApplications);
+ Assert.Equal(3, this.img.ProcessorApplications.Count); // 3 fills where applied
+ Assert.IsType>(this.img.ProcessorApplications[0].processor);
+ }
+
+ [Fact]
+ public void DrawForEachACharachterWhenPenSetAndNotBrushDefaultOptions()
+ {
+ this.img.DrawText("123", this.Font, null, Pens.Dash(Rgba32.Red, 1), path);
+
+ Assert.NotEmpty(this.img.ProcessorApplications);
+ Assert.Equal(3, this.img.ProcessorApplications.Count); // 3 fills where applied
+ Assert.IsType>(this.img.ProcessorApplications[0].processor);
+ }
+
+ [Fact]
+ public void DrawForEachACharachterWhenPenSet()
+ {
+ this.img.DrawText("123", this.Font, Pens.Dash(Rgba32.Red, 1), path, new TextGraphicsOptions(true));
+
+ Assert.NotEmpty(this.img.ProcessorApplications);
+ Assert.Equal(3, this.img.ProcessorApplications.Count); // 3 fills where applied
+ Assert.IsType>(this.img.ProcessorApplications[0].processor);
+ }
+
+ [Fact]
+ public void DrawForEachACharachterWhenPenSetDefaultOptions()
+ {
+ this.img.DrawText("123", this.Font, Pens.Dash(Rgba32.Red, 1), path);
+
+ Assert.NotEmpty(this.img.ProcessorApplications);
+ Assert.Equal(3, this.img.ProcessorApplications.Count); // 3 fills where applied
+ Assert.IsType>(this.img.ProcessorApplications[0].processor);
+ }
+
+ [Fact]
+ public void DrawForEachACharachterWhenPenSetAndFillFroEachWhenBrushSet()
+ {
+ this.img.DrawText(
+ "123",
+ this.Font,
+ Brushes.Solid(Rgba32.Red),
+ Pens.Dash(Rgba32.Red, 1),
+ path,
+ new TextGraphicsOptions(true));
+
+ Assert.NotEmpty(this.img.ProcessorApplications);
+ Assert.Equal(6, this.img.ProcessorApplications.Count);
+ }
+
+ [Fact]
+ public void DrawForEachACharachterWhenPenSetAndFillFroEachWhenBrushSetDefaultOptions()
+ {
+ this.img.DrawText("123", this.Font, Brushes.Solid(Rgba32.Red), Pens.Dash(Rgba32.Red, 1), path);
+
+ Assert.NotEmpty(this.img.ProcessorApplications);
+ Assert.Equal(6, this.img.ProcessorApplications.Count);
+ }
+
+ [Fact]
+ public void BrushAppliesBeforPen()
+ {
+ this.img.DrawText(
+ "1",
+ this.Font,
+ Brushes.Solid(Rgba32.Red),
+ Pens.Dash(Rgba32.Red, 1),
+ path,
+ new TextGraphicsOptions(true));
+
+ Assert.NotEmpty(this.img.ProcessorApplications);
+ Assert.Equal(2, this.img.ProcessorApplications.Count);
+ Assert.IsType>(this.img.ProcessorApplications[0].processor);
+ Assert.IsType>(this.img.ProcessorApplications[1].processor);
+ }
+
+ [Fact]
+ public void BrushAppliesBeforPenDefaultOptions()
+ {
+ this.img.DrawText("1", this.Font, Brushes.Solid(Rgba32.Red), Pens.Dash(Rgba32.Red, 1), path);
+
+ Assert.NotEmpty(this.img.ProcessorApplications);
+ Assert.Equal(2, this.img.ProcessorApplications.Count);
+ Assert.IsType>(this.img.ProcessorApplications[0].processor);
+ Assert.IsType>(this.img.ProcessorApplications[1].processor);
+ }
+
+ [Fact]
+ public void GlyphHeightChangesBasedOnuseImageResolutionFlag()
+ {
+ this.img.MetaData.VerticalResolution = 1;
+ this.img.MetaData.HorizontalResolution = 1;
+ this.img.DrawText("1", this.Font, Brushes.Solid(Rgba32.Red), path, new TextGraphicsOptions(true) {
+ UseImageResolution = false
+ });
+
+ this.img.DrawText("1", this.Font, Brushes.Solid(Rgba32.Red), path, new TextGraphicsOptions(true)
+ {
+ UseImageResolution = true
+ });
+
+ Assert.NotEmpty(this.img.ProcessorApplications);
+ Assert.Equal(2, this.img.ProcessorApplications.Count);
+ FillRegionProcessor ownResolution = Assert.IsType>(this.img.ProcessorApplications[0].processor);
+ FillRegionProcessor imgResolution = Assert.IsType>(this.img.ProcessorApplications[1].processor);
+
+ ShapeRegion ownRegion = Assert.IsType(ownResolution.Region);
+ ShapeRegion imgRegion = Assert.IsType(imgResolution.Region);
+
+ // magic numbers based on the font used at well known resolutions
+ Assert.Equal(7.44, ownRegion.Shape.Bounds.Height, 2);
+ Assert.Equal(0.1, imgRegion.Shape.Bounds.Height, 2);
+ }
+ }
+}
diff --git a/tests/ImageSharp.Tests/Drawing/Text/GlyphBuilder.cs b/tests/ImageSharp.Tests/Drawing/Text/GlyphBuilder.cs
deleted file mode 100644
index 7f16f30bb..000000000
--- 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());
- }
- }
-}