137 lines
6.3 KiB
C#
137 lines
6.3 KiB
C#
using Elwig.Windows;
|
|
using PdfiumViewer;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Drawing.Printing;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Net.Sockets;
|
|
using System.Reflection;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Windows;
|
|
|
|
namespace Elwig.Helpers.Printing {
|
|
public static class Pdf {
|
|
|
|
private static readonly string WinziPrint = (Assembly.GetEntryAssembly()?.Location.Contains(@"\bin\") ?? false) ?
|
|
Path.Combine(Assembly.GetEntryAssembly()!.Location.Split(@"\bin\")[0], "../Installer/Files/WinziPrint.exe") :
|
|
new string[] { App.InstallPath }
|
|
.Union(Environment.GetEnvironmentVariable("PATH")?.Split(';') ?? [])
|
|
.Select(x => Path.Combine(x, "WinziPrint.exe"))
|
|
.Where(File.Exists)
|
|
.FirstOrDefault() ?? throw new FileNotFoundException("WiniPrint executable not found");
|
|
private static Process? WinziPrintProc;
|
|
public static bool IsReady => WinziPrintProc != null;
|
|
|
|
public static async Task Init(Action? evtHandler = null) {
|
|
// NOTE: If the WinziPrint daemon is already running this will succeed, but the process will fail.
|
|
// Should be no problem, as long as the daemon is not closed
|
|
var p = new Process() { StartInfo = new() {
|
|
FileName = WinziPrint,
|
|
CreateNoWindow = true,
|
|
UseShellExecute = false,
|
|
RedirectStandardOutput = true,
|
|
} };
|
|
p.StartInfo.ArgumentList.Add("-D");
|
|
p.StartInfo.ArgumentList.Add("-d");
|
|
p.StartInfo.ArgumentList.Add(App.TempPath);
|
|
p.Start();
|
|
await p.StandardOutput.ReadLineAsync();
|
|
WinziPrintProc = p;
|
|
evtHandler?.Invoke();
|
|
}
|
|
|
|
public static Task Cleanup() {
|
|
WinziPrintProc?.Kill(true);
|
|
WinziPrintProc?.Close();
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public static async Task<(int Pages, IEnumerable<int> PerDoc)> Convert(string htmlPath, string pdfPath, bool doublePaged = false, CancellationToken? cancelToken = null, IProgress<double>? progress = null) {
|
|
return await Convert([htmlPath], pdfPath, doublePaged, cancelToken, progress);
|
|
}
|
|
|
|
public static async Task<(int Pages, IEnumerable<int> PerDoc)> Convert(IEnumerable<string> htmlPath, string pdfPath, bool doublePaged = false, CancellationToken? cancelToken = null, IProgress<double>? progress = null) {
|
|
if (WinziPrintProc == null) throw new InvalidOperationException("The WinziPrint process has not been initialized yet");
|
|
progress?.Report(0.0);
|
|
using var client = new TcpClient("127.0.0.1", 30983);
|
|
using var stream = client.GetStream();
|
|
string cnxId;
|
|
using var reader = new StreamReader(stream);
|
|
var first = await reader.ReadLineAsync() ?? throw new IOException("Invalid response from WinziPrint");
|
|
if (first.StartsWith("id:")) {
|
|
cnxId = first[3..].Trim();
|
|
} else {
|
|
throw new IOException("Invalid response from WinziPrint");
|
|
}
|
|
await stream.WriteAsync(Utils.UTF8.GetBytes(
|
|
"-e utf-8;-p;" + (doublePaged ? "-2;" : "") +
|
|
$"{string.Join(';', htmlPath)};{pdfPath}" +
|
|
"\r\n"));
|
|
bool cancelled = false;
|
|
while (true) {
|
|
if (!cancelled && (cancelToken?.IsCancellationRequested ?? false)) {
|
|
try {
|
|
using var cancelClient = new TcpClient("127.0.0.1", 30983);
|
|
using var cancelStream = cancelClient.GetStream();
|
|
using var cancelReader = new StreamReader(cancelStream);
|
|
await cancelReader.ReadLineAsync();
|
|
await cancelStream.WriteAsync(Utils.UTF8.GetBytes($"cancel;{cnxId}\r\n"));
|
|
} catch { }
|
|
cancelled = true;
|
|
}
|
|
var line = await reader.ReadLineAsync() ?? throw new IOException("Invalid response from WinziPrint");
|
|
if (line.StartsWith("error:")) {
|
|
var msg = line[6..].Trim();
|
|
if (msg == "aborted")
|
|
throw new OperationCanceledException("Dokumentenerzeugung abgebrochen!");
|
|
throw new IOException($"WinziPrint: {msg}");
|
|
} else if (line.StartsWith("progress:")) {
|
|
var parts = line[9..].Trim().Split('/').Select(int.Parse).ToArray();
|
|
progress?.Report(100.0 * parts[0] / parts[1]);
|
|
} else if (line.StartsWith("success:")) {
|
|
var m = Regex.Match(line, @"([0-9]+) pages \(([0-9, ]+)\)");
|
|
return (int.Parse(m.Groups[1].Value), m.Groups[2].Value.Split(", ").Select(int.Parse).ToList());
|
|
}
|
|
}
|
|
}
|
|
|
|
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 doc = PdfDocument.Load(path);
|
|
using var printDoc = doc.CreatePrintDocument(PdfPrintMode.CutMargin);
|
|
printDoc.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;
|
|
}
|
|
}
|
|
}
|