From 9b33d8b7157c8cf8c11816111f1b9a9d0a21c90f Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Thu, 23 Mar 2017 10:08:30 +0000 Subject: [PATCH 1/4] add range checks --- .../Processors/FillRegionProcessor.cs | 37 ++++++++++++++----- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs index 66e1f4380c..3c07d41a86 100644 --- a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs @@ -65,6 +65,15 @@ namespace ImageSharp.Drawing.Processors int maxX = Math.Min(source.Width, rect.Right); int minY = Math.Max(0, rect.Top); int maxY = Math.Min(source.Height, rect.Bottom); + if (minX >= maxX) + { + return; // no effect inside image; + } + + if (minY >= maxY) + { + return; // no effect inside image; + } ArrayPool arrayPool = ArrayPool.Shared; @@ -122,22 +131,32 @@ namespace ImageSharp.Drawing.Processors int startX = (int)Math.Floor(scanStart); int endX = (int)Math.Floor(scanEnd); - for (float x = scanStart; x < startX + 1; x += subpixelFraction) + if (startX >= 0 && startX < scanline.Length) { - scanline[startX] += subpixelFractionPoint; - scanlineDirty = true; + for (float x = scanStart; x < startX + 1; x += subpixelFraction) + { + scanline[startX] += subpixelFractionPoint; + scanlineDirty = true; + } } - for (float x = endX; x < scanEnd; x += subpixelFraction) + if (endX >= 0 && endX < scanline.Length) { - scanline[endX] += subpixelFractionPoint; - scanlineDirty = true; + for (float x = endX; x < scanEnd; x += subpixelFraction) + { + scanline[endX] += subpixelFractionPoint; + scanlineDirty = true; + } } - for (int x = startX + 1; x < endX; x++) + int nextX = startX + 1; + if (nextX >= 0 && nextX < scanline.Length && endX >= 0 && endX < scanline.Length) { - scanline[x] += subpixelFraction; - scanlineDirty = true; + for (int x = nextX; x < endX; x++) + { + scanline[x] += subpixelFraction; + scanlineDirty = true; + } } } } From b028126fe333f195939b6a7d4b8dbe84ae45d5ad Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Thu, 23 Mar 2017 10:15:59 +0000 Subject: [PATCH 2/4] reduce range check --- src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs index 3c07d41a86..060ead6e4d 100644 --- a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs @@ -150,7 +150,7 @@ namespace ImageSharp.Drawing.Processors } int nextX = startX + 1; - if (nextX >= 0 && nextX < scanline.Length && endX >= 0 && endX < scanline.Length) + if (nextX >= 0 && endX < scanline.Length) { for (int x = nextX; x < endX; x++) { From 122ebccdc2dd57c5966a10b06160a8a01c6494bc Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Thu, 23 Mar 2017 10:18:25 +0000 Subject: [PATCH 3/4] scan to end of line even if longer --- src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs index 060ead6e4d..9a616d408b 100644 --- a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs @@ -150,7 +150,8 @@ namespace ImageSharp.Drawing.Processors } int nextX = startX + 1; - if (nextX >= 0 && endX < scanline.Length) + endX = Math.Min(endX, scanline.Length); // reduce to end to the right edge + if (nextX >= 0) { for (int x = nextX; x < endX; x++) { From 8847f12913466e10b2852a33c94810e256da4d86 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Thu, 23 Mar 2017 15:21:13 +0000 Subject: [PATCH 4/4] Default text drawing at an image dpi independent size This changes the default behavour to by defaulting all text to be drawn as 72 dpi as apposed to the images native resolution thus ensuing that the pixel hight per point is consisten across images by defualt. Can be switched back to image resolution byt setting `UseImageResolution` in `TextGraphicsOptions` to `true` --- src/ImageSharp.Drawing/Text/DrawText.cs | 9 ++++++- .../Text/TextGraphicsOptions.cs | 7 +++++ .../ImageSharp.Tests/Drawing/Text/DrawText.cs | 27 +++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp.Drawing/Text/DrawText.cs b/src/ImageSharp.Drawing/Text/DrawText.cs index 28781fab22..1f5f4cdb12 100644 --- a/src/ImageSharp.Drawing/Text/DrawText.cs +++ b/src/ImageSharp.Drawing/Text/DrawText.cs @@ -18,6 +18,8 @@ namespace ImageSharp /// public static partial class ImageExtensions { + private static readonly Vector2 DefaultTextDpi = new Vector2(72); + /// /// Draws the text onto the the image filled via the brush. /// @@ -169,7 +171,12 @@ namespace ImageSharp TextRenderer renderer = new TextRenderer(glyphBuilder); - Vector2 dpi = new Vector2((float)source.MetaData.HorizontalResolution, (float)source.MetaData.VerticalResolution); + Vector2 dpi = DefaultTextDpi; + if (options.UseImageResolution) + { + dpi = new Vector2((float)source.MetaData.HorizontalResolution, (float)source.MetaData.VerticalResolution); + } + FontSpan style = new FontSpan(font) { ApplyKerning = options.ApplyKerning, diff --git a/src/ImageSharp.Drawing/Text/TextGraphicsOptions.cs b/src/ImageSharp.Drawing/Text/TextGraphicsOptions.cs index 253bb2aaca..b58a40b34d 100644 --- a/src/ImageSharp.Drawing/Text/TextGraphicsOptions.cs +++ b/src/ImageSharp.Drawing/Text/TextGraphicsOptions.cs @@ -35,6 +35,12 @@ namespace ImageSharp.Drawing /// public float TabWidth; + /// + /// Flag weather to use the current image resultion to for point size scaling. + /// If this is [false] the text renders at 72dpi otherwise it renders at Image resolution + /// + public bool UseImageResolution; + /// /// Initializes a new instance of the struct. /// @@ -45,6 +51,7 @@ namespace ImageSharp.Drawing this.ApplyKerning = true; this.TabWidth = 4; this.AntialiasSubpixelDepth = 16; + this.UseImageResolution = false; } /// diff --git a/tests/ImageSharp.Tests/Drawing/Text/DrawText.cs b/tests/ImageSharp.Tests/Drawing/Text/DrawText.cs index 68db4d9a27..52b7fcbb65 100644 --- a/tests/ImageSharp.Tests/Drawing/Text/DrawText.cs +++ b/tests/ImageSharp.Tests/Drawing/Text/DrawText.cs @@ -219,5 +219,32 @@ namespace ImageSharp.Tests.Drawing.Text Assert.IsType>(this.img.ProcessorApplications[0].processor); Assert.IsType>(this.img.ProcessorApplications[1].processor); } + + [Fact] + public void GlyphHeightChangesBasedOnuseImageResolutionFlag() + { + this.img.MetaData.VerticalResolution = 1; + this.img.MetaData.HorizontalResolution = 1; + this.img.DrawText("1", this.Font, Brushes.Solid(Color.Red), Vector2.Zero, new TextGraphicsOptions(true) { + UseImageResolution = false + }); + + this.img.DrawText("1", this.Font, Brushes.Solid(Color.Red), Vector2.Zero, new TextGraphicsOptions(true) + { + UseImageResolution = true + }); + + Assert.NotEmpty(this.img.ProcessorApplications); + Assert.Equal(2, this.img.ProcessorApplications.Count); + FillRegionProcessor ownResolution = Assert.IsType>(this.img.ProcessorApplications[0].processor); + FillRegionProcessor imgResolution = Assert.IsType>(this.img.ProcessorApplications[1].processor); + + ShapeRegion ownRegion = Assert.IsType(ownResolution.Region); + ShapeRegion imgRegion = Assert.IsType(imgResolution.Region); + + // magic numbers based on the font used at well known resolutions + Assert.Equal(7.44, ownRegion.Shape.Bounds.Height, 2); + Assert.Equal(0.1, imgRegion.Shape.Bounds.Height, 2); + } } }