Files
QuestPDF/QuestPDF/Elements/ScaleToFit.cs
T
MarcinZiabek 657bbe2aac 2022.2.4
2022-02-18 21:48:57 +01:00

80 lines
2.4 KiB
C#

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 scaledSpace = ScaleSize(availableSpace, 1 / perfectScale.Value);
var childSizeInScale = Child.Measure(scaledSpace);
var childSizeInOriginalScale = ScaleSize(childSizeInScale, perfectScale.Value);
return SpacePlan.FullRender(childSizeInOriginalScale);
}
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;
}
}
}
}