You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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.Common NuGet包。
  • 保存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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 08:28:25