Documents: Replace Razor templates with iText
All checks were successful
Test / Run tests (push) Successful in 2m24s
All checks were successful
Test / Run tests (push) Successful in 2m24s
This commit is contained in:
@@ -1,19 +1,42 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.IO;
|
||||
using Elwig.Helpers;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
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 abstract partial class Document : IDisposable {
|
||||
public class Document : IDisposable {
|
||||
|
||||
public static string Name => "Dokument";
|
||||
|
||||
protected static readonly double GenerationProportion = 0.125;
|
||||
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;
|
||||
@@ -24,22 +47,18 @@ namespace Elwig.Documents {
|
||||
public bool ShowFoldMarks = App.Config.Debug;
|
||||
public bool IsDoublePaged = false;
|
||||
public bool IsPreview = false;
|
||||
private iText.Layout.Document? _doc;
|
||||
|
||||
public string DocumentsPath;
|
||||
public int CurrentNextSeason;
|
||||
public string? DocumentId;
|
||||
public string Title;
|
||||
public string Author;
|
||||
public string Header;
|
||||
public DateOnly Date;
|
||||
|
||||
public Document(string title) {
|
||||
var c = App.Client;
|
||||
DocumentsPath = App.DocumentsPath;
|
||||
CurrentNextSeason = Utils.CurrentNextSeason;
|
||||
Title = title;
|
||||
Author = c.NameFull;
|
||||
Header = "";
|
||||
Author = App.Client.NameFull;
|
||||
Date = DateOnly.FromDateTime(Utils.Today);
|
||||
}
|
||||
|
||||
@@ -58,99 +77,173 @@ namespace Elwig.Documents {
|
||||
}
|
||||
|
||||
public static Document FromPdf(string path) {
|
||||
return new PdfDocument(path);
|
||||
return new RawPdfDocument(path);
|
||||
}
|
||||
|
||||
private async Task<string> Render() {
|
||||
string name;
|
||||
if (this is BusinessLetter) {
|
||||
name = "BusinessLetter";
|
||||
} else if (this is DeliveryNote) {
|
||||
name = "DeliveryNote";
|
||||
} else if (this is CreditNote) {
|
||||
name = "CreditNote";
|
||||
} else if (this is DeliveryJournal) {
|
||||
name = "DeliveryJournal";
|
||||
} else if (this is DeliveryDepreciationList) {
|
||||
name = "DeliveryDepreciationList";
|
||||
} else if (this is Letterhead) {
|
||||
name = "Letterhead";
|
||||
} else if (this is DeliveryConfirmation) {
|
||||
name = "DeliveryConfirmation";
|
||||
} else if (this is MemberDataSheet) {
|
||||
name = "MemberDataSheet";
|
||||
} else if (this is MemberList) {
|
||||
name = "MemberList";
|
||||
} else if (this is WineQualityStatistics) {
|
||||
name = "WineQualityStatistics";
|
||||
} else if (this is PaymentVariantSummary) {
|
||||
name = "PaymentVariantSummary";
|
||||
} else if (this is DeliveryAncmtList) {
|
||||
name = "DeliveryAncmtList";
|
||||
} else {
|
||||
throw new InvalidOperationException("Invalid document object");
|
||||
private class RawPdfDocument : Document {
|
||||
public RawPdfDocument(string pdfPath) :
|
||||
base(Path.GetFileNameWithoutExtension(pdfPath)) {
|
||||
_pdfPath = pdfPath;
|
||||
}
|
||||
return await Render(name);
|
||||
}
|
||||
|
||||
private async Task<string> Render(string name) {
|
||||
return await Html.CompileRenderAsync(name, this); ;
|
||||
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 PdfDocument) {
|
||||
if (this is RawPdfDocument) {
|
||||
// nothing to do
|
||||
} else if (this is MergedDocument m) {
|
||||
using var tmpPdf = new TempFile("pdf");
|
||||
var pdf = new TempFile("pdf");
|
||||
var tmpHtmls = new List<TempFile>();
|
||||
var tmpFiles = new List<string>();
|
||||
try {
|
||||
var n = m.Documents.Count();
|
||||
int i = 0;
|
||||
foreach (var doc in m.Documents) {
|
||||
if (doc is PdfDocument) {
|
||||
tmpFiles.Add(doc.PdfPath!);
|
||||
continue;
|
||||
}
|
||||
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 tmpHtml = new TempFile("html");
|
||||
await File.WriteAllTextAsync(tmpHtml.FilePath, await doc.Render(), Utils.UTF8);
|
||||
tmpHtmls.Add(tmpHtml);
|
||||
tmpFiles.Add((doc is Letterhead ? "#" : "") + tmpHtml.FilePath);
|
||||
i++;
|
||||
progress?.Report(GenerationProportion * 100 * i / n);
|
||||
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));
|
||||
}
|
||||
progress?.Report(GenerationProportion * 100);
|
||||
var pages = Pdf.Convert(tmpFiles, pdf.FilePath, IsDoublePaged, m.Documents, cancelToken, new Progress<double>(v => progress?.Report(GenerationProportion * 100 + v * (1 - GenerationProportion))));
|
||||
TotalPages = pages.Pages;
|
||||
_pdfFile = pdf;
|
||||
|
||||
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;
|
||||
} finally {
|
||||
foreach (var tmp in tmpHtmls) {
|
||||
tmp.Dispose();
|
||||
}
|
||||
}
|
||||
_pdfFile = pdf;
|
||||
} else {
|
||||
if (cancelToken?.IsCancellationRequested ?? false)
|
||||
throw new OperationCanceledException("Dokumentenerzeugung abgebrochen!");
|
||||
var pdf = new TempFile("pdf");
|
||||
try {
|
||||
using var tmpHtml = new TempFile("html");
|
||||
await File.WriteAllTextAsync(tmpHtml.FilePath, await Render(), Utils.UTF8);
|
||||
progress?.Report(50.0);
|
||||
var pages = Pdf.Convert(tmpHtml.FilePath, pdf.FilePath, this);
|
||||
TotalPages = pages.Pages;
|
||||
_pdfFile = pdf;
|
||||
TotalPages = Render(pdf.FilePath);
|
||||
} catch {
|
||||
pdf.Dispose();
|
||||
throw;
|
||||
}
|
||||
_pdfFile = pdf;
|
||||
}
|
||||
progress?.Report(100.0);
|
||||
}
|
||||
@@ -180,14 +273,239 @@ namespace Elwig.Documents {
|
||||
};
|
||||
}
|
||||
|
||||
private class MergedDocument(IEnumerable<Document> docs) : Document("Mehrere Dokumente") {
|
||||
public IEnumerable<Document> Documents = docs;
|
||||
private class MergedDocument : Document {
|
||||
public List<Document> Documents;
|
||||
|
||||
public MergedDocument(IEnumerable<Document> docs) :
|
||||
base("Mehrere Dokumente") {
|
||||
Documents = [.. docs];
|
||||
IsDoublePaged = docs.Any(x => x.IsDoublePaged);
|
||||
}
|
||||
}
|
||||
|
||||
private class PdfDocument : Document {
|
||||
public PdfDocument(string pdfPath) :
|
||||
base(Path.GetFileNameWithoutExtension(pdfPath)) {
|
||||
_pdfPath = pdfPath;
|
||||
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(rotated ? 0.5 * Math.PI : 0);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user