mirror of https://github.com/SixLabors/ImageSharp
14 changed files with 928 additions and 0 deletions
@ -0,0 +1,204 @@ |
|||||
|
// <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; |
||||
|
using System.Linq; |
||||
|
|
||||
|
/// <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; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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> |
||||
@ -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`
|
||||
@ -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); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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-ci0041", |
||||
|
"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" |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Binary file not shown.
Loading…
Reference in new issue