Simple drawing text

This commit is contained in:
Marcin Ziąbek
2021-04-28 00:24:26 +02:00
parent 81a9599b99
commit f4181de3d2
8 changed files with 269 additions and 8 deletions
+147
View File
@@ -0,0 +1,147 @@
using System;
using System.Collections.Generic;
using System.Linq;
using QuestPDF.Elements;
using QuestPDF.Examples.Engine;
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
namespace QuestPDF.Examples
{
public class TextExample : ExampleTestBase
{
[ShowResult]
[ImageSize(1200, 500)]
public void Test(IContainer container)
{
List<TextElement> Lorem()
{
return new List<TextElement>
{
new TextElement()
{
Style = TextStyle.Default.Size(32).BackgroundColor(Colors.Red.Lighten3),
Text = "Lorem ipsum "
},
new TextElement()
{
Style = TextStyle.Default.Size(24).BackgroundColor(Colors.Orange.Lighten3),
Text = " dolor "
},
new TextElement()
{
Style = TextStyle.Default.Size(64).BackgroundColor(Colors.Yellow.Lighten3),
Text = " sit "
},
new TextElement()
{
Style = TextStyle.Default.Size(32).BackgroundColor(Colors.Green.Lighten3),
Text = " amet"
}
};
}
Func<List<TextElement>> Source = Lorem ;
container
.Padding(50)
.Stack(row =>
{
row.Spacing(50);
row.Element().Box().Border(1).Stack(stack =>
{
stack
.Element()
.Box()
//.Background(Placeholders.BackgroundColor())
.Element(new TextRun()
{
Elements = Source()
});
stack
.Element()
.Box()
//.Background(Placeholders.BackgroundColor())
.Element(new TextRun()
{
Elements = Source()
});
stack
.Element()
.Box()
//.Background(Placeholders.BackgroundColor())
.Element(new TextRun()
{
Elements = Split(Source())
});
});
row.Element().Box().Border(1).Stack(stack =>
{
stack
.Element()
.Box()
.Background(Placeholders.BackgroundColor())
.Element(new TextRun()
{
Elements = Dense(Source())
});
stack
.Element()
.Box()
.Background(Placeholders.BackgroundColor())
.Element(new TextRun()
{
Elements = Dense(Source())
});
stack
.Element()
.Box()
.Background(Placeholders.BackgroundColor())
.Element(new TextRun()
{
Elements = Dense(Split(Source()))
});
});
});
}
List<TextElement> RandomText()
{
return Placeholders
.Sentence()
.Split(" ")
.Select(x => new TextElement
{
Text = $"{x} ",
Style = TextStyle.Default.Size(Placeholders.Random.Next(24, 64))
})
.ToList();
}
List<TextElement> Split(List<TextElement> elements)
{
return elements
.SelectMany(x => x
.Text
.Select(y => new TextElement
{
Style = x.Style,
Text = y.ToString()
}))
.ToList();
}
List<TextElement> Dense(List<TextElement> elements)
{
elements.ForEach(x => x.Style.IsDense = true);
return elements;
}
}
}
+1 -1
View File
@@ -37,7 +37,7 @@ namespace QuestPDF.Drawing
Typeface = SKTypeface.FromFamilyName(style.FontType, (int)style.FontWeight, (int)SKFontStyleWidth.Normal, slant),
TextSize = style.Size,
TextEncoding = SKTextEncoding.Utf32,
TextAlign = style.Alignment switch
{
HorizontalAlignment.Left => SKTextAlign.Left,
+7 -3
View File
@@ -24,6 +24,7 @@ namespace QuestPDF.Elements
return new FullRender(Size.Zero);
var heightOnCurrentPage = 0f;
var maxWidth = 0f;
foreach (var renderer in ChildrenQueue)
{
@@ -34,17 +35,20 @@ namespace QuestPDF.Elements
if (heightOnCurrentPage < Size.Epsilon)
return new Wrap();
return new PartialRender(availableSpace.Width, heightOnCurrentPage);
return new PartialRender(maxWidth, heightOnCurrentPage);
}
var size = space as Size;
heightOnCurrentPage += size.Height;
if (size.Width > maxWidth)
maxWidth = size.Width;
if (space is PartialRender)
return new PartialRender(availableSpace.Width, heightOnCurrentPage);
return new PartialRender(maxWidth, heightOnCurrentPage);
}
return new FullRender(availableSpace.Width, heightOnCurrentPage);
return new FullRender(maxWidth, heightOnCurrentPage);
}
internal override void Draw(ICanvas canvas, Size availableSpace)
+55
View File
@@ -0,0 +1,55 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using QuestPDF.Drawing;
using QuestPDF.Drawing.SpacePlan;
using QuestPDF.Infrastructure;
using SkiaSharp;
namespace QuestPDF.Elements
{
public struct TextMeasurement
{
public float Width { get; set; }
public float Height { get; set; }
public SKRect Position { get; set; }
}
internal class TextElement
{
public TextStyle Style { get; set; }
public string Text { get; set; }
private static ConcurrentDictionary<string, TextMeasurement> Measurements = new ConcurrentDictionary<string, TextMeasurement>();
public TextMeasurement Measure()
{
return Measure(Text, Style);
}
public void Draw(ICanvas canvas)
{
(canvas as QuestPDF.Drawing.Canvas).SkiaCanvas.DrawText(Text, 0, 0, Style.ToPaint());
}
internal static TextMeasurement Measure(string text, TextStyle style)
{
var key = $"{text}_{style}";
return Measurements.GetOrAdd(key, x =>
{
var rect = new SKRect();
var width = style.ToPaint().MeasureText(text, ref rect);
return new TextMeasurement
{
Position = rect,
Height = style.IsDense
? rect.Bottom + rect.Height
: style.LineHeight * style.Size,
Width = width
};
});
}
}
}
+48
View File
@@ -0,0 +1,48 @@
using System.Collections.Generic;
using System.Linq;
using QuestPDF.Drawing.SpacePlan;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
namespace QuestPDF.Elements
{
internal class TextRun : Element
{
public List<TextElement> Elements = new List<TextElement>();
internal override ISpacePlan Measure(Size availableSpace)
{
var measurements = Elements.Select(x => x.Measure()).ToList();
var width = measurements.Sum(x => x.Width);
//var height = measurements.Max(x => x.Height);
var height = measurements.Max(x => x.Position.Bottom) + measurements.Max(x => x.Position.Height);
return new FullRender(width, height);
}
internal override void Draw(ICanvas canvas, Size availableSpace)
{
var measurements = Elements.Select(x => x.Measure()).ToList();
var top = measurements.Max(x => x.Position.Height);
var bottom = measurements.Max(x => x.Position.Bottom);
var offset = measurements.Min(x => x.Position.Top);
canvas.Translate(new Position(0, -offset));
foreach (var textElement in Elements)
{
var size = textElement.Measure();
canvas.DrawRectangle(new Position(0, -top), new Size(size.Width, bottom + top), textElement.Style.BackgroundColor);
//canvas.DrawRectangle(new Position(size.Position.Left, size.Position.Top), new Size(size.Position.Width, size.Position.Height), textElement.Style.BackgroundColor);
textElement.Draw(canvas);
canvas.Translate(new Position(size.Width, 0));
}
canvas.Translate(new Position(-measurements.Sum(x => x.Width), offset));
}
}
}
+5
View File
@@ -18,6 +18,11 @@ namespace QuestPDF.Fluent
return style.Mutate(x => x.Color = value);
}
public static TextStyle BackgroundColor(this TextStyle style, string value)
{
return style.Mutate(x => x.BackgroundColor = value);
}
public static TextStyle FontType(this TextStyle style, string value)
{
return style.Mutate(x => x.FontType = value);
+1 -1
View File
@@ -7,7 +7,7 @@ namespace QuestPDF.Helpers
{
public static class Placeholders
{
private static Random Random = new Random();
public static Random Random = new Random();
#region Word Cache
+5 -3
View File
@@ -5,18 +5,20 @@ namespace QuestPDF.Infrastructure
public class TextStyle
{
internal string Color { get; set; } = Colors.Black;
internal string BackgroundColor { get; set; } = Colors.Transparent;
internal string FontType { get; set; } = "Calibri";
internal float Size { get; set; } = 12;
internal float LineHeight { get; set; } = 1.2f;
internal float LineHeight { get; set; } = 1f;
internal HorizontalAlignment Alignment { get; set; } = HorizontalAlignment.Left;
internal FontWeight FontWeight { get; set; } = FontWeight.Normal;
internal bool IsItalic { get; set; } = false;
internal bool IsDense { get; set; }
public static TextStyle Default => new TextStyle();
public override string ToString()
{
return $"{Color}|{FontType}|{Size}|{LineHeight}|{Alignment}|{FontWeight}|{IsItalic}";
return $"{Color}|{BackgroundColor}|{FontType}|{Size}|{LineHeight}|{Alignment}|{FontWeight}|{IsItalic}|{IsDense}";
}
internal TextStyle Clone() => (TextStyle)MemberwiseClone();