从PDF嵌入字体解码Flate的问题

时间:2013-03-30 18:41:49

标签: c# pdf itextsharp pdfbox embedded-fonts

好的,在我们开始之前。我在一家公司工作,该公司有权以任何媒体形式从各种发布商处重新发布PDF文件。因此,可以说,从给定的PDF文件中提取嵌入字体不仅合法 - 而且对演示也很重要。

我正在使用本网站上的代码,但我不记得作者,当我找到它时,我会引用它们。我已经在PDF文件中找到了包含嵌入字体的流,我已将此编码流隔离为字符串,然后再隔离到byte[]。当我使用以下代码时出现错误

Block length does not match with its complement.

代码(错误发生在下面的while行中):

private static byte[] DecodeFlateDecodeData(byte[] data)
{
    MemoryStream outputStream;
    using (outputStream = new MemoryStream())
    {
        using (var compressedDataStream = new MemoryStream(data))
        {
            // Remove the first two bytes to skip the header (it isn't recognized by the DeflateStream class)
            compressedDataStream.ReadByte();
            compressedDataStream.ReadByte();

            var deflateStream = new DeflateStream(compressedDataStream, CompressionMode.Decompress, true);
            var decompressedBuffer = new byte[compressedDataStream.Length];
            int read;

            // The error occurs in the following line
            while ((read = deflateStream.Read(decompressedBuffer, 0, decompressedBuffer.Length)) != 0)
            {
                outputStream.Write(decompressedBuffer, 0, read);
            }
            outputStream.Flush();
            compressedDataStream.Close();
        }

        return ReadFully(outputStream);
    }
}

在使用常用工具(谷歌,Bing,这里的档案)之后,我发现大多数时候发生这种情况是因为没有消耗编码流的前两个字节 - 但这是在这里完成的,所以我不能找到此错误的来源。以下是编码流:

H‰LT}lg?7ñù¤aŽÂ½ãnÕ´jh›Ú?-T’ÑRL–¦
ëš:Uí6Ÿ¶“ø+ñ÷ùü™”ÒÆŸŸíóWlDZ“ºu“°tƒ¦t0ÊD¶jˆ
Ö   m:$½×^*qABBï?Þç÷|ýÞßóJÖˆD"yâP—òpgÇó¦Q¾S¯9£Û¾mçÁçÚ„cÂÛO¡É‡·¥ï~á³ÇãO¡ŸØö=öPD"d‚ìA—$H'‚DC¢D®¤·éC'Å:È—€ìEV%cÿŽS;þÔ’kYkùcË_ZÇZ/·þYº(ý݇Ã_ó3m¤[3¤²4ÿo?²õñÖ*Z/Þiãÿ¿¾õ8Ü    ?»„O Ê£ðÅ­P9ÿ•¿Â¯*–z×No˜0ãÆ-êàîoR‹×ÉêÊêÂulaƒÝü

请帮助,我在这里撞墙!

注意:上面的流是Arial Black的编码版本 - 根据PDF中的规范:

661 0 obj
<< 
/Type /FontDescriptor 
/FontFile3 662 0 R 
/FontBBox [ -194 -307 1688 1083 ] 
/FontName /HLJOBA+ArialBlack 
/Flags 4 
/StemV 0 
/CapHeight 715 
/XHeight 518 
/Ascent 0 
/Descent -209 
/ItalicAngle 0 
/CharSet (/space/T/e/s/t/a/k/i/n/g/S/r/E/x/m/O/u/l)
>> 
endobj
662 0 obj
<< /Length 1700 /Filter /FlateDecode /Subtype /Type1C >> 
stream
H‰LT}lg?7ñù¤aŽÂ½ãnÕ´jh›Ú?-T’ÑRL–¦
ëš:Uí6Ÿ¶“ø+ñ÷ùü™”ÒÆŸŸíóWlDZ“ºu“°tƒ¦t0ÊD¶jˆ
Ö   m:$½×^*qABBï?Þç÷|ýÞßóJÖˆD"yâP—òpgÇó¦Q¾S¯9£Û¾mçÁçÚ„cÂÛO¡É‡·¥ï~á³ÇãO¡ŸØö=öPD"d‚ìA—$H'‚DC¢D®¤·éC'Å:È—€ìEV%cÿŽS;þÔ’kYkùcË_ZÇZ/·þYº(ý݇Ã_ó3m¤[3¤²4ÿo?²õñÖ*Z/Þiãÿ¿¾õ8Ü    ?»„O Ê£ðÅ­P9ÿ•¿Â¯*–z×No˜0ãÆ-êàîoR‹×ÉêÊêÂulaƒÝü

3 个答案:

答案 0 :(得分:1)

您是否有特殊原因未使用iText提供的GetStreamBytes()方法?那么data呢?你确定你正在查看正确的字节吗?您是否正确创建了PRStream对象,并且获得了PdfReader.GetStreamBytesRaw()的字节数?如果是这样,为什么要自己解码字节?这让我想到了我最初的反问题:你有没有使用GetStreamBytes()方法的特殊原因?

答案 1 :(得分:1)

看起来GetStreamBytes()可能会解决您的问题,但我要指出,我认为您正在做一些关于行尾标记的危险事件。 7.3.8.1中的PDF规范指出:

  

流字典后面的关键字流应为   然后是由CARRIAGE组成的行尾标记   返回和线路馈送或只是一个LINE FEED,而不是一个CARRIAGE   单独返回。

在您的代码中,看起来您总是跳过两个字节,而规范说它可能是一个或两个(CR LF或LF)。

您应该能够通过比较要解码的确切字节数与流字典中(必需)“长度”键的值来了解您是否遇到此问题。

答案 2 :(得分:0)

好吧,对于那些可能偶然发现这个问题的人来说,我可以向你发出警告 - 这是一条没有很多好解决方案的艰难道路。我最终放弃了编写所有代码来自己提取字体。我只是下载了MuPDF(开源),然后对mutool.exe进行了命令行调用:

    mutool extract C:\mypdf.pdf

这会将所有字体拉入mutool所在的文件夹中(它还会提取一些图像(这些是无法转换的字体(我认为通常是小的子集)))。然后我编写了一个方法将那些文件夹中的文件移动到我想要的文件夹中。

当然,将这些转换为任何可用的东西本身就是一个令人头痛的问题 - 但我发现它是可行的。

提醒一下,字体盗版是盗版行为。