如何将内存中的ImageSharp Image<Rgb24>转换为SkiaSharp SkImage?
ImageSharp
Image<Rgb24> 与 SkiaSharp SKImage 内存转换方案 你的现有代码存在关键错误:SKImage.FromEncodedData 用于解析编码后图像字节流(如PNG、JPG格式),但 CopyPixelDataTo 获取的是原始像素数据,两者格式不匹配,无法生成有效的 SKImage。以下是正确的内存转换方案,包含双向转换的高效实现:
正向转换:ImageSharp → SkiaSharp
方案1:临时像素复制(兼容通用场景)
先将 Rgb24 格式转为 Skia 默认的 RGBA8888 格式,再通过像素数组生成 SKImage:
public SKImage ConvertImageSharpToSkia(Image<Rgb24> imageSharpImage) { // 将Rgb24转为Rgba32,匹配Skia的RGBA8888像素格式 using var rgbaImage = imageSharpImage.CloneAs<Rgba32>(); byte[] pixelData = new byte[rgbaImage.Width * rgbaImage.Height * 4]; rgbaImage.CopyPixelDataTo(pixelData); // 创建SKBitmap并写入像素数据 using var bitmap = new SKBitmap(rgbaImage.Width, rgbaImage.Height, SKColorType.Rgba8888, SKAlphaType.Opaque); fixed (byte* ptr = pixelData) { bitmap.SetPixels(new IntPtr(ptr)); } // 从SKBitmap生成SKImage,SKImage会接管Bitmap的像素内存 return SKImage.FromBitmap(bitmap); }
方案2:直接复用内存(高效优化)
利用 ImageSharp 的内存缓冲区直接创建 SKBitmap,减少一次字节复制(需注意内存生命周期):
public SKImage ConvertImageSharpToSkiaDirect(Image<Rgb24> imageSharpImage) { using var rgbaImage = imageSharpImage.CloneAs<Rgba32>(); var pixelBufferGroup = rgbaImage.DangerousGetPixelMemoryGroup(); var pixelBuffer = pixelBufferGroup.First(); // 基于ImageSharp的内存块创建SKBitmap var skBitmap = new SKBitmap( rgbaImage.Width, rgbaImage.Height, SKColorType.Rgba8888, SKAlphaType.Opaque, pixelBuffer.Span, rgbaImage.Width * 4 // 每行字节步长 ); // 若SKImage需要长期使用,调用MakeCopy()复制独立内存,避免原Image释放后内存失效 // skBitmap = skBitmap.MakeCopy(); return SKImage.FromBitmap(skBitmap); }
反向转换:SkiaSharp → ImageSharp
若流水线从 SKImage 开始,转 Image<Rgb24> 的实现如下:
public Image<Rgb24> ConvertSkiaToImageSharp(SKImage skImage) { using var bitmap = skImage.ToBitmap(); var image = new Image<Rgb24>(bitmap.Width, bitmap.Height); // 直接操作像素内存,避免额外数组复制 using var skPixelLock = bitmap.LockPixels(); image.ProcessPixelRows(accessor => { var skPixelSpan = skPixelLock.Span.Cast<SKColor>(); for (int y = 0; y < accessor.Height; y++) { var targetRow = accessor.GetRowSpan(y); var sourceRow = skPixelSpan.Slice(y * accessor.Width, accessor.Width); for (int x = 0; x < accessor.Width; x++) { var skColor = sourceRow[x]; targetRow[x] = new Rgb24(skColor.Red, skColor.Green, skColor.Blue); } } }); return image; }
两种转换方向均无需磁盘操作,可根据流水线需求选择。若对性能要求较高,优先选择直接复用内存的方案,但需严格管理对象生命周期,避免内存访问异常。
内容的提问来源于stack exchange,提问作者Webreaper
相关产品推荐
相关产品推荐

