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 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 PerDoc) Convert(IEnumerable inputFiles, string pdfPath, bool doublePaged = false, IEnumerable? docs = null, CancellationToken? cancelToken = null, IProgress? progress = null) { var tmpFileNames = new List(); var pageNums = new List(); var tmpPageNums = new List(); 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; } } }