diff --git a/QuestPDF.Examples/ScaleToFitExamples.cs b/QuestPDF.Examples/ScaleToFitExamples.cs new file mode 100644 index 0000000..a5017d0 --- /dev/null +++ b/QuestPDF.Examples/ScaleToFitExamples.cs @@ -0,0 +1,42 @@ +using System.Linq; +using NUnit.Framework; +using QuestPDF.Examples.Engine; +using QuestPDF.Fluent; +using QuestPDF.Helpers; +using QuestPDF.Infrastructure; + +namespace QuestPDF.Examples +{ + public class ScaleToFitExamples + { + [Test] + public void ScaleToFit() + { + RenderingTest + .Create() + .PageSize(PageSizes.A4) + .ProducePdf() + .ShowResults() + .Render(container => + { + container.Padding(25).Stack(stack => + { + var text = Placeholders.Paragraph(); + + foreach (var i in Enumerable.Range(0, 16)) + { + stack + .Item() + .MinimalBox() + .Border(1) + .Padding(5) + .Width(50 + i * 25) + .Height(25 + i * 5) + .ScaleToFit() + .Text(text); + } + }); + }); + } + } +} \ No newline at end of file diff --git a/QuestPDF/Elements/ScaleToFit.cs b/QuestPDF/Elements/ScaleToFit.cs new file mode 100644 index 0000000..354df6b --- /dev/null +++ b/QuestPDF/Elements/ScaleToFit.cs @@ -0,0 +1,78 @@ +using System; +using System.Linq; +using QuestPDF.Drawing; +using QuestPDF.Infrastructure; + +namespace QuestPDF.Elements +{ + internal class ScaleToFit : ContainerElement + { + internal override SpacePlan Measure(Size availableSpace) + { + if (Child == null) + return SpacePlan.FullRender(Size.Zero); + + var perfectScale = FindPerfectScale(Child, availableSpace); + + if (perfectScale == null) + return SpacePlan.Wrap(); + + var targetSpace = ScaleSize(availableSpace, perfectScale.Value); + return SpacePlan.FullRender(targetSpace); + } + + internal override void Draw(Size availableSpace) + { + var perfectScale = FindPerfectScale(Child, availableSpace); + + if (!perfectScale.HasValue) + return; + + var targetScale = perfectScale.Value; + var targetSpace = ScaleSize(availableSpace, 1 / targetScale); + + Canvas.Scale(targetScale, targetScale); + Child?.Draw(targetSpace); + Canvas.Scale(1 / targetScale, 1 / targetScale); + } + + private static Size ScaleSize(Size size, float factor) + { + return new Size(size.Width * factor, size.Height * factor); + } + + private static float? FindPerfectScale(Element child, Size availableSpace) + { + if (ChildFits(1)) + return 1; + + var maxScale = 1f; + var minScale = Size.Epsilon; + + var lastWorkingScale = (float?)null; + + foreach (var _ in Enumerable.Range(0, 8)) + { + var halfScale = (maxScale + minScale) / 2; + + if (ChildFits(halfScale)) + { + minScale = halfScale; + lastWorkingScale = halfScale; + } + else + { + maxScale = halfScale; + } + } + + return lastWorkingScale; + + bool ChildFits(float scale) + { + var scaledSpace = ScaleSize(availableSpace, 1 / scale); + return child.Measure(scaledSpace).Type == SpacePlanType.FullRender; + } + } + } +} \ No newline at end of file diff --git a/QuestPDF/Fluent/ElementExtensions.cs b/QuestPDF/Fluent/ElementExtensions.cs index d9a2a06..54fc738 100644 --- a/QuestPDF/Fluent/ElementExtensions.cs +++ b/QuestPDF/Fluent/ElementExtensions.cs @@ -165,5 +165,10 @@ namespace QuestPDF.Fluent { return element.Element(new PreventPaging()); } + + public static IContainer ScaleToFit(this IContainer element) + { + return element.Element(new ScaleToFit()); + } } }