Browse Source

Merge pull request #124 from JimBobSquarePants/font-render

Add ImageSharp.Drawing.Text package
pull/112/merge
Scott Williams 9 years ago
committed by GitHub
parent
commit
05bcdf6ed4
  1. 7
      ImageSharp.sln
  2. 203
      src/ImageSharp.Drawing.Text/DrawText.cs
  3. 126
      src/ImageSharp.Drawing.Text/GlyphBuilder.cs
  4. 25
      src/ImageSharp.Drawing.Text/ImageSharp.Drawing.Text.xproj
  5. 6
      src/ImageSharp.Drawing.Text/Properties/AssemblyInfo.cs
  6. 68
      src/ImageSharp.Drawing.Text/TextGraphicsOptions.cs
  7. 95
      src/ImageSharp.Drawing.Text/project.json
  8. 194
      tests/ImageSharp.Tests/Drawing/Text/DrawText.cs
  9. 68
      tests/ImageSharp.Tests/Drawing/Text/GlyphBuilder.cs
  10. 41
      tests/ImageSharp.Tests/Drawing/Text/OutputText.cs
  11. 90
      tests/ImageSharp.Tests/TestFont.cs
  12. BIN
      tests/ImageSharp.Tests/TestFonts/SixLaborsSampleAB.woff
  13. 3
      tests/ImageSharp.Tests/project.json

7
ImageSharp.sln

@ -68,6 +68,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageSharp.Sandbox46", "tes
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ImageSharp.Drawing.Paths", "src\ImageSharp.Drawing.Paths\ImageSharp.Drawing.Paths.xproj", "{E5BD4F96-28A8-410C-8B63-1C5731948549}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ImageSharp.Drawing.Text", "src\ImageSharp.Drawing.Text\ImageSharp.Drawing.Text.xproj", "{329D7698-65BC-48AD-A16F-428682964493}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -122,6 +124,10 @@ Global
{E5BD4F96-28A8-410C-8B63-1C5731948549}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E5BD4F96-28A8-410C-8B63-1C5731948549}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E5BD4F96-28A8-410C-8B63-1C5731948549}.Release|Any CPU.Build.0 = Release|Any CPU
{329D7698-65BC-48AD-A16F-428682964493}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{329D7698-65BC-48AD-A16F-428682964493}.Debug|Any CPU.Build.0 = Debug|Any CPU
{329D7698-65BC-48AD-A16F-428682964493}.Release|Any CPU.ActiveCfg = Release|Any CPU
{329D7698-65BC-48AD-A16F-428682964493}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -140,5 +146,6 @@ Global
{9E574A07-F879-4811-9C41-5CBDC6BAFDB7} = {815C0625-CD3D-440F-9F80-2D83856AB7AE}
{96188137-5FA6-4924-AB6E-4EFF79C6E0BB} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC}
{E5BD4F96-28A8-410C-8B63-1C5731948549} = {815C0625-CD3D-440F-9F80-2D83856AB7AE}
{329D7698-65BC-48AD-A16F-428682964493} = {815C0625-CD3D-440F-9F80-2D83856AB7AE}
EndGlobalSection
EndGlobal

203
src/ImageSharp.Drawing.Text/DrawText.cs

@ -0,0 +1,203 @@
// <copyright file="DrawText.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Numerics;
using Drawing;
using Drawing.Brushes;
using Drawing.Pens;
using SixLabors.Fonts;
/// <summary>
/// Extension methods for the <see cref="Image{TColor}"/> type.
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Draws the text onto the the image filled via the brush.
/// </summary>
/// <typeparam name="TColor">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="location">The location.</param>
/// <returns>
/// The <see cref="Image{TColor}" />.
/// </returns>
public static Image<TColor> DrawText<TColor>(this Image<TColor> source, string text, Font font, TColor color, Vector2 location)
where TColor : struct, IPixel<TColor>
{
return source.DrawText(text, font, color, location, TextGraphicsOptions.Default);
}
/// <summary>
/// Draws the text onto the the image filled via the brush.
/// </summary>
/// <typeparam name="TColor">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="location">The location.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The <see cref="Image{TColor}" />.
/// </returns>
public static Image<TColor> DrawText<TColor>(this Image<TColor> source, string text, Font font, TColor color, Vector2 location, TextGraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.DrawText(text, font, Brushes<TColor>.Solid(color), null, location, options);
}
/// <summary>
/// Draws the text onto the the image filled via the brush.
/// </summary>
/// <typeparam name="TColor">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="location">The location.</param>
/// <returns>
/// The <see cref="Image{TColor}" />.
/// </returns>
public static Image<TColor> DrawText<TColor>(this Image<TColor> source, string text, Font font, IBrush<TColor> brush, Vector2 location)
where TColor : struct, IPixel<TColor>
{
return source.DrawText(text, font, brush, location, TextGraphicsOptions.Default);
}
/// <summary>
/// Draws the text onto the the image filled via the brush.
/// </summary>
/// <typeparam name="TColor">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="location">The location.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The <see cref="Image{TColor}" />.
/// </returns>
public static Image<TColor> DrawText<TColor>(this Image<TColor> source, string text, Font font, IBrush<TColor> brush, Vector2 location, TextGraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.DrawText(text, font, brush, null, location, options);
}
/// <summary>
/// Draws the text onto the the image outlined via the pen.
/// </summary>
/// <typeparam name="TColor">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="location">The location.</param>
/// <returns>
/// The <see cref="Image{TColor}" />.
/// </returns>
public static Image<TColor> DrawText<TColor>(this Image<TColor> source, string text, Font font, IPen<TColor> pen, Vector2 location)
where TColor : struct, IPixel<TColor>
{
return source.DrawText(text, font, pen, location, TextGraphicsOptions.Default);
}
/// <summary>
/// Draws the text onto the the image outlined via the pen.
/// </summary>
/// <typeparam name="TColor">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="location">The location.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The <see cref="Image{TColor}" />.
/// </returns>
public static Image<TColor> DrawText<TColor>(this Image<TColor> source, string text, Font font, IPen<TColor> pen, Vector2 location, TextGraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.DrawText(text, font, null, pen, location, options);
}
/// <summary>
/// Draws the text onto the the image filled via the brush then outlined via the pen.
/// </summary>
/// <typeparam name="TColor">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="location">The location.</param>
/// <returns>
/// The <see cref="Image{TColor}" />.
/// </returns>
public static Image<TColor> DrawText<TColor>(this Image<TColor> source, string text, Font font, IBrush<TColor> brush, IPen<TColor> pen, Vector2 location)
where TColor : struct, IPixel<TColor>
{
return source.DrawText(text, font, brush, pen, location, TextGraphicsOptions.Default);
}
/// <summary>
/// Draws the text onto the the image filled via the brush then outlined via the pen.
/// </summary>
/// <typeparam name="TColor">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="location">The location.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The <see cref="Image{TColor}" />.
/// </returns>
public static Image<TColor> DrawText<TColor>(this Image<TColor> source, string text, Font font, IBrush<TColor> brush, IPen<TColor> pen, Vector2 location, TextGraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
GlyphBuilder glyphBuilder = new GlyphBuilder(location);
TextRenderer renderer = new TextRenderer(glyphBuilder);
Vector2 dpi = new Vector2((float)source.MetaData.HorizontalResolution, (float)source.MetaData.VerticalResolution);
FontSpan style = new FontSpan(font)
{
ApplyKerning = options.ApplyKerning,
TabWidth = options.TabWidth
};
renderer.RenderText(text, style, dpi);
System.Collections.Generic.IEnumerable<SixLabors.Shapes.IPath> shapesToDraw = glyphBuilder.Paths;
GraphicsOptions pathOptions = (GraphicsOptions)options;
if (brush != null)
{
foreach (SixLabors.Shapes.IPath s in shapesToDraw)
{
source.Fill(brush, s, pathOptions);
}
}
if (pen != null)
{
foreach (SixLabors.Shapes.IPath s in shapesToDraw)
{
source.Draw(pen, s, pathOptions);
}
}
return source;
}
}
}

126
src/ImageSharp.Drawing.Text/GlyphBuilder.cs

@ -0,0 +1,126 @@
// <copyright file="GlyphBuilder.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing
{
using System.Collections.Generic;
using System.Numerics;
using SixLabors.Fonts;
using SixLabors.Shapes;
/// <summary>
/// rendering surface that Fonts can use to generate Shapes.
/// </summary>
internal class GlyphBuilder : IGlyphRenderer
{
private readonly PathBuilder builder = new PathBuilder();
private readonly List<IPath> paths = new List<IPath>();
private Vector2 currentPoint = default(Vector2);
/// <summary>
/// Initializes a new instance of the <see cref="GlyphBuilder"/> class.
/// </summary>
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();
}
/// <summary>
/// Initializes a new instance of the <see cref="GlyphBuilder"/> class.
/// </summary>
/// <param name="origin">The origin.</param>
public GlyphBuilder(Vector2 origin)
{
this.builder = new PathBuilder();
this.builder.SetOrigin(origin);
}
/// <summary>
/// Gets the paths that have been rendered by this.
/// </summary>
public IEnumerable<IPath> Paths => this.paths;
/// <summary>
/// Begins the glyph.
/// </summary>
void IGlyphRenderer.BeginGlyph()
{
this.builder.Clear();
}
/// <summary>
/// Begins the figure.
/// </summary>
void IGlyphRenderer.BeginFigure()
{
this.builder.StartFigure();
}
/// <summary>
/// Draws a cubic bezier from the current point to the <paramref name="point"/>
/// </summary>
/// <param name="secondControlPoint">The second control point.</param>
/// <param name="thirdControlPoint">The third control point.</param>
/// <param name="point">The point.</param>
void IGlyphRenderer.CubicBezierTo(Vector2 secondControlPoint, Vector2 thirdControlPoint, Vector2 point)
{
this.builder.AddBezier(this.currentPoint, secondControlPoint, thirdControlPoint, point);
this.currentPoint = point;
}
/// <summary>
/// Ends the glyph.
/// </summary>
void IGlyphRenderer.EndGlyph()
{
this.paths.Add(this.builder.Build());
}
/// <summary>
/// Ends the figure.
/// </summary>
void IGlyphRenderer.EndFigure()
{
this.builder.CloseFigure();
}
/// <summary>
/// Draws a line from the current point to the <paramref name="point"/>.
/// </summary>
/// <param name="point">The point.</param>
void IGlyphRenderer.LineTo(Vector2 point)
{
this.builder.AddLine(this.currentPoint, point);
this.currentPoint = point;
}
/// <summary>
/// Moves to current point to the supplied vector.
/// </summary>
/// <param name="point">The point.</param>
void IGlyphRenderer.MoveTo(Vector2 point)
{
this.builder.StartFigure();
this.currentPoint = point;
}
/// <summary>
/// Draws a quadratics bezier from the current point to the <paramref name="point"/>
/// </summary>
/// <param name="secondControlPoint">The second control point.</param>
/// <param name="point">The point.</param>
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;
}
}
}

25
src/ImageSharp.Drawing.Text/ImageSharp.Drawing.Text.xproj

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>329d7698-65bc-48ad-a16f-428682964493</ProjectGuid>
<RootNamespace>ImageSharp.Drawing</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<ProduceOutputsOnBuild>True</ProduceOutputsOnBuild>
</PropertyGroup>
<ItemGroup>
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
</ItemGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

6
src/ImageSharp.Drawing.Text/Properties/AssemblyInfo.cs

@ -0,0 +1,6 @@
// <copyright file="AssemblyInfo.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// Common values read from `AssemblyInfo.Common.cs`

68
src/ImageSharp.Drawing.Text/TextGraphicsOptions.cs

@ -0,0 +1,68 @@
// <copyright file="TextGraphicsOptions.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing
{
/// <summary>
/// Options for influencing the drawing functions.
/// </summary>
public struct TextGraphicsOptions
{
/// <summary>
/// Represents the default <see cref="TextGraphicsOptions"/>.
/// </summary>
public static readonly TextGraphicsOptions Default = new TextGraphicsOptions(true);
/// <summary>
/// Whether antialiasing should be applied.
/// </summary>
public bool Antialias;
/// <summary>
/// Whether the text should be drawing with kerning enabled.
/// </summary>
public bool ApplyKerning;
/// <summary>
/// The number of space widths a tab should lock to.
/// </summary>
public float TabWidth;
/// <summary>
/// Initializes a new instance of the <see cref="TextGraphicsOptions" /> struct.
/// </summary>
/// <param name="enableAntialiasing">If set to <c>true</c> [enable antialiasing].</param>
public TextGraphicsOptions(bool enableAntialiasing)
{
this.Antialias = enableAntialiasing;
this.ApplyKerning = true;
this.TabWidth = 4;
}
/// <summary>
/// Performs an implicit conversion from <see cref="GraphicsOptions"/> to <see cref="TextGraphicsOptions"/>.
/// </summary>
/// <param name="options">The options.</param>
/// <returns>
/// The result of the conversion.
/// </returns>
public static implicit operator TextGraphicsOptions(GraphicsOptions options)
{
return new TextGraphicsOptions(options.Antialias);
}
/// <summary>
/// Performs an explicit conversion from <see cref="TextGraphicsOptions"/> to <see cref="GraphicsOptions"/>.
/// </summary>
/// <param name="options">The options.</param>
/// <returns>
/// The result of the conversion.
/// </returns>
public static explicit operator GraphicsOptions(TextGraphicsOptions options)
{
return new GraphicsOptions(options.Antialias);
}
}
}

95
src/ImageSharp.Drawing.Text/project.json

@ -0,0 +1,95 @@
{
"version": "1.0.0-alpha2-*",
"title": "ImageSharp.Drawing.Text",
"description": "A cross-platform library for the processing of image files; written in C#",
"authors": [
"James Jackson-South and contributors"
],
"packOptions": {
"owners": [
"James Jackson-South and contributors"
],
"projectUrl": "https://github.com/JimBobSquarePants/ImageSharp",
"licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0",
"iconUrl": "https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/build/icons/imagesharp-logo-128.png",
"requireLicenseAcceptance": false,
"repository": {
"type": "git",
"url": "https://github.com/JimBobSquarePants/ImageSharp"
},
"tags": [
"Image Resize Crop Gif Jpg Jpeg Bitmap Png Core"
]
},
"buildOptions": {
"allowUnsafe": true,
"xmlDoc": true,
"additionalArguments": [ "/additionalfile:../Shared/stylecop.json", "/ruleset:../../ImageSharp.ruleset" ],
"compile": [
"../Shared/*.cs"
]
},
"configurations": {
"Release": {
"buildOptions": {
"warningsAsErrors": true,
"optimize": true
}
}
},
"dependencies": {
"ImageSharp": {
"target": "project"
},
"SixLabors.Fonts": "0.1.0-alpha0001",
"ImageSharp.Drawing.Paths": {
"target": "project"
},
"StyleCop.Analyzers": {
"version": "1.0.0",
"type": "build"
},
"System.Buffers": "4.0.0",
"System.Runtime.CompilerServices.Unsafe": "4.0.0"
},
"frameworks": {
"netstandard1.1": {
"dependencies": {
"System.Collections": "4.0.11",
"System.Diagnostics.Debug": "4.0.11",
"System.Diagnostics.Tools": "4.0.1",
"System.IO": "4.1.0",
"System.IO.Compression": "4.1.0",
"System.Linq": "4.1.0",
"System.Numerics.Vectors": "4.1.1",
"System.ObjectModel": "4.0.12",
"System.Resources.ResourceManager": "4.0.1",
"System.Runtime.Extensions": "4.1.0",
"System.Runtime.InteropServices": "4.1.0",
"System.Runtime.Numerics": "4.0.1",
"System.Text.Encoding.Extensions": "4.0.11",
"System.Threading": "4.0.11",
"System.Threading.Tasks": "4.0.11",
"System.Threading.Tasks.Parallel": "4.0.1"
}
},
"net45": {
"dependencies": {
"System.Numerics.Vectors": "4.1.1",
"System.Threading.Tasks.Parallel": "4.0.0"
},
"frameworkAssemblies": {
"System.Runtime": { "type": "build" }
}
},
"net461": {
"dependencies": {
"System.Threading.Tasks.Parallel": "4.0.0"
},
"frameworkAssemblies": {
"System.Runtime": { "type": "build" },
"System.Numerics": "4.0.0.0"
}
}
}
}

194
tests/ImageSharp.Tests/Drawing/Text/DrawText.cs

@ -0,0 +1,194 @@

namespace ImageSharp.Tests.Drawing.Text
{
using System;
using System.IO;
using ImageSharp;
using ImageSharp.Drawing.Brushes;
using Processing;
using System.Collections.Generic;
using Xunit;
using ImageSharp.Drawing;
using System.Numerics;
using SixLabors.Shapes;
using ImageSharp.Drawing.Processors;
using ImageSharp.Drawing.Pens;
using SixLabors.Fonts;
using Paths;
public class DrawText : IDisposable
{
Color color = Color.HotPink;
SolidBrush brush = Brushes.Solid(Color.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()
{
this.FontCollection = new FontCollection();
this.Font = FontCollection.Install(TestFontUtilities.GetPath("SixLaborsSampleAB.woff"));
this.img = new ProcessorWatchingImage(10, 10);
}
public void Dispose()
{
img.Dispose();
}
[Fact]
public void FillsForEachACharachterWhenBrushSetAndNotPen()
{
img.DrawText("123", this.Font, Brushes.Solid(Color.Red), null, Vector2.Zero, new TextGraphicsOptions(true));
Assert.NotEmpty(img.ProcessorApplications);
Assert.Equal(3, img.ProcessorApplications.Count); // 3 fills where applied
Assert.IsType<FillRegionProcessor<Color>>(img.ProcessorApplications[0].processor);
}
[Fact]
public void FillsForEachACharachterWhenBrushSetAndNotPenDefaultOptions()
{
img.DrawText("123", this.Font, Brushes.Solid(Color.Red), null, Vector2.Zero);
Assert.NotEmpty(img.ProcessorApplications);
Assert.Equal(3, img.ProcessorApplications.Count); // 3 fills where applied
Assert.IsType<FillRegionProcessor<Color>>(img.ProcessorApplications[0].processor);
}
[Fact]
public void FillsForEachACharachterWhenBrushSet()
{
img.DrawText("123", this.Font, Brushes.Solid(Color.Red), Vector2.Zero, new TextGraphicsOptions(true));
Assert.NotEmpty(img.ProcessorApplications);
Assert.Equal(3, img.ProcessorApplications.Count); // 3 fills where applied
Assert.IsType<FillRegionProcessor<Color>>(img.ProcessorApplications[0].processor);
}
[Fact]
public void FillsForEachACharachterWhenBrushSetDefaultOptions()
{
img.DrawText("123", this.Font, Brushes.Solid(Color.Red), Vector2.Zero);
Assert.NotEmpty(img.ProcessorApplications);
Assert.Equal(3, img.ProcessorApplications.Count); // 3 fills where applied
Assert.IsType<FillRegionProcessor<Color>>(img.ProcessorApplications[0].processor);
}
[Fact]
public void FillsForEachACharachterWhenColorSet()
{
img.DrawText("123", this.Font, Color.Red, Vector2.Zero, new TextGraphicsOptions(true));
Assert.NotEmpty(img.ProcessorApplications);
Assert.Equal(3, img.ProcessorApplications.Count);
FillRegionProcessor<Color> processor = Assert.IsType<FillRegionProcessor<Color>>(img.ProcessorApplications[0].processor);
SolidBrush<Color> brush = Assert.IsType<SolidBrush<Color>>(processor.Brush);
Assert.Equal(Color.Red, brush.Color);
}
[Fact]
public void FillsForEachACharachterWhenColorSetDefaultOptions()
{
img.DrawText("123", this.Font, Color.Red, Vector2.Zero);
Assert.NotEmpty(img.ProcessorApplications);
Assert.Equal(3, img.ProcessorApplications.Count);
Assert.IsType<FillRegionProcessor<Color>>(img.ProcessorApplications[0].processor);
FillRegionProcessor<Color> processor = Assert.IsType<FillRegionProcessor<Color>>(img.ProcessorApplications[0].processor);
SolidBrush<Color> brush = Assert.IsType<SolidBrush<Color>>(processor.Brush);
Assert.Equal(Color.Red, brush.Color);
}
[Fact]
public void DrawForEachACharachterWhenPenSetAndNotBrush()
{
img.DrawText("123", this.Font, null, Pens.Dash(Color.Red, 1), Vector2.Zero, new TextGraphicsOptions(true));
Assert.NotEmpty(img.ProcessorApplications);
Assert.Equal(3, img.ProcessorApplications.Count); // 3 fills where applied
Assert.IsType<DrawPathProcessor<Color>>(img.ProcessorApplications[0].processor);
}
[Fact]
public void DrawForEachACharachterWhenPenSetAndNotBrushDefaultOptions()
{
img.DrawText("123", this.Font, null, Pens.Dash(Color.Red, 1), Vector2.Zero);
Assert.NotEmpty(img.ProcessorApplications);
Assert.Equal(3, img.ProcessorApplications.Count); // 3 fills where applied
Assert.IsType<DrawPathProcessor<Color>>(img.ProcessorApplications[0].processor);
}
[Fact]
public void DrawForEachACharachterWhenPenSet()
{
img.DrawText("123", this.Font, Pens.Dash(Color.Red, 1), Vector2.Zero, new TextGraphicsOptions(true));
Assert.NotEmpty(img.ProcessorApplications);
Assert.Equal(3, img.ProcessorApplications.Count); // 3 fills where applied
Assert.IsType<DrawPathProcessor<Color>>(img.ProcessorApplications[0].processor);
}
[Fact]
public void DrawForEachACharachterWhenPenSetDefaultOptions()
{
img.DrawText("123", this.Font, Pens.Dash(Color.Red, 1), Vector2.Zero);
Assert.NotEmpty(img.ProcessorApplications);
Assert.Equal(3, img.ProcessorApplications.Count); // 3 fills where applied
Assert.IsType<DrawPathProcessor<Color>>(img.ProcessorApplications[0].processor);
}
[Fact]
public void DrawForEachACharachterWhenPenSetAndFillFroEachWhenBrushSet()
{
img.DrawText("123", this.Font, Brushes.Solid(Color.Red), Pens.Dash(Color.Red, 1), Vector2.Zero, new TextGraphicsOptions(true));
Assert.NotEmpty(img.ProcessorApplications);
Assert.Equal(6, img.ProcessorApplications.Count);
}
[Fact]
public void DrawForEachACharachterWhenPenSetAndFillFroEachWhenBrushSetDefaultOptions()
{
img.DrawText("123", this.Font, Brushes.Solid(Color.Red), Pens.Dash(Color.Red, 1), Vector2.Zero);
Assert.NotEmpty(img.ProcessorApplications);
Assert.Equal(6, img.ProcessorApplications.Count);
}
[Fact]
public void BrushAppliesBeforPen()
{
img.DrawText("1", this.Font, Brushes.Solid(Color.Red), Pens.Dash(Color.Red, 1), Vector2.Zero, new TextGraphicsOptions(true));
Assert.NotEmpty(img.ProcessorApplications);
Assert.Equal(2, img.ProcessorApplications.Count);
Assert.IsType<FillRegionProcessor<Color>>(img.ProcessorApplications[0].processor);
Assert.IsType<DrawPathProcessor<Color>>(img.ProcessorApplications[1].processor);
}
[Fact]
public void BrushAppliesBeforPenDefaultOptions()
{
img.DrawText("1", this.Font, Brushes.Solid(Color.Red), Pens.Dash(Color.Red, 1), Vector2.Zero);
Assert.NotEmpty(img.ProcessorApplications);
Assert.Equal(2, img.ProcessorApplications.Count);
Assert.IsType<FillRegionProcessor<Color>>(img.ProcessorApplications[0].processor);
Assert.IsType<DrawPathProcessor<Color>>(img.ProcessorApplications[1].processor);
}
}
}

68
tests/ImageSharp.Tests/Drawing/Text/GlyphBuilder.cs

@ -0,0 +1,68 @@

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
var fullBuilder = new GlyphBuilder(new System.Numerics.Vector2(10, 99));
IGlyphRenderer builder = fullBuilder;
builder.BeginGlyph();
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();
var 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 (var i = 0; i < 10; i++)
{
builder.BeginGlyph();
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());
}
}
}

41
tests/ImageSharp.Tests/Drawing/Text/OutputText.cs

@ -0,0 +1,41 @@

namespace ImageSharp.Tests.Drawing.Text
{
using System;
using System.IO;
using ImageSharp;
using ImageSharp.Drawing.Brushes;
using Processing;
using System.Collections.Generic;
using Xunit;
using ImageSharp.Drawing;
using System.Numerics;
using SixLabors.Shapes;
using ImageSharp.Drawing.Processors;
using ImageSharp.Drawing.Pens;
using SixLabors.Fonts;
public class OutputText : FileTestBase
{
private readonly FontCollection FontCollection;
private readonly Font Font;
public OutputText()
{
this.FontCollection = new FontCollection();
this.Font = FontCollection.Install(TestFontUtilities.GetPath("SixLaborsSampleAB.woff"));
}
[Fact]
public void DrawAB()
{
//draws 2 overlapping triangle glyphs twice 1 set on each line
using (var img = new Image(100, 200))
{
img.Fill(Color.DarkBlue)
.DrawText("AB\nAB", new Font(this.Font, 50), Color.Red, new Vector2(0, 0));
img.Save($"{this.CreateOutputDirectory("Drawing", "Text")}/AB.png");
}
}
}
}

90
tests/ImageSharp.Tests/TestFont.cs

@ -0,0 +1,90 @@
// <copyright file="TestImage.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Tests
{
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
/// <summary>
/// A test image file.
/// </summary>
public static class TestFontUtilities
{
/// <summary>
/// The formats directory.
/// </summary>
private static readonly string FormatsDirectory = GetFontsDirectory();
/// <summary>
/// Gets the full qualified path to the file.
/// </summary>
/// <param name="file">
/// The file path.
/// </param>
/// <returns>
/// The <see cref="string"/>.
/// </returns>
public static string GetPath(string file)
{
return Path.Combine(FormatsDirectory, file);
}
/// <summary>
/// Gets the correct path to the formats directory.
/// </summary>
/// <returns>
/// The <see cref="string"/>.
/// </returns>
private static string GetFontsDirectory()
{
List<string> directories = new List< string > {
"TestFonts/", // Here for code coverage tests.
"tests/ImageSharp.Tests/TestFonts/", // from travis/build script
"../../../ImageSharp.Tests/TestFonts/", // from Sandbox46
"../../../../TestFonts/"
};
directories = directories.SelectMany(x => new[]
{
Path.GetFullPath(x)
}).ToList();
AddFormatsDirectoryFromTestAssebmlyPath(directories);
var directory = directories.FirstOrDefault(x => Directory.Exists(x));
if(directory != null)
{
return directory;
}
throw new System.Exception($"Unable to find Fonts directory at any of these locations [{string.Join(", ", directories)}]");
}
/// <summary>
/// The path returned by Path.GetFullPath(x) can be relative to dotnet framework directory
/// in certain scenarios like dotTrace test profiling.
/// This method calculates and adds the format directory based on the ImageSharp.Tests assembly location.
/// </summary>
/// <param name="directories">The directories list</param>
private static void AddFormatsDirectoryFromTestAssebmlyPath(List<string> directories)
{
string assemblyLocation = typeof(TestFile).GetTypeInfo().Assembly.Location;
assemblyLocation = Path.GetDirectoryName(assemblyLocation);
if (assemblyLocation != null)
{
string dirFromAssemblyLocation = Path.Combine(assemblyLocation, "../../../TestFonts/");
dirFromAssemblyLocation = Path.GetFullPath(dirFromAssemblyLocation);
directories.Add(dirFromAssemblyLocation);
}
}
}
}

BIN
tests/ImageSharp.Tests/TestFonts/SixLaborsSampleAB.woff

Binary file not shown.

3
tests/ImageSharp.Tests/project.json

@ -31,6 +31,9 @@
"ImageSharp.Drawing.Paths": {
"target": "project"
},
"ImageSharp.Drawing.Text": {
"target": "project"
},
"ImageSharp.Formats.Png": {
"target": "project"
},

Loading…
Cancel
Save