为什么字符 ID 160 在 PDFMiner 中不被识别为 Unicode?
Why character ID 160 is not recognised as Unicode in PDFMiner?
我正在使用 PDFMiner.
将 .pdf 文件转换为 .xml 文件
对于 .pdf 文件中的每个单词,PDFMiner 会检查它是否是 Unicode(以及许多其他内容)。如果是,它 returns 字符,如果不是,它引发异常和 returns 字符串 "(cid:%d)" 其中 %d 是字符 ID,我认为是Unicode 十进制。
这个问题的编辑部分对此有很好的解释:
What is this (cid:51) in the output of pdf2txt?。为了方便,我在这里报告代码:
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 文件,我通常会遇到此异常。但是,有一个使用简单英语的文件,我在其中得到了非中断 spaces(具有 cid=160)的异常。我不明白为什么这个字符不被识别为 Unicode,而同一文件中的所有其他字符都是。
如果在相同的环境中,我在控制台中 运行 isinstance(u'160', unicode)
我得到 True
,而(显然)等效命令返回 False
运行 在 PDFMiner 中。
如果我调试,我发现字体被正确识别,即我得到:
cid = 160
font = <PDFType1Font: basefont='Helvetica'>
PDFMiner 接受编解码器作为参数。我选择了 utf-8,它有 160 作为不间断的 Unicode Decimal space (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)
有没有办法set/change代码识别的字符映射?
您认为我应该更改什么,或者您认为我应该调查哪里,以便 cid=160 不会引发异常?
示例文档中的相关字体是简单字体并使用 WinAnsiEncoding。此编码在 PDF 规范 ISO 32000-1 中定义为附件 D.2 拉丁字符集和编码 中 table 中的四种特殊编码之一。 table 不 在 WIN
列中包含 240(= 十进制 160。table 条目以八进制数字给出!)的条目.
此 table 被提取为 latin_enc.py 中的 ENCODING
数组,并从该数组中生成这四种编码的映射encodingdb.py 然后使用,例如对于具有这种编码的字体,请参见 pdffont.py.
中的 PDFSimpleFont
因此,PdfMiner 无法将代码 160 识别为在 WinAnsiEncoding 中具有任何关联字符。这会导致您的问题。
只看table似乎是正确的,但如果阅读table下面的注释,就会发现:
- The SPACE character shall also be encoded as 312 in MacRomanEncoding and as 240 in
WinAnsiEncoding. This duplicate code shall signify a nonbreaking space; it shall be typographically
the same as (U+003A) SPACE.
PdfMiner 开发似乎忽略了这一点。
可以通过为 space
添加第二个条目来修复此疏忽
('nbspace', None, 202, 160, None)
到ENCODING
数组(使用十进制数);如果您愿意,可以改用 space
。
(我说 可能 是因为我不喜欢 Python 编程,因此无法检查,尤其是无法检查不需要的副作用。)
对于出现上述错误的人,以下代码可能会对您有所帮助。
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()
希望对您有所帮助!!
对于不同文件中的相似字符,对我有用的一个解决方案是使用 ftfy.fix_text()
。我被这个包修复了 mojibake 烘焙成 pdf 的 unicode,基本上是不同编码之间典型的卷曲引用 hijinks。 Pdfminer 将它们捕获为“(cid:146)”等,但我想进一步清理它们。这个 class 目前在那个文件上工作;它包括使其打印某些东西的最小值,但工作模块中可能会有更多 pdfminer 元素。如果使用 pdf2txt.py
,也许可以将副本放在安全的地方,将 pdfminer.high_level.extract_text_to_fp(fp, **locals())
行重定向到该模块的安全副本,将此 class 添加到该模块的末尾,然后交换它继承了基础class。我刚刚完成了 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)
我正在使用 PDFMiner.
将 .pdf 文件转换为 .xml 文件对于 .pdf 文件中的每个单词,PDFMiner 会检查它是否是 Unicode(以及许多其他内容)。如果是,它 returns 字符,如果不是,它引发异常和 returns 字符串 "(cid:%d)" 其中 %d 是字符 ID,我认为是Unicode 十进制。
这个问题的编辑部分对此有很好的解释: What is this (cid:51) in the output of pdf2txt?。为了方便,我在这里报告代码:
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 文件,我通常会遇到此异常。但是,有一个使用简单英语的文件,我在其中得到了非中断 spaces(具有 cid=160)的异常。我不明白为什么这个字符不被识别为 Unicode,而同一文件中的所有其他字符都是。
如果在相同的环境中,我在控制台中 运行 isinstance(u'160', unicode)
我得到 True
,而(显然)等效命令返回 False
运行 在 PDFMiner 中。
如果我调试,我发现字体被正确识别,即我得到:
cid = 160
font = <PDFType1Font: basefont='Helvetica'>
PDFMiner 接受编解码器作为参数。我选择了 utf-8,它有 160 作为不间断的 Unicode Decimal space (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)
有没有办法set/change代码识别的字符映射?
您认为我应该更改什么,或者您认为我应该调查哪里,以便 cid=160 不会引发异常?
示例文档中的相关字体是简单字体并使用 WinAnsiEncoding。此编码在 PDF 规范 ISO 32000-1 中定义为附件 D.2 拉丁字符集和编码 中 table 中的四种特殊编码之一。 table 不 在 WIN
列中包含 240(= 十进制 160。table 条目以八进制数字给出!)的条目.
此 table 被提取为 latin_enc.py 中的 ENCODING
数组,并从该数组中生成这四种编码的映射encodingdb.py 然后使用,例如对于具有这种编码的字体,请参见 pdffont.py.
PDFSimpleFont
因此,PdfMiner 无法将代码 160 识别为在 WinAnsiEncoding 中具有任何关联字符。这会导致您的问题。
只看table似乎是正确的,但如果阅读table下面的注释,就会发现:
- The SPACE character shall also be encoded as 312 in MacRomanEncoding and as 240 in WinAnsiEncoding. This duplicate code shall signify a nonbreaking space; it shall be typographically the same as (U+003A) SPACE.
PdfMiner 开发似乎忽略了这一点。
可以通过为 space
('nbspace', None, 202, 160, None)
到ENCODING
数组(使用十进制数);如果您愿意,可以改用 space
。
(我说 可能 是因为我不喜欢 Python 编程,因此无法检查,尤其是无法检查不需要的副作用。)
对于出现上述错误的人,以下代码可能会对您有所帮助。
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()
希望对您有所帮助!!
对于不同文件中的相似字符,对我有用的一个解决方案是使用 ftfy.fix_text()
。我被这个包修复了 mojibake 烘焙成 pdf 的 unicode,基本上是不同编码之间典型的卷曲引用 hijinks。 Pdfminer 将它们捕获为“(cid:146)”等,但我想进一步清理它们。这个 class 目前在那个文件上工作;它包括使其打印某些东西的最小值,但工作模块中可能会有更多 pdfminer 元素。如果使用 pdf2txt.py
,也许可以将副本放在安全的地方,将 pdfminer.high_level.extract_text_to_fp(fp, **locals())
行重定向到该模块的安全副本,将此 class 添加到该模块的末尾,然后交换它继承了基础class。我刚刚完成了 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)