利用libtiff.net进行BigTiff的读写

读入多张tif影像水平拼接成bigtiff

using (Tiff bigTiff = Tiff.Open(@"D:\desktop\test\新建文件夹 (17)\5.tif", "w"))
{
    int originalImageWidth = 0, originalImageHeight = 0;
    using (Tiff image = Tiff.Open(singleComparisonJobConfig.IntensityImageFilePathList[0], "r"))
    {
        originalImageWidth = image.GetField(TiffTag.IMAGEWIDTH)[0].ToInt();
        originalImageHeight = image.GetField(TiffTag.IMAGELENGTH)[0].ToInt();
    }

    bigTiff.SetField(
        TiffTag.IMAGEWIDTH,
        singleComparisonJobConfig.IntensityImageFilePathList.Count * originalImageWidth);
    bigTiff.SetField(TiffTag.IMAGELENGTH, originalImageHeight);
    bigTiff.SetField(TiffTag.PHOTOMETRIC, Photometric.MINISBLACK);

    bigTiff.SetField(TiffTag.BITSPERSAMPLE, 8);
    bigTiff.SetField(TiffTag.SAMPLESPERPIXEL, 1);

    // 这个参数很关键
    // The default is 2 * *32 - 1, which is effectively infinity. That is, the entire image is one strip. 
    // Use of a single strip is not recommended.Choose RowsPerStrip such that each strip is about 8K bytes, even if the data is not compressed, 
    // since it makes buffering simpler for readers.The 8K value is fairly arbitrary, but seems to work well.
    bigTiff.SetField(TiffTag.ROWSPERSTRIP, 1);
    bigTiff.SetField(TiffTag.COMPRESSION, Compression.NONE);
    bigTiff.SetField(TiffTag.PLANARCONFIG, PlanarConfig.CONTIG);

    // TILEWIDTH TILELENGTH要是16的倍数
    // bigTiff.SetField(TiffTag.TILEWIDTH, 5120);
    // bigTiff.SetField(TiffTag.TILELENGTH, 10240);
    // bigTiff.SetField(TiffTag.TILEDEPTH, 10240);

    // var a = bigTiff.TileSize();
    Tiff[] originalImages = new Tiff[singleComparisonJobConfig.IntensityImageFilePathList.Count];
    for (int i = 0; i < singleComparisonJobConfig.IntensityImageFilePathList.Count; i++)
    {
        originalImages[i] = Tiff.Open(singleComparisonJobConfig.IntensityImageFilePathList[i], "r");
    }

    byte[] newBuff =
        new byte[originalImageWidth * singleComparisonJobConfig.IntensityImageFilePathList.Count];
    byte[] buffer = new byte[originalImageWidth];
    for (int j = 0; j < originalImageHeight; j++)
    {
        Console.WriteLine(j);
        Console.WriteLine(DateTime.Now);
        for (int i = 0; i < singleComparisonJobConfig.IntensityImageFilePathList.Count; i++)
        {
            originalImages[i].ReadScanline(buffer, j);
            Buffer.BlockCopy(buffer, 0, newBuff, i * originalImageWidth, originalImageWidth * sizeof(byte));
        }

        bigTiff.WriteScanline(newBuff, j);
    }
    bigTiff.WriteDirectory();
    bigTiff.Close();
}

strip这个参数很关键,如果文件很大,比如超过4g,不设置strip的话会导致libtiff.net报错,所以一般是一个strip为8000个byte,这样设置读的比较快
1)简单的文件,1个Strip足以。
2)每个Strip大小是相同的。
3)出于某种目的,文件可以分成若干Strip。
4)Script需要对齐处理。
5)文件有两种基本分块模式 Strip,Tile
Strip 高度方向分块
Tile 像打豆腐一样分块

分块就是若干字节(若干行)写一次;
并且要记录每一块,写的位置。
Some manufacturers make life difficult by writing large amounts of uncompressed data as a single strip. This is contrary to the recommendations of the spec. The following makes an attempt at breaking such images into strips closer to the recommended 8k bytes. A side effect, however, is that the RowsPerStrip tag value may be changed.

在wpf展示bigtiff(只读一些行,直接用bitmap加载会报错,所以有缩放功能时需要自己判断读入哪些行)

using (Tiff bigTiff = Tiff.Open(@"D:\desktop\test\新建文件夹 (17)\5.tif", "r"))
{
    int originalImageWidth = bigTiff.GetField(TiffTag.IMAGEWIDTH)[0].ToInt();
    int originalImageHeight = bigTiff.GetField(TiffTag.IMAGELENGTH)[0].ToInt();

    double canvasHeight = grid.Height;
    int skip = Convert.ToInt32(originalImageHeight / canvasHeight);
    int resizedHeight = Convert.ToInt32(canvasHeight);
    int resizedWidth = Convert.ToInt32(originalImageWidth / skip);

    byte[,] bufferRect = new byte[resizedHeight, resizedWidth];
    byte[] buffer = new byte[originalImageWidth];
    for (int j = 0; j < originalImageHeight; j += skip)
    {
        bigTiff.ReadScanline(buffer, j);
        for (int i = 0; i / skip < resizedWidth; i += skip)
        {
            bufferRect[j / skip, i / skip] = buffer[i];
        }
    }

    byte[] bufferRectFlatten = new byte[resizedHeight * resizedWidth];
    Buffer.BlockCopy(bufferRect, 0, bufferRectFlatten, 0, resizedHeight * resizedWidth * sizeof(byte));
    BitmapSource bitmapSource = BitmapSource.Create(
        resizedWidth,
        resizedHeight,
        96.0,
        96.0,
        PixelFormats.Gray8,
        BitmapPalettes.Gray256,
        bufferRectFlatten,
        (resizedWidth * 8 + 7) / 8);

    image.Source = bitmapSource;
}