使用C# TiffLibrary提取BigTiff切片:无法生成Bitmap保存
解决BigTiff切片转Bitmap并保存的问题
核心问题说明
TiffRgba32的字节顺序是R→G→B→A,而.NET的Bitmap中Format32bppArgb的字节顺序是A→R→G→B,直接映射会导致颜色错乱,需要先调整字节顺序,再生成Bitmap。
方法一:安全遍历转换(适合小切片)
直接遍历TiffRgba32数组,转换每个像素的字节顺序后写入Bitmap:
using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; using TiffLibrary; using TiffLibrary.PixelFormats; public void MakeTile(int px, int py, int lxx, int lyy) { string Origin = @"HugeTiff.tif"; using TiffFileReader tiff = TiffFileReader.Open(Origin); TiffImageFileDirectory ifd = tiff.ReadImageFileDirectory(); TiffImageDecoder decoder = tiff.CreateImageDecoder(ifd); // 初始化像素缓冲区 TiffRgba32[] pixels = new TiffRgba32[lxx * lyy]; TiffMemoryPixelBuffer<TiffRgba32> pixelBuffer = new TiffMemoryPixelBuffer<TiffRgba32>(pixels, lxx, lyy, writable: true); decoder.Decode(new TiffPoint(px, py), pixelBuffer); // 创建Bitmap并写入像素 using Bitmap bitmap = new Bitmap(lxx, lyy, PixelFormat.Format32bppArgb); BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, lxx, lyy), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); for (int i = 0; i < pixels.Length; i++) { TiffRgba32 tiffPixel = pixels[i]; // 转换字节顺序:TiffRgba32(R,G,B,A) → Bitmap(A,R,G,B) int argb = (tiffPixel.A << 24) | (tiffPixel.R << 16) | (tiffPixel.G << 8) | tiffPixel.B; Marshal.WriteInt32(bitmapData.Scan0, i * 4, argb); } bitmap.UnlockBits(bitmapData); // 保存为JPG或PNG bitmap.Save($"Tile_{px}_{py}.jpg", ImageFormat.Jpeg); }
方法二:Unsafe高效转换(适合大切片)
利用指针直接操作内存,避免逐像素Marshal调用,提升性能:
using System.Drawing; using System.Drawing.Imaging; using TiffLibrary; using TiffLibrary.PixelFormats; public unsafe void MakeTile(int px, int py, int lxx, int lyy) { string Origin = @"HugeTiff.tif"; using TiffFileReader tiff = TiffFileReader.Open(Origin); TiffImageFileDirectory ifd = tiff.ReadImageFileDirectory(); TiffImageDecoder decoder = tiff.CreateImageDecoder(ifd); // 初始化像素缓冲区 TiffRgba32[] pixels = new TiffRgba32[lxx * lyy]; TiffMemoryPixelBuffer<TiffRgba32> pixelBuffer = new TiffMemoryPixelBuffer<TiffRgba32>(pixels, lxx, lyy, writable: true); decoder.Decode(new TiffPoint(px, py), pixelBuffer); // 创建Bitmap并锁定内存 using Bitmap bitmap = new Bitmap(lxx, lyy, PixelFormat.Format32bppArgb); BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, lxx, lyy), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); fixed (TiffRgba32* tiffPixels = pixels) { int* bitmapPixels = (int*)bitmapData.Scan0; int pixelCount = lxx * lyy; for (int i = 0; i < pixelCount; i++) { TiffRgba32 tiffPixel = tiffPixels[i]; // 转换字节顺序 bitmapPixels[i] = (tiffPixel.A << 24) | (tiffPixel.R << 16) | (tiffPixel.G << 8) | tiffPixel.B; } } bitmap.UnlockBits(bitmapData); // 保存为PNG(无损格式适合切片) bitmap.Save($"Tile_{px}_{py}.png", ImageFormat.Png); }
额外优化提示
- .NET Core/.NET 5+项目需要手动安装
System.Drawing.CommonNuGet包。 - 保存JPG时可调整压缩质量,避免细节损失:
EncoderParameters encoderParams = new EncoderParameters(1); encoderParams.Param[0] = new EncoderParameter(Encoder.Quality, 90L); ImageCodecInfo jpgCodec = ImageCodecInfo.GetImageDecoders().First(c => c.FormatID == ImageFormat.Jpeg.Guid); bitmap.Save($"Tile_{px}_{py}.jpg", jpgCodec, encoderParams);
内容的提问来源于stack exchange,提问作者gpol
相关产品推荐
相关产品推荐

