|
@@ -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;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|