Files
elwig/Elwig/Helpers/Printing/Pdf.cs
Lorenz Stechauner 4bd68eb16b
Some checks failed
Test / Run tests (push) Has been cancelled
Printing: Replace WinziPrint with iText
2026-02-18 23:00:21 +01:00

183 lines
7.7 KiB
C#

using Elwig.Windows;
using iText.Html2pdf;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Event;
using iText.Kernel.Utils;
using System;
using System.Collections.Generic;
using System.Drawing.Printing;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
namespace Elwig.Helpers.Printing {
public static class Pdf {
public static Task Init(Action? evtHandler = null) {
PdfiumNative.FPDF_InitLibrary();
evtHandler?.Invoke();
return Task.CompletedTask;
}
public static Task Cleanup() {
PdfiumNative.FPDF_DestroyLibrary();
return Task.CompletedTask;
}
public static (int Pages, IEnumerable<int> PerDoc) Convert(string htmlPath, string pdfPath, Documents.Document? doc = null) {
int nPages;
using var html = File.Open(htmlPath, FileMode.Open);
using var writer = new PdfWriter(pdfPath);
using var pdf = new PdfDocument(writer);
var footerHandler = new FooterEventHandler(doc);
pdf.AddEventHandler(PdfDocumentEvent.END_PAGE, footerHandler);
pdf.AddEventHandler(PdfDocumentEvent.START_DOCUMENT_CLOSING, footerHandler);
// TODO embed fonts?
//pdf.AddFont(PdfFontFactory.CreateFont(StandardFonts.TIMES_ROMAN));
HtmlConverter.ConvertToPdf(html, pdf);
nPages = footerHandler.NumberOfPages;
return (nPages, [nPages]);
}
public static (int Pages, IEnumerable<int> PerDoc) Convert(IEnumerable<string> inputFiles, string pdfPath, bool doublePaged = false, IEnumerable<Documents.Document>? docs = null, CancellationToken? cancelToken = null, IProgress<double>? progress = null) {
var tmpFileNames = new List<string>();
var pageNums = new List<int>();
var tmpPageNums = new List<int>();
var htmlFiles = inputFiles
.Where(f => !f.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase))
.Select(f => f.TrimStart('!', '#'))
.ToList();
try {
for (int i = 0; i < htmlFiles.Count; i++) {
string tmpFile = $"{pdfPath}.{i:0000}.part";
tmpFileNames.Add(tmpFile);
var (pages, _) = Convert(htmlFiles[i], tmpFile, docs?.ElementAt(i));
tmpPageNums.Add(pages);
}
using var writer = new PdfWriter(pdfPath);
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 < inputFiles.Count(); i++) {
var fileName = inputFiles.ElementAt(i);
int p0 = mergedPdf.GetNumberOfPages();
if (letterheadPage != null && fileName.StartsWith('#')) {
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;
letterheadPage = null;
}
if (fileName.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase)) {
var cleanName = fileName.TrimStart('!', '#');
if (doublePaged && fileName.StartsWith('#')) {
using var reader = new PdfReader(cleanName);
using var src = new PdfDocument(reader);
letterheadPage = src.GetPage(1).CopyTo(mergedPdf);
letterheadInsertIndex = p0;
letterheadDocIndex = i;
} else {
using var reader = new PdfReader(cleanName);
using var src = new PdfDocument(reader);
merger.Merge(src, 1, src.GetNumberOfPages());
}
} else {
string tmpFile = tmpFileNames[i];
if (doublePaged && fileName.StartsWith('#')) {
using var reader = new PdfReader(tmpFile);
using var src = new PdfDocument(reader);
letterheadPage = src.GetPage(1).CopyTo(mergedPdf);
letterheadInsertIndex = p0;
letterheadDocIndex = i;
} else {
using var reader = new PdfReader(tmpFile);
using var src = new PdfDocument(reader);
merger.Merge(src, 1, tmpPageNums[i]);
}
}
int p1 = mergedPdf.GetNumberOfPages();
pageNums.Add(p1 - p0);
if (doublePaged && fileName[0] != '!' && fileName[0] != '#' && mergedPdf.GetNumberOfPages() % 2 != 0) {
if (letterheadPage != null) {
mergedPdf.AddPage(letterheadPage.CopyTo(mergedPdf));
letterheadPage = null;
} else {
mergedPdf.AddNewPage();
}
}
}
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;
}
} finally {
foreach (var tmp in tmpFileNames) {
if (File.Exists(tmp)) File.Delete(tmp);
}
}
return (pageNums.Sum(), pageNums);
}
public static void Show(TempFile file, string title) {
App.MainDispatcher.BeginInvoke(() => {
var w = new DocumentViewerWindow(title, file);
w.Show();
});
}
public static void Show(string path, string title) {
App.MainDispatcher.BeginInvoke(() => {
var w = new DocumentViewerWindow(title, path);
w.Show();
});
}
public static async Task Print(string path, int copies = 1, bool doublePaged = false) {
await Print(path, new() {
Copies = (short)copies,
Collate = true,
Duplex = doublePaged ? Duplex.Vertical : Duplex.Simplex,
});
}
public static Task Print(string path, PrinterSettings settings) {
try {
using var printDoc = new PdfPrintDocument(path) {
PrinterSettings = settings,
};
printDoc.Print();
} catch (Exception e) {
MessageBox.Show("Beim Drucken ist ein Fehler aufgetreten:\n\n" + e.Message, "Fehler beim Drucken", MessageBoxButton.OK, MessageBoxImage.Error);
}
return Task.CompletedTask;
}
}
}