在 Python 的 PDFrw 中使用流?
Working with streams in PDFrw for Python?
我正在尝试使用 PDFrw 阅读示例 PDF。 PDF 在坐标 (100, 100)
的左下角包含短语 Hello Matthew
。当我尝试输出文本时(如果可以的话?),我得到了一个数据流。我似乎无法弄清楚如何将其作为文本获取。
>>> import pdfrw
>>> file_object = pdfrw.PdfReader("Hello.pdf")
>>> file_object
{'/ID': ['<f643bc0910dfb67725d53e11054f4609>', '<f643bc0910dfb67725d53e11054f4609>'], '/Info': (5, 0), '/Root': {'/Outl
ines': (8, 0), '/PageMode': '/UseNone', '/Pages': {'/Count': '1', '/Kids': [{'/Contents': (7, 0), '/MediaBox': ['0', '0
', '595.2756', '841.8898'], '/Parent': {...}, '/Resources': {'/Font': (1, 0), '/ProcSet': ['/PDF', '/Text', '/ImageB',
'/ImageC', '/ImageI']}, '/Rotate': '0', '/Trans': {}, '/Type': '/Page'}], '/Type': '/Pages'}, '/Type': '/Catalog'}, '/S
ize': '9'}
>>> file_object.pages[0]
{'/Contents': (7, 0), '/MediaBox': ['0', '0', '595.2756', '841.8898'], '/Parent': {'/Count': '1', '/Kids': [{...}], '/T
ype': '/Pages'}, '/Resources': {'/Font': (1, 0), '/ProcSet': ['/PDF', '/Text', '/ImageB', '/ImageC', '/ImageI']}, '/Rot
ate': '0', '/Trans': {}, '/Type': '/Page'}
>>> file_object.pages[0].keys()
['/Contents', '/MediaBox', '/Parent', '/Resources', '/Rotate', '/Trans', '/Type']
>>> file_object.pages[0].Contents
{'/Filter': ['/ASCII85Decode', '/FlateDecode'], '/Length': '102'}
>>> file_object.pages[0].Contents.stream
'GapQh0E=F,0U\H3T\pNYT^QKk?tc>IP,;W#U1^23ihPEM_?CW4KISi90EC-p>QkRte=<%V"lI7]P)Rn29neZ[Kb,htEWn&q7Q2"V~>'
该流已压缩。您可以通过字典 /Filter 参数来判断。
不幸的是,pdfrw(还?)不知道如何使用那种类型的过滤器进行解压缩。如果你 运行 你的 pdf 先通过 pdftk 之类的东西解压它,你可能会看到更合理的东西。
免责声明:我是 pdfrw 的主要作者。
但是...
即便如此,尤其是对于非 ASCII 字体,PDF 中字符到字形的映射仍然很复杂,因此您不会总能看到看起来合理的内容。
如果您真的想深入检查文本 PDF 文件,pdfminer 可能更有用——pdfrw 还没有真正发展出可以很好地完成这项工作的工具。
如果您的过滤器只有 /Flatedecode,或者您可以先找到 运行 的 ASCII85Decode 过滤器(它们必须按顺序 运行)。我一直在使用 pdfrw.uncompress.uncompress(page.Contents) 来解码 /Flatedecode 流(与 PdfReader.uncompress() 不同,该方法不会将流传递给处理函数,它给出了所有indirect_objects).
>>> pdf = pdfrw.PdfReader('foo.pdf')
>>> pages = pdf.Root.Pages.Kids
>>> p1 = pages[0]
>>> p1.Contents
{'/Filter': '/FlateDecode', '/Length': '13679'}
>>> p1.Contents.stream[:30]
'x\x9cÕ}Ý\x92æ¶\x91å½"ô\x0eu5Q߬ëk\x02üßP8BRwË'
>>> pdfrw.uncompress.uncompress([p1.Contents]) # Contents object/s in a list.
True # it returns True even if the stream is not decoded.
>>> p1.Contents.stream[:30]
'/Artifact <</Attached [/Top]/T' # ready for parsing
然后搜索以 'TJ' 或 'Tj' 结尾的行,并从这些行中获取圆括号内的任何值...然后您就有了文本。
如果您需要文本的位置信息,请查找 BT 和 ET 之间的行块。然后检查行尾,如果你有 Tm 它应该是一个包含 6 个值的数组 [1,0,0,1,x,y] 最后两个数字给你文本起始位置的左下角。
我正在尝试使用 PDFrw 阅读示例 PDF。 PDF 在坐标 (100, 100)
的左下角包含短语 Hello Matthew
。当我尝试输出文本时(如果可以的话?),我得到了一个数据流。我似乎无法弄清楚如何将其作为文本获取。
>>> import pdfrw
>>> file_object = pdfrw.PdfReader("Hello.pdf")
>>> file_object
{'/ID': ['<f643bc0910dfb67725d53e11054f4609>', '<f643bc0910dfb67725d53e11054f4609>'], '/Info': (5, 0), '/Root': {'/Outl
ines': (8, 0), '/PageMode': '/UseNone', '/Pages': {'/Count': '1', '/Kids': [{'/Contents': (7, 0), '/MediaBox': ['0', '0
', '595.2756', '841.8898'], '/Parent': {...}, '/Resources': {'/Font': (1, 0), '/ProcSet': ['/PDF', '/Text', '/ImageB',
'/ImageC', '/ImageI']}, '/Rotate': '0', '/Trans': {}, '/Type': '/Page'}], '/Type': '/Pages'}, '/Type': '/Catalog'}, '/S
ize': '9'}
>>> file_object.pages[0]
{'/Contents': (7, 0), '/MediaBox': ['0', '0', '595.2756', '841.8898'], '/Parent': {'/Count': '1', '/Kids': [{...}], '/T
ype': '/Pages'}, '/Resources': {'/Font': (1, 0), '/ProcSet': ['/PDF', '/Text', '/ImageB', '/ImageC', '/ImageI']}, '/Rot
ate': '0', '/Trans': {}, '/Type': '/Page'}
>>> file_object.pages[0].keys()
['/Contents', '/MediaBox', '/Parent', '/Resources', '/Rotate', '/Trans', '/Type']
>>> file_object.pages[0].Contents
{'/Filter': ['/ASCII85Decode', '/FlateDecode'], '/Length': '102'}
>>> file_object.pages[0].Contents.stream
'GapQh0E=F,0U\H3T\pNYT^QKk?tc>IP,;W#U1^23ihPEM_?CW4KISi90EC-p>QkRte=<%V"lI7]P)Rn29neZ[Kb,htEWn&q7Q2"V~>'
该流已压缩。您可以通过字典 /Filter 参数来判断。
不幸的是,pdfrw(还?)不知道如何使用那种类型的过滤器进行解压缩。如果你 运行 你的 pdf 先通过 pdftk 之类的东西解压它,你可能会看到更合理的东西。
免责声明:我是 pdfrw 的主要作者。
但是...
即便如此,尤其是对于非 ASCII 字体,PDF 中字符到字形的映射仍然很复杂,因此您不会总能看到看起来合理的内容。
如果您真的想深入检查文本 PDF 文件,pdfminer 可能更有用——pdfrw 还没有真正发展出可以很好地完成这项工作的工具。
如果您的过滤器只有 /Flatedecode,或者您可以先找到 运行 的 ASCII85Decode 过滤器(它们必须按顺序 运行)。我一直在使用 pdfrw.uncompress.uncompress(page.Contents) 来解码 /Flatedecode 流(与 PdfReader.uncompress() 不同,该方法不会将流传递给处理函数,它给出了所有indirect_objects).
>>> pdf = pdfrw.PdfReader('foo.pdf')
>>> pages = pdf.Root.Pages.Kids
>>> p1 = pages[0]
>>> p1.Contents
{'/Filter': '/FlateDecode', '/Length': '13679'}
>>> p1.Contents.stream[:30]
'x\x9cÕ}Ý\x92æ¶\x91å½"ô\x0eu5Q߬ëk\x02üßP8BRwË'
>>> pdfrw.uncompress.uncompress([p1.Contents]) # Contents object/s in a list.
True # it returns True even if the stream is not decoded.
>>> p1.Contents.stream[:30]
'/Artifact <</Attached [/Top]/T' # ready for parsing
然后搜索以 'TJ' 或 'Tj' 结尾的行,并从这些行中获取圆括号内的任何值...然后您就有了文本。
如果您需要文本的位置信息,请查找 BT 和 ET 之间的行块。然后检查行尾,如果你有 Tm 它应该是一个包含 6 个值的数组 [1,0,0,1,x,y] 最后两个数字给你文本起始位置的左下角。