Example #1
0
        public (int, RectangleF) GetAdjustedFont(string graphicString, float containerWidth, float containerHeight, int maxFontSize,
                                                 int minFontSize)
        {
            var sizeRect = new RectangleF();

            for (int adjustedSize = maxFontSize; adjustedSize >= minFontSize; adjustedSize--)
            {
                var testFont      = new Font(_dummyFont, adjustedSize);
                var renderOptions = new RendererOptions(testFont)
                {
                    WrappingWidth = containerWidth
                };

                // Test the string with the new size
                sizeRect = TextMeasurer.MeasureBounds(graphicString, renderOptions);
                float volume = sizeRect.Height * sizeRect.Width;

                if (volume < containerWidth * containerHeight)
                {
                    // Good font, return it
                    return(adjustedSize, sizeRect);
                }
            }

            return(minFontSize, sizeRect);
        }
Example #2
0
        public void TextFailsToRender()
        {
            var text = "2016-12-10";

            // first make sure the text rectangle actually overlaps
            var destArea = new RectangleF(PointF.Empty, this.ActualImage.Size());
            var textArea = TextMeasurer.MeasureBounds(text, new RendererOptions(Drawing.Roboto10, new Point(-10, 3)));

            Assert.IsTrue(destArea.IntersectsWith(textArea.AsRect()));

            // THIS SHOULD IDEALLY NOT THROW
            Assert.ThrowsException <ImageProcessingException>(
                () =>
                this.ActualImage.Mutate(
                    x => { x.DrawText(text, Drawing.Roboto10, Color.White, new PointF(-10, 3)); }));

            // but our custom safe method side steps the problem
            this.ActualImage.Mutate(x => { x.DrawTextSafe(text, Drawing.Roboto10, Color.White, new PointF(-10, 3)); });

            this.ExpectedImage = Drawing.NewImage(100, 100, Color.Black);
            this.ExpectedImage.Mutate(
                x => x.DrawText("016-12-10", Drawing.Roboto10, Color.White, new PointF(-3.8232422f, 3)));

            // if we're on a system where Arial isn't installed, we fall back to roboto font,
            // thus we allow a slight tolerance on the image
            var tolerance = SystemFonts.TryFind(Drawing.Arial, out _) ? 0.0 : 1.5E-06;

            this.AssertImagesEqual(tolerance);
        }
Example #3
0
        public static void DrawEventLabel(this SpectralEvent @event, IImageProcessingContext graphics, EventRenderingOptions options)
        {
            if (!options.DrawLabel)
            {
                return;
            }

            var text = @event.Name;

            if (string.IsNullOrWhiteSpace(text))
            {
                return;
            }

            var bounds  = TextMeasurer.MeasureBounds(text, new RendererOptions(Roboto6));
            var topLeft = options.Converters.GetPoint(@event);

            topLeft.Offset(0, -bounds.Height);

            graphics.DrawTextSafe(
                @event.Name,
                Roboto6,
                options.Label,
                topLeft);
        }
Example #4
0
        public static Font ScaleFont(Font font, string text, float targetWidth, float targetHeight)
        {
            var maxFontSize = font.Size;
            var minFontSize = 0f;

            while (maxFontSize - minFontSize > 0.1f)
            {
                var actual = TextMeasurer.MeasureBounds(text, new RendererOptions(font)
                {
                    WrappingWidth = targetWidth
                });

                if (actual.Height > targetHeight || actual.Width > targetWidth)
                {
                    maxFontSize = font.Size;
                }
                else
                {
                    minFontSize = font.Size;
                }

                font = new Font(font, (maxFontSize + minFontSize) / 2);
            }

            return(new Font(font, minFontSize));
        }
Example #5
0
        public void TextFailsToRender()
        {
            var text = "2016-12-10";

            // first make sure the text rectangle actually overlaps
            var destArea = new RectangleF(PointF.Empty, this.Actual.Size());
            var textArea = TextMeasurer.MeasureBounds(text, new RendererOptions(Drawing.Arial10, new Point(-10, 3)));

            Assert.IsTrue(destArea.IntersectsWith(textArea.AsRect()));

            // THIS SHOULD IDEALLY NOT THROW
            Assert.ThrowsException <ImageProcessingException>(
                () =>
                this.Actual.Mutate(
                    x => { x.DrawText(text, Drawing.Arial10, Color.White, new PointF(-10, 3)); }));

            // but our custom safe method side steps the problem
            this.Actual.Mutate(x => { x.DrawTextSafe(text, Drawing.Arial10, Color.White, new PointF(-10, 3)); });

            this.Expected = Drawing.NewImage(100, 100, Color.Black);
            this.Expected.Mutate(
                x => x.DrawText("016-12-10", Drawing.Arial10, Color.White, new PointF((float)(-10f + 4.741211f), 3)));

            this.AssertImagesEqual();
        }
Example #6
0
        public void WhiteSpaceAtStartOfLineNotMeasured(string text, float width, float height)
        {
            Font          font = CreateFont(text);
            FontRectangle size = TextMeasurer.MeasureBounds(text, new RendererOptions(font, 72 * font.EmSize));

            Assert.Equal(height, size.Height, 2);
            Assert.Equal(width, size.Width, 2);
        }
Example #7
0
        public void TwoTabsAreDoubleWidthOfOneTab()
        {
            Font font        = CreateFont("\t x");
            var  xWidth      = TextMeasurer.MeasureBounds("x", new RendererOptions(font, (72 * font.EmSize)));
            var  tabWidth    = TextMeasurer.MeasureBounds("\t", new RendererOptions(font, (72 * font.EmSize)));
            var  twoTabWidth = TextMeasurer.MeasureBounds("\t\t", new RendererOptions(font, (72 * font.EmSize)));

            Assert.Equal(twoTabWidth.Width, tabWidth.Width * 2, 2);
        }
Example #8
0
        public void TwoTabsAreDoubleWidthOfOneTabMinusXWidth()
        {
            var   font        = CreateFont("\t x");
            SizeF xWidth      = TextMeasurer.MeasureBounds("x", new RendererOptions(font, (72 * font.EmSize))).Size;
            SizeF tabWidth    = TextMeasurer.MeasureBounds("\tx", new RendererOptions(font, (72 * font.EmSize))).Size;
            SizeF twoTabWidth = TextMeasurer.MeasureBounds("\t\tx", new RendererOptions(font, (72 * font.EmSize))).Size;

            Assert.Equal(twoTabWidth.Width - xWidth.Width, (tabWidth.Width - xWidth.Width) * 2, 2);
        }
Example #9
0
        public void ThrowsMeasuringWhitespace()
        {
            // wendy one returns wrong points for 'o'
            Font          font = new FontCollection().Add(TestFonts.WendyOneFile).CreateFont(12);
            FontRectangle size = TextMeasurer.MeasureBounds("          ", new TextOptions(new Font(font, 30)));

            Assert.Equal(60, size.Width, 1);
            Assert.Equal(31.6, size.Height, 1);
        }
Example #10
0
        public void TwoTabsAreDoubleWidthOfOneTabMinusXWidth()
        {
            Font          font        = CreateFont("\t x");
            FontRectangle xWidth      = TextMeasurer.MeasureBounds("x", new RendererOptions(font, 72 * font.EmSize));
            FontRectangle tabWidth    = TextMeasurer.MeasureBounds("\tx", new RendererOptions(font, 72 * font.EmSize));
            FontRectangle twoTabWidth = TextMeasurer.MeasureBounds("\t\tx", new RendererOptions(font, 72 * font.EmSize));

            Assert.Equal(twoTabWidth.Width - xWidth.Width, (tabWidth.Width - xWidth.Width) * 2, 2);
        }
Example #11
0
        public void Rendering2TabsAtStartOfLineTooShort()
        {
            var   font          = CreateFont("\t x");
            SizeF xWidth        = TextMeasurer.MeasureBounds("x", new RendererOptions(font, (72 * font.EmSize))).Size;
            SizeF tabWidth      = TextMeasurer.MeasureBounds("\t\t", new RendererOptions(font, (72 * font.EmSize))).Size;
            SizeF tabWithXWidth = TextMeasurer.MeasureBounds("\t\tx", new RendererOptions(font, (72 * font.EmSize))).Size;

            Assert.Equal(tabWidth.Width + xWidth.Width, tabWithXWidth.Width, 2);
        }
Example #12
0
 private RectangleF GetTextBounds(int wrapWidth, string text, Font font)
 {
     return(TextMeasurer.MeasureBounds(text, new RendererOptions(font)
     {
         HorizontalAlignment = HorizontalAlignment,
         VerticalAlignment = VerticalAlignment,
         WrappingWidth = wrapWidth
     }));
 }
Example #13
0
        public void Rendering2TabsAtStartOfLineTooShort()
        {
            Font          font          = CreateFont("\t x");
            FontRectangle xWidth        = TextMeasurer.MeasureBounds("x", new RendererOptions(font, 72 * font.EmSize));
            FontRectangle tabWidth      = TextMeasurer.MeasureBounds("\t\t", new RendererOptions(font, 72 * font.EmSize));
            FontRectangle tabWithXWidth = TextMeasurer.MeasureBounds("\t\tx", new RendererOptions(font, 72 * font.EmSize));

            Assert.Equal(tabWidth.Width + xWidth.Width, tabWithXWidth.Width, 2);
        }
Example #14
0
        public void TextWidthFroTabOnlyTextSouldBeSingleTabWidthMultipliedByTabCount(int tabCount)
        {
            Font font = CreateFont("\t x");

            SizeF  tabWidth      = TextMeasurer.MeasureBounds("\t", new RendererOptions(font, (72 * font.EmSize))).Size;
            string tabString     = "".PadRight(tabCount, '\t');
            SizeF  tabCountWidth = TextMeasurer.MeasureBounds(tabString, new RendererOptions(font, (72 * font.EmSize))).Size;

            Assert.Equal(tabWidth.Width * tabCount, tabCountWidth.Width, 2);
        }
Example #15
0
        public void RenderingTabAtStartOrLineTooShort()
        {
            Font font          = CreateFont("\t x");
            var  xWidth        = TextMeasurer.MeasureBounds("x", new RendererOptions(font, (72 * font.EmSize)));
            var  tabWidth      = TextMeasurer.MeasureBounds("\t", new RendererOptions(font, (72 * font.EmSize)));
            var  doublTabWidth = TextMeasurer.MeasureBounds("\t\t", new RendererOptions(font, (72 * font.EmSize)));
            var  tabWithXWidth = TextMeasurer.MeasureBounds("\tx", new RendererOptions(font, (72 * font.EmSize)));

            Assert.Equal(tabWidth.Width + xWidth.Width, tabWithXWidth.Width, 2);
        }
Example #16
0
        public void MeasureText(string text, float height, float width)
        {
            Font font = CreateFont(text);

            int           scaleFactor = 72 * font.EmSize; // 72 * emSize means 1 point = 1px
            FontRectangle size        = TextMeasurer.MeasureBounds(text, new RendererOptions(font, 72 * font.EmSize));

            Assert.Equal(height, size.Height, 4);
            Assert.Equal(width, size.Width, 4);
        }
Example #17
0
        public void WhiteSpaceAtStartOfLineNotMeasured(string text, float width, float height)
        {
            Font          font = CreateFont(text);
            FontRectangle size = TextMeasurer.MeasureBounds(text, new TextOptions(font)
            {
                Dpi = font.FontMetrics.ScaleFactor
            });

            Assert.Equal(height, size.Height, 2);
            Assert.Equal(width, size.Width, 2);
        }
Example #18
0
        public void ThrowsMeasureingWhitespace()
        {
            // wendy one returns wrong points for 'o'
            Font font = new FontCollection().Install(TestFonts.WendyOneFile).CreateFont(12);

            var r = new GlyphRenderer();

            var size = TextMeasurer.MeasureBounds("          ", new RendererOptions(new Font(font, 30), 72));

            Assert.Equal(60, size.Width, 1);
            Assert.Equal(31.6, size.Height, 1);
        }
Example #19
0
        public static void DrawTextBoxes <TPixel>(Image <TPixel> image, Font font, IEnumerable <TextBox> boxes) where TPixel : struct, IPixel <TPixel>
        {
            image.Mutate(context =>
            {
                foreach (var box in boxes)
                {
                    var boxBounds = new RectangleF(
                        x: (float)(image.Width * box.X / 100),
                        y: (float)(image.Height * box.Y / 100),
                        width: (float)(image.Width * box.Width / 100),
                        height: (float)(image.Height * box.Height / 100)
                        );
                    var scaledFont = ScaleFont(new Font(font, image.Height / 8), box.Text, boxBounds.Width - 2 * outlineSize, boxBounds.Height - 2 * outlineSize);
                    var wrapWidth  = ScaleWidth(scaledFont, box.Text, boxBounds.Width - 2 * outlineSize);
                    var lineColor  = ColorBuilder <TPixel> .FromRGBA(box.LineColor.R, box.LineColor.G, box.LineColor.B, box.LineColor.A);
                    var fillColor  = ColorBuilder <TPixel> .FromRGBA(box.FillColor.R, box.FillColor.G, box.FillColor.B, box.FillColor.A);
                    var pen        = Pens.Solid(lineColor, 3f);
                    var brush      = Brushes.Solid(fillColor);

                    var textBounds = TextMeasurer.MeasureBounds(box.Text, new RendererOptions(scaledFont)
                    {
                        WrappingWidth       = wrapWidth,
                        HorizontalAlignment = ConvertHorizontalAlignment(box.Horizontal),
                    });

                    var drawLocation = GetLocation(box, boxBounds, textBounds);

                    // draw outline
                    context.DrawText(
                        new TextGraphicsOptions(true)
                    {
                        WrapTextWidth       = wrapWidth,
                        HorizontalAlignment = ConvertHorizontalAlignment(box.Horizontal),
                    },
                        box.Text,
                        scaledFont,
                        pen,
                        drawLocation);

                    // draw fill
                    context.DrawText(new TextGraphicsOptions(true)
                    {
                        WrapTextWidth       = wrapWidth,
                        HorizontalAlignment = ConvertHorizontalAlignment(box.Horizontal),
                    },
                                     box.Text,
                                     scaledFont,
                                     brush,
                                     drawLocation);
                }
            });
        }
Example #20
0
        public void MeasureTextWordWrapping(string text, float height, float width)
        {
            Font font = CreateFont(text);

            int   scaleFactor = 72 * font.EmSize; // 72 * emSize means 1 point = 1px
            SizeF size        = TextMeasurer.MeasureBounds(text, new RendererOptions(font, 72 * font.EmSize)
            {
                WrappingWidth = 350
            }).Size;

            Assert.Equal(width, size.Width, 4);
            Assert.Equal(height, size.Height, 4);
        }
Example #21
0
        public unsafe void MeasureTextWithSpan()
        {
            Font font = CreateFont("hello");

            Span <char> text = stackalloc char[] { 'h', 'e', 'l', 'l', 'o' };

            int scaleFactor = 72 * font.EmSize; // 72 * emSize means 1 point = 1px

            FontRectangle size = TextMeasurer.MeasureBounds(text, new RendererOptions(font, 72 * font.EmSize));

            Assert.Equal(10, size.Height, 4);
            Assert.Equal(130, size.Width, 4);
        }
Example #22
0
        public void TabWidth0CausesBadTabRendering()
        {
            string text = "Hello\tworld";
            Font   font = CreateFont(text);
            var    size = TextMeasurer.MeasureBounds(text, new RendererOptions(font, 72 * font.EmSize)
            {
                TabWidth = 0
            });

            // tab width of 0 should make tabs not render at all
            Assert.Equal(10, size.Height, 4);
            Assert.Equal(280, size.Width, 4);
        }
Example #23
0
        public MemoryStream SpoilerTxt(string spoil)
        {
            var             fill  = Brushes.Solid <Rgba32>(Rgba32.Black);
            var             brush = Brushes.Solid <Rgba32>(Rgba32.White);
            RendererOptions op    = new RendererOptions(_Spoiltxt);
            var             text  = WordWrap(spoil, 120);
            var             tsize = TextMeasurer.MeasureBounds(text, op);

            int[] size = { Convert.ToInt32(tsize.Width) + 20, Convert.ToInt32(tsize.Height) + 20 };
            var   img2 = new Image <Rgba32>(size[0], size[1]);

            img2.DrawText(text, _Spoiltxt, brush, new PointF(0, 0), new TextGraphicsOptions(true));
            img2.BackgroundColor(Rgba32.Black);
            var img1 = new Image <Rgba32>(img2.Width, img2.Height);

            _Spoil = _fonts.Find("Whitney-Bold").CreateFont(img2.Width * 0.064f);
            var rect = new Rectangle(0, 0, img2.Width, img2.Height);

            img1.BackgroundColor(Rgba32.Black, rect);
            img1.DrawText("Spoiler Warning" + "\r\n" + "(Mouse over to view)", _Spoil, brush, new PointF(0, 0), new TextGraphicsOptions(true)
            {
                WrapTextWidth = img1.Width - 20
            });
            MagickImage f1 = new MagickImage(img1.ToStream());
            MagickImage f2 = new MagickImage(img2.ToStream());

            MagickImage[] frames = { f1, f2 };
            MemoryStream  ms     = new MemoryStream();

            using (MagickImageCollection gif = new MagickImageCollection())
            {
                gif.Add(f1);
                gif.Add(f2);

                for (int i = 0; i < gif.Count; i++)
                {
                    gif[i].AnimationDelay      = 50;
                    gif[i].AnimationIterations = 1;
                }
                QuantizeSettings settings = new QuantizeSettings
                {
                    Colors       = 256,
                    DitherMethod = DitherMethod.No
                };
                gif.Quantize(settings);
                gif.Optimize();
                gif.Write(ms, MagickFormat.Gif);
                ms.Position = 0;
            }
            return(ms);
        }
Example #24
0
        public void MakeSureWeAccountForKerning()
        {
            var text = "i1i1i1i1i1i1i1i1i1";

            var textArea = TextMeasurer.MeasureBounds(text, new RendererOptions(Drawing.Roboto10, new Point(-70, 3)));

            this.ActualImage.Mutate(x => { x.DrawTextSafe(text, Drawing.Roboto10, Color.White, new PointF(-70, 3)); });

            this.ExpectedImage = Drawing.NewImage(100, 100, Color.Black);
            this.ExpectedImage.Mutate(
                x => x.DrawText("i1", Drawing.Roboto10, Color.White, new PointF(-4.975585f, 3)));

            this.AssertImagesEqual();
        }
Example #25
0
        public void MeasureTextWithKerning(string text, float height, float width, bool enableKerning)
        {
            var  c    = new FontCollection();
            Font font = c.Install(TestFonts.SimpleFontFileData()).CreateFont(12);

            int           scaleFactor = 72 * font.EmSize; // 72 * emSize means 1 point = 1px
            FontRectangle size        = TextMeasurer.MeasureBounds(text, new RendererOptions(new Font(font, 1), 72 * font.EmSize)
            {
                ApplyKerning = enableKerning
            });

            Assert.Equal(height, size.Height, 4);
            Assert.Equal(width, size.Width, 4);
        }
        public void DrawProcessors_CompleteOverlap()
        {
            // complete overlap does NOT throw for text
            var textSize = TextMeasurer.MeasureBounds(TestText, new RendererOptions(TestFont));

            Assert.IsTrue(textSize.Width < 50 && textSize.Height < 50);
            this.testImage.Mutate(Parallel, x => x.DrawText(TestText, TestFont, TestBrush, CompleteOverlap));

            // complete overlap does NOT throw for images
            this.testImage.Mutate(Parallel, x => x.DrawImage(OverImage, (Point)CompleteOverlap, 1f));

            // complete overlap does NOT throw for rects
            this.testImage.Mutate(Parallel, x => x.Draw(TestPen, new Rectangle((Point)CompleteOverlap, TestSize)));
        }
Example #27
0
        public void TextWidthFroTabOnlyTextSouldBeSingleTabWidthMultipliedByTabCountMinusX(int tabCount)
        {
            Font font = CreateFont("\t x");

            SizeF  xWidth        = TextMeasurer.MeasureBounds("x", new RendererOptions(font, (72 * font.EmSize))).Size;
            SizeF  tabWidth      = TextMeasurer.MeasureBounds("\tx", new RendererOptions(font, (72 * font.EmSize))).Size;
            string tabString     = "x".PadLeft(tabCount + 1, '\t');
            SizeF  tabCountWidth = TextMeasurer.MeasureBounds(tabString, new RendererOptions(font, (72 * font.EmSize))).Size;

            float singleTabWidth = tabWidth.Width - xWidth.Width;
            float finalTabWidth  = tabCountWidth.Width - xWidth.Width;

            Assert.Equal(singleTabWidth * tabCount, finalTabWidth, 2);
        }
        public void TabWidth0CausesBadTabRendering()
        {
            string        text = "Hello\tworld";
            Font          font = CreateFont(text);
            FontRectangle size = TextMeasurer.MeasureBounds(text, new TextOptions(font)
            {
                Dpi      = font.FontMetrics.ScaleFactor,
                TabWidth = 0
            });

            // tab width of 0 should make tabs not render at all
            Assert.Equal(10, size.Height, 4);
            Assert.Equal(280, size.Width, 4);
        }
        public void TextWidthForTabOnlyTextShouldBeSingleTabWidthMultipliedByTabCount(int tabCount)
        {
            Font font = CreateFont("\t x");

            FontRectangle tabWidth = TextMeasurer.MeasureBounds("\t", new TextOptions(font)
            {
                Dpi = font.FontMetrics.ScaleFactor
            });
            string        tabString     = string.Empty.PadRight(tabCount, '\t');
            FontRectangle tabCountWidth = TextMeasurer.MeasureBounds(tabString, new TextOptions(font)
            {
                Dpi = font.FontMetrics.ScaleFactor
            });

            Assert.Equal(tabWidth.Width * tabCount, tabCountWidth.Width, 2);
        }
Example #30
0
        public Task <CommandResult> RunImageCommand(params string[] args)
        {
            Image <Rgba32> baseImage = Image.Load(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Assets", $"clippy.png"));

            try
            {
                IEnumerable <string> txtBase = args;
                if (characters.Contains(args[0].ToLowerInvariant()))
                {
                    baseImage = ChangeImage(ref txtBase);
                }

                string txt = string.Join("\r\n\r\n", txtBase);

                RectangleF size = TextMeasurer.MeasureBounds(txt, new RendererOptions(font)
                {
                    WrappingWidth = clippyTop.Width - 20
                });
                using (Image <Rgba32> textImage = new Image <Rgba32>(clippyTop.Width, (int)Math.Ceiling(size.Height + 5)))
                {
                    textImage.Mutate(m => m
                                     .Fill(colour)
                                     .DrawLines(Rgba32.Black, 2, new PointF[] { new PointF(0, 0), new PointF(0, textImage.Height) })
                                     .DrawLines(Rgba32.Black, 2, new PointF[] { new PointF(textImage.Width, 0), new PointF(textImage.Width, textImage.Height) })
                                     .DrawText(txt, font, Rgba32.Black, new PointF(10, 0), new TextGraphicsOptions()
                    {
                        WrapTextWidth = clippyTop.Width - 20
                    }));

                    Image <Rgba32> returnImage = new Image <Rgba32>(clippyTop.Width, clippyTop.Height + textImage.Height + clippyBottom.Height + baseImage.Height);

                    returnImage.Mutate(m => m
                                       .Fill(Rgba32.Transparent)
                                       .DrawImage(clippyTop, 1, new Size(clippyTop.Width, clippyTop.Height), new Point(0, 0))
                                       .DrawImage(textImage, 1, new Size(textImage.Width, textImage.Height), new Point(0, clippyTop.Height))
                                       .DrawImage(clippyBottom, 1, new Size(clippyBottom.Width, clippyBottom.Height), new Point(0, clippyTop.Height + textImage.Height))
                                       .DrawImage(baseImage, 1, new Size(baseImage.Width, baseImage.Height), new Point((clippyTop.Width - baseImage.Width) / 2, clippyTop.Height + textImage.Height + clippyBottom.Height)));

                    return(Task.FromResult(returnImage.ToResult(Context)));
                }
            }
            finally
            {
                baseImage?.Dispose();
            }
        }