问题解码平面从PDF嵌入字体

本文关键字:字体 PDF 解码 平面 问题 | 更新日期: 2023-09-27 18:06:43

好的,在我们开始之前。我在一家公司工作,该公司有权以任何媒体形式重新分发来自各种出版商的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, archives here)之后,我发现大多数情况下发生这种情况是当一个人没有消耗编码流的前两个字节时-但这是在这里完成的,所以我找不到这个错误的来源。下面是编码后的流:

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:

中的规范,上面的流是Arial Black的编码版本。
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嵌入字体

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

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

流字典后面的关键字stream应为然后是由一个回车符组成的行尾标记RETURN和换行符或只是换行符,而不是回车符独自返回。

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

您应该能够通过比较您想要解码的确切字节数与(Required)的值来捕获您是否遇到此问题。

好吧,对于那些自己可能遇到这个问题的人,请允许我警告你——这是一条没有大量好的解决方案的崎岖之路。我最终放弃了自己编写所有的代码来提取字体。我只是下载了MuPDF(开源),然后对mutool.exe进行命令行调用:

    mutool extract C:'mypdf.pdf

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

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

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