public void TryMeasureCharacterBounds() { string text = "a b\nc"; GlyphMetric[] expectedGlyphMetrics = new GlyphMetric[] { new GlyphMetric('a', new RectangleF(10, 10, 10, 10), false), new GlyphMetric(' ', new RectangleF(40, 10, 30, 10), false), new GlyphMetric('b', new RectangleF(70, 10, 10, 10), false), new GlyphMetric('\n', new RectangleF(100, 10, 0, 10), true), new GlyphMetric('c', new RectangleF(10, 40, 10, 10), false), }; Font font = CreateFont(text); int scaleFactor = 72 * font.EmSize; // 72 * emSize means 1 point = 1px IReadOnlyList <GlyphMetric> glyphMetrics; Assert.True(TextMeasurer.TryMeasureCharacterBounds(text, new RendererOptions(font, 72 * font.EmSize), out glyphMetrics)); Assert.Equal(text.Length, glyphMetrics.Count); int i = 0; foreach (GlyphMetric glyphMetric in glyphMetrics) { Assert.Equal(expectedGlyphMetrics[i++], glyphMetric); } }
public void MeasuringWordWithAccentedCharacterDoesNotThrow(char c) { FontFamily arial = new FontCollection().Install(TestFonts.OpenSansFile); var font = new Font(arial, 1f, FontStyle.Regular); FontRectangle size = TextMeasurer.Measure($"abc{c}def", new RendererOptions(font, 72)); }
public Task Initialize(MatrixParams mparams) { this.sizex = mparams.SizeX; this.sizey = mparams.SizeY; var size = new Size((int)this.sizex, (int)this.sizey); this.pbuf = new RGBPixel[sizex, sizey]; Font font = null; var fonts = new FontCollection(); foreach (var f in fontpfade) { if (System.IO.File.Exists(f)) { fonts.Install(f); } } try{ font = SystemFonts.CreateFont(this.FontFamily, this.Size, this.Style); } catch (Exception d) {} FontRectangle sz = TextMeasurer.Measure(this.Text, new RendererOptions(font)); Size _tsize = new Size(Convert.ToInt32(sz.Width + 1), Convert.ToInt32(sz.Height + 1)); this._image = new Image <Rgba32>(_tsize.Width, _tsize.Height); _image.Mutate(ctx => { //ctx.Fill(Rgba32.Black); ctx.DrawText(this.Text, font, Brushes.Solid(Color.White), Pens.Solid(Color.Beige, 1), PointF.Empty); }); _tpos = _image.Width / 2; return(Task.CompletedTask); }
public void AddWaterMark(Image image, string watermark) { var collection = new FontCollection(); var family = collection.Install("Font/Ganttlets.ttf"); var font = family.CreateFont(12, FontStyle.Italic); var imgSize = image.Size(); var size = TextMeasurer.Measure(watermark, new RendererOptions(font)); var scalingFactor = Math.Min(imgSize.Width / size.Width, imgSize.Height / size.Height); var scaledFont = new Font(font, scalingFactor * font.Size); var center = new PointF(imgSize.Width / 2, imgSize.Height / 2); var textGraphicOptions = new TextGraphicsOptions() { TextOptions = { HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center } }; image.Mutate(context => context.DrawText(textGraphicOptions, watermark, scaledFont, Color.Aqua, center)); }
public void MeasuringWordWithAccentedCharacterDoesNotThrow(char c) { FontFamily arial = SystemFonts.Find("Arial"); Font font = new Font(arial, 1f, FontStyle.Regular); SizeF size = TextMeasurer.Measure($"abc{c}def", new RendererOptions(font, 72)); }
public static IImageProcessingContext <TPixel> ApplyScalingWaterMarkWordWrap <TPixel>(this IImageProcessingContext <TPixel> processingContext, Font font, string text, TPixel color, float padding) where TPixel : struct, IPixel <TPixel> { return(processingContext.Apply(img => { float targetWidth = img.Width - (padding * 2); float targetHeight = img.Height - (padding * 2); float targetMinHeight = img.Height - (padding * 3); var scaledFont = font; SizeF s = new SizeF(float.MaxValue, float.MaxValue); float scaleFactor = (scaledFont.Size / 2); int trapCount = (int)scaledFont.Size * 2; if (trapCount < 10) { trapCount = 10; } bool isTooSmall = false; while ((s.Height > targetHeight || s.Height < targetMinHeight) && trapCount > 0) { if (s.Height > targetHeight) { if (isTooSmall) { scaleFactor = scaleFactor / 2; } scaledFont = new Font(scaledFont, scaledFont.Size - scaleFactor); isTooSmall = false; } if (s.Height < targetMinHeight) { if (!isTooSmall) { scaleFactor = scaleFactor / 2; } scaledFont = new Font(scaledFont, scaledFont.Size + scaleFactor); isTooSmall = true; } trapCount--; s = TextMeasurer.Measure(text, new RendererOptions(scaledFont) { WrappingWidth = targetWidth }); } var center = new PointF(padding, img.Height / 2); img.Mutate(i => i.DrawText(text, scaledFont, color, center, new TextGraphicsOptions(true) { HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center, WrapTextWidth = targetWidth })); })); }
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(); }
private static Image <T> RenderImage <T>(this FontAtlas fa, T color) where T : struct, IPixel <T> { // TODO we need the extra pixels here because ImageSharp renders out of bounds and crashes. var img = new Image <T>(Configuration.Default, fa.Width + 2, fa.Height); var tgo = new TextGraphicsOptions(true); tgo.AntialiasSubpixelDepth = 8; for (var i = 0; i < fa.MapCount; i++) { var gm = fa[i]; var font = gm.Font; foreach (var gd in gm) { // TODO lower level control to render single character? This API sucks balls for FA layout + rendering var charStr = char.ConvertFromUtf32(gd.Character); var pos = (Vector2)gd.Bounds.TopLeft; var ro = new RendererOptions(font); TextMeasurer.TryMeasureCharacterBounds(charStr.AsSpan(), ro, out var cbs); var cb = cbs[0]; img.Mutate(c => c.DrawText(tgo, charStr, font, color, pos - (Vector2)cb.Bounds.Location)); } } return(img); }
static void Main(string[] args) { using var module = PiTop4Board.Instance; var display = module.Display; Console.WriteLine("press enter key to render square"); Console.ReadLine(); display.Draw((d, cr) => { var square = new RectangularPolygon(0, 0, cr.Width / 2, cr.Height / 2); d.Fill(Color.White, square); }); Console.WriteLine("press enter key to render text"); Console.ReadLine(); var font = SystemFonts.Collection.Find("Roboto").CreateFont(10); module.Display.Draw((context, cr) => { context.Clear(Color.Black); var rect = TextMeasurer.Measure("Diego was here", new RendererOptions(font)); var x = (cr.Width - rect.Width) / 2; var y = (cr.Height + (rect.Height)) / 2; context.DrawText("Hello\nWorld", font, Color.White, new PointF(0, 0)); }); Console.WriteLine("press enter key to exit"); Console.ReadLine(); }
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); }
private static IEnumerable <string> SplitTextForMaxWidth(float width, Font font, string input) { var render = new RendererOptions(font); var words = input.Replace("\n", " ").Split(' '); string currentLine = null; foreach (var word in words) { if (currentLine == null) { currentLine = ""; } if (GetWidth(currentLine + word + " ") > width) { yield return(currentLine.Trim()); currentLine = word; } else { currentLine += " " + word; } } if (currentLine != null) { yield return(currentLine); } float GetWidth(string line) { return(TextMeasurer.Measure(line, render).Width); } }
public static Stream Render(string text, Image <Rgba32> image) { var words = text.Split(' '); var font = Arial.CreateFont(2, FontStyle.Regular); var canvasPoint = new PointF(image.Width * 0.125F, image.Height * 0.70F); var canvasSize = new SizeF(image.Width * 0.75F, image.Height * 0.3F); font = GetLargestFont(canvasSize, font, text); var render = new RendererOptions(font); foreach (var line in SplitTextForMaxWidth(canvasSize.Width, font, text)) { var textSize = TextMeasurer.Measure(line, render); var point = new PointF(canvasPoint.X + (canvasSize.Width - textSize.Width) / 2, canvasPoint.Y); image.Mutate(cl => cl.DrawText(line, font, Brushes.Solid(Color.WhiteSmoke), Pens.Solid(Color.Black, 1), point)); canvasPoint.Y += textSize.Height; } var str = new MemoryStream(); image.SaveAsJpeg(str); str.Seek(0, SeekOrigin.Begin); return(str); }
public Vector2 GetCursorPosition() { var mousePos = InputTracker.MousePosition; if (IsMouseHoveringOver) { // Iterate all combinations of letters and get closest var xPosList = new List <float>() { 0 }; for (int i = 1; i <= Text.Length; i++) { var substr = Text.Substring(0, i); var size = TextMeasurer.Measure(substr, new RendererOptions(Label.DrawableText.Font)); xPosList.Add(size.Width); } var relativePos = mousePos - (Label.AbsolutePosition + new Vector2(CursorControl.Size.X, 0)); var minDistance = xPosList.Min(n => Math.Abs(relativePos.X - n)); var closest = xPosList.First(n => Math.Abs(relativePos.X - n) == minDistance); CursorIndex = xPosList.IndexOf(closest); return(new Vector2(closest + Label.Position.X - 1, 3)); } return(Vector2.Zero); }
// Colors: Red,Blue,Purple,#006666 private static IImageProcessingContext DrawWatermark(this IImageProcessingContext context, WatermarkSettings settings) { var imgSize = context.GetCurrentSize(); // measure the text size var size = TextMeasurer.Measure(settings.Text, new RendererOptions(settings.TextFont)); //find out how much we need to scale the text to fill the space (up or down) var scalingFactor = Math.Min(imgSize.Width / size.Width, imgSize.Height / size.Height) / 3; //create a new settings.TextFont var scaledFont = new Font(settings.TextFont, scalingFactor * settings.TextFont.Size); var center = settings.Position switch { WatermarkPosition.Top => new PointF(imgSize.Width / 2, (imgSize.Height / 9)), WatermarkPosition.TopLeft => new PointF(imgSize.Width / 2, (imgSize.Height / 9)), WatermarkPosition.TopRight => new PointF(imgSize.Width / 2, (imgSize.Height / 9)), _ => new PointF(imgSize.Width / 2, imgSize.Height - (imgSize.Height / 9)), }; var textGraphicOptions = new TextGraphicsOptions(true) { HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center, }; // Apply Banner context.DrawBanner(settings) .DrawText(textGraphicOptions, settings.Text, scaledFont, settings.TextColor, center); return(context); }
public void TryMeasureCharacterBounds() { string text = "a b\nc"; var expectedGlyphMetrics = new GlyphMetric[] { new GlyphMetric('a', new FontRectangle(10, 0, 10, 10), false), new GlyphMetric(' ', new FontRectangle(40, 0, 30, 10), false), new GlyphMetric('b', new FontRectangle(70, 0, 10, 10), false), new GlyphMetric('\n', new FontRectangle(100, 0, 0, 10), true), new GlyphMetric('c', new FontRectangle(10, 30, 10, 10), false), }; Font font = CreateFont(text); int scaleFactor = 72 * font.EmSize; // 72 * emSize means 1 point = 1px Assert.True(TextMeasurer.TryMeasureCharacterBounds(text.AsSpan(), new RendererOptions(font, 72 * font.EmSize), out GlyphMetric[] glyphMetrics)); Assert.Equal(text.Length, glyphMetrics.Length); for (int i = 0; i < glyphMetrics.Length; i++) { GlyphMetric expected = expectedGlyphMetrics[i]; GlyphMetric actual = glyphMetrics[i]; Assert.Equal(expected.Character, actual.Character); Assert.Equal(expected.IsControlCharacter, actual.IsControlCharacter); // 4 dp as there is minor offset difference in the float values Assert.Equal(expected.Bounds.X, actual.Bounds.X, 4); Assert.Equal(expected.Bounds.Y, actual.Bounds.Y, 4); Assert.Equal(expected.Bounds.Height, actual.Bounds.Height, 4); Assert.Equal(expected.Bounds.Width, actual.Bounds.Width, 4); } }
public static void DrawText(this Image image, Font font, string text, bool bottom) { if (string.IsNullOrWhiteSpace(text)) { return; } var rect = TextMeasurer.Measure(text, new RendererOptions(font, DPI) { WrappingWidth = image.Width, }); var position = new PointF( 0.0f, bottom ? image.Height - Margin - rect.Height : Margin); image.Mutate(x => x.DrawText(new TextGraphicsOptions { TextOptions = new TextOptions { DpiX = DPI, DpiY = DPI, WrapTextWidth = image.Width, HorizontalAlignment = HorizontalAlignment.Center } }, text, font, Brushes.Solid(Color.White), Pens.Solid(Color.Black, 2.0f), position)); }
/// <summary> /// Add a password to the image. /// </summary> /// <param name="curImg">Image to add password to.</param> /// <param name="pass">Password to add to top left corner.</param> /// <returns>Image with the password in the top left corner.</returns> private (Stream, string) AddPassword(byte[] curImg, string pass) { // draw lower, it looks better pass = pass.TrimTo(10, true).ToLowerInvariant(); using (var img = Image.Load(curImg, out var format)) { // choose font size based on the image height, so that it's visible var font = _fonts.NotoSans.CreateFont(img.Height / 12, FontStyle.Bold); img.Mutate(x => { // measure the size of the text to be drawing var size = TextMeasurer.Measure(pass, new RendererOptions(font, new PointF(0, 0))); // fill the background with black, add 5 pixels on each side to make it look better x.FillPolygon(Rgba32.FromHex("00000080"), new PointF(0, 0), new PointF(size.Width + 5, 0), new PointF(size.Width + 5, size.Height + 10), new PointF(0, size.Height + 10)); // draw the password over the background x.DrawText(pass, font, Brushes.Solid(Rgba32.White), new PointF(0, 0)); }); // return image as a stream for easy sending return(img.ToStream(format), format.FileExtensions.FirstOrDefault() ?? "png"); } }
public static IImageProcessingContext <TPixel> ApplyScalingWaterMarkSimple <TPixel>(this IImageProcessingContext <TPixel> processingContext, Font font, string text, TPixel color, float padding) where TPixel : struct, IPixel <TPixel> { return(processingContext.Apply(img => { float targetWidth = img.Width - (padding * 2); float targetHeight = img.Height - (padding * 2); // measure the text size SizeF size = TextMeasurer.Measure(text, new RendererOptions(font)); //find out how much we need to scale the text to fill the space (up or down) float scalingFactor = Math.Min(img.Width / size.Width, img.Height / size.Height); //create a new font Font scaledFont = new Font(font, scalingFactor * font.Size); var center = new PointF(img.Width / 2, img.Height / 2); var textGraphicOptions = new TextGraphicsOptions(true) { HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center }; img.Mutate(i => i.DrawText(textGraphicOptions, text, scaledFont, color, center)); })); }
public void DoesntThrowExceptionWhenOverlappingRightEdge_Issue688 <TPixel>(TestImageProvider <TPixel> provider) where TPixel : struct, IPixel <TPixel> { Font font = CreateFont("OpenSans-Regular.ttf", 36); Color color = Color.Black; float padding = 5; var text = "A short piece of text"; using (var img = provider.GetImage()) { float targetWidth = img.Width - (padding * 2); float targetHeight = img.Height - (padding * 2); // measure the text size SizeF size = TextMeasurer.Measure(text, new RendererOptions(font)); //find out how much we need to scale the text to fill the space (up or down) float scalingFactor = Math.Min(img.Width / size.Width, img.Height / size.Height); //create a new font Font scaledFont = new Font(font, scalingFactor * font.Size); var center = new PointF(img.Width / 2, img.Height / 2); var textGraphicOptions = new TextGraphicsOptions(true) { HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center }; img.Mutate(i => i.DrawText(textGraphicOptions, text, scaledFont, color, center)); } }
private static IImageProcessingContext ApplyScalingWaterMarkSimple(IImageProcessingContext processingContext, Font font, string text, Color color, float padding) { Size imgSize = processingContext.GetCurrentSize(); float targetWidth = imgSize.Width - (padding * 2); float targetHeight = imgSize.Height - (padding * 2); // measure the text size FontRectangle size = TextMeasurer.Measure(text, new RendererOptions(font)); //find out how much we need to scale the text to fill the space (up or down) float scalingFactor = Math.Min(imgSize.Width / size.Width, imgSize.Height / size.Height); //create a new font Font scaledFont = new Font(font, scalingFactor * font.Size); var center = new PointF(imgSize.Width / 2, imgSize.Height / 2); var textGraphicOptions = new TextGraphicsOptions() { TextOptions = { HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center } }; return(processingContext.DrawText(textGraphicOptions, text, scaledFont, color, center)); }
private static void DrawStats(int rank, int level, int ep, Image <Rgba32> output, Vector2 posRank, Vector2 posLevel, Vector2 posEP, Rgba32 color) { // measure each string and split the margin between them?? var font = new Font(_titleFont, 42, FontStyle.Bold); var rankText = $"Rank: {rank}"; var levelText = $"Level: {level}"; var epText = $"EP: {ep}"; //var fontSpan = new FontSpan(font, 72); //imagesharp renders at 72 var rankSize = TextMeasurer.Measure(rankText, font, 72); // find the width of the rank text var epSize = TextMeasurer.Measure(epText, font, 72); // find the width of the EP text var left = posRank.X + rankSize.Width; // find the point the rankText stops var right = posEP.X - epSize.Width; // find the point the epText starts var posLevel2 = new Vector2(left + (right - left) / 2, posRank.Y); // find the point halfway between the 2 other bits of text output.DrawText(rankText, font, color, posRank, new ImageSharp.Drawing.TextGraphicsOptions { VerticalAlignment = VerticalAlignment.Center, HorizontalAlignment = HorizontalAlignment.Left }); output.DrawText(levelText, font, color, posLevel2, new ImageSharp.Drawing.TextGraphicsOptions { VerticalAlignment = VerticalAlignment.Center, HorizontalAlignment = HorizontalAlignment.Center }); output.DrawText(epText, font, color, posEP, new ImageSharp.Drawing.TextGraphicsOptions { VerticalAlignment = VerticalAlignment.Center, HorizontalAlignment = HorizontalAlignment.Right }); }
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)); }
public OpenXmlSize MeasureText(IOpenXmlTextStyle defaultTextStyle, IOpenXmlTheme theme, OpenXmlUnit?width) { // TODO: subtract border // TODO: measure each pararaph individually int level = 1; IOpenXmlParagraphTextStyle defaultParagraphTextStyle = defaultTextStyle.GetParagraphTextStyle(level); string text = this.GetText(); string typeface = theme.ResolveFontTypeface(this.GetFont() ?? defaultParagraphTextStyle.LatinTypeface); double fontSize = this.GetFontSize() ?? defaultParagraphTextStyle.Size ?? 9.0; double kerning = this.GetKerning() ?? defaultParagraphTextStyle.Kerning ?? 0.0; OpenXmlMargin margin = this.GetTextMargin(); Font font = SystemFonts.Find(typeface).CreateFont((float)fontSize); RendererOptions options = new RendererOptions(font, 72) { WrappingWidth = width.HasValue ? (float)(width.Value - margin.Left - margin.Right).AsPoints() : -1.0f, ApplyKerning = kerning != 0.0, LineSpacing = 1 / 1.2f }; FontRectangle rect = TextMeasurer.Measure(text, options); OpenXmlSize result = new OpenXmlSize( width.HasValue ? width.Value : (OpenXmlUnit.Points(rect.Width) + margin.Left + margin.Right), OpenXmlUnit.Points(rect.Height * 1.2) + margin.Top + margin.Bottom ); return(result); }
private string GetBase64StringOfImageWithText(string base64Image, string text) { string str = ""; var bytes = Convert.FromBase64String(base64Image); // Creates a new image with all the pixels set as transparent. using (var image = Image.Load(bytes)) { image.Mutate(context => { var textGraphicsOptions = new TextGraphicsOptions(true) { HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center }; //Pick any font size, since it will be replaced later var initialFont = SystemFonts.CreateFont("Arial", 10); var size = TextMeasurer.Measure(text, new RendererOptions(initialFont)); var scalingFactor = Math.Min(image.Width / 2 / size.Width, image.Height / 2 / size.Height); var font = new Font(initialFont, scalingFactor * initialFont.Size, FontStyle.Bold); var textColor = GetContrastColorBW(image); var center = new PointF(image.Width / 2, image.Height / 2); context.DrawText(textGraphicsOptions, text, font, textColor, center); }); str = image.ToBase64String <Rgba32>(PngFormat.Instance); } return(str); }
public static void RenderTextProcessor( FontFamily fontFamily, string text, float pointSize = 12, IEnumerable <FontFamily> fallbackFonts = null) { Font font = new(fontFamily, pointSize); TextOptions textOptions = new(font) { Dpi = 96, }; if (fallbackFonts != null) { textOptions.FallbackFontFamilies = fallbackFonts.ToArray(); } FontRectangle textSize = TextMeasurer.Measure(text, textOptions); textOptions.Origin = new PointF(5, 5); using var img = new Image <Rgba32>((int)Math.Ceiling(textSize.Width) + 20, (int)Math.Ceiling(textSize.Height) + 20); img.Mutate(x => x.Fill(Color.White).ApplyProcessor(new DrawTextProcessor(x.GetDrawingOptions(), textOptions, text, new SolidBrush(Color.Black), null))); string fullPath = CreatePath(font.Name, text + ".caching.png"); Directory.CreateDirectory(IOPath.GetDirectoryName(fullPath)); img.Save(fullPath); }
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); }
public static void DrawTextAnySize(this IImageProcessingContext context, TextGraphicsOptions op, string?text, FontFamily font, Color color, Rectangle bounds) { if (string.IsNullOrEmpty(text)) { return; } int fontSize = 64; bool fits = false; Font currentFont = font.CreateFont(fontSize); while (!fits) { currentFont = font.CreateFont(fontSize); SizeF size = TextMeasurer.Measure(text, new RendererOptions(currentFont)); fits = size.Height <= bounds.Height && size.Width <= bounds.Width; if (!fits) { fontSize -= 2; } if (fontSize <= 2) { return; } } context.DrawText(op, text, currentFont, color, new Point(bounds.X, bounds.Y)); }
public static void DrawText(this IImageProcessingContext context, TextGraphicsOptions op, string?text, Font font, Color color, Rectangle bounds) { if (string.IsNullOrEmpty(text)) { return; } op.WrapTextWidth = bounds.Width; RendererOptions rOp = new RendererOptions(font); rOp.WrappingWidth = bounds.Width; bool fits = false; while (!fits) { SizeF size = TextMeasurer.Measure(text, rOp); fits = size.Height <= bounds.Height && size.Width <= bounds.Width; if (!fits) { text = text.Truncate(text.Length - 5); } } context.DrawText(op, text, font, color, new Point(bounds.X, bounds.Y)); }
static void Main(string[] args) { var squareSize = 512; var backgroundColor = Rgba32.Salmon; var font = SystemFonts.CreateFont("Arial", 300); var text = "KS"; var textSize = TextMeasurer.Measure(text, new RendererOptions(font, 72)); Console.WriteLine($"Measured size: {textSize.Width}, {textSize.Height}, Text: {text}"); using (var img = new Image <Rgba32>(squareSize, squareSize)) { var textGraphicsOptions = new TextGraphicsOptions(true); var textPosition = new PointF(squareSize / 2f - textSize.Width / 2, squareSize / 2f - textSize.Height / 2f); img.Mutate(ctx => ctx .Fill(backgroundColor) .DrawText(text, font, Rgba32.White, textPosition)); byte[] buffer; using (var ms = new MemoryStream()) { img.SaveAsPng(ms); ms.Seek(0, SeekOrigin.Begin); buffer = ms.ToArray(); } var base64Image = Convert.ToBase64String(buffer); Console.WriteLine("\x1b]1337;File=inline=1;width=100px;height=100px:" + base64Image + "\a\n"); File.WriteAllBytes("result.png", buffer); } }
public void VerticalAlignmentTests( VerticalAlignment vertical, HorizontalAlignment horizental, float top, float left) { string text = "hello world\nhello"; Font font = CreateFont(text); int scaleFactor = 72 * font.EmSize; // 72 * emSize means 1 point = 1px var span = new RendererOptions(font, scaleFactor) { HorizontalAlignment = horizental, VerticalAlignment = vertical }; IReadOnlyList <GlyphLayout> glyphsToRender = new TextLayout().GenerateLayout(text.AsSpan(), span); IFontInstance fontInst = span.Font.Instance; float lineHeight = (fontInst.LineHeight * span.Font.Size) / (fontInst.EmSize * 72); lineHeight *= scaleFactor; FontRectangle bound = TextMeasurer.GetBounds(glyphsToRender, new Vector2(span.DpiX, span.DpiY)); Assert.Equal(310, bound.Width, 3); Assert.Equal(40, bound.Height, 3); Assert.Equal(left, bound.Left, 3); Assert.Equal(top, bound.Top, 3); }
public static TextBlock createTextBlock(string text, Font font, Paint paint, float maxWidth, int maxLines, TextMeasurer measurer) { TextBlock textBlock = new TextBlock(); BreakIterator lineInstance = BreakIterator.getLineInstance(); lineInstance.setText(text); int num1 = 0; int num2 = 0; int num3 = String.instancehelper_length(text); label_1: while (num1 < num3 && num2 < maxLines) { int num4 = TextUtilities.nextLineBreak(text, num1, maxWidth, lineInstance, measurer); if (num4 == -1) { textBlock.addLine(String.instancehelper_substring(text, num1), font, paint); return textBlock; } else { textBlock.addLine(String.instancehelper_substring(text, num1, num4), font, paint); ++num2; num1 = num4; while (true) { if (num1 < String.instancehelper_length(text) && (int) String.instancehelper_charAt(text, num1) == 10) ++num1; else goto label_1; } } } if (num1 < num3) { TextLine lastLine = textBlock.getLastLine(); TextFragment lastTextFragment = lastLine.getLastTextFragment(); string text1 = lastTextFragment.getText(); string text2 = "..."; if (String.instancehelper_length(text1) > 3) text2 = new StringBuffer().append(String.instancehelper_substring(text1, 0, String.instancehelper_length(text1) - 3)).append("...").toString(); lastLine.removeFragment(lastTextFragment); TextFragment.__\u003Cclinit\u003E(); TextFragment fragment = new TextFragment(text2, lastTextFragment.getFont(), lastTextFragment.getPaint()); lastLine.addFragment(fragment); } return textBlock; }
public static TextBlock createTextBlock(string text, Font font, Paint paint, float maxWidth, TextMeasurer measurer) { return TextUtilities.createTextBlock(text, font, paint, maxWidth, int.MaxValue, measurer); }