如何在WinUI 3桌面应用中离线显示只读PDF流(无需外部程序)
解决方案:嵌入PdfiumCore实现WinUI3内PDF离线渲染
核心思路
使用PdfiumCore(Google Pdfium的.NET绑定),将PDF页面渲染为WinUI支持的BitmapSource,直接在应用内的Image或自定义控件中显示,同时将Pdfium的原生库嵌入应用程序,无需外部安装依赖,完全离线运行。
具体实现步骤
1. 安装NuGet包
在项目中安装PdfiumCore和SkiaSharp.Views.WinUI(用于将Pdfium渲染的位图转换为WinUI可用格式):
Install-Package PdfiumCore Install-Package SkiaSharp.Views.WinUI
2. 嵌入Pdfium原生库
- 从PdfiumCore的NuGet包中提取对应架构(x86/x64/arm64)的
pdfium.dll文件,添加到项目中。 - 设置
pdfium.dll的属性:复制到输出目录选择“始终复制”,生成操作选择“内容”。这样打包应用时会将原生库包含在内,无需用户额外安装。
3. 编写PDF流渲染代码
以下是从解密后的PDF流中渲染单页并显示的示例代码:
using PdfiumCore; using SkiaSharp; using SkiaSharp.Views.WinUI; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media.Imaging; // decryptedPdfStream为已获取的解密PDF流 public async Task RenderSinglePdfPage(Stream decryptedPdfStream, Image pdfDisplayImage) { // 加载PDF文档 using var document = PdfDocument.Load(decryptedPdfStream); // 取第一页(可根据需求指定页码) using var page = document.Pages[0]; // 设置渲染参数(DPI可根据显示需求调整) const int dpi = 96; var renderWidth = (int)(page.Width * dpi / 72); var renderHeight = (int)(page.Height * dpi / 72); // 创建SkiaSharp位图用于承载渲染内容 using var bitmap = new SKBitmap(renderWidth, renderHeight, SKColorType.Rgba8888, SKAlphaType.Premul); using var canvas = new SKCanvas(bitmap); canvas.Clear(SKColors.White); // 渲染PDF页面到位图 page.Render(canvas, renderWidth, renderHeight, dpi, dpi, PdfRenderFlags.Annotations); // 将SkiaSharp位图转换为WinUI可用的BitmapSource using var imageStream = new MemoryStream(); bitmap.Encode(imageStream, SKEncodedImageFormat.Png, 100); imageStream.Position = 0; var bitmapImage = new BitmapImage(); await bitmapImage.SetSourceAsync(imageStream.AsRandomAccessStream()); // 在Image控件中显示渲染结果 pdfDisplayImage.Source = bitmapImage; }
4. 多页PDF滚动浏览实现
如果需要显示完整的多页PDF,可以将每个页面的渲染结果添加到ScrollViewer的StackPanel容器中,实现滚动浏览:
public async Task RenderAllPdfPages(Stream decryptedPdfStream, ScrollViewer scrollViewer) { var pageContainer = new StackPanel(); using var document = PdfDocument.Load(decryptedPdfStream); foreach (var page in document.Pages) { const int dpi = 96; var renderWidth = (int)(page.Width * dpi / 72); var renderHeight = (int)(page.Height * dpi / 72); using var bitmap = new SKBitmap(renderWidth, renderHeight, SKColorType.Rgba8888, SKAlphaType.Premul); using var canvas = new SKCanvas(bitmap); canvas.Clear(SKColors.White); page.Render(canvas, renderWidth, renderHeight, dpi, dpi, PdfRenderFlags.Annotations); using var imageStream = new MemoryStream(); bitmap.Encode(imageStream, SKEncodedImageFormat.Png, 100); imageStream.Position = 0; var bitmapImage = new BitmapImage(); await bitmapImage.SetSourceAsync(imageStream.AsRandomAccessStream()); var pageImage = new Image { Source = bitmapImage, Margin = new Thickness(0, 0, 0, 10) }; pageContainer.Children.Add(pageImage); } scrollViewer.Content = pageContainer; }
方案优势
- 完全离线:所有依赖(Pdfium原生库、.NET包)均嵌入应用,无需用户安装任何外部组件。
- 无外部调用:全程在应用内完成PDF渲染,无需启动第三方程序。
- 天然只读:渲染结果为静态图片,满足只读显示需求,无法直接编辑PDF内容。
内容的提问来源于stack exchange,提问作者אפרת
相关产品推荐
相关产品推荐

