Browse Source

remove draw text along path

pull/614/head
Scott Williams 8 years ago
parent
commit
503ae5b1a8
  1. 199
      src/ImageSharp.Drawing/Processing/Text/DrawTextExtensions.Path.cs
  2. 123
      src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextOnPathProcessor.cs
  3. 179
      tests/ImageSharp.Tests/Drawing/Text/DrawText.Path.cs
  4. 82
      tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs

199
src/ImageSharp.Drawing/Processing/Text/DrawTextExtensions.Path.cs

@ -1,199 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.Fonts;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Drawing;
using SixLabors.ImageSharp.Processing.Drawing.Brushes;
using SixLabors.ImageSharp.Processing.Drawing.Pens;
using SixLabors.ImageSharp.Processing.Text.Processors;
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Processing.Text
{
/// <summary>
/// Adds extensions that allow the drawing of text along given paths to the <see cref="Image{TPixel}"/> type.
/// </summary>
public static partial class DrawTextExtensions
{
/// <summary>
/// Draws the text onto the the image filled via the brush.
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="color">The color.</param>
/// <param name="path">The path.</param>
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static IImageProcessingContext<TPixel> DrawText<TPixel>(
this IImageProcessingContext<TPixel> source,
string text,
Font font,
TPixel color,
IPath path)
where TPixel : struct, IPixel<TPixel> =>
source.DrawText(TextGraphicsOptions.Default, text, font, color, path);
/// <summary>
/// Draws the text onto the the image filled via the brush.
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="color">The color.</param>
/// <param name="path">The path.</param>
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static IImageProcessingContext<TPixel> DrawText<TPixel>(
this IImageProcessingContext<TPixel> source,
TextGraphicsOptions options,
string text,
Font font,
TPixel color,
IPath path)
where TPixel : struct, IPixel<TPixel> =>
source.DrawText(options, text, font, Brushes.Solid(color), null, path);
/// <summary>
/// Draws the text onto the the image filled via the brush.
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="brush">The brush.</param>
/// <param name="path">The location.</param>
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static IImageProcessingContext<TPixel> DrawText<TPixel>(
this IImageProcessingContext<TPixel> source,
string text,
Font font,
IBrush<TPixel> brush,
IPath path)
where TPixel : struct, IPixel<TPixel> =>
source.DrawText(TextGraphicsOptions.Default, text, font, brush, path);
/// <summary>
/// Draws the text onto the the image filled via the brush.
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="brush">The brush.</param>
/// <param name="path">The path.</param>
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static IImageProcessingContext<TPixel> DrawText<TPixel>(
this IImageProcessingContext<TPixel> source,
TextGraphicsOptions options,
string text,
Font font,
IBrush<TPixel> brush,
IPath path)
where TPixel : struct, IPixel<TPixel> =>
source.DrawText(options, text, font, brush, null, path);
/// <summary>
/// Draws the text onto the the image outlined via the pen.
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="pen">The pen.</param>
/// <param name="path">The path.</param>
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static IImageProcessingContext<TPixel> DrawText<TPixel>(
this IImageProcessingContext<TPixel> source,
string text,
Font font,
IPen<TPixel> pen,
IPath path)
where TPixel : struct, IPixel<TPixel> =>
source.DrawText(TextGraphicsOptions.Default, text, font, pen, path);
/// <summary>
/// Draws the text onto the the image outlined via the pen.
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="pen">The pen.</param>
/// <param name="path">The path.</param>
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static IImageProcessingContext<TPixel> DrawText<TPixel>(
this IImageProcessingContext<TPixel> source,
TextGraphicsOptions options,
string text,
Font font,
IPen<TPixel> pen,
IPath path)
where TPixel : struct, IPixel<TPixel> =>
source.DrawText(options, text, font, null, pen, path);
/// <summary>
/// Draws the text onto the the image filled via the brush then outlined via the pen.
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="brush">The brush.</param>
/// <param name="pen">The pen.</param>
/// <param name="path">The path.</param>
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static IImageProcessingContext<TPixel> DrawText<TPixel>(
this IImageProcessingContext<TPixel> source,
string text,
Font font,
IBrush<TPixel> brush,
IPen<TPixel> pen,
IPath path)
where TPixel : struct, IPixel<TPixel> =>
source.DrawText(TextGraphicsOptions.Default, text, font, brush, pen, path);
/// <summary>
/// Draws the text onto the the image filled via the brush then outlined via the pen.
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="brush">The brush.</param>
/// <param name="pen">The pen.</param>
/// <param name="path">The path.</param>
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static IImageProcessingContext<TPixel> DrawText<TPixel>(
this IImageProcessingContext<TPixel> source,
TextGraphicsOptions options,
string text,
Font font,
IBrush<TPixel> brush,
IPen<TPixel> pen,
IPath path)
where TPixel : struct, IPixel<TPixel> =>
source.ApplyProcessor(new DrawTextOnPathProcessor<TPixel>(options, text, font, brush, pen, path));
}
}

123
src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextOnPathProcessor.cs

@ -1,123 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Threading.Tasks;
using SixLabors.Fonts;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Drawing.Brushes;
using SixLabors.ImageSharp.Processing.Drawing.Pens;
using SixLabors.ImageSharp.Processing.Drawing.Processors;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Primitives;
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Processing.Text.Processors
{
/// <summary>
/// Using the brush as a source of pixels colors blends the brush color with source.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class DrawTextOnPathProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private FillRegionProcessor<TPixel> fillRegionProcessor = null;
/// <summary>
/// Initializes a new instance of the <see cref="DrawTextOnPathProcessor{TPixel}"/> class.
/// </summary>
/// <param name="options">The options</param>
/// <param name="text">The text we want to render</param>
/// <param name="font">The font we want to render with</param>
/// <param name="brush">The brush to source pixel colors from.</param>
/// <param name="pen">The pen to outline text with.</param>
/// <param name="path">The path on which to draw the text along.</param>
public DrawTextOnPathProcessor(TextGraphicsOptions options, string text, Font font, IBrush<TPixel> brush, IPen<TPixel> pen, IPath path)
{
this.Brush = brush;
this.Options = options;
this.Text = text;
this.Pen = pen;
this.Font = font;
this.Path = path;
}
/// <summary>
/// Gets or sets the brush.
/// </summary>
public IBrush<TPixel> Brush { get; set; }
/// <summary>
/// Gets or sets the options
/// </summary>
private TextGraphicsOptions Options { get; set; }
/// <summary>
/// Gets or sets the text
/// </summary>
private string Text { get; set; }
/// <summary>
/// Gets or sets the pen used for outlining the text, if Null then we will not outline
/// </summary>
public IPen<TPixel> Pen { get; set; }
/// <summary>
/// Gets or sets the font used to render the text.
/// </summary>
public Font Font { get; set; }
/// <summary>
/// Gets or sets the path to draw the text along.
/// </summary>
public IPath Path { get; set; }
protected override void BeforeImageApply(Image<TPixel> source, Rectangle sourceRectangle)
{
base.BeforeImageApply(source, sourceRectangle);
// do everythign at the image level as we are deligating the processing down to other processors
var style = new RendererOptions(this.Font, this.Options.DpiX, this.Options.DpiY)
{
ApplyKerning = this.Options.ApplyKerning,
TabWidth = this.Options.TabWidth,
WrappingWidth = this.Path.Length,
HorizontalAlignment = this.Options.HorizontalAlignment,
VerticalAlignment = this.Options.VerticalAlignment
};
IPathCollection glyphs = TextBuilder.GenerateGlyphs(this.Text, this.Path, style);
this.fillRegionProcessor = new FillRegionProcessor<TPixel>();
this.fillRegionProcessor.Options = (GraphicsOptions)this.Options;
if (this.Brush != null)
{
this.fillRegionProcessor.Brush = this.Brush;
foreach (IPath p in glyphs)
{
this.fillRegionProcessor.Region = new ShapeRegion(p);
this.fillRegionProcessor.Apply(source, sourceRectangle);
}
}
if (this.Pen != null)
{
this.fillRegionProcessor.Brush = this.Pen.StrokeFill;
foreach (IPath p in glyphs)
{
this.fillRegionProcessor.Region = new ShapePath(p, this.Pen);
this.fillRegionProcessor.Apply(source, sourceRectangle);
}
}
}
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
// this is a no-op as we have processes all as an image, we should be able to pass out of before email apply a skip frames outcome
}
}
}

179
tests/ImageSharp.Tests/Drawing/Text/DrawText.Path.cs

@ -1,179 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Numerics;
using SixLabors.Fonts;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Drawing.Brushes;
using SixLabors.ImageSharp.Processing.Drawing.Pens;
using SixLabors.ImageSharp.Processing.Drawing.Processors;
using SixLabors.ImageSharp.Processing.Text;
using SixLabors.ImageSharp.Processing.Text.Processors;
using SixLabors.Shapes;
using Xunit;
namespace SixLabors.ImageSharp.Tests.Drawing.Text
{
public class DrawText_Path : BaseImageOperationsExtensionTest
{
Rgba32 color = Rgba32.HotPink;
SolidBrush<Rgba32> brush = Brushes.Solid(Rgba32.HotPink);
IPath path = new SixLabors.Shapes.Path(
new LinearLineSegment(
new SixLabors.Primitives.PointF[] { new Vector2(10, 10), new Vector2(20, 10), new Vector2(20, 10), new Vector2(30, 10), }));
private readonly FontCollection FontCollection;
private readonly Font Font;
public DrawText_Path()
{
this.FontCollection = new FontCollection();
this.Font = this.FontCollection.Install(TestFontUtilities.GetPath("SixLaborsSampleAB.woff")).CreateFont(12);
}
[Fact]
public void FillsForEachACharachterWhenBrushSetAndNotPen()
{
this.operations.DrawText(
new TextGraphicsOptions(true),
"123",
this.Font,
Brushes.Solid(Rgba32.Red),
null,
this.path);
this.Verify<DrawTextOnPathProcessor<Rgba32>>(0);
}
[Fact]
public void FillsForEachACharachterWhenBrushSetAndNotPenDefaultOptions()
{
this.operations.DrawText("123", this.Font, Brushes.Solid(Rgba32.Red), null, this.path);
this.Verify<DrawTextOnPathProcessor<Rgba32>>(0);
}
[Fact]
public void FillsForEachACharachterWhenBrushSet()
{
this.operations.DrawText(new TextGraphicsOptions(true), "123", this.Font, Brushes.Solid(Rgba32.Red), this.path);
this.Verify<DrawTextOnPathProcessor<Rgba32>>(0);
}
[Fact]
public void FillsForEachACharachterWhenBrushSetDefaultOptions()
{
this.operations.DrawText("123", this.Font, Brushes.Solid(Rgba32.Red), this.path);
this.Verify<DrawTextOnPathProcessor<Rgba32>>(0);
}
[Fact]
public void FillsForEachACharachterWhenColorSet()
{
this.operations.DrawText(new TextGraphicsOptions(true), "123", this.Font, Rgba32.Red, this.path);
var processor = this.Verify<DrawTextOnPathProcessor<Rgba32>>(0);
SolidBrush<Rgba32> brush = Assert.IsType<SolidBrush<Rgba32>>(processor.Brush);
Assert.Equal(Rgba32.Red, brush.Color);
}
[Fact]
public void FillsForEachACharachterWhenColorSetDefaultOptions()
{
this.operations.DrawText("123", this.Font, Rgba32.Red, this.path);
DrawTextOnPathProcessor<Rgba32> processor = this.Verify<DrawTextOnPathProcessor<Rgba32>>(0);
SolidBrush<Rgba32> brush = Assert.IsType<SolidBrush<Rgba32>>(processor.Brush);
Assert.Equal(Rgba32.Red, brush.Color);
}
[Fact]
public void DrawForEachACharachterWhenPenSetAndNotBrush()
{
this.operations.DrawText(
new TextGraphicsOptions(true),
"123",
this.Font,
null,
Pens.Dash(Rgba32.Red, 1),
this.path);
var processor = this.Verify<DrawTextOnPathProcessor<Rgba32>>(0);
}
[Fact]
public void DrawForEachACharachterWhenPenSetAndNotBrushDefaultOptions()
{
this.operations.DrawText("123", this.Font, null, Pens.Dash(Rgba32.Red, 1), this.path);
var processor = this.Verify<DrawTextOnPathProcessor<Rgba32>>(0);
}
[Fact]
public void DrawForEachACharachterWhenPenSet()
{
this.operations.DrawText(new TextGraphicsOptions(true), "123", this.Font, Pens.Dash(Rgba32.Red, 1), this.path);
var processor = this.Verify<DrawTextOnPathProcessor<Rgba32>>(0);
}
[Fact]
public void DrawForEachACharachterWhenPenSetDefaultOptions()
{
this.operations.DrawText("123", this.Font, Pens.Dash(Rgba32.Red, 1), this.path);
DrawTextOnPathProcessor<Rgba32> processor = this.Verify<DrawTextOnPathProcessor<Rgba32>>(0);
}
[Fact]
public void DrawForEachACharachterWhenPenSetAndFillFroEachWhenBrushSet()
{
this.operations.DrawText(
new TextGraphicsOptions(true),
"123",
this.Font,
Brushes.Solid(Rgba32.Red),
Pens.Dash(Rgba32.Red, 1),
this.path);
var processor = this.Verify<DrawTextOnPathProcessor<Rgba32>>(0);
}
[Fact]
public void DrawForEachACharachterWhenPenSetAndFillFroEachWhenBrushSetDefaultOptions()
{
this.operations.DrawText("123", this.Font, Brushes.Solid(Rgba32.Red), Pens.Dash(Rgba32.Red, 1), this.path);
var processor = this.Verify<DrawTextOnPathProcessor<Rgba32>>(0);
}
[Fact]
public void BrushAppliesBeforPen()
{
this.operations.DrawText(
new TextGraphicsOptions(true),
"1",
this.Font,
Brushes.Solid(Rgba32.Red),
Pens.Dash(Rgba32.Red, 1),
this.path);
var processor = this.Verify<DrawTextOnPathProcessor<Rgba32>>(0);
}
[Fact]
public void BrushAppliesBeforPenDefaultOptions()
{
this.operations.DrawText("1", this.Font, Brushes.Solid(Rgba32.Red), Pens.Dash(Rgba32.Red, 1), this.path);
var processor = this.Verify<DrawTextOnPathProcessor<Rgba32>>(0);
}
}
}

82
tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs

@ -159,88 +159,6 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text
appendSourceFileOrDescription: true);
}
[Theory]
[WithSolidFilledImages(200, 100, "White", PixelTypes.Rgba32, 50, "SixLaborsSampleAB.woff", AB)]
[WithSolidFilledImages(900, 100, "White", PixelTypes.Rgba32, 50, "OpenSans-Regular.ttf", TestText)]
public void FontShapesAreRenderedCorrectlyAlongAPath<TPixel>(
TestImageProvider<TPixel> provider,
int fontSize,
string fontName,
string text)
where TPixel : struct, IPixel<TPixel>
{
Font font = CreateFont(fontName, fontSize);
TPixel colorFill = NamedColors<TPixel>.Gray;
TPixel colorOutline = NamedColors<TPixel>.Black;
IBrush<TPixel> fillBrush = Brushes.Solid(colorFill);
IPen<TPixel> outlinePen = Pens.DashDot(colorOutline, 3);
provider.VerifyOperation(
OutlinedTextDrawingComparer,
img =>
{
IPath path = new Path(new LinearLineSegment(new Point(0, img.Height), new Point(img.Width, 0)));
img.Mutate(
c =>
{
c.DrawText(
new TextGraphicsOptions
{
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Top
},
text,
new Font(font, fontSize),
fillBrush,
outlinePen,
path);
});
},
$"pen_{fontName}-{fontSize}-{ToTestOutputDisplayText(text)}",
appendPixelTypeToFileName: false,
appendSourceFileOrDescription: true);
}
[Theory]
[WithSolidFilledImages(600, 600, "White", PixelTypes.Rgba32, 50, "OpenSans-Regular.ttf", TestText)]
public void FontShapesAreRenderedCorrectlyAlongACirclePath<TPixel>(
TestImageProvider<TPixel> provider,
int fontSize,
string fontName,
string text)
where TPixel : struct, IPixel<TPixel>
{
Font font = CreateFont(fontName, fontSize);
TPixel colorFill = NamedColors<TPixel>.Black;
IBrush<TPixel> fillBrush = Brushes.Solid(colorFill);
provider.VerifyOperation(
TextDrawingComparer,
img =>
{
int w = (int)(img.Width * 0.6);
int h = (int)(img.Height * 0.6);
IPath path = new EllipsePolygon(img.Width/2, img.Height/2, w, h);
img.Mutate(c =>
{
c.DrawText(
new TextGraphicsOptions
{
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Top
},
text,
new Font(font, fontSize),
fillBrush,
path);
});
},
$"pen_{fontName}-{fontSize}-{ToTestOutputDisplayText(text)}",
appendPixelTypeToFileName: false,
appendSourceFileOrDescription: true);
}
private static string Repeat(string str, int times) => string.Concat(Enumerable.Repeat(str, times));
private static string ToTestOutputDisplayText(string text)

Loading…
Cancel
Save