using System.IO; using System.Text; using System.Windows; using Microsoft.Web.WebView2.Core; using Microsoft.Web.WebView2.Wpf; using YY.Admin.Core.Util; namespace YY.Admin.Infrastructure.Print; /// /// 使用隐藏 WebView2 窗口将 HTML 字符串渲染为 PDF base64。 /// 所有调用必须最终在 WPF UI 线程执行,由内部 Dispatcher 保证。 /// public static class HtmlToPdfRenderer { public static Task RenderAsync(string html, double widthMm = 210, double heightMm = 297) { var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); Application.Current.Dispatcher.InvokeAsync(async () => { try { var result = await RenderOnUiThreadAsync(html, widthMm, heightMm); tcs.SetResult(result); } catch (Exception ex) { tcs.SetException(ex); } }); return tcs.Task; } private static async Task RenderOnUiThreadAsync(string html, double widthMm, double heightMm) { var tempHtml = Path.ChangeExtension(Path.GetTempFileName(), ".html"); var tempPdf = Path.ChangeExtension(Path.GetTempFileName(), ".pdf"); Window? win = null; try { File.WriteAllText(tempHtml, html, Encoding.UTF8); var userData = AppWritablePaths.EnsureDirectoryExists( Path.Combine(AppWritablePaths.LocalApplicationRoot, "WebView2", "HtmlToPdf")); var env = await CoreWebView2Environment.CreateAsync(browserExecutableFolder: null, userDataFolder: userData); var wv = new WebView2(); win = new Window { Width = 1, Height = 1, Left = -99999, Top = -99999, ShowInTaskbar = false, WindowStyle = WindowStyle.None, Visibility = Visibility.Visible }; win.Content = wv; win.Show(); await wv.EnsureCoreWebView2Async(env); var navTcs = new TaskCompletionSource(); wv.CoreWebView2.NavigationCompleted += (_, _) => navTcs.TrySetResult(); wv.CoreWebView2.Navigate(new Uri(tempHtml).AbsoluteUri); await navTcs.Task; // 短暂等待 JS/CSS 完成渲染 await Task.Delay(200); var settings = env.CreatePrintSettings(); settings.PageWidth = widthMm / 25.4; settings.PageHeight = heightMm / 25.4; settings.MarginTop = 0; settings.MarginBottom = 0; settings.MarginLeft = 0; settings.MarginRight = 0; settings.ShouldPrintHeaderAndFooter = false; settings.ShouldPrintBackgrounds = true; await wv.CoreWebView2.PrintToPdfAsync(tempPdf, settings); var pdfBytes = File.ReadAllBytes(tempPdf); return Convert.ToBase64String(pdfBytes); } finally { win?.Close(); try { File.Delete(tempHtml); } catch { } try { File.Delete(tempPdf); } catch { } } } }