Skip to content

Commit 6e61579

Browse files
committed
wip : Enable rich text
1 parent 5d46d68 commit 6e61579

17 files changed

Lines changed: 159 additions & 59 deletions

File tree

ImageSharp.Drawing.sln

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,9 +334,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{5286
334334
EndProject
335335
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DrawShapesWithImageSharp", "samples\DrawShapesWithImageSharp\DrawShapesWithImageSharp.csproj", "{5493F024-0A3F-420C-AC2D-05B77A36025B}"
336336
EndProject
337+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SixLabors.Fonts", "..\Fonts\src\SixLabors.Fonts\SixLabors.Fonts.csproj", "{4D91946D-29EC-4F16-958C-DFEE706363CE}"
338+
EndProject
337339
Global
338340
GlobalSection(SharedMSBuildProjectFiles) = preSolution
339341
shared-infrastructure\src\SharedInfrastructure\SharedInfrastructure.projitems*{2e33181e-6e28-4662-a801-e2e7dc206029}*SharedItemsImports = 5
342+
..\Fonts\shared-infrastructure\src\SharedInfrastructure\SharedInfrastructure.projitems*{4d91946d-29ec-4f16-958c-dfee706363ce}*SharedItemsImports = 5
340343
shared-infrastructure\src\SharedInfrastructure\SharedInfrastructure.projitems*{68a8cc40-6aed-4e96-b524-31b1158fdeea}*SharedItemsImports = 13
341344
EndGlobalSection
342345
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -360,6 +363,10 @@ Global
360363
{5493F024-0A3F-420C-AC2D-05B77A36025B}.Debug|Any CPU.Build.0 = Debug|Any CPU
361364
{5493F024-0A3F-420C-AC2D-05B77A36025B}.Release|Any CPU.ActiveCfg = Release|Any CPU
362365
{5493F024-0A3F-420C-AC2D-05B77A36025B}.Release|Any CPU.Build.0 = Release|Any CPU
366+
{4D91946D-29EC-4F16-958C-DFEE706363CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
367+
{4D91946D-29EC-4F16-958C-DFEE706363CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
368+
{4D91946D-29EC-4F16-958C-DFEE706363CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
369+
{4D91946D-29EC-4F16-958C-DFEE706363CE}.Release|Any CPU.Build.0 = Release|Any CPU
363370
EndGlobalSection
364371
GlobalSection(SolutionProperties) = preSolution
365372
HideSolutionNode = FALSE

samples/DrawShapesWithImageSharp/Program.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ private static void DrawText(string text)
6565
{
6666
FontFamily fam = SystemFonts.Get("Arial");
6767
var font = new Font(fam, 30);
68-
TextOptions textOptions = new(font);
68+
TextDrawingOptions textOptions = new(font);
6969
IPathCollection glyphs = TextBuilder.GenerateGlyphs(text, textOptions);
7070

7171
glyphs.SaveImage("Text", text + ".png");
@@ -75,7 +75,7 @@ private static void DrawText(string text, IPath path)
7575
{
7676
FontFamily fam = SystemFonts.Get("Arial");
7777
var font = new Font(fam, 30);
78-
TextOptions textOptions = new(font)
78+
TextDrawingOptions textOptions = new(font)
7979
{
8080
WrappingLength = path.ComputeLength(),
8181
VerticalAlignment = VerticalAlignment.Top,

src/ImageSharp.Drawing/ImageSharp.Drawing.csproj

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,14 @@
2020
</ItemGroup>
2121

2222
<ItemGroup>
23-
<PackageReference Include="SixLabors.Fonts" Version="1.0.0-beta16" />
23+
<!--<PackageReference Include="SixLabors.Fonts" Version="1.0.0-beta16" />-->
2424
<PackageReference Include="SixLabors.ImageSharp" Version="2.0.0" />
2525
</ItemGroup>
2626

27+
<ItemGroup>
28+
<ProjectReference Include="..\..\..\Fonts\src\SixLabors.Fonts\SixLabors.Fonts.csproj" />
29+
</ItemGroup>
30+
2731
<Import Project="..\..\shared-infrastructure\src\SharedInfrastructure\SharedInfrastructure.projitems" Label="Shared" />
2832

2933
</Project>

src/ImageSharp.Drawing/Processing/Extensions/DrawTextExtensions.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public static IImageProcessingContext DrawText(
5858
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
5959
public static IImageProcessingContext DrawText(
6060
this IImageProcessingContext source,
61-
TextOptions textOptions,
61+
TextDrawingOptions textOptions,
6262
string text,
6363
Color color) =>
6464
source.DrawText(textOptions, text, Brushes.Solid(color), null);
@@ -115,7 +115,7 @@ public static IImageProcessingContext DrawText(
115115
IPen pen,
116116
PointF location)
117117
{
118-
TextOptions textOptions = new(font) { Origin = location };
118+
TextDrawingOptions textOptions = new(font) { Origin = location };
119119
return source.DrawText(textOptions, text, brush, pen);
120120
}
121121

@@ -129,7 +129,7 @@ public static IImageProcessingContext DrawText(
129129
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
130130
public static IImageProcessingContext DrawText(
131131
this IImageProcessingContext source,
132-
TextOptions textOptions,
132+
TextDrawingOptions textOptions,
133133
string text,
134134
IBrush brush) =>
135135
source.DrawText(source.GetDrawingOptions(), textOptions, text, brush, null);
@@ -144,7 +144,7 @@ public static IImageProcessingContext DrawText(
144144
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
145145
public static IImageProcessingContext DrawText(
146146
this IImageProcessingContext source,
147-
TextOptions textOptions,
147+
TextDrawingOptions textOptions,
148148
string text,
149149
IPen pen) =>
150150
source.DrawText(source.GetDrawingOptions(), textOptions, text, null, pen);
@@ -160,7 +160,7 @@ public static IImageProcessingContext DrawText(
160160
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
161161
public static IImageProcessingContext DrawText(
162162
this IImageProcessingContext source,
163-
TextOptions textOptions,
163+
TextDrawingOptions textOptions,
164164
string text,
165165
IBrush brush,
166166
IPen pen) =>
@@ -224,7 +224,7 @@ public static IImageProcessingContext DrawText(
224224
IPen pen,
225225
PointF location)
226226
{
227-
TextOptions textOptions = new(font) { Origin = location };
227+
TextDrawingOptions textOptions = new(font) { Origin = location };
228228
return source.ApplyProcessor(new DrawTextProcessor(drawingOptions, textOptions, text, brush, pen));
229229
}
230230

@@ -241,7 +241,7 @@ public static IImageProcessingContext DrawText(
241241
public static IImageProcessingContext DrawText(
242242
this IImageProcessingContext source,
243243
DrawingOptions drawingOptions,
244-
TextOptions textOptions,
244+
TextDrawingOptions textOptions,
245245
string text,
246246
IBrush brush,
247247
IPen pen)

src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public class DrawTextProcessor : IImageProcessor
2121
/// <param name="text">The text we want to render</param>
2222
/// <param name="brush">The brush to source pixel colors from.</param>
2323
/// <param name="pen">The pen to outline text with.</param>
24-
public DrawTextProcessor(DrawingOptions drawingOptions, TextOptions textOptions, string text, IBrush brush, IPen pen)
24+
public DrawTextProcessor(DrawingOptions drawingOptions, TextDrawingOptions textOptions, string text, IBrush brush, IPen pen)
2525
{
2626
Guard.NotNull(text, nameof(text));
2727
if (brush is null && pen is null)
@@ -47,9 +47,9 @@ public DrawTextProcessor(DrawingOptions drawingOptions, TextOptions textOptions,
4747
public DrawingOptions DrawingOptions { get; }
4848

4949
/// <summary>
50-
/// Gets the <see cref="Fonts.TextOptions"/> defining text-specific drawing settings.
50+
/// Gets the <see cref="Fonts.TextDrawingOptions"/> defining text-specific drawing settings.
5151
/// </summary>
52-
public TextOptions TextOptions { get; }
52+
public TextDrawingOptions TextOptions { get; }
5353

5454
/// <summary>
5555
/// Gets the text to draw.

src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ protected override void BeforeImageApply()
3737
this.definition.Text.Length,
3838
this.definition.TextOptions,
3939
this.definition.Pen,
40-
this.definition.Brush != null,
40+
this.definition.Brush,
4141
this.definition.DrawingOptions.Transform)
4242
{
4343
Options = this.definition.DrawingOptions
@@ -149,6 +149,8 @@ private struct DrawingOperation
149149
public Point Location { get; set; }
150150

151151
public Color? Color { get; set; }
152+
153+
public IBrush Brush { get; internal set; }
152154
}
153155

154156
private class CachingGlyphRenderer : IColorGlyphRenderer, IDisposable
@@ -167,31 +169,22 @@ private class CachingGlyphRenderer : IColorGlyphRenderer, IDisposable
167169
private readonly int offset;
168170
private PointF currentPoint;
169171
private Color? currentColor;
172+
private IBrush? currentBrush;
173+
private IPen? currentPen;
170174

171175
private readonly Dictionary<(GlyphRendererParameters Glyph, PointF SubPixelOffset), GlyphRenderData> glyphData = new();
172176

173-
private readonly bool renderOutline;
174-
private readonly bool renderFill;
175177
private bool rasterizationRequired;
176178

177-
public CachingGlyphRenderer(MemoryAllocator memoryAllocator, int size, TextOptions textOptions, IPen pen, bool renderFill, Matrix3x2 transform)
179+
public CachingGlyphRenderer(MemoryAllocator memoryAllocator, int size, TextDrawingOptions textOptions, IPen pen, IBrush brush, Matrix3x2 transform)
178180
{
179181
this.MemoryAllocator = memoryAllocator;
180182
this.currentRenderPosition = default;
181183
this.Pen = pen;
182-
this.renderFill = renderFill;
183-
this.renderOutline = pen != null;
184+
this.Brush = brush;
184185
this.offset = (int)textOptions.Font.Size;
185-
if (this.renderFill)
186-
{
187-
this.FillOperations = new List<DrawingOperation>(size);
188-
}
189-
190-
if (this.renderOutline)
191-
{
192-
this.OutlineOperations = new List<DrawingOperation>(size);
193-
}
194-
186+
this.FillOperations = new List<DrawingOperation>(size);
187+
this.OutlineOperations = new List<DrawingOperation>(size);
195188
this.transform = transform;
196189
this.builder = new PathBuilder();
197190
}
@@ -204,6 +197,8 @@ public CachingGlyphRenderer(MemoryAllocator memoryAllocator, int size, TextOptio
204197

205198
public IPen Pen { get; internal set; }
206199

200+
public IBrush Brush { get; internal set; }
201+
207202
public DrawingOptions Options { get; internal set; }
208203

209204
protected void SetLayerColor(Color color) => this.currentColor = color;
@@ -215,6 +210,18 @@ public CachingGlyphRenderer(MemoryAllocator memoryAllocator, int size, TextOptio
215210
public bool BeginGlyph(FontRectangle bounds, GlyphRendererParameters parameters)
216211
{
217212
this.currentColor = null;
213+
214+
if (parameters.TextRun is TextDrawingRun drawingRun)
215+
{
216+
this.currentBrush = drawingRun.Brush;
217+
this.currentPen = drawingRun.Pen;
218+
}
219+
else
220+
{
221+
this.currentBrush = null;
222+
this.currentPen = null;
223+
}
224+
218225
RectangleF currentBounds = new RectangularPolygon(bounds.X, bounds.Y, bounds.Width, bounds.Height)
219226
.Transform(this.transform)
220227
.Bounds;
@@ -292,21 +299,23 @@ public void EndGlyph()
292299
// If we are using the fonts color layers we ignore the request to draw an outline only
293300
// cause that wont really work and instead force drawing with fill with the requested color
294301
// if color fonts disabled then this.currentColor will always be null
295-
if (this.renderFill || this.currentColor != null)
302+
var brush = this.Brush ?? this.currentBrush;
303+
if (brush != null || this.currentColor != null)
296304
{
297305
renderData.FillMap = this.Render(path);
298306
renderData.Color = this.currentColor;
299307
}
300308

301-
if (this.renderOutline && this.currentColor == null)
309+
var pen = this.currentPen ?? this.Pen;
310+
if (pen != null && this.currentColor == null)
302311
{
303-
if (this.Pen.StrokePattern.Length == 0)
312+
if (pen.StrokePattern.Length == 0)
304313
{
305-
path = path.GenerateOutline(this.Pen.StrokeWidth);
314+
path = path.GenerateOutline(pen.StrokeWidth);
306315
}
307316
else
308317
{
309-
path = path.GenerateOutline(this.Pen.StrokeWidth, this.Pen.StrokePattern, this.Pen.JointStyle, this.Pen.EndCapStyle);
318+
path = path.GenerateOutline(pen.StrokeWidth, pen.StrokePattern, pen.JointStyle, pen.EndCapStyle);
310319
}
311320

312321
renderData.OutlineMap = this.Render(path);
@@ -325,7 +334,8 @@ public void EndGlyph()
325334
{
326335
Location = this.currentRenderPosition,
327336
Map = renderData.FillMap,
328-
Color = renderData.Color
337+
Color = this.currentColor,
338+
Brush = this.currentBrush,
329339
});
330340
}
331341

@@ -334,7 +344,8 @@ public void EndGlyph()
334344
this.OutlineOperations.Add(new DrawingOperation
335345
{
336346
Location = this.currentRenderPosition,
337-
Map = renderData.OutlineMap
347+
Map = renderData.OutlineMap,
348+
Brush = this.currentPen?.StrokeFill,
338349
});
339350
}
340351
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Apache License, Version 2.0.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Text;
7+
using SixLabors.Fonts;
8+
using SixLabors.ImageSharp.Drawing.Processing;
9+
10+
namespace SixLabors.Fonts
11+
{
12+
public class TextDrawingOptions : TextOptions
13+
{
14+
public TextDrawingOptions(Font font)
15+
: base(font)
16+
{
17+
}
18+
19+
public TextDrawingOptions(TextDrawingOptions options)
20+
: base(options)
21+
{
22+
}
23+
24+
public new IReadOnlyList<TextDrawingRun> TextRuns
25+
{
26+
get => (IReadOnlyList<TextDrawingRun>)base.TextRuns;
27+
set => base.TextRuns = value;
28+
}
29+
}
30+
31+
public class TextDrawingRun : TextRun
32+
{
33+
public IBrush Brush { get; set; }
34+
35+
public IPen Pen { get; set; }
36+
37+
public TextDrawingRun()
38+
{
39+
}
40+
}
41+
}

src/ImageSharp.Drawing/Shapes/Text/TextBuilder.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public static class TextBuilder
1717
/// <param name="text">The text to generate glyphs for.</param>
1818
/// <param name="textOptions">The text rendering options.</param>
1919
/// <returns>The <see cref="IPathCollection"/></returns>
20-
public static IPathCollection GenerateGlyphs(string text, TextOptions textOptions)
20+
public static IPathCollection GenerateGlyphs(string text, TextDrawingOptions textOptions)
2121
{
2222
GlyphBuilder glyphBuilder = new();
2323
TextRenderer renderer = new(glyphBuilder);
@@ -34,7 +34,7 @@ public static IPathCollection GenerateGlyphs(string text, TextOptions textOption
3434
/// <param name="path">The path to draw the text in relation to</param>
3535
/// <param name="textOptions">The text rendering options.</param>
3636
/// <returns>The <see cref="IPathCollection"/></returns>
37-
public static IPathCollection GenerateGlyphs(string text, IPath path, TextOptions textOptions)
37+
public static IPathCollection GenerateGlyphs(string text, IPath path, TextDrawingOptions textOptions)
3838
{
3939
PathGlyphBuilder glyphBuilder = new(path);
4040
TextRenderer renderer = new(glyphBuilder);

tests/ImageSharp.Drawing.Benchmarks/Drawing/DrawText.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public void SystemDrawing()
8080
[Benchmark]
8181
public void ImageSharp()
8282
{
83-
TextOptions textOptions = new(this.font)
83+
TextDrawingOptions textOptions = new(this.font)
8484
{
8585
WrappingLength = 780,
8686
Origin = new PointF(10, 10)

tests/ImageSharp.Drawing.Benchmarks/Drawing/DrawTextOutline.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public void DrawTextCore()
5353
{
5454
using var image = new Image<Rgba32>(800, 800);
5555
Fonts.Font font = Fonts.SystemFonts.CreateFont("Arial", 12);
56-
TextOptions textOptions = new(font)
56+
TextDrawingOptions textOptions = new(font)
5757
{
5858
WrappingLength = 780,
5959
Origin = new PointF(10, 10)
@@ -71,7 +71,7 @@ public void DrawTextCoreOld()
7171
using (var image = new Image<Rgba32>(800, 800))
7272
{
7373
Fonts.Font font = Fonts.SystemFonts.CreateFont("Arial", 12);
74-
TextOptions textOptions = new(font)
74+
TextDrawingOptions textOptions = new(font)
7575
{
7676
WrappingLength = 780,
7777
Origin = new PointF(10, 10)
@@ -90,7 +90,7 @@ public void DrawTextCoreOld()
9090
static IImageProcessingContext DrawTextOldVersion(
9191
IImageProcessingContext source,
9292
DrawingOptions options,
93-
TextOptions textOptions,
93+
TextDrawingOptions textOptions,
9494
string text,
9595
IBrush brush,
9696
IPen pen)

0 commit comments

Comments
 (0)