BitMiracle LibTIFF.NET 无法解压之前自己创建的 TIFF
BitMiracle LibTIFF.NET Can't Decompress TIFF Previously Created By Itself
我实现了一个 class 读取由 Microsoft.Reporting.WinForms.ReportViewer
生成的每像素 24 位 TIFF,将其转换为每像素 1 位 TIFF 并将结果存储到文件中.
这部分工作正常 - 我能够在 TIFF 查看器中打开生成的 TIFF 并查看内容。
对于压缩,我使用以下编解码器:
outImage.SetField(TiffTag.COMPRESSION, Compression.CCITT_T6);
现在我正在尝试读取相同的每像素 1 位 TIFF 并将其解压缩。我写了以下方法:
public static void DecompressTiff(byte[] inputTiffBytes)
{
using (var tiffStream = new MemoryStream(inputTiffBytes))
using (var inImage = Tiff.ClientOpen("in-memory", "r", tiffStream, new TiffStream()))
{
if (inImage == null)
return null;
int totalPages = inImage.NumberOfDirectories();
for (var i = 0; i < totalPages; )
{
if (!inImage.SetDirectory((short) i))
return null;
var decompressedTiff = DecompressTiff(inImage);
...
}
private static byte[] DecompressTiff(Tiff image)
{
// Read in the possibly multiple strips
var stripSize = image.StripSize();
var stripMax = image.NumberOfStrips();
var imageOffset = 0;
int row = 0;
var bufferSize = image.NumberOfStrips() * stripSize;
var buffer = new byte[bufferSize];
int height = 0;
var result = image.GetField(TiffTag.IMAGELENGTH);
if (result != null)
height = result[0].ToInt();
int rowsperstrip = 0;
result = image.GetField(TiffTag.ROWSPERSTRIP);
if (result != null)
rowsperstrip = result[0].ToInt();
if (rowsperstrip > height && rowsperstrip != -1)
rowsperstrip = height;
for (var stripCount = 0; stripCount < stripMax; stripCount++)
{
int countToRead = (row + rowsperstrip > height) ? image.VStripSize(height - row) : stripSize;
var readBytesCount = image.ReadEncodedStrip(stripCount, buffer, imageOffset, countToRead); // Returns -1 for the last strip of the very first page
if (readBytesCount == -1)
return null;
imageOffset += readBytesCount;
row += rowsperstrip;
}
return buffer;
}
问题是,当为第一页的最后一段调用 ReadEncodedStrip()
时 - 它 returns -1,表明存在错误。即使在调试 LibTIFF.NET 解码器代码之后,我也不知道出了什么问题。这是在意想不到的地方发现了 EOL TIFF 标记。
由于某种原因,LibTIFF.NET 无法读取它自己生成的 TIFF,或者很可能是我遗漏了什么。 Here 是 TIFF 的问题。
谁能帮忙找出根本原因?
经过半天多的排查,我终于找到了这个奇怪问题的原因。
为了从每像素 24 位的 TIFF 转换为每像素 1 位,我将算法从 C 移植到 C#,这两个工具随原始 libtiff 一起提供:tiff2bw and tiffdither.
tiffdither 有一个错误,它不包括输出图像中的最后一个图像行,即如果你给它一个 2200 行高的图像,你会得到 2199 行高的图像作为输出。
我在移植的一开始就注意到了这个错误并试图修复,但是,最终结果证明,并没有完全修复,而且移植的算法实际上并没有通过 [=10= 写入最后一行] 方法输出 TIFF。所以这就是为什么 LibTIFF.NET 无法读取图像最后 strip\row 的原因,具体取决于我使用的阅读方法。
令我惊讶的是,LibTIFF.NET 允许写入此类实际损坏的 TIFF 而不会在写入过程中出现任何错误。例如 WriteDirectory()
方法 returns true
在这种情况下,通过 TiffTag.IMAGELENGTH
设置的图像高度与写入它的实际行数不同。但是后来读不到这样的图片,读的时候报错。
不过,也许这种行为继承自原始 libtiff。
我实现了一个 class 读取由 Microsoft.Reporting.WinForms.ReportViewer
生成的每像素 24 位 TIFF,将其转换为每像素 1 位 TIFF 并将结果存储到文件中.
这部分工作正常 - 我能够在 TIFF 查看器中打开生成的 TIFF 并查看内容。
对于压缩,我使用以下编解码器:
outImage.SetField(TiffTag.COMPRESSION, Compression.CCITT_T6);
现在我正在尝试读取相同的每像素 1 位 TIFF 并将其解压缩。我写了以下方法:
public static void DecompressTiff(byte[] inputTiffBytes)
{
using (var tiffStream = new MemoryStream(inputTiffBytes))
using (var inImage = Tiff.ClientOpen("in-memory", "r", tiffStream, new TiffStream()))
{
if (inImage == null)
return null;
int totalPages = inImage.NumberOfDirectories();
for (var i = 0; i < totalPages; )
{
if (!inImage.SetDirectory((short) i))
return null;
var decompressedTiff = DecompressTiff(inImage);
...
}
private static byte[] DecompressTiff(Tiff image)
{
// Read in the possibly multiple strips
var stripSize = image.StripSize();
var stripMax = image.NumberOfStrips();
var imageOffset = 0;
int row = 0;
var bufferSize = image.NumberOfStrips() * stripSize;
var buffer = new byte[bufferSize];
int height = 0;
var result = image.GetField(TiffTag.IMAGELENGTH);
if (result != null)
height = result[0].ToInt();
int rowsperstrip = 0;
result = image.GetField(TiffTag.ROWSPERSTRIP);
if (result != null)
rowsperstrip = result[0].ToInt();
if (rowsperstrip > height && rowsperstrip != -1)
rowsperstrip = height;
for (var stripCount = 0; stripCount < stripMax; stripCount++)
{
int countToRead = (row + rowsperstrip > height) ? image.VStripSize(height - row) : stripSize;
var readBytesCount = image.ReadEncodedStrip(stripCount, buffer, imageOffset, countToRead); // Returns -1 for the last strip of the very first page
if (readBytesCount == -1)
return null;
imageOffset += readBytesCount;
row += rowsperstrip;
}
return buffer;
}
问题是,当为第一页的最后一段调用 ReadEncodedStrip()
时 - 它 returns -1,表明存在错误。即使在调试 LibTIFF.NET 解码器代码之后,我也不知道出了什么问题。这是在意想不到的地方发现了 EOL TIFF 标记。
由于某种原因,LibTIFF.NET 无法读取它自己生成的 TIFF,或者很可能是我遗漏了什么。 Here 是 TIFF 的问题。
谁能帮忙找出根本原因?
经过半天多的排查,我终于找到了这个奇怪问题的原因。
为了从每像素 24 位的 TIFF 转换为每像素 1 位,我将算法从 C 移植到 C#,这两个工具随原始 libtiff 一起提供:tiff2bw and tiffdither.
tiffdither 有一个错误,它不包括输出图像中的最后一个图像行,即如果你给它一个 2200 行高的图像,你会得到 2199 行高的图像作为输出。
我在移植的一开始就注意到了这个错误并试图修复,但是,最终结果证明,并没有完全修复,而且移植的算法实际上并没有通过 [=10= 写入最后一行] 方法输出 TIFF。所以这就是为什么 LibTIFF.NET 无法读取图像最后 strip\row 的原因,具体取决于我使用的阅读方法。
令我惊讶的是,LibTIFF.NET 允许写入此类实际损坏的 TIFF 而不会在写入过程中出现任何错误。例如 WriteDirectory()
方法 returns true
在这种情况下,通过 TiffTag.IMAGELENGTH
设置的图像高度与写入它的实际行数不同。但是后来读不到这样的图片,读的时候报错。
不过,也许这种行为继承自原始 libtiff。