如何在Xamarin Forms中使用SkiaSharp在Canvas上绘制PDF?
如何在Xamarin Forms中使用SkiaSharp在Canvas上绘制PDF?
嘿,刚好我之前在项目里实现过类似的功能,给你一步步说清楚怎么操作,很容易上手的:
1. 安装必要的NuGet包
首先得把SkiaSharp相关的包装上,这是基础:
SkiaSharp:核心绘图库SkiaSharp.Views.Forms:Xamarin Forms的视图绑定SkiaSharp.Extended.Pdf:处理PDF的扩展包(这个很关键,原生SkiaSharp不直接支持PDF加载)
你可以通过NuGet包管理器搜索安装,或者用Package Manager控制台执行命令(版本选最新稳定版即可,注意三个包版本保持一致):
Install-Package SkiaSharp Install-Package SkiaSharp.Views.Forms Install-Package SkiaSharp.Extended.Pdf
2. 在XAML中添加SKCanvasView
在你的ContentPage里添加用于绘制的SKCanvasView,并绑定PaintSurface事件:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms" x:Class="YourAppName.MainPage"> <skia:SKCanvasView x:Name="PdfCanvasView" PaintSurface="OnPdfCanvasViewPaintSurface"/> </ContentPage>
3. 加载PDF文档并处理资源
在页面的后台代码里,我们需要先加载PDF文件,同时要注意释放资源避免内存泄漏:
using SkiaSharp; using SkiaSharp.Extended.Pdf; using System.Reflection; using Xamarin.Forms; namespace YourAppName { public partial class MainPage : ContentPage { private SKPdfDocument _pdfDocument; public MainPage() { InitializeComponent(); } protected override void OnAppearing() { base.OnAppearing(); LoadPdfDocument(); } protected override void OnDisappearing() { // 释放PDF资源,务必记得这一步 _pdfDocument?.Dispose(); _pdfDocument = null; base.OnDisappearing(); } private void LoadPdfDocument() { // 这里以嵌入式PDF资源为例,你也可以换成本地文件路径、Assets等 var assembly = typeof(MainPage).GetTypeInfo().Assembly; // 替换成你的项目中PDF资源的完整名称(项目名.文件夹.文件名.pdf) using var pdfStream = assembly.GetManifestResourceStream("YourAppName.Resources.Sample.pdf"); if (pdfStream == null) { // 处理文件加载失败的情况,比如提示用户 return; } _pdfDocument = SKPdfDocument.Load(pdfStream); // 触发画布重绘 PdfCanvasView.InvalidateSurface(); } } }
4. 在PaintSurface事件中绘制PDF页面
最后一步就是把PDF页面画到Canvas上,我们可以做自适应缩放和居中处理:
private void OnPdfCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs e) { var surface = e.Surface; var canvas = surface.Canvas; // 清空画布为白色背景 canvas.Clear(SKColors.White); // 如果PDF未加载完成,直接返回 if (_pdfDocument == null || _pdfDocument.PageCount == 0) { return; } // 打开PDF的第一页(如果要显示多页,可以循环处理或者加分页逻辑) using var pdfPage = _pdfDocument.OpenPage(0); var pageSize = pdfPage.Size; var canvasSize = e.Info.Size; // 计算缩放比例,让页面完整适配画布 var scaleFactor = Math.Min(canvasSize.Width / pageSize.Width, canvasSize.Height / pageSize.Height); // 计算偏移量,让页面在画布中居中 var offsetX = (canvasSize.Width - pageSize.Width * scaleFactor) / 2; var offsetY = (canvasSize.Height - pageSize.Height * scaleFactor) / 2; // 平移和缩放画布 canvas.Translate(offsetX, offsetY); canvas.Scale(scaleFactor); // 绘制PDF页面 using var paint = new SKPaint(); canvas.DrawPdfPage(pdfPage, paint); }
一些额外的小提示
- 资源路径注意:如果是Android的Assets文件夹,需要设置文件的Build Action为
AndroidAsset,然后用AssetManager获取流;iOS则放在Resources文件夹,Build Action设为BundleResource。 - 多页处理:如果PDF有多个页面,可以添加按钮切换页码,在绘制时打开对应索引的页面即可。
- 内存管理:
SKPdfDocument和SKPdfPage都是IDisposable类型,一定要记得Dispose,避免内存泄漏。
备注:内容来源于stack exchange,提问作者Hamza Oubouzid
相关产品推荐
相关产品推荐

