pyPdf для извлечения IndirectObject
Вопрос
Следуя этому примеру, я могу перечислить все элементы в файл PDF.
import pyPdf
pdf = pyPdf.PdfFileReader(open("pdffile.pdf"))
list(pdf.pages) # Process all the objects.
print pdf.resolvedObjects
теперь мне нужно извлечь нестандартный объект из файла PDF.
Мой объект называется MYOBJECT и представляет собой строку.
Меня беспокоит фрагмент, напечатанный скриптом Python:
{'/MYOBJECT': IndirectObject(584, 0)}
PDF-файл такой:
558 0 obj
<</Contents 583 0 R/CropBox[0 0 595.22 842]/MediaBox[0 0 595.22 842]/Parent 29 0 R/Resources
<</ColorSpace <</CS0 563 0 R>>
/ExtGState <</GS0 568 0 R>>
/Font<</TT0 559 0 R/TT1 560 0 R/TT2 561 0 R/TT3 562 0 R>>
/ProcSet[/PDF/Text/ImageC]
/Properties<</MC0<</MYOBJECT 584 0 R>>/MC1<</SubKey 582 0 R>> >>
/XObject<</Im0 578 0 R>>>>
/Rotate 0/StructParents 0/Type/Page>>
endobj
...
...
...
584 0 obj
<</Length 8>>stream
1_22_4_1 --->>>> this is the string I need to extract from the object
endstream
endobj
Как я могу следить за 584
значение, чтобы ссылаться на мою строку (конечно, в pyPdf)??
Решение
каждый элемент в pdf.pages
это словарь, поэтому предположим, что он находится на первой странице, pdf.pages[0]['/MYOBJECT']
должен быть тот элемент, который вам нужен.
Вы можете попробовать распечатать это отдельно или ткнуть в него с помощью help
и dir
в приглашении Python для получения дополнительной информации о том, как получить нужную строку
Редактировать:
получив копию PDF-файла, я нашел объект по адресу pdf.resolvedObjects[0][558]['/Resources']['/Properties']['/MC0']['/MYOBJECT']
и значение можно получить с помощью getData()
следующая функция дает более общий способ решения этой проблемы путем рекурсивного поиска рассматриваемого ключа
import types
import pyPdf
pdf = pyPdf.PdfFileReader(open('file.pdf'))
pages = list(pdf.pages)
def findInDict(needle,haystack):
for key in haystack.keys():
try:
value = haystack[key]
except:
continue
if key == needle:
return value
if type(value) == types.DictType or isinstance(value,pyPdf.generic.DictionaryObject):
x = findInDict(needle,value)
if x is not None:
return x
answer = findInDict('/MYOBJECT',pdf.resolvedObjects).getData()
Другие советы
IndirectObject ссылается на реальный объект (это как ссылка или псевдоним, так что общий размер PDF может быть уменьшен, когда один и тот же контент появляется в нескольких местах). Метод getObject даст вам реальный объект.
Если объект является текстовым объектом, то просто выполнение str () или unicode () над объектом должно получить данные внутри него.
Кроме того, pyPdf сохраняет объекты в атрибуте resolvedObjects. Например, PDF-файл, содержащий этот объект:
13 0 obj
<< /Type /Catalog /Pages 3 0 R >>
endobj
Можно прочитать с этим:
>>> import pyPdf
>>> pdf = pyPdf.PdfFileReader(open("pdffile.pdf"))
>>> pages = list(pdf.pages)
>>> pdf.resolvedObjects
{0: {2: {'/Parent': IndirectObject(3, 0), '/Contents': IndirectObject(4, 0), '/Type': '/Page', '/Resources': IndirectObject(6, 0), '/MediaBox': [0, 0, 595.2756, 841.8898]}, 3: {'/Kids': [IndirectObject(2, 0)], '/Count': 1, '/Type': '/Pages', '/MediaBox': [0, 0, 595.2756, 841.8898]}, 4: {'/Filter': '/FlateDecode'}, 5: 147, 6: {'/ColorSpace': {'/Cs1': IndirectObject(7, 0)}, '/ExtGState': {'/Gs2': IndirectObject(9, 0), '/Gs1': IndirectObject(10, 0)}, '/ProcSet': ['/PDF', '/Text'], '/Font': {'/F1.0': IndirectObject(8, 0)}}, 13: {'/Type': '/Catalog', '/Pages': IndirectObject(3, 0)}}}
>>> pdf.resolvedObjects[0][13]
{'/Type': '/Catalog', '/Pages': IndirectObject(3, 0)}
Метод Джехии хорош, если везде искать объект. Я предполагаю (глядя на PDF), что он всегда находится в одном и том же месте (первая страница, в свойстве 'MC0'), и поэтому гораздо более простой метод поиска строки будет выглядеть так:
import pyPdf
pdf = pyPdf.PdfFileReader(open("file.pdf"))
pdf.getPage(0)['/Resources']['/Properties']['/MC0']['/MYOBJECT'].getData()