SkiaSharp转换SVG为PNG时图像未填满画布问题求助
问题:SkiaSharp转换SVG为PNG时未填满画布
我尝试使用SkiaSharp将SVG图像转换为PNG,再转为PdfSharp的XImage对象以添加至PDF页面(因PdfSharp不直接支持SVG格式)。已编写对应代码:
private XImage LoadSvgIcon(string iconUrl) { XElement root = XElement.Load(iconUrl); using (Stream xmlStream = new MemoryStream()) { root.Save(xmlStream); xmlStream.Flush(); xmlStream.Position = 0; var svg = new SkiaSharp.Extended.Svg.SKSvg(); svg.Load(xmlStream); var bitmap = new SKBitmap((int)svg.CanvasSize.Width, (int)svg.CanvasSize.Height); var canvas = new SKCanvas(bitmap); var p = new SKPaint(); p.Color = SKColor.Parse("#219de1"); canvas.DrawPaint(p); canvas.DrawPicture(svg.Picture); using (var skData = SKImage.FromBitmap(bitmap).Encode(SKEncodedImageFormat.Png, 100)) { Stream stream = new MemoryStream(); skData.SaveTo(stream); return XImage.FromStream(stream); } } }
虽将画布大小设置为SVG的CanvasSize,但SVG图像仍未填满整个画布(画布为淡蓝色背景,SVG自身带红色背景及内部图标,未占满画布空间),请问遗漏了什么?
解决方案
问题核心是SVG的实际内容尺寸(由Picture.CullRect定义)和画布尺寸不匹配,直接绘制svg.Picture只会按它自身的原始尺寸渲染,不会自动拉伸填满画布。需要添加缩放适配逻辑,修改后的代码如下:
private XImage LoadSvgIcon(string iconUrl) { XElement root = XElement.Load(iconUrl); using (Stream xmlStream = new MemoryStream()) { root.Save(xmlStream); xmlStream.Flush(); xmlStream.Position = 0; var svg = new SkiaSharp.Extended.Svg.SKSvg(); svg.Load(xmlStream); var bitmap = new SKBitmap((int)svg.CanvasSize.Width, (int)svg.CanvasSize.Height); var canvas = new SKCanvas(bitmap); var p = new SKPaint(); p.Color = SKColor.Parse("#219de1"); canvas.DrawPaint(p); // 获取SVG内容的实际边界范围 var pictureBounds = svg.Picture.CullRect; if (!pictureBounds.IsEmpty) { // 计算缩放比例:让SVG内容填满画布,同时保持宽高比例 float scaleX = svg.CanvasSize.Width / pictureBounds.Width; float scaleY = svg.CanvasSize.Height / pictureBounds.Height; float scale = Math.Max(scaleX, scaleY); // 计算偏移量,让SVG在画布中居中显示 float offsetX = (svg.CanvasSize.Width - pictureBounds.Width * scale) / 2; float offsetY = (svg.CanvasSize.Height - pictureBounds.Height * scale) / 2; // 创建变换矩阵:先平移到居中位置,再执行缩放 var matrix = SKMatrix.CreateTranslation(offsetX, offsetY); matrix = SKMatrix.Concat(matrix, SKMatrix.CreateScale(scale, scale)); canvas.SetMatrix(matrix); } canvas.DrawPicture(svg.Picture); using (var skData = SKImage.FromBitmap(bitmap).Encode(SKEncodedImageFormat.Png, 100)) { Stream stream = new MemoryStream(); skData.SaveTo(stream); // 重置流指针到起始位置,否则XImage无法读取内容 stream.Position = 0; return XImage.FromStream(stream); } } }
额外补充两个关键细节:
- 新增
stream.Position = 0:SaveTo操作后流的指针会停在末尾,必须重置才能让XImage读取到完整内容 - 若不需要保持宽高比例,可直接用
scaleX和scaleY分别缩放,去掉scale = Math.Max(...)的逻辑,直接创建SKMatrix.CreateScale(scaleX, scaleY)即可
内容的提问来源于stack exchange,提问作者developer82
相关产品推荐
相关产品推荐

