1

我正在使用PDFMiner将 .pdf 文件转换为 .xml 文件。

对于 .pdf 文件中的每个单词,PDFMiner 会检查它是否是 Unicode(以及许多其他内容)。如果是,则返回字符,如果不是,则引发异常并返回字符串“(cid:%d)”,其中 %d 是字符 id,我认为是 Unicode Decimal。

这在这个问题的编辑部分得到了很好的解释 :pdf2txt 的输出中的 this (cid:51) 是什么?. 为了方便起见,我在这里报告代码:

def render_char(self, matrix, font, fontsize, scaling, rise, cid):
    try:
        text = font.to_unichr(cid)
        assert isinstance(text, unicode), text
    except PDFUnicodeNotDefined:
        text = self.handle_undefined_char(font, cid)


def handle_undefined_char(self, font, cid):
    if self.debug:
        print >>sys.stderr, 'undefined: %r, %r' % (font, cid)
    return '(cid:%d)' % cid

对于用西里尔文编写的 .pdf 文件,我通常会收到此异常。但是,有一个文件使用简单的英语,并且我在其中得到了非中断空格(具有 cid=160)的异常。我不明白为什么这个字符不被识别为 Unicode,而同一文件中的所有其他字符都是。

如果在相同的环境中,我isinstance(u'160', unicode)在我得到的控制台中运行True,而(显然)等效命令False在 PDFMiner 中运行时返回。

如果我调试,我看到字体被正确识别,即我得到:

cid = 160
font =  <PDFType1Font: basefont='Helvetica'>

PDFMiner 接受编解码器作为参数。我选择了 utf-8,它有 160 作为 Unicode Decimal 用于非中断空间(http://dev.networkerror.org/utf8/)。

如果它可能有帮助,这里是 to_unichr 的代码:

def to_unichr(self, cid):
    if self.unicode_map:
        try:
            return self.unicode_map.get_unichr(cid)
        except KeyError:
            pass
    try:
        return self.cid2unicode[cid]
    except KeyError:
        raise PDFUnicodeNotDefined(None, cid)

有没有办法设置/更改代码识别的字符映射?

你认为我应该改变什么,或者你认为我应该在哪里调查,以便 cid=160 不会引发异常?

4

3 回答 3

2

示例文档中有问题的字体是 Simple Font 并使用WinAnsiEncoding。此编码在 PDF 规范ISO 32000-1中定义为附件D.2 拉丁字符集和编码中表格中的四种特殊编码之一。此表不包含240 的条目(= 十进制 160。表格条目以八进制数给出!)在WIN列中。

该表被提取为latin_enc.pyENCODING中的数组,并从该数组中生成这四种编码的映射,然后在encodingdb.py中使用这些映射,例如,对于具有该编码的字体,参见pdffont.pyPDFSimpleFont

因此,代码 160 不会被 PdfMiner 识别为在 WinAnsiEncoding 中具有任何关联字符。这会导致您的问题。


只看似乎正确的表格,但如果阅读表格下方的注释,就会发现:

  1. SPACE 字符也应在MacRomanEncoding中编码为 312,在WinAnsiEncoding中编码为 240 。该重复代码应表示不间断的空格;它在印刷上应与 (U+003A) SPACE 相同。

PdfMiner 开发似乎忽略了这一点。

这种疏忽可以通过添加第二个条目来解决space

('nbspace', None, 202, 160, None)

ENCODING数组(使用十进制数);如果你愿意,你可能想space改用。

(我说可能是因为我不喜欢 Python 编程,因此无法检查,特别是不能检查不需要的副作用。)

于 2015-12-07T16:37:49.013 回答
0

一种适用于不同文件中类似字符的解决方案是使用ftfy.fix_text(). 我被这个修复 mojibake 的包吸引到了 pdf 的 unicode 中,基本上是你典型的不同编码之间的弯引号。Pdfminer 将它们捕获为“(cid:146)”等,但我想进一步清理它们。到目前为止,此类适用于该文件;它包括使它打印某些东西的最低限度,但工作模块中可能会有更多的 pdfminer 元素。如果有人正在使用pdf2txt.py,也许可以将副本放在安全的地方,将pdfminer.high_level.extract_text_to_fp(fp, **locals())行重定向到该模块的安全副本,将此类添加到其末尾,并将其交换为它继承的基类。我刚刚完成了 HTMLConverter,但其他的可能也可以类似地处理。

from pdfminer.converter import HTMLConverter
from io                 import BytesIO
class HTMLConvertOre(HTMLConverter):
    import ftfy, six
    from pdfminer.layout    import LTChar
    from pdfminer.pdffont   import PDFUnicodeNotDefined
    def __init__(self, rsrcmgr, outfp, codec='utf-8', pageno=1, laparams=None,
                 scale=1, fontscale=1.0, layoutmode='normal', showpageno=True,
                 pagemargin=50, imagewriter=None, debug=0,
                 rect_colors={'curve': 'black', 'page': 'gray'},
                 text_colors={'char': 'black'}):
        """Initialize pdfminer.converter HTMLConverter."""
        HTMLConverter.__init__(**locals())
    def render_char(self, matrix, font, fontsize, scaling, rise, cid, ncs,
                    graphicstate):
        """Mod invoking ftfy.fix_text() to possibly rescue bad cids."""
        try:
            text = font.to_unichr(cid)
            assert isinstance(text, six.text_type), str(type(text))
        except PDFUnicodeNotDefined:
            try:
                text = ftfy.fix_text(chr(cid), uncurl_quotes=False)
                assert isinstance(text, six.text_type), str(type(text))
                cid=ord(text)
            except PDFUnicodeNotDefined:
                text = self.handle_undefined_char(font, cid)
        textwidth = font.char_width(cid)
        textdisp = font.char_disp(cid)
        item = LTChar(matrix, font, fontsize, scaling, rise, text, textwidth,
                      textdisp, ncs, graphicstate)
        self.cur_item.add(item)
        return item.adv
if __name__ == '__main__':
    rsrcmgr = PDFResourceManager()
    outfp = BytesIO()
    device = HTMLConvertOre(rsrcmgr, outfp)
    print(device)
于 2019-12-11T17:22:09.873 回答
-1

对于那些遇到上述错误的人,下面的代码可能会对您有所帮助。

import minecart
from PIL import Image
import io

pdffile = open('sample.pdf', 'rb')
doc = minecart.Document(pdffile)

for page in doc.iter_pages():
    im = page.images[0]#taking only one image per page
    byteArray = im.obj.get_data()
    image = Image.open(io.BytesIO(byteArray))
    image.show()

希望能帮助到你!!

请参考https://github.com/felipeochoa/minecart/issues/16

于 2019-10-14T07:52:38.410 回答