diff --git a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs index 66e1f4380c..9a616d408b 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,33 @@ 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; + endX = Math.Min(endX, scanline.Length); // reduce to end to the right edge + if (nextX >= 0) { - scanline[x] += subpixelFraction; - scanlineDirty = true; + for (int x = nextX; x < endX; x++) + { + scanline[x] += subpixelFraction; + scanlineDirty = true; + } } } } 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); + } } }