如何使用SkiaSharp在WPF的WriteableBitmap上绘制文本
引言
在图像处理和图形渲染的世界里,SkiaSharp和WPF都是不可或缺的工具。然而,当需要在WPF的WriteableBitmap
上绘制文本或图形时,如何优雅地结合这两个工具呢?在这篇文章中,我们将介绍一个简单的扩展方法,它允许你在WriteableBitmap
上使用SkiaSharp进行文本绘制。
基础准备
首先,确保你已经安装了SkiaSharp的NuGet包。
Install-Package SkiaSharp -Version 2.80.3
创建一个扩展方法
我们首先创建一个WriteableBitmapExtensions
类来存放我们的扩展方法。
public static class WriteableBitmapExtensions { // 扩展方法将在这里定义 }
添加对齐枚举
在WPF中,我们通常使用TextAlignment
和VerticalAlignment
来设置对齐方式。然而,在SkiaSharp中,这些需要手动设置。为了解决这个问题,我们可以定义自己的枚举类型。
public enum TextAlignment { Left, Center, Right } public enum VerticalAlignment { Top, Center, Bottom }
绘制文本的扩展方法
接下来,我们定义DrawText
方法,该方法接受一个WriteableBitmap
实例、文本、字体和各种其他参数。
具体的代码:
// File: WriteableBitmapExtensions // Author: linxmouse@gmail.com // Creation: 2023/10/17 13:55:49 using System; using System.Windows.Media.Imaging; using System.Windows.Media; using System.Windows; using SkiaSharp; namespace WritableBitmapDemo { public enum TextAlignment { Left, Center, Right } public enum VerticalAlignment { Top, Center, Bottom } public static class WriteableBitmapExtensions { public static void DrawText(this WriteableBitmap writeableBitmap, string text, Point position, Typeface typeface, double fontSize, Brush brush, TextAlignment horizontalAlign = TextAlignment.Left, VerticalAlignment verticalAlign = VerticalAlignment.Top) { // 锁定 WriteableBitmap 的后备缓冲区 writeableBitmap.Lock(); // 获取后备缓冲区的信息 IntPtr buffer = writeableBitmap.BackBuffer; int width = writeableBitmap.PixelWidth; int height = writeableBitmap.PixelHeight; int stride = writeableBitmap.BackBufferStride; // 创建 Skia 的图像信息对象 SKImageInfo imageInfo = new SKImageInfo(width, height, SKColorType.Bgra8888); // 创建 Skia 的绘图表面 using (SKBitmap bitmap = new SKBitmap(imageInfo)) { bitmap.InstallPixels(imageInfo, buffer, stride); using (SKCanvas canvas = new SKCanvas(bitmap)) { // 绘制文本或其他图形元素 using (SKPaint paint = new SKPaint()) { paint.TextSize = (float)fontSize; paint.IsAntialias = true; // 使用 WPF 的 Typeface 创建 SkiaSharp 的 SKTypeface if (typeface != null) { var fontFamily = typeface.FontFamily.ToString(); var weight = typeface.Weight.ToOpenTypeWeight(); var slant = typeface.Style == FontStyles.Normal ? SKFontStyleSlant.Upright : SKFontStyleSlant.Italic; var skFontStyle = new SKFontStyle(weight, 5, slant); // 这里的5是宽度参数,通常默认值即可 using (var skTypeface = SKTypeface.FromFamilyName(fontFamily, skFontStyle)) { paint.Typeface = skTypeface; } } // 根据自定义的对齐方式枚举设置Skia的对齐方式 switch (horizontalAlign) { case TextAlignment.Left: paint.TextAlign = SKTextAlign.Left; break; case TextAlignment.Center: paint.TextAlign = SKTextAlign.Center; break; case TextAlignment.Right: paint.TextAlign = SKTextAlign.Right; break; } // 从WPF的Brush对象中获取颜色信息 var solidColorBrush = brush as SolidColorBrush; if (solidColorBrush != null) { var color = solidColorBrush.Color; paint.Color = new SKColor(color.R, color.G, color.B, color.A); } paint.BlendMode = SKBlendMode.SrcOver; // 计算文本宽度和高度 float textWidth = paint.MeasureText(text); float textHeight = paint.FontMetrics.Descent - paint.FontMetrics.Ascent; float textBaseline = -paint.FontMetrics.Ascent; // 根据对齐方式调整x, y坐标 float adjustedX = (float)position.X; float adjustedY = (float)position.Y; if (horizontalAlign == TextAlignment.Center) adjustedX -= textWidth / 2; else if (horizontalAlign == TextAlignment.Right) adjustedX -= textWidth; if (verticalAlign == VerticalAlignment.Center) adjustedY += textHeight / 2 - textBaseline; else if (verticalAlign == VerticalAlignment.Bottom) adjustedY += textHeight - textBaseline; else adjustedY += textBaseline; canvas.DrawText(text, adjustedX, adjustedY, paint); } // 将绘制结果复制回 WriteableBitmap 的后备缓冲区 SKPixmap pixmap = bitmap.PeekPixels(); pixmap.ReadPixels(imageInfo, buffer, stride, 0, 0); } } // 解锁 WriteableBitmap 的后备缓冲区并进行刷新 writeableBitmap.AddDirtyRect(new Int32Rect(0, 0, width, height)); writeableBitmap.Unlock(); } } }
使用示例
var writeableBitmap = new WriteableBitmap(200, 200, 96, 96, PixelFormats.Bgra32, null); var typeface = new Typeface(new FontFamily("Arial"), FontStyles.Normal, FontWeights.Bold, FontStretches.Normal); var brush = new SolidColorBrush(Colors.Black); writeableBitmap.DrawText("Hello, world!", new Point(50, 50), typeface, 12, brush, TextAlignment.Center, VerticalAlignment.Center);
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗