Export training plan as one continuous PDF page
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
using MigraDoc.DocumentObjectModel;
|
||||
using MigraDoc.Rendering;
|
||||
|
||||
namespace TrainingPlanner.Infrastructure.Pdf;
|
||||
|
||||
public class ContinuousPdfLayout(PdfOptions options)
|
||||
{
|
||||
public void Fit(Document document)
|
||||
{
|
||||
var measurement = new DocumentRenderer(document.Clone());
|
||||
measurement.PrepareDocument();
|
||||
if (measurement.FormattedDocument?.PageCount != 1)
|
||||
throw new InvalidOperationException("Программа слишком длинная для одной страницы PDF. Сократите её объём.");
|
||||
var elements = measurement.GetRenderInfoFromPage(1)
|
||||
?? throw new InvalidOperationException("Не удалось рассчитать высоту PDF.");
|
||||
var contentBottom = elements.Max(info => info.LayoutInfo.ContentArea.Y.Point + info.LayoutInfo.ContentArea.Height.Point);
|
||||
document.Sections[0].PageSetup.PageHeight = Unit.FromPoint(
|
||||
Math.Ceiling(contentBottom + Unit.FromCentimeter(options.MarginCentimeters).Point));
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ public class PdfOptions
|
||||
public double FontSize { get; set; }
|
||||
public double CameraSizePoints { get; set; }
|
||||
public double HeadingSize { get; set; }
|
||||
public double PageWidthCentimeters { get; set; }
|
||||
public double MaxContinuousPageHeightCentimeters { get; set; }
|
||||
public double MarginCentimeters { get; set; }
|
||||
public double ClientLabelWidthCentimeters { get; set; }
|
||||
public int ClientDetailsGapLines { get; set; }
|
||||
|
||||
@@ -33,6 +33,12 @@ public class PdfWeekTableBuilder(PdfOptions options)
|
||||
"Отдых, мин", "Съёмка", "Время тренировки" };
|
||||
for (var index = 0; index < labels.Length; index++)
|
||||
header.Cells[index].AddParagraph(labels[index]);
|
||||
if (week.Workouts.Count == 0)
|
||||
{
|
||||
var empty = table.AddRow();
|
||||
empty.Cells[0].MergeRight = table.Columns.Count - 1;
|
||||
empty.Cells[0].AddParagraph("Тренировки не назначены.");
|
||||
}
|
||||
foreach (var workout in week.Workouts)
|
||||
AddWorkout(table, workout);
|
||||
for (var rowIndex = 0; rowIndex < table.Rows.Count; rowIndex++)
|
||||
|
||||
@@ -26,34 +26,23 @@ public class PlanPdfExporter : IPlanPdfExporter
|
||||
normal.Font.Name = options.FontFamily;
|
||||
normal.Font.Size = options.FontSize;
|
||||
normal.ParagraphFormat.SpaceAfter = Unit.FromPoint(options.FontSize / 2);
|
||||
var firstWeek = true;
|
||||
foreach (var week in plan.Weeks)
|
||||
var section = document.AddSection();
|
||||
section.PageSetup.PageWidth = Unit.FromCentimeter(options.PageWidthCentimeters);
|
||||
section.PageSetup.PageHeight = Unit.FromCentimeter(options.MaxContinuousPageHeightCentimeters);
|
||||
section.PageSetup.TopMargin = section.PageSetup.BottomMargin = Unit.FromCentimeter(options.MarginCentimeters);
|
||||
section.PageSetup.LeftMargin = section.PageSetup.RightMargin = Unit.FromCentimeter(options.MarginCentimeters);
|
||||
new PdfClientTableBuilder(options).Add(section, client);
|
||||
for (var line = 0; line < options.ClientDetailsGapLines; line++)
|
||||
{
|
||||
var section = document.AddSection();
|
||||
section.PageSetup.PageFormat = PageFormat.A4;
|
||||
section.PageSetup.Orientation = Orientation.Landscape;
|
||||
section.PageSetup.TopMargin = section.PageSetup.BottomMargin = Unit.FromCentimeter(options.MarginCentimeters);
|
||||
section.PageSetup.LeftMargin = section.PageSetup.RightMargin = Unit.FromCentimeter(options.MarginCentimeters);
|
||||
if (firstWeek)
|
||||
{
|
||||
new PdfClientTableBuilder(options).Add(section, client);
|
||||
for (var line = 0; line < options.ClientDetailsGapLines; line++)
|
||||
{
|
||||
var spacer = section.AddParagraph();
|
||||
spacer.Format.SpaceBefore = Unit.FromPoint(0);
|
||||
spacer.Format.SpaceAfter = Unit.FromPoint(0);
|
||||
spacer.Format.LineSpacingRule = LineSpacingRule.Single;
|
||||
}
|
||||
firstWeek = false;
|
||||
}
|
||||
var footer = section.Footers.Primary.AddParagraph();
|
||||
footer.Format.Alignment = ParagraphAlignment.Right;
|
||||
footer.AddPageField();
|
||||
if (week.Workouts.Count == 0)
|
||||
section.AddParagraph($"Неделя {week.Position + 1}. Тренировки не назначены.");
|
||||
else
|
||||
tables.Add(section, week);
|
||||
var spacer = section.AddParagraph();
|
||||
spacer.Format.SpaceBefore = Unit.FromPoint(0);
|
||||
spacer.Format.SpaceAfter = Unit.FromPoint(0);
|
||||
spacer.Format.LineSpacingRule = LineSpacingRule.Single;
|
||||
}
|
||||
foreach (var week in plan.Weeks)
|
||||
tables.Add(section, week);
|
||||
|
||||
new ContinuousPdfLayout(options).Fit(document);
|
||||
var renderer = new PdfDocumentRenderer { Document = document };
|
||||
renderer.RenderDocument();
|
||||
using var stream = new MemoryStream();
|
||||
|
||||
@@ -68,6 +68,8 @@
|
||||
"MaximumReceiveMessageBytes": 1048576
|
||||
},
|
||||
"Pdf": {
|
||||
"PageWidthCentimeters": 29.7,
|
||||
"MaxContinuousPageHeightCentimeters": 500,
|
||||
"ClientDetailsGapLines": 5,
|
||||
"ClientLabelWidthCentimeters": 4.5,
|
||||
"FontPath": "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
|
||||
|
||||
Reference in New Issue
Block a user