Documents: use WinziPrint instead of WeasyPrint
This commit is contained in:
		@@ -3,14 +3,12 @@ using System.Threading.Tasks;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using Elwig.Helpers;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Text.RegularExpressions;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
 | 
			
		||||
namespace Elwig.Documents {
 | 
			
		||||
    public abstract partial class Document : IDisposable {
 | 
			
		||||
 | 
			
		||||
        private TempFile? _pdfFile = null;
 | 
			
		||||
        private string? _renderedHtml = null;
 | 
			
		||||
 | 
			
		||||
        public bool ShowFoldMarks = App.Config.Debug;
 | 
			
		||||
 | 
			
		||||
@@ -39,18 +37,6 @@ namespace Elwig.Documents {
 | 
			
		||||
            Date = DateTime.Today;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [GeneratedRegex(@"</body>.*?</footer>\s*</div>", RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Compiled)]
 | 
			
		||||
        private static partial Regex GeneratedDocumentHeaderRegex();
 | 
			
		||||
        private static readonly Regex DocumentHeaderRegex = GeneratedDocumentHeaderRegex();
 | 
			
		||||
 | 
			
		||||
        [GeneratedRegex(@"<style>.*?/style>", RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Compiled)]
 | 
			
		||||
        private static partial Regex GeneratedHtmlStyleRegex();
 | 
			
		||||
        private static readonly Regex HtmlStyleRegex = GeneratedHtmlStyleRegex();
 | 
			
		||||
 | 
			
		||||
        [GeneratedRegex(@"<link[^>]*>", RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Compiled)]
 | 
			
		||||
        private static partial Regex GeneratedHtmlLinkRegex();
 | 
			
		||||
        private static readonly Regex HtmlLinkRegex = GeneratedHtmlLinkRegex();
 | 
			
		||||
 | 
			
		||||
        ~Document() {
 | 
			
		||||
            Dispose();
 | 
			
		||||
        }
 | 
			
		||||
@@ -62,33 +48,10 @@ namespace Elwig.Documents {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static async Task<Document> Merge(IEnumerable<Document> docs) {
 | 
			
		||||
            string html = "";
 | 
			
		||||
            var styles = new List<string>();
 | 
			
		||||
            foreach (var d in docs) {
 | 
			
		||||
                var h = await d.Render();
 | 
			
		||||
                var s = HtmlStyleRegex.Matches(h).Select(m => m.Value).ToList();
 | 
			
		||||
                var l = HtmlLinkRegex.Matches(h).Select(m => m.Value).ToList();
 | 
			
		||||
                if (s.All(styles.Contains)) {
 | 
			
		||||
                    h = HtmlStyleRegex.Replace(h, "");
 | 
			
		||||
                } else {
 | 
			
		||||
                    styles.AddRange(s);
 | 
			
		||||
                }
 | 
			
		||||
                if (l.All(styles.Contains)) {
 | 
			
		||||
                    h = HtmlLinkRegex.Replace(h, "");
 | 
			
		||||
                } else {
 | 
			
		||||
                    styles.AddRange(l);
 | 
			
		||||
                }
 | 
			
		||||
                html += h;
 | 
			
		||||
            }
 | 
			
		||||
            html = DocumentHeaderRegex.Replace(html, "<div class='document-break'/>");
 | 
			
		||||
            return new InternalDocument("Mehrere Dokumente") {
 | 
			
		||||
                _renderedHtml = html,
 | 
			
		||||
            };
 | 
			
		||||
            return new MergedDocument(docs);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async Task<string> Render() {
 | 
			
		||||
            if (_renderedHtml != null)
 | 
			
		||||
                return _renderedHtml;
 | 
			
		||||
            string name;
 | 
			
		||||
            if (this is BusinessLetter) {
 | 
			
		||||
                name = "BusinessLetter";
 | 
			
		||||
@@ -109,17 +72,32 @@ namespace Elwig.Documents {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async Task<string> Render(string name) {
 | 
			
		||||
            _renderedHtml = await Html.CompileRenderAsync(name, this);
 | 
			
		||||
            return _renderedHtml;
 | 
			
		||||
            return await Html.CompileRenderAsync(name, this); ;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task Generate() {
 | 
			
		||||
            var pdf = new TempFile("pdf");
 | 
			
		||||
            using (var tmpHtml = new TempFile("html")) {
 | 
			
		||||
                await File.WriteAllTextAsync(tmpHtml.FilePath, await Render(), Utils.UTF8);
 | 
			
		||||
                await Pdf.Convert(tmpHtml.FilePath, pdf.FilePath);
 | 
			
		||||
            if (this is MergedDocument m) {
 | 
			
		||||
                var pdf = new TempFile("pdf");
 | 
			
		||||
                var tmpHtmls = new List<TempFile>();
 | 
			
		||||
                foreach (var doc in m.Documents) {
 | 
			
		||||
                    var tmpHtml = new TempFile("html");
 | 
			
		||||
                    await doc.Render();
 | 
			
		||||
                    await File.WriteAllTextAsync(tmpHtml.FilePath, await doc.Render(), Utils.UTF8);
 | 
			
		||||
                    tmpHtmls.Add(tmpHtml);
 | 
			
		||||
                }
 | 
			
		||||
                await Pdf.Convert(tmpHtmls.Select(f => f.FilePath), pdf.FilePath);
 | 
			
		||||
                foreach (var tmp in tmpHtmls) {
 | 
			
		||||
                    tmp.Dispose();
 | 
			
		||||
                }
 | 
			
		||||
                _pdfFile = pdf;
 | 
			
		||||
            } else {
 | 
			
		||||
                var pdf = new TempFile("pdf");
 | 
			
		||||
                using (var tmpHtml = new TempFile("html")) {
 | 
			
		||||
                    await File.WriteAllTextAsync(tmpHtml.FilePath, await Render(), Utils.UTF8);
 | 
			
		||||
                    await Pdf.Convert(tmpHtml.FilePath, pdf.FilePath);
 | 
			
		||||
                }
 | 
			
		||||
                _pdfFile = pdf;
 | 
			
		||||
            }
 | 
			
		||||
            _pdfFile = pdf;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SaveTo(string pdfPath) {
 | 
			
		||||
@@ -137,8 +115,11 @@ namespace Elwig.Documents {
 | 
			
		||||
            Pdf.Show(_pdfFile.NewReference(), Title + (this is BusinessDocument b ? $" - {b.Member.Name}" : ""));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private class InternalDocument : Document {
 | 
			
		||||
            public InternalDocument(string title) : base(title) { }
 | 
			
		||||
        private class MergedDocument : Document {
 | 
			
		||||
            public IEnumerable<Document> Documents;
 | 
			
		||||
            public MergedDocument(IEnumerable<Document> docs) : base("Mehrere Dokumente") {
 | 
			
		||||
                Documents = docs;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,44 +2,50 @@ using System.Threading.Tasks;
 | 
			
		||||
using Elwig.Helpers;
 | 
			
		||||
using Elwig.Windows;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
using Balbarak.WeasyPrint;
 | 
			
		||||
using System;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Windows;
 | 
			
		||||
using System.Text.RegularExpressions;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
 | 
			
		||||
namespace Elwig.Documents {
 | 
			
		||||
    public static class Pdf {
 | 
			
		||||
 | 
			
		||||
        private static readonly string PdfToPrinter = App.ExePath + "PDFtoPrinter.exe";
 | 
			
		||||
        private static readonly FilesManager WeasyPrintManager = new();
 | 
			
		||||
        private static string? WeasyPrintPython = null;
 | 
			
		||||
        private static string? WeasyPrintDir => WeasyPrintManager.FolderPath;
 | 
			
		||||
        public static bool IsReady => WeasyPrintPython != null && WeasyPrintDir != null;
 | 
			
		||||
        private static readonly string WinziPrint = App.ExePath + "WinziPrint.exe";
 | 
			
		||||
        private static Process? WinziPrintProc;
 | 
			
		||||
        public static bool IsReady => WinziPrintProc != null;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public static async Task Init(Action evtHandler) {
 | 
			
		||||
            if (!WeasyPrintManager.IsFilesExsited()) {
 | 
			
		||||
                await WeasyPrintManager.InitFilesAsync();
 | 
			
		||||
            }
 | 
			
		||||
            WeasyPrintPython = Path.Combine(WeasyPrintManager.FolderPath, "python.exe");
 | 
			
		||||
            var p = new Process() { StartInfo = new() {
 | 
			
		||||
                FileName = WinziPrint,
 | 
			
		||||
                Arguments = "-",
 | 
			
		||||
                CreateNoWindow = true,
 | 
			
		||||
                UseShellExecute = false,
 | 
			
		||||
                RedirectStandardInput = true,
 | 
			
		||||
                RedirectStandardOutput = true
 | 
			
		||||
            } };
 | 
			
		||||
            p.Start();
 | 
			
		||||
            WinziPrintProc = p;
 | 
			
		||||
            evtHandler();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static async Task Convert(string htmlPath, string pdfPath) {
 | 
			
		||||
            var p = new Process() { StartInfo = new() {
 | 
			
		||||
                FileName = WeasyPrintPython,
 | 
			
		||||
                CreateNoWindow = true,
 | 
			
		||||
                WorkingDirectory = WeasyPrintDir,
 | 
			
		||||
                RedirectStandardError = true,
 | 
			
		||||
            } };
 | 
			
		||||
            p.StartInfo.EnvironmentVariables["PATH"] = "Scripts;gtk3;" + Environment.GetEnvironmentVariable("PATH");
 | 
			
		||||
            p.StartInfo.ArgumentList.Add("scripts/weasyprint.exe");
 | 
			
		||||
            p.StartInfo.ArgumentList.Add("-e");
 | 
			
		||||
            p.StartInfo.ArgumentList.Add("utf8");
 | 
			
		||||
            p.StartInfo.ArgumentList.Add(htmlPath);
 | 
			
		||||
            p.StartInfo.ArgumentList.Add(pdfPath);
 | 
			
		||||
            p.Start();
 | 
			
		||||
            await p.WaitForExitAsync();
 | 
			
		||||
            var stderr = await p.StandardError.ReadToEndAsync();
 | 
			
		||||
            if (p.ExitCode != 0) throw new Exception(stderr);
 | 
			
		||||
        public static async Task<IEnumerable<int>> Convert(string htmlPath, string pdfPath) {
 | 
			
		||||
            return await Convert(new string[] { htmlPath }, pdfPath);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static async Task<IEnumerable<int>> Convert(IEnumerable<string> htmlPath, string pdfPath) {
 | 
			
		||||
            if (WinziPrintProc == null) throw new InvalidOperationException("The WinziPrint process has not been initialized yet");
 | 
			
		||||
            await WinziPrintProc.StandardInput.WriteLineAsync($"{string.Join(';', htmlPath)};{pdfPath}");
 | 
			
		||||
            var line = await WinziPrintProc.StandardOutput.ReadLineAsync() ?? throw new IOException("Invalid response from WinziPrint");
 | 
			
		||||
            if (line.StartsWith("error:")) {
 | 
			
		||||
                MessageBox.Show(line[6..].Trim(), "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
 | 
			
		||||
                return Array.Empty<int>();
 | 
			
		||||
            }
 | 
			
		||||
            var m = Regex.Match(line, @"\(([0-9, ]+)\)");
 | 
			
		||||
            return m.Groups[1].Value.Split(", ").Select(n => int.Parse(n));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void Show(TempFile file, string title) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user