【问题标题】:Error while trying to decompress stream in PDF尝试在 PDF 中解压缩流时出错
【发布时间】:2019-10-01 19:44:45
【问题描述】:

我正在尝试从 file 中的 PDF 对象解压缩流:

 4 0 obj
<< 
/Filter /FlateDecode
/Length 64
>>
stream
xœs
QÐw34V02UIS0´0P030PIQÐpÉÏKIUH-.ITH.-*Ê··×TÉRp
á T‰
Ê
endstream
endobj

我将此流以与原始文件相同的格式复制粘贴到名为Stream.file 的文件中

xœs
QÐw34V02UIS0´0P030PIQÐpÉÏKIUH-.ITH.-*Ê··×TÉRp
á T‰
Ê

此流应转换为:Donde esta curro??。在 C# 控制台应用程序中将该流添加到 Stream.file

using System.IO;
using System.IO.Compression;

namespace Filters
{
    public static class FiltersLoader
    {
        public static void Parse()
        {
            var bytes = File.ReadAllBytes("Stream.file");
            var originalFileStream = new MemoryStream(bytes);

            using (var decompressedFileStream = new MemoryStream())
            using (var decompressionStream = new DeflateStream(originalFileStream, CompressionMode.Decompress))
            {
                decompressionStream.CopyTo(decompressedFileStream);
            }    
        }
    }
}

但是在尝试复制它时会产生异常:

The archive entry was compressed using an unsupported compression method.

如果可能的话,我想知道如何用 .net 代码解码这个流。

谢谢。

【问题讨论】:

  • 您不能复制粘贴二进制数据,如果它是文本并期望它顺利进行。那里有很多可能出错的地方,即使幸运的是,您使用的编码包含所有字符的单个代码点。你需要更狡猾一点,编写一个小程序来读取文件,直到它到达&gt;&gt;stream(或者只是尝试直到你得到正确的偏移量)并将字节提取为真正的二进制内容。 (除了您是否可以在此处实际使用DeflateStream 之外;我对 PDF 的了解还不够,无法说出这是否正确。)
  • 你说的有一部分是对的,我没有意识到在复制它时添加了 Windows 返回行,但是在将其更改为 Unix LF 并确保两个流在 mh-nexus.de/en/hxd 中看起来相同并且仍然具有相同问题。
  • 错误消息对我来说似乎很不言自明。您正在尝试解压缩 DeflateStream() 类无法识别为受支持的压缩方法的数据。数据已损坏或使用了不同的压缩方法。
  • 嗨,我也看到了。但是,正如您从 PDF 文件中看到的那样,我使用 FlateDecode 算法将其中的流压缩了一次,这与我在尝试解压缩时在 c# 中使用的相同(Deflate)

标签: c# pdf .net-core deflatestream


【解决方案1】:

主要问题是 DeflateStream 类可以解码裸 FLATE 压缩流(根据 RFC 1951),但带有 FlateDecode 过滤器的 PDF 流的内容实际上呈现在 ZLIB Compressed数据格式(根据RFC 1950包装 FLATE 压缩数据。

要解决此问题,只需删除两字节 ZLIB 标头即可。

另一个问题在您的第一个示例文档中变得很清楚:该文档已加密,因此在 FLATE 解码之前必须解密其中的流内容。

###Drop ZLIB 标头以获取 FLATE 编码数据

DeflateStream 类可以解码裸 FLATE 压缩流(根据 RFC 1951),但带有 FlateDecode 过滤器的 PDF 流的内容实际上以 ZLIB 压缩数据格式(根据RFC 1950) 包装 FLATE压缩数据。

幸运的是,跳转到其中的 FLATE 编码数据非常容易,只需删除前两个字节即可。 (严格来说,它们与 FLATE 编码数据之间可能存在一个字典标识符,但这似乎很少使用。)

如果是您的代码:

var bytes = File.ReadAllBytes("Stream.file");
var originalFileStream = new MemoryStream(bytes);

originalFileStream.ReadByte();
originalFileStream.ReadByte();

using (var decompressedFileStream = new MemoryStream())
using (var decompressionStream = new DeflateStream(originalFileStream, CompressionMode.Decompress))
{
    decompressionStream.CopyTo(decompressedFileStream);
}   

###如果是加密的PDF,请先解密

您的第一个示例文件 pdf-test.pdf 已加密,如预告片中存在 Encrypt 条目所示:

trailer
<</Size 37/Encrypt 38 0 R>>
startxref
116
%%EOF

因此,在解压缩流内容之前,您必须对其进行解密。

【讨论】:

  • 这是预告片:预告片 > 它没有显示加密对象。
  • 这可能是您将问题更改为引用完全不同的测试文件后的预告片。请不要让您的问题成为一个移动的目标。
  • 我找不到以前的文件,所以我把它改成了一个更简单的文件。但问题是一样的。
  • 请分享新文件。将二进制数据作为文本转储很可能会损坏它。
  • 该 PDF 已损坏(提示在 Adob​​e Reader 中打开并再次关闭后,Adobe Reader 会询问是否应保存)。特别是您的示例流已损坏,它声称大小为 64 字节,但大小仅为 60 或 61 字节。
猜你喜欢
  • 1970-01-01
  • 2011-09-14
  • 2017-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-07
相关资源
最近更新 更多