513 lines
23 KiB
C#
513 lines
23 KiB
C#
using Elwig.Helpers;
|
|
using Elwig.Helpers.Printing;
|
|
using iText.IO.Font;
|
|
using iText.Kernel.Font;
|
|
using iText.Kernel.Pdf;
|
|
using iText.Kernel.Pdf.Canvas;
|
|
using iText.Kernel.Pdf.Event;
|
|
using iText.Kernel.Pdf.Xobject;
|
|
using iText.Kernel.Utils;
|
|
using iText.Layout;
|
|
using iText.Layout.Borders;
|
|
using iText.Layout.Element;
|
|
using iText.Layout.Properties;
|
|
using MimeKit;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Elwig.Documents {
|
|
public class Document : IDisposable {
|
|
|
|
public static string Name => "Dokument";
|
|
|
|
public const float PtInMM = 2.8346456693f;
|
|
public const float BorderThickness = 0.5f;
|
|
|
|
protected PdfFont NF = null!;
|
|
protected PdfFont BF = null!;
|
|
protected PdfFont IF = null!;
|
|
protected PdfFont BI = null!;
|
|
protected PdfFont SF = null!;
|
|
|
|
//protected readonly PdfFont NF = PdfFontFactory.CreateFont(StandardFonts.TIMES_ROMAN);
|
|
//protected readonly PdfFont BF = PdfFontFactory.CreateFont(StandardFonts.TIMES_BOLD);
|
|
//protected readonly PdfFont IF = PdfFontFactory.CreateFont(StandardFonts.TIMES_ITALIC);
|
|
//protected readonly PdfFont BI = PdfFontFactory.CreateFont(StandardFonts.TIMES_BOLDITALIC);
|
|
|
|
protected TempFile? _pdfFile = null;
|
|
protected string? _pdfPath;
|
|
protected string? PdfPath => _pdfPath ?? _pdfFile?.FilePath;
|
|
public int? TotalPages { get; private set; }
|
|
public int? Pages => TotalPages / (IsDoublePaged ? 2 : 1);
|
|
|
|
public bool ShowFoldMarks = App.Config.Debug;
|
|
public bool IsDoublePaged = false;
|
|
public bool IsPreview = false;
|
|
private iText.Layout.Document? _doc;
|
|
|
|
public int CurrentNextSeason;
|
|
public string? DocumentId;
|
|
public string Title;
|
|
public string Author;
|
|
public DateOnly Date;
|
|
|
|
public Document(string title) {
|
|
CurrentNextSeason = Utils.CurrentNextSeason;
|
|
Title = title;
|
|
Author = App.Client.NameFull;
|
|
Date = DateOnly.FromDateTime(Utils.Today);
|
|
}
|
|
|
|
~Document() {
|
|
Dispose();
|
|
}
|
|
|
|
public void Dispose() {
|
|
_pdfFile?.Dispose();
|
|
_pdfFile = null;
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
public static Document Merge(IEnumerable<Document> docs) {
|
|
return new MergedDocument(docs);
|
|
}
|
|
|
|
public static Document FromPdf(string path) {
|
|
return new RawPdfDocument(path);
|
|
}
|
|
|
|
private class RawPdfDocument : Document {
|
|
public RawPdfDocument(string pdfPath) :
|
|
base(Path.GetFileNameWithoutExtension(pdfPath)) {
|
|
_pdfPath = pdfPath;
|
|
}
|
|
}
|
|
|
|
public int Render(string path) {
|
|
using var writer = new PdfWriter(path);
|
|
return Render(writer);
|
|
}
|
|
|
|
private int Render(PdfWriter writer) {
|
|
NF = PdfFontFactory.CreateFont(@"C:\Windows\Fonts\times.ttf", PdfEncodings.IDENTITY_H, PdfFontFactory.EmbeddingStrategy.PREFER_NOT_EMBEDDED);
|
|
BF = PdfFontFactory.CreateFont(@"C:\Windows\Fonts\timesbd.ttf", PdfEncodings.IDENTITY_H, PdfFontFactory.EmbeddingStrategy.PREFER_NOT_EMBEDDED);
|
|
IF = PdfFontFactory.CreateFont(@"C:\Windows\Fonts\timesi.ttf", PdfEncodings.IDENTITY_H, PdfFontFactory.EmbeddingStrategy.PREFER_NOT_EMBEDDED);
|
|
BI = PdfFontFactory.CreateFont(@"C:\Windows\Fonts\timesbi.ttf", PdfEncodings.IDENTITY_H, PdfFontFactory.EmbeddingStrategy.PREFER_NOT_EMBEDDED);
|
|
SF = PdfFontFactory.CreateFont(@"C:\Windows\Fonts\seguisym.ttf", PdfEncodings.IDENTITY_H, PdfFontFactory.EmbeddingStrategy.PREFER_NOT_EMBEDDED);
|
|
NF.SetSubset(true);
|
|
BF.SetSubset(true);
|
|
IF.SetSubset(true);
|
|
BI.SetSubset(true);
|
|
SF.SetSubset(true);
|
|
writer.SetCompressionLevel(CompressionConstants.BEST_COMPRESSION);
|
|
writer.SetSmartMode(true);
|
|
using var pdf = new PdfDocument(writer);
|
|
pdf.GetDocumentInfo()
|
|
.SetTitle(Title)
|
|
.SetAuthor(Author)
|
|
.SetCreator($"Elwig {App.Version}");
|
|
var handler = new EventHandler(this);
|
|
pdf.AddEventHandler(PdfDocumentEvent.START_PAGE, handler);
|
|
pdf.AddEventHandler(PdfDocumentEvent.END_PAGE, handler);
|
|
pdf.AddEventHandler(PdfDocumentEvent.START_DOCUMENT_CLOSING, handler);
|
|
_doc = new iText.Layout.Document(pdf, iText.Kernel.Geom.PageSize.A4);
|
|
try {
|
|
_doc.SetFont(NF).SetFontSize(12);
|
|
RenderHeader(_doc, pdf);
|
|
RenderBody(_doc, pdf);
|
|
var pageNum = pdf.GetNumberOfPages();
|
|
return pageNum;
|
|
} finally {
|
|
_doc.Close();
|
|
}
|
|
}
|
|
|
|
protected virtual void RenderHeader(iText.Layout.Document doc, PdfDocument pdf) { }
|
|
|
|
protected virtual void RenderBody(iText.Layout.Document doc, PdfDocument pdf) { }
|
|
|
|
protected virtual Paragraph GetFooter() {
|
|
return new KernedParagraph(App.Client.NameFull, 10);
|
|
}
|
|
|
|
public async Task Generate(CancellationToken? cancelToken = null, IProgress<double>? progress = null) {
|
|
if (_pdfFile != null)
|
|
return;
|
|
progress?.Report(0.0);
|
|
if (this is RawPdfDocument) {
|
|
// nothing to do
|
|
} else if (this is MergedDocument m) {
|
|
using var tmpPdf = new TempFile("pdf");
|
|
var pdf = new TempFile("pdf");
|
|
try {
|
|
var pageNums = new List<int>();
|
|
|
|
using var writer = new PdfWriter(pdf.FilePath);
|
|
using var mergedPdf = new PdfDocument(writer);
|
|
var merger = new PdfMerger(mergedPdf);
|
|
|
|
PdfPage? letterheadPage = null;
|
|
int letterheadInsertIndex = 0;
|
|
int letterheadDocIndex = 0;
|
|
|
|
for (int i = 0; i < m.Documents.Count; i++) {
|
|
if (cancelToken?.IsCancellationRequested ?? false)
|
|
throw new OperationCanceledException("Dokumentenerzeugung abgebrochen!");
|
|
var doc = m.Documents[i];
|
|
int p0 = mergedPdf.GetNumberOfPages();
|
|
|
|
if (letterheadPage != null && doc is Letterhead) {
|
|
if (mergedPdf.GetNumberOfPages() <= letterheadInsertIndex) {
|
|
mergedPdf.AddPage(letterheadPage);
|
|
mergedPdf.AddNewPage();
|
|
} else {
|
|
mergedPdf.AddPage(letterheadInsertIndex + 1, letterheadPage);
|
|
mergedPdf.AddNewPage(letterheadInsertIndex + 2);
|
|
}
|
|
|
|
pageNums[letterheadDocIndex] = 1;
|
|
letterheadPage = null;
|
|
}
|
|
|
|
if (doc is RawPdfDocument) {
|
|
if (IsDoublePaged && doc is Letterhead) {
|
|
using var reader = new PdfReader(doc.PdfPath);
|
|
using var src = new PdfDocument(reader);
|
|
letterheadPage = src.GetPage(1).CopyTo(mergedPdf);
|
|
letterheadInsertIndex = p0;
|
|
letterheadDocIndex = i;
|
|
} else {
|
|
using var reader = new PdfReader(doc.PdfPath);
|
|
using var src = new PdfDocument(reader);
|
|
merger.Merge(src, 1, src.GetNumberOfPages());
|
|
}
|
|
} else {
|
|
int pageNum = doc.Render(tmpPdf.FilePath);
|
|
if (IsDoublePaged && doc is Letterhead) {
|
|
using var reader = new PdfReader(tmpPdf.FilePath);
|
|
using var src = new PdfDocument(reader);
|
|
letterheadPage = src.GetPage(1).CopyTo(mergedPdf);
|
|
letterheadInsertIndex = p0;
|
|
letterheadDocIndex = i;
|
|
} else {
|
|
using var reader = new PdfReader(tmpPdf.FilePath);
|
|
using var src = new PdfDocument(reader);
|
|
merger.Merge(src, 1, pageNum);
|
|
}
|
|
}
|
|
|
|
int p1 = mergedPdf.GetNumberOfPages();
|
|
pageNums.Add(p1 - p0);
|
|
|
|
if (IsDoublePaged && doc is not Letterhead && mergedPdf.GetNumberOfPages() % 2 != 0) {
|
|
if (letterheadPage != null) {
|
|
mergedPdf.AddPage(letterheadPage);
|
|
letterheadPage = null;
|
|
} else {
|
|
mergedPdf.AddNewPage();
|
|
}
|
|
}
|
|
|
|
progress?.Report(100.0 * (i + 1) / (m.Documents.Count + 1));
|
|
}
|
|
|
|
if (letterheadPage != null) {
|
|
if (mergedPdf.GetNumberOfPages() <= letterheadInsertIndex) {
|
|
mergedPdf.AddPage(letterheadPage.CopyTo(mergedPdf));
|
|
mergedPdf.AddNewPage();
|
|
} else {
|
|
mergedPdf.AddPage(letterheadInsertIndex + 1, letterheadPage.CopyTo(mergedPdf));
|
|
mergedPdf.AddNewPage(letterheadInsertIndex + 2);
|
|
}
|
|
|
|
pageNums[letterheadDocIndex] = 1;
|
|
}
|
|
|
|
TotalPages = pageNums.Sum();
|
|
} catch {
|
|
pdf.Dispose();
|
|
throw;
|
|
}
|
|
_pdfFile = pdf;
|
|
} else {
|
|
if (cancelToken?.IsCancellationRequested ?? false)
|
|
throw new OperationCanceledException("Dokumentenerzeugung abgebrochen!");
|
|
var pdf = new TempFile("pdf");
|
|
try {
|
|
TotalPages = Render(pdf.FilePath);
|
|
} catch {
|
|
pdf.Dispose();
|
|
throw;
|
|
}
|
|
_pdfFile = pdf;
|
|
}
|
|
progress?.Report(100.0);
|
|
}
|
|
|
|
public void SaveTo(string pdfPath) {
|
|
if (PdfPath == null) throw new InvalidOperationException("Pdf file has not been generated yet");
|
|
File.Copy(PdfPath, pdfPath, true);
|
|
}
|
|
|
|
public async Task Print(int copies = 1) {
|
|
if (PdfPath == null) throw new InvalidOperationException("Pdf file has not been generated yet");
|
|
await Pdf.Print(PdfPath, copies, IsDoublePaged);
|
|
}
|
|
|
|
public void Show() {
|
|
if (_pdfFile == null) throw new InvalidOperationException("Pdf file has not been generated yet");
|
|
Pdf.Show(_pdfFile.NewReference(), Title + (this is BusinessDocument b ? $" - {b.Member.FullName}" : ""));
|
|
}
|
|
|
|
public MimePart AsEmailAttachment(string filename) {
|
|
if (PdfPath == null) throw new InvalidOperationException("Pdf file has not been generated yet");
|
|
return new("application", "pdf") {
|
|
Content = new MimeContent(File.OpenRead(PdfPath)),
|
|
ContentDisposition = new ContentDisposition(ContentDisposition.Attachment),
|
|
ContentTransferEncoding = ContentEncoding.Base64,
|
|
FileName = filename
|
|
};
|
|
}
|
|
|
|
private class MergedDocument : Document {
|
|
public List<Document> Documents;
|
|
|
|
public MergedDocument(IEnumerable<Document> docs) :
|
|
base("Mehrere Dokumente") {
|
|
Documents = [.. docs];
|
|
IsDoublePaged = docs.Any(x => x.IsDoublePaged);
|
|
}
|
|
}
|
|
|
|
protected static Cell NewCell(Paragraph? p = null, int rowspan = 1, int colspan = 1, bool overflow = false) {
|
|
var cell = new Cell(rowspan, colspan)
|
|
.SetBorder(Border.NO_BORDER)
|
|
.SetPaddingsMM(0.5f, 1, 0.5f, 1);
|
|
if (p != null) {
|
|
p.SetProperty(Property.NO_SOFT_WRAP_INLINE, true);
|
|
if (!overflow) p.SetProperty(Property.OVERFLOW_X, OverflowPropertyValue.HIDDEN);
|
|
cell.Add(p);
|
|
}
|
|
return cell;
|
|
}
|
|
|
|
protected Cell NewTh(string? text, float fontSize = 8, int rowspan = 1, int colspan = 1, bool left = false, bool rotated = false) {
|
|
var p = new KernedParagraph(text ?? "", fontSize);
|
|
if (rotated) p.SetRotationAngle(0.5 * Math.PI);
|
|
var cell = NewCell(p, rowspan: rowspan, colspan: colspan)
|
|
.SetTextAlignment(left ? TextAlignment.LEFT : TextAlignment.CENTER)
|
|
.SetVerticalAlignment(VerticalAlignment.MIDDLE)
|
|
.SetFont(IF);
|
|
if (rotated || !left) cell.SetPadding(0);
|
|
return cell;
|
|
}
|
|
|
|
protected Cell NewTd(string? text = null, float fontSize = 10, int rowspan = 1, int colspan = 1, bool center = false, bool right = false, bool bold = false, bool italic = false, bool borderTop = false, bool overflow = false) {
|
|
return NewTd(new KernedParagraph(text ?? "", fontSize), rowspan: rowspan, colspan: colspan, center: center, right: right, bold: bold, italic: italic, borderTop: borderTop, overflow: overflow);
|
|
}
|
|
|
|
protected Cell NewTd(KernedParagraph p, int rowspan = 1, int colspan = 1, bool center = false, bool right = false, bool bold = false, bool italic = false, bool borderTop = false, bool overflow = false) {
|
|
return NewCell(p, rowspan: rowspan, colspan: colspan, overflow: overflow)
|
|
.SetTextAlignment(center ? TextAlignment.CENTER : right ? TextAlignment.RIGHT : TextAlignment.LEFT)
|
|
.SetVerticalAlignment(VerticalAlignment.MIDDLE)
|
|
.SetBorderTop(borderTop ? new SolidBorder(BorderThickness) : Border.NO_BORDER)
|
|
.SetFont(bold ? (italic ? BI : BF) : (italic ? IF : NF));
|
|
}
|
|
|
|
public static float[] ColsMM(params double[] widths) {
|
|
return [.. widths.Select(w => (float)w * PtInMM)];
|
|
}
|
|
|
|
public Text Normal(string? text, float? fontSize = null) {
|
|
var t = new Text(text ?? "").SetFont(NF);
|
|
if (fontSize != null) t.SetFontSize(fontSize.Value);
|
|
return t;
|
|
}
|
|
|
|
public Text Bold(string? text, float? fontSize = null) {
|
|
var t = new Text(text ?? "").SetFont(BF);
|
|
if (fontSize != null) t.SetFontSize(fontSize.Value);
|
|
return t;
|
|
}
|
|
|
|
public Text Italic(string? text, float? fontSize = null) {
|
|
var t = new Text(text ?? "").SetFont(IF);
|
|
if (fontSize != null) t.SetFontSize(fontSize.Value);
|
|
return t;
|
|
}
|
|
|
|
public Text BoldItalic(string? text, float? fontSize = null) {
|
|
var t = new Text(text ?? "").SetFont(BI);
|
|
if (fontSize != null) t.SetFontSize(fontSize.Value);
|
|
return t;
|
|
}
|
|
|
|
private class EventHandler : AbstractPdfDocumentEventHandler {
|
|
|
|
private const float _fontSize = 10;
|
|
private const float _placeholderWidth = 50 * PtInMM;
|
|
|
|
private readonly Document _doc;
|
|
private readonly List<PdfFormXObject> _pageNumPlaceholders;
|
|
|
|
|
|
public int NumberOfPages { get; private set; }
|
|
|
|
public EventHandler(Document doc) {
|
|
_doc = doc;
|
|
_pageNumPlaceholders = [];
|
|
}
|
|
|
|
protected override void OnAcceptedEvent(AbstractPdfDocumentEvent evt) {
|
|
if (evt.GetType() == PdfDocumentEvent.START_PAGE) {
|
|
OnPageStart((PdfDocumentEvent)evt);
|
|
} else if (evt.GetType() == PdfDocumentEvent.END_PAGE) {
|
|
OnPageEnd((PdfDocumentEvent)evt);
|
|
} else if (evt.GetType() == PdfDocumentEvent.START_DOCUMENT_CLOSING) {
|
|
OnDocumentClose((PdfDocumentEvent)evt);
|
|
}
|
|
}
|
|
|
|
private void OnPageStart(PdfDocumentEvent evt) {
|
|
var pdf = evt.GetDocument();
|
|
var page = evt.GetPage();
|
|
var pageNum = pdf.GetPageNumber(page);
|
|
|
|
if (pageNum == 1) {
|
|
// first page
|
|
if (_doc is BusinessDocument) {
|
|
_doc._doc?.SetMarginsMM(90, 20, 35, 25);
|
|
} else {
|
|
_doc._doc?.SetMarginsMM(20, 20, 35, 25);
|
|
}
|
|
} else if (_doc.IsDoublePaged && (pageNum % 2) == 0) {
|
|
// left page (= swapped)
|
|
_doc._doc?.SetMarginsMM(20, 25, 25, 20);
|
|
} else {
|
|
// right page
|
|
_doc._doc?.SetMarginsMM(20, 20, 25, 25);
|
|
}
|
|
}
|
|
|
|
private void OnPageEnd(PdfDocumentEvent evt) {
|
|
var pdf = evt.GetDocument();
|
|
var page = evt.GetPage();
|
|
var pageNum = pdf.GetPageNumber(page);
|
|
|
|
var pageSize = page.GetPageSize();
|
|
float leftX1 = pageSize.GetLeft() + 25 * PtInMM;
|
|
float leftX2 = pageSize.GetLeft() + 20 * PtInMM;
|
|
float rightX1 = pageSize.GetRight() - 20 * PtInMM;
|
|
float rightX2 = pageSize.GetRight() - 25 * PtInMM;
|
|
float footerY = pageSize.GetBottom() + 25 * PtInMM;
|
|
float y1 = footerY + _fontSize;
|
|
float y2 = footerY - _fontSize;
|
|
|
|
var pdfCanvas = new PdfCanvas(page.NewContentStreamAfter(), page.GetResources(), pdf);
|
|
using var canvas = new Canvas(pdfCanvas, pageSize);
|
|
|
|
var placeholder = new PdfFormXObject(new iText.Kernel.Geom.Rectangle(0, 0, _placeholderWidth, _fontSize));
|
|
_pageNumPlaceholders.Add(placeholder);
|
|
|
|
var c = App.Client;
|
|
var dateP = new KernedParagraph($"{_doc.Date:dddd, d. MMMM yyyy}", _fontSize).SetFont(_doc.NF);
|
|
var centerP = new KernedParagraph(_doc.DocumentId ?? "", _fontSize).SetFont(_doc.IF);
|
|
var pageNumP = new KernedParagraph(_fontSize).Add(new Image(placeholder)).SetFont(_doc.NF);
|
|
|
|
if (pageNum == 1) {
|
|
// first page
|
|
canvas.ShowTextAligned(dateP, leftX1, y1, TextAlignment.LEFT, VerticalAlignment.BOTTOM);
|
|
canvas.ShowTextAligned(centerP, (leftX1 + rightX1) / 2, y1, TextAlignment.CENTER, VerticalAlignment.BOTTOM);
|
|
canvas.ShowTextAligned(pageNumP, rightX1, y1, TextAlignment.RIGHT, VerticalAlignment.BOTTOM);
|
|
|
|
var footer = _doc.GetFooter();
|
|
using var footerCanvas = new Canvas(page, pageSize);
|
|
footerCanvas.Add(new Table(1).AddCell(new Cell().Add(footer).SetBorder(Border.NO_BORDER).SetPaddingsMM(1, 0, 0, 0))
|
|
.SetFixedPositionMM(25, 0, 165).SetHeightMM(25)
|
|
.SetFont(_doc.NF).SetFontSize(10)
|
|
.SetTextAlignment(TextAlignment.CENTER)
|
|
.SetBorder(Border.NO_BORDER)
|
|
.SetBorderTop(new SolidBorder(BorderThickness)));
|
|
} else if (_doc.IsDoublePaged && (pageNum % 2 == 0)) {
|
|
// left page (= swapped)
|
|
canvas.ShowTextAligned(pageNumP, leftX2, y2, TextAlignment.LEFT, VerticalAlignment.TOP);
|
|
canvas.ShowTextAligned(centerP, (leftX2 + rightX2) / 2, y2, TextAlignment.CENTER, VerticalAlignment.TOP);
|
|
canvas.ShowTextAligned(dateP, rightX2, y2, TextAlignment.RIGHT, VerticalAlignment.TOP);
|
|
} else {
|
|
// right page
|
|
canvas.ShowTextAligned(dateP, leftX1, y2, TextAlignment.LEFT, VerticalAlignment.TOP);
|
|
canvas.ShowTextAligned(centerP, (leftX1 + rightX1) / 2, y2, TextAlignment.CENTER, VerticalAlignment.TOP);
|
|
canvas.ShowTextAligned(pageNumP, rightX1, y2, TextAlignment.RIGHT, VerticalAlignment.TOP);
|
|
}
|
|
|
|
if (_doc.ShowFoldMarks) {
|
|
var m1 = pageSize.GetTop() - 105 * PtInMM;
|
|
var m2 = pageSize.GetTop() - 148.5 * PtInMM;
|
|
var m3 = pageSize.GetTop() - 210 * PtInMM;
|
|
pdfCanvas.SetLineWidth(BorderThickness);
|
|
|
|
pdfCanvas.MoveTo(0, m1);
|
|
pdfCanvas.LineTo(10 * PtInMM, m1);
|
|
pdfCanvas.MoveTo(pageSize.GetRight(), m1);
|
|
pdfCanvas.LineTo(pageSize.GetRight() - 10 * PtInMM, m1);
|
|
|
|
pdfCanvas.MoveTo(0, m2);
|
|
pdfCanvas.LineTo(7 * PtInMM, m2);
|
|
pdfCanvas.MoveTo(pageSize.GetRight(), m2);
|
|
pdfCanvas.LineTo(pageSize.GetRight() - 7 * PtInMM, m2);
|
|
|
|
pdfCanvas.MoveTo(0, m3);
|
|
pdfCanvas.LineTo(10 * PtInMM, m3);
|
|
pdfCanvas.MoveTo(pageSize.GetRight(), m3);
|
|
pdfCanvas.LineTo(pageSize.GetRight() - 10 * PtInMM, m3);
|
|
|
|
pdfCanvas.ClosePathStroke();
|
|
}
|
|
|
|
if (NumberOfPages > 0) {
|
|
// FillPlaceholders() was already called
|
|
FillPlaceholder(pdf, pageNum);
|
|
}
|
|
}
|
|
|
|
private void OnDocumentClose(PdfDocumentEvent evt) {
|
|
var pdf = evt.GetDocument();
|
|
var page = evt.GetPage();
|
|
var pageNum = pdf.GetPageNumber(page);
|
|
|
|
// ...
|
|
|
|
FillPlaceholders(pdf);
|
|
}
|
|
|
|
private void FillPlaceholders(PdfDocument pdf) {
|
|
NumberOfPages = pdf.GetNumberOfPages();
|
|
for (int i = 0; i < _pageNumPlaceholders.Count; i++)
|
|
FillPlaceholder(pdf, i + 1);
|
|
}
|
|
|
|
private void FillPlaceholder(PdfDocument pdf, int pageNum) {
|
|
var placeholder = _pageNumPlaceholders[pageNum - 1];
|
|
using var canvas = new Canvas(placeholder, pdf);
|
|
if (_doc.IsDoublePaged && (pageNum % 2 == 0)) {
|
|
// left page (= swapped)
|
|
var p = new KernedParagraph(_fontSize).SetFont(_doc.NF);
|
|
if (_doc.IsPreview) p.Add(_doc.Bold("(vorläufig) "));
|
|
p.Add(_doc.Normal($"Seite {pageNum:N0} von {NumberOfPages:N0} "));
|
|
canvas.ShowTextAligned(p, 0, 0, TextAlignment.LEFT);
|
|
} else {
|
|
// right page
|
|
var p = new KernedParagraph(_fontSize).SetFont(_doc.NF)
|
|
.Add(_doc.Normal($"Seite {pageNum:N0} von {NumberOfPages:N0}"));
|
|
if (_doc.IsPreview) p.Add(_doc.Bold(" (vorläufig)"));
|
|
canvas.ShowTextAligned(p, _placeholderWidth, 0, TextAlignment.RIGHT);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|