BitMiracle LibTIFF.NET无法解压缩先前由自己创建的TIFF

时间:2015-08-10 12:42:34

标签: c# .net image image-processing tiff

我实现了一个类,它读取由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()时,它返回-1,表示存在错误。在调试LibTIFF.NET解码器代码后,我无法弄清楚出了什么问题。这是EOL TIFF标记发现的地方,它不是预料到的。

由于某种原因,LibTIFF.NET无法读取自己生成的TIFF,或者很可能我错过了一些东西。 Here是问题TIFF。

有人可以帮忙找到根本原因吗?

1 个答案:

答案 0 :(得分:1)

经过一天半的调查,我终于设法发现了这个奇怪问题的原因。

要将每像素24位TIFF转换为每像素1位,我将原始libtiff附带的2个工具的C算法移植到C#:tiff2bwtiffdither

tiffdither有一个错误,即它没有包含输出图像中的最后一个图像行,即如果你向它输入一个2200行高的图像,你得到的图像有2199行高度作为输出。

我在移植的最初阶段注意到了这个错误,并尝试修复,但是,最终结果并非完全,并且移植的算法实际上并没有通过{{写入最后一行1}}输出TIFF的方法。所以这就是为什么LibTIFF.NET无法读取图像的最后一个条带\行的原因,这取决于我使用的读取方法。

让我感到惊讶的是,LibTIFF.NET允许在写入过程中编写实际损坏的TIFF而不会出现任何错误。例如,WriteScanline()方法在此情况下返回WriteDirectory(),此时通过true设置的图像高度与写入其中的实际行数不同。但是,以后它无法读取这样的图像,并且在阅读时会抛出错误。

可能这种行为继承自原始的libtiff。