Browse Source

CachingGlyphRenderer: use a 1 dictionary instead of 3

af/merge-core
Anton Firszov 8 years ago
parent
commit
bd65fc543c
  1. 71
      src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs

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

@ -167,19 +167,19 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors
private PathBuilder builder; private PathBuilder builder;
private Point currentRenderPosition = default; private Point currentRenderPosition = default;
private GlyphRendererParameters currentRenderingGlyph = default; private GlyphRendererParameters currentGlyphRenderParams = default;
private int offset = 0; private int offset = 0;
private PointF currentPoint = default(PointF); private PointF currentPoint = default(PointF);
private HashSet<GlyphRendererParameters> renderedGlyphs = new HashSet<GlyphRendererParameters>();
private Dictionary<GlyphRendererParameters, Buffer2D<float>> glyphMap; private readonly Dictionary<GlyphRendererParameters, GlyphRenderData> glyphData = new Dictionary<GlyphRendererParameters, GlyphRenderData>();
private Dictionary<GlyphRendererParameters, Buffer2D<float>> glyphMapPen;
private bool renderOutline = false; private bool renderOutline = false;
private bool renderFill = false; private bool renderFill = false;
private bool raterizationRequired = false; private bool raterizationRequired = false;
public CachingGlyphRenderer(MemoryAllocator memoryManager, int size, IPen pen, bool renderFill) public CachingGlyphRenderer(MemoryAllocator memoryAllocator, int size, IPen pen, bool renderFill)
{ {
this.MemoryManager = memoryManager; this.MemoryAllocator = memoryAllocator;
this.Pen = pen; this.Pen = pen;
this.renderFill = renderFill; this.renderFill = renderFill;
this.renderOutline = pen != null; this.renderOutline = pen != null;
@ -187,14 +187,12 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors
if (this.renderFill) if (this.renderFill)
{ {
this.FillOperations = new List<DrawingOperation>(size); this.FillOperations = new List<DrawingOperation>(size);
this.glyphMap = new Dictionary<GlyphRendererParameters, Buffer2D<float>>();
} }
if (this.renderOutline) if (this.renderOutline)
{ {
this.offset = (int)MathF.Ceiling((pen.StrokeWidth * 2) + 2); this.offset = (int)MathF.Ceiling((pen.StrokeWidth * 2) + 2);
this.OutlineOperations = new List<DrawingOperation>(size); this.OutlineOperations = new List<DrawingOperation>(size);
this.glyphMapPen = new Dictionary<GlyphRendererParameters, Buffer2D<float>>();
} }
this.builder = new PathBuilder(); this.builder = new PathBuilder();
@ -204,7 +202,7 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors
public List<DrawingOperation> OutlineOperations { get; } public List<DrawingOperation> OutlineOperations { get; }
public MemoryAllocator MemoryManager { get; internal set; } public MemoryAllocator MemoryAllocator { get; internal set; }
public IPen Pen { get; internal set; } public IPen Pen { get; internal set; }
@ -221,8 +219,8 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors
// we have offset our rendering origion a little bit down to prevent edge cropping, move the draw origin up to compensate // we have offset our rendering origion a little bit down to prevent edge cropping, move the draw origin up to compensate
this.currentRenderPosition = new Point(this.currentRenderPosition.X - this.offset, this.currentRenderPosition.Y - this.offset); this.currentRenderPosition = new Point(this.currentRenderPosition.X - this.offset, this.currentRenderPosition.Y - this.offset);
this.currentRenderingGlyph = paramters; this.currentGlyphRenderParams = paramters;
if (this.renderedGlyphs.Contains(paramters)) if (this.glyphData.ContainsKey(paramters))
{ {
// we have already drawn the glyph vectors skip trying again // we have already drawn the glyph vectors skip trying again
this.raterizationRequired = false; this.raterizationRequired = false;
@ -254,21 +252,12 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors
public void Dispose() public void Dispose()
{ {
if (this.renderFill) foreach (KeyValuePair<GlyphRendererParameters, GlyphRenderData> kv in this.glyphData)
{ {
foreach (KeyValuePair<GlyphRendererParameters, Buffer2D<float>> m in this.glyphMap) kv.Value.Dispose();
{
m.Value.Dispose();
}
} }
if (this.renderOutline) this.glyphData.Clear();
{
foreach (KeyValuePair<GlyphRendererParameters, Buffer2D<float>> m in this.glyphMapPen)
{
m.Value.Dispose();
}
}
} }
public void EndFigure() public void EndFigure()
@ -278,13 +267,16 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors
public void EndGlyph() public void EndGlyph()
{ {
GlyphRenderData renderData = default;
// has the glyoh been rendedered already???? // has the glyoh been rendedered already????
if (this.raterizationRequired) if (this.raterizationRequired)
{ {
IPath path = this.builder.Build(); IPath path = this.builder.Build();
if (this.renderFill) if (this.renderFill)
{ {
this.glyphMap[this.currentRenderingGlyph] = this.Render(path); renderData.FillMap = this.Render(path);
} }
if (this.renderOutline) if (this.renderOutline)
@ -298,10 +290,14 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors
path = path.GenerateOutline(this.Pen.StrokeWidth, this.Pen.StrokePattern); path = path.GenerateOutline(this.Pen.StrokeWidth, this.Pen.StrokePattern);
} }
this.glyphMapPen[this.currentRenderingGlyph] = this.Render(path); renderData.OutlineMap = this.Render(path);
} }
this.renderedGlyphs.Add(this.currentRenderingGlyph); this.glyphData[this.currentGlyphRenderParams] = renderData;
}
else
{
renderData = this.glyphData[this.currentGlyphRenderParams];
} }
if (this.renderFill) if (this.renderFill)
@ -309,7 +305,7 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors
this.FillOperations.Add(new DrawingOperation this.FillOperations.Add(new DrawingOperation
{ {
Location = this.currentRenderPosition, Location = this.currentRenderPosition,
Map = this.glyphMap[this.currentRenderingGlyph] Map = renderData.FillMap
}); });
} }
@ -318,7 +314,7 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors
this.OutlineOperations.Add(new DrawingOperation this.OutlineOperations.Add(new DrawingOperation
{ {
Location = this.currentRenderPosition, Location = this.currentRenderPosition,
Map = this.glyphMapPen[this.currentRenderingGlyph] Map = renderData.OutlineMap
}); });
} }
} }
@ -341,10 +337,10 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors
} }
// take the path inside the path builder, scan thing and generate a Buffer2d representing the glyph and cache it. // take the path inside the path builder, scan thing and generate a Buffer2d representing the glyph and cache it.
Buffer2D<float> fullBuffer = this.MemoryManager.Allocate2D<float>(size.Width + 1, size.Height + 1, true); Buffer2D<float> fullBuffer = this.MemoryAllocator.Allocate2D<float>(size.Width + 1, size.Height + 1, true);
using (IBuffer<float> bufferBacking = this.MemoryManager.Allocate<float>(path.MaxIntersections)) using (IBuffer<float> bufferBacking = this.MemoryAllocator.Allocate<float>(path.MaxIntersections))
using (IBuffer<PointF> rowIntersectionBuffer = this.MemoryManager.Allocate<PointF>(size.Width)) using (IBuffer<PointF> rowIntersectionBuffer = this.MemoryAllocator.Allocate<PointF>(size.Width))
{ {
float subpixelFraction = 1f / subpixelCount; float subpixelFraction = 1f / subpixelCount;
float subpixelFractionPoint = subpixelFraction / subpixelCount; float subpixelFractionPoint = subpixelFraction / subpixelCount;
@ -457,6 +453,19 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors
this.builder.AddBezier(this.currentPoint, secondControlPoint, point); this.builder.AddBezier(this.currentPoint, secondControlPoint, point);
this.currentPoint = point; this.currentPoint = point;
} }
private struct GlyphRenderData : IDisposable
{
public Buffer2D<float> FillMap;
public Buffer2D<float> OutlineMap;
public void Dispose()
{
this.FillMap?.Dispose();
this.OutlineMap?.Dispose();
}
}
} }
} }
} }
Loading…
Cancel
Save