Documents: use WinziPrint instead of WeasyPrint

This commit is contained in:
2023-10-19 16:38:03 +02:00
parent a2f49e1b8b
commit a832879b73
3 changed files with 60 additions and 74 deletions

View File

@ -3,14 +3,12 @@ using System.Threading.Tasks;
using System.IO; using System.IO;
using Elwig.Helpers; using Elwig.Helpers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Linq; using System.Linq;
namespace Elwig.Documents { namespace Elwig.Documents {
public abstract partial class Document : IDisposable { public abstract partial class Document : IDisposable {
private TempFile? _pdfFile = null; private TempFile? _pdfFile = null;
private string? _renderedHtml = null;
public bool ShowFoldMarks = App.Config.Debug; public bool ShowFoldMarks = App.Config.Debug;
@ -39,18 +37,6 @@ namespace Elwig.Documents {
Date = DateTime.Today; 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() { ~Document() {
Dispose(); Dispose();
} }
@ -62,33 +48,10 @@ namespace Elwig.Documents {
} }
public static async Task<Document> Merge(IEnumerable<Document> docs) { public static async Task<Document> Merge(IEnumerable<Document> docs) {
string html = ""; return new MergedDocument(docs);
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,
};
} }
private async Task<string> Render() { private async Task<string> Render() {
if (_renderedHtml != null)
return _renderedHtml;
string name; string name;
if (this is BusinessLetter) { if (this is BusinessLetter) {
name = "BusinessLetter"; name = "BusinessLetter";
@ -109,17 +72,32 @@ namespace Elwig.Documents {
} }
private async Task<string> Render(string name) { private async Task<string> Render(string name) {
_renderedHtml = await Html.CompileRenderAsync(name, this); return await Html.CompileRenderAsync(name, this); ;
return _renderedHtml;
} }
public async Task Generate() { public async Task Generate() {
var pdf = new TempFile("pdf"); if (this is MergedDocument m) {
using (var tmpHtml = new TempFile("html")) { var pdf = new TempFile("pdf");
await File.WriteAllTextAsync(tmpHtml.FilePath, await Render(), Utils.UTF8); var tmpHtmls = new List<TempFile>();
await Pdf.Convert(tmpHtml.FilePath, pdf.FilePath); 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) { public void SaveTo(string pdfPath) {
@ -137,8 +115,11 @@ namespace Elwig.Documents {
Pdf.Show(_pdfFile.NewReference(), Title + (this is BusinessDocument b ? $" - {b.Member.Name}" : "")); Pdf.Show(_pdfFile.NewReference(), Title + (this is BusinessDocument b ? $" - {b.Member.Name}" : ""));
} }
private class InternalDocument : Document { private class MergedDocument : Document {
public InternalDocument(string title) : base(title) { } public IEnumerable<Document> Documents;
public MergedDocument(IEnumerable<Document> docs) : base("Mehrere Dokumente") {
Documents = docs;
}
} }
} }
} }

View File

@ -2,44 +2,50 @@ using System.Threading.Tasks;
using Elwig.Helpers; using Elwig.Helpers;
using Elwig.Windows; using Elwig.Windows;
using System.Diagnostics; using System.Diagnostics;
using Balbarak.WeasyPrint;
using System; using System;
using System.IO; using System.IO;
using System.Collections.Generic;
using System.Windows;
using System.Text.RegularExpressions;
using System.Linq;
namespace Elwig.Documents { namespace Elwig.Documents {
public static class Pdf { public static class Pdf {
private static readonly string PdfToPrinter = App.ExePath + "PDFtoPrinter.exe"; private static readonly string PdfToPrinter = App.ExePath + "PDFtoPrinter.exe";
private static readonly FilesManager WeasyPrintManager = new(); private static readonly string WinziPrint = App.ExePath + "WinziPrint.exe";
private static string? WeasyPrintPython = null; private static Process? WinziPrintProc;
private static string? WeasyPrintDir => WeasyPrintManager.FolderPath; public static bool IsReady => WinziPrintProc != null;
public static bool IsReady => WeasyPrintPython != null && WeasyPrintDir != null;
public static async Task Init(Action evtHandler) { public static async Task Init(Action evtHandler) {
if (!WeasyPrintManager.IsFilesExsited()) { var p = new Process() { StartInfo = new() {
await WeasyPrintManager.InitFilesAsync(); FileName = WinziPrint,
} Arguments = "-",
WeasyPrintPython = Path.Combine(WeasyPrintManager.FolderPath, "python.exe"); CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = true
} };
p.Start();
WinziPrintProc = p;
evtHandler(); evtHandler();
} }
public static async Task Convert(string htmlPath, string pdfPath) { public static async Task<IEnumerable<int>> Convert(string htmlPath, string pdfPath) {
var p = new Process() { StartInfo = new() { return await Convert(new string[] { htmlPath }, pdfPath);
FileName = WeasyPrintPython, }
CreateNoWindow = true,
WorkingDirectory = WeasyPrintDir, public static async Task<IEnumerable<int>> Convert(IEnumerable<string> htmlPath, string pdfPath) {
RedirectStandardError = true, if (WinziPrintProc == null) throw new InvalidOperationException("The WinziPrint process has not been initialized yet");
} }; await WinziPrintProc.StandardInput.WriteLineAsync($"{string.Join(';', htmlPath)};{pdfPath}");
p.StartInfo.EnvironmentVariables["PATH"] = "Scripts;gtk3;" + Environment.GetEnvironmentVariable("PATH"); var line = await WinziPrintProc.StandardOutput.ReadLineAsync() ?? throw new IOException("Invalid response from WinziPrint");
p.StartInfo.ArgumentList.Add("scripts/weasyprint.exe"); if (line.StartsWith("error:")) {
p.StartInfo.ArgumentList.Add("-e"); MessageBox.Show(line[6..].Trim(), "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
p.StartInfo.ArgumentList.Add("utf8"); return Array.Empty<int>();
p.StartInfo.ArgumentList.Add(htmlPath); }
p.StartInfo.ArgumentList.Add(pdfPath); var m = Regex.Match(line, @"\(([0-9, ]+)\)");
p.Start(); return m.Groups[1].Value.Split(", ").Select(n => int.Parse(n));
await p.WaitForExitAsync();
var stderr = await p.StandardError.ReadToEndAsync();
if (p.ExitCode != 0) throw new Exception(stderr);
} }
public static void Show(TempFile file, string title) { public static void Show(TempFile file, string title) {

View File

@ -16,7 +16,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Balbarak.WeasyPrint" Version="2.0.2" />
<PackageReference Include="Extended.Wpf.Toolkit" Version="4.5.1" /> <PackageReference Include="Extended.Wpf.Toolkit" Version="4.5.1" />
<PackageReference Include="ini-parser" Version="2.5.2" /> <PackageReference Include="ini-parser" Version="2.5.2" />
<PackageReference Include="LinqKit" Version="1.2.4" /> <PackageReference Include="LinqKit" Version="1.2.4" />