【问题标题】:Issues Decoding Flate from PDF Embedded Font从 PDF 嵌入字体解码 Flate 的问题
【发布时间】:2013-03-21 06:25:13
【问题描述】:

好的,在我们开始之前。我在一家公司工作,该公司拥有从各种出版商以任何媒体形式重新分发 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);
    }
}

在使用常用工具(Google、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ƒÝü

【问题讨论】:

  • 如果我对您的理解正确,您只有一个(或数量有限的)PDF 文件会遇到这个问题,但通常它可以正常工作。因此,问题可能出在那些 PDF 上。可以提供样品吗?
  • @mkl,不,我从来没有做过这项工作。我怀疑问题在于我如何尝试将字体对象转换为流,它应该来自我从中获取它的字符串 - 但我不确定。我将流字符串放入字符串中,然后使用“Encoding.UTF8.GetBytes(stringValue);”转换为字节数组。

标签: c# pdf itextsharp pdfbox embedded-fonts


【解决方案1】:

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

【讨论】:

  • 嗯,原因是我对 iTextSharp 还很陌生,并且几乎找不到任何帮助来指引我这样的方向。我不确定如何使用 iTextSharp 隔离流以直接从中提取流 - 我一直在从文本中提取(我怀疑我的错误所在) - 在 streamendstream 标签。所以,简短的回答,我不知道这种方法!谢谢你,到目前为止你的帮助,我开始认为我不会在这方面得到任何帮助。
【解决方案2】:

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

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

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

您应该能够通过将要解码的确切字节数与流字典中的(必需)“长度”键的值进行比较来确定您是否遇到了这种情况。

【讨论】:

    【解决方案3】:

    好的,对于任何可能自己偶然发现此问题的人,请允许我警告您 - 这是一条崎岖不平的道路,没有很多好的解决方案。我最终放弃了自己编写所有代码来提取字体。我只是下载了 MuPDF(开源),然后对 mutool.exe 进行了命令行调用:

        mutool extract C:\mypdf.pdf
    

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

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

    提醒一下,字体盗版就是盗版。

    【讨论】:

      猜你喜欢
      • 2014-03-02
      • 1970-01-01
      • 2015-06-20
      • 1970-01-01
      • 1970-01-01
      • 2019-12-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多