Browse Source

additional tests around pen rendering with patterns

af/merge-core
Scott Williams 8 years ago
parent
commit
3896723bfb
  1. 35
      src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs
  2. 33
      tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs
  3. 2
      tests/Images/External

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

@ -121,11 +121,29 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors
IBuffer2D<float> buffer = operation.Map; IBuffer2D<float> buffer = operation.Map;
int startY = operation.Location.Y; int startY = operation.Location.Y;
int startX = operation.Location.X; int startX = operation.Location.X;
int offSetSpan = 0;
if (startX < 0)
{
offSetSpan = -startX;
startX = 0;
}
int fistRow = 0;
if (startY < 0)
{
fistRow = -startY;
}
int end = operation.Map.Height; int end = operation.Map.Height;
for (int row = 0; row < end; row++)
int maxHeight = source.Height - startY;
end = Math.Min(end, maxHeight);
for (int row = fistRow; row < end; row++)
{ {
int y = startY + row; int y = startY + row;
app.Apply(buffer.GetRowSpan(row), startX, y); Span<float> span = buffer.GetRowSpan(row).Slice(offSetSpan);
app.Apply(span, startX, y);
} }
} }
} }
@ -146,7 +164,7 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors
private Point currentRenderPosition = default(Point); private Point currentRenderPosition = default(Point);
private int currentRenderingGlyph = 0; private int currentRenderingGlyph = 0;
private int offset = 0;
private PointF currentPoint = default(PointF); private PointF currentPoint = default(PointF);
private HashSet<int> renderedGlyphs = new HashSet<int>(); private HashSet<int> renderedGlyphs = new HashSet<int>();
private Dictionary<int, Buffer2D<float>> glyphMap; private Dictionary<int, Buffer2D<float>> glyphMap;
@ -161,6 +179,7 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors
this.Pen = pen; this.Pen = pen;
this.renderFill = renderFill; this.renderFill = renderFill;
this.renderOutline = pen != null; this.renderOutline = pen != null;
this.offset = 2;
if (this.renderFill) if (this.renderFill)
{ {
this.FillOperations = new List<DrawingOperation>(size); this.FillOperations = new List<DrawingOperation>(size);
@ -169,6 +188,7 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors
if (this.renderOutline) if (this.renderOutline)
{ {
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<int, Buffer2D<float>>(); this.glyphMapPen = new Dictionary<int, Buffer2D<float>>();
} }
@ -194,6 +214,9 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors
public bool BeginGlyph(RectangleF bounds, int cacheKey) public bool BeginGlyph(RectangleF bounds, int cacheKey)
{ {
this.currentRenderPosition = Point.Truncate(bounds.Location); this.currentRenderPosition = Point.Truncate(bounds.Location);
// 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.currentRenderingGlyph = cacheKey; this.currentRenderingGlyph = cacheKey;
if (this.renderedGlyphs.Contains(cacheKey)) if (this.renderedGlyphs.Contains(cacheKey))
{ {
@ -206,7 +229,7 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors
this.builder.Clear(); this.builder.Clear();
// ensure all glyphs render around [zero, zero] so offset negative root positions so when we draw the glyph we can offet it back // ensure all glyphs render around [zero, zero] so offset negative root positions so when we draw the glyph we can offet it back
this.builder.SetOrigin(new PointF(-(int)bounds.X, -(int)bounds.Y)); this.builder.SetOrigin(new PointF(-(int)bounds.X + this.offset, -(int)bounds.Y + this.offset));
this.raterizationRequired = true; this.raterizationRequired = true;
return true; return true;
@ -298,7 +321,9 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors
private Buffer2D<float> Render(IPath path) private Buffer2D<float> Render(IPath path)
{ {
var size = Rectangle.Ceiling(path.Bounds); Size size = Rectangle.Ceiling(path.Bounds).Size;
size = new Size(size.Width + (this.offset * 2), size.Height + (this.offset * 2));
float subpixelCount = 4; float subpixelCount = 4;
float offset = 0.5f; float offset = 0.5f;
if (this.Options.Antialias) if (this.Options.Antialias)

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

@ -52,6 +52,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text
TPixel color = NamedColors<TPixel>.Black; TPixel color = NamedColors<TPixel>.Black;
provider.VerifyOperation( provider.VerifyOperation(
ImageComparer.Tolerant(imageThreshold: 0.1f, perPixelManhattanThreshold: 20),
img => img =>
{ {
img.Mutate(c => c.DrawText(text, new Font(font, fontSize), color, new PointF(x, y))); img.Mutate(c => c.DrawText(text, new Font(font, fontSize), color, new PointF(x, y)));
@ -95,6 +96,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text
TPixel color = NamedColors<TPixel>.Black; TPixel color = NamedColors<TPixel>.Black;
provider.VerifyOperation( provider.VerifyOperation(
ImageComparer.Tolerant(imageThreshold: 0.1f, perPixelManhattanThreshold: 20),
img => img =>
{ {
img.Mutate(c => c.DrawText(textOptions, sb.ToString(), font, color, new PointF(10, 5))); img.Mutate(c => c.DrawText(textOptions, sb.ToString(), font, color, new PointF(10, 5)));
@ -125,7 +127,36 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text
ImageComparer.Tolerant(imageThreshold: 0.1f, perPixelManhattanThreshold: 20), ImageComparer.Tolerant(imageThreshold: 0.1f, perPixelManhattanThreshold: 20),
img => img =>
{ {
img.Mutate(c => c.DrawText(text, new Font(font, fontSize),null, Pens.Solid(color, 1), new PointF(x, y))); img.Mutate(c => c.DrawText(text, new Font(font, fontSize), null, Pens.Solid(color, 1), new PointF(x, y)));
},
$"pen_{fontName}-{fontSize}-{fnDisplayText}-({x},{y})",
appendPixelTypeToFileName: false,
appendSourceFileOrDescription: true);
}
[Theory]
[WithSolidFilledImages(200, 100, "White", PixelTypes.Rgba32, 50, 0, 0, "SixLaborsSampleAB.woff", AB)]
[WithSolidFilledImages(900, 100, "White", PixelTypes.Rgba32, 50, 0, 0, "OpenSans-Regular.ttf", TestText)]
[WithSolidFilledImages(1100, 200, "White", PixelTypes.Rgba32, 50, 150, 100, "OpenSans-Regular.ttf", TestText)]
public void FontShapesAreRenderedCorrectlyWithAPenPatterned<TPixel>(
TestImageProvider<TPixel> provider,
int fontSize,
int x,
int y,
string fontName,
string text)
where TPixel : struct, IPixel<TPixel>
{
Font font = CreateFont(fontName, fontSize);
string fnDisplayText = text.Replace("\n", "");
fnDisplayText = fnDisplayText.Substring(0, Math.Min(fnDisplayText.Length, 4));
TPixel color = NamedColors<TPixel>.Black;
provider.VerifyOperation(
ImageComparer.Tolerant(imageThreshold: 0.1f, perPixelManhattanThreshold: 20),
img =>
{
img.Mutate(c => c.DrawText(text, new Font(font, fontSize), null, Pens.DashDot(color, 3), new PointF(x, y)));
}, },
$"pen_{fontName}-{fontSize}-{fnDisplayText}-({x},{y})", $"pen_{fontName}-{fontSize}-{fnDisplayText}-({x},{y})",
appendPixelTypeToFileName: false, appendPixelTypeToFileName: false,

2
tests/Images/External

@ -1 +1 @@
Subproject commit 07cdbcfca121081eae97d6a9cd0e230c653eeb39 Subproject commit 09059fae2d8bea3a4c9288ab10fb184f1b648f40
Loading…
Cancel
Save