利用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;
}