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 { }
}
}
}