如何将TIFF图像转换为SkiaSharp的SKBitmap对象?
我来帮你梳理下SkiaSharp处理TIFF转SKBitmap的可行方案,结合你提到的思路,给你详细拆解并补充实用的实现方式:
方案1:借助System.Drawing中转(简单易实现,注意平台限制)
System.Drawing确实能完成TIFF转PNG的操作,对于常规尺寸的图片来说效率完全够用,不过要注意它的平台局限性:在.NET Core/.NET 5+的非Windows平台(比如Linux、macOS)上,需要额外安装libgdiplus依赖,而且从.NET 6开始它被标记为Windows-only的库了。
如果你的场景是Windows环境,或者能接受非Windows平台的依赖安装,这个方案最省事。代码示例:
using System.Drawing; using System.Drawing.Imaging; using SkiaSharp; using System.IO; public static SKBitmap TiffToSkBitmapViaSystemDrawing(Stream tiffStream) { // 加载TIFF流 using var tiffImage = Image.FromStream(tiffStream); // 转为PNG内存流 using var pngStream = new MemoryStream(); tiffImage.Save(pngStream, ImageFormat.Png); pngStream.Seek(0, SeekOrigin.Begin); // 用SkiaSharp解码PNG得到SKBitmap return SKBitmap.Decode(pngStream); }
⚠️ 注意:这个方法默认只处理TIFF的第一页,如果是多页TIFF,需要遍历FrameDimensions来获取每一页的图像。
方案2:使用LibTiff.Net(专业TIFF处理,跨平台可靠)
LibTiff.Net是专门针对TIFF格式的处理库,跨平台支持,能应对各种复杂的TIFF场景(多页、不同压缩格式、特殊色彩空间等),比System.Drawing更稳定。下面给你TIFF流转SKBitmap的直接实现(也可以中转PNG流,不过直接转像素更高效):
首先需要安装对应的NuGet包BitMiracle.LibTiff.NET,然后看代码:
using BitMiracle.LibTiff.Classic; using SkiaSharp; using System.IO; public static SKBitmap TiffToSkBitmapViaLibTiff(Stream tiffStream) { // 打开内存中的TIFF流 using var tiff = Tiff.ClientOpen("memory-tiff", "r", tiffStream, new TiffStream()); if (tiff == null) throw new InvalidOperationException("无法读取TIFF流"); // 获取TIFF的基本参数 int width = tiff.GetField(TiffTag.IMAGEWIDTH)[0].ToInt(); int height = tiff.GetField(TiffTag.IMAGELENGTH)[0].ToInt(); int stride = tiff.ScanlineSize(); // 读取所有扫描线的像素数据 byte[] pixelBuffer = new byte[stride * height]; for (int y = 0; y < height; y++) { tiff.ReadScanline(pixelBuffer, y); } // 创建SKBitmap并写入像素 var imageInfo = new SKImageInfo(width, height, SKColorType.Rgb888, SKAlphaType.Opaque); var skBitmap = new SKBitmap(imageInfo); skBitmap.WritePixels(imageInfo, pixelBuffer, stride, 0, 0); return skBitmap; }
如果一定要中转成PNG流,也可以在得到SKBitmap后做编码:
// 将SKBitmap编码为PNG流 using var pngStream = new MemoryStream(); skBitmap.Encode(pngStream, SKEncodedImageFormat.Png, 100); pngStream.Seek(0, SeekOrigin.Begin); // 后续可以用这个PNG流做其他操作,或者重新解码为SKBitmap var reDecodedBitmap = SKBitmap.Decode(pngStream);
这个方案的优势是能完美处理多页TIFF,通过调用tiff.ReadDirectory()可以遍历每一页图像,适合专业的TIFF处理场景。
方案3:直接读取TIFF像素绘制到SKCanvas
这个思路本质和方案2类似,都是直接操作像素数据。但TIFF的格式非常复杂,包含多种压缩算法、色彩空间,自己写解析逻辑成本极高,除非你只需要处理特定格式的无压缩TIFF,否则不建议自己造轮子,直接用LibTiff.Net或者ImageSharp会更高效。
额外推荐:使用ImageSharp中转(跨平台友好,API简洁)
ImageSharp是一款现代跨平台图像处理库,原生支持TIFF格式,而且和SkiaSharp的兼容性很好,没有System.Drawing的平台限制,API也更简洁。
先安装NuGet包SixLabors.ImageSharp和SixLabors.ImageSharp.Formats.Tiff,然后看代码:
using SixLabors.ImageSharp; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.PixelFormats; using SkiaSharp; using System.IO; public static SKBitmap TiffToSkBitmapViaImageSharp(Stream tiffStream) { // 加载TIFF流 using var tiffImage = Image.Load<Rgba32>(tiffStream); // 转为PNG内存流 using var pngStream = new MemoryStream(); tiffImage.Save(pngStream, new PngEncoder()); pngStream.Seek(0, SeekOrigin.Begin); // 解码为SKBitmap return SKBitmap.Decode(pngStream); }
这个方案处理多页TIFF也很方便,通过tiffImage.Frames可以遍历每一页,非常适合跨平台的项目场景。
总结一下:
- 简单场景+Windows环境:选System.Drawing
- 跨平台+常规TIFF处理:选ImageSharp
- 专业TIFF需求(多页、特殊压缩):选LibTiff.Net
- 自己解析TIFF:仅在处理特定极简TIFF时考虑,否则不推荐
内容的提问来源于stack exchange,提问作者Doug S




