使用SkiaSharp裁剪4096×4096精灵图时遇图像畸形与空引用异常
SkiaSharp精灵图裁剪问题排查与修复
核心错误分析
1. SKRectI参数理解错误
SKRectI的构造参数是left(左边界)、top(上边界)、right(右边界)、bottom(下边界),并非你误以为的x, y, width, height:
- 你写的
new SKRectI(256, 256, 256, 256)会生成宽高均为0的无效矩形(right-left=0、bottom-top=0),ExtractSubset遇到无效矩形会直接返回null,触发空引用异常。 - 正确裁剪从(256,256)起始的256×256子图,应写成:
new SKRectI(256, 256, 256+256, 256+256),即SKRectI(256, 256, 512, 512)。
2. 图像畸形的原因:SKImageInfo不匹配
你直接用info创建SKPixmap时,这个info必须完全匹配原图像的属性(宽度、高度、颜色类型、Alpha通道、行字节跨度)。如果info参数错误,会导致像素排列错乱,输出图像畸形。
修复后的代码示例
推荐使用更简洁且不易出错的SKBitmap解码+裁剪方式,无需手动处理内存指针:
// 直接解码byte[]为SKBitmap,自动处理图像信息 using var originalBitmap = SkiaSharp.SKBitmap.Decode(spriteContent); // 定义正确的裁剪矩形:左256,上256,右512,下512(对应256×256的子图) var cropRect = new SkiaSharp.SKRectI(256, 256, 512, 512); // 创建对应尺寸的空bitmap用于存放裁剪结果 using var cropBitmap = new SkiaSharp.SKBitmap(cropRect.Width, cropRect.Height, originalBitmap.ColorType, originalBitmap.AlphaType); // 提取子图 originalBitmap.ExtractSubset(cropBitmap, cropRect); // 编码并保存 using var data = cropBitmap.Encode(SkiaSharp.SKPngEncoderOptions.Default); File.WriteAllBytes("test2.png", data.ToArray());
如果坚持使用SKPixmap方案,必须保证info与原图像一致:
// 先解码获取原图像的正确信息 using var tempBitmap = SkiaSharp.SKBitmap.Decode(spriteContent); var correctInfo = tempBitmap.Info; var gch = GCHandle.Alloc(spriteContent, GCHandleType.Pinned); try { var addr = gch.AddrOfPinnedObject(); using var pixmap = new SkiaSharp.SKPixmap(correctInfo, addr); // 正确的裁剪矩形 var cropRect = new SkiaSharp.SKRectI(256, 256, 512, 512); var subset = pixmap.ExtractSubset(cropRect); // 空值判断,避免异常 if (subset == null) return; using var data = subset.Encode(SkiaSharp.SKPngEncoderOptions.Default); File.WriteAllBytes("test2.png", data.ToArray()); } finally { gch.Free(); }
关键注意事项
- 始终确保
SKRectI的right > left且bottom > top,否则裁剪矩形无效。 - 手动操作
SKPixmap时,必须严格匹配原图像的SKImageInfo参数,包括颜色格式、行字节数等,否则会出现像素错乱。 - 优先使用
SKBitmap的封装方法,减少手动内存操作的出错概率。
内容的提问来源于stack exchange,提问作者Den
相关产品推荐
相关产品推荐

