pyPdf para extracção IndirectObject
Pergunta
A seguir este exemplo, eu posso listar todos os elementos em um arquivo PDF
import pyPdf
pdf = pyPdf.PdfFileReader(open("pdffile.pdf"))
list(pdf.pages) # Process all the objects.
print pdf.resolvedObjects
Agora, eu preciso extrair um objeto não-padrão do arquivo pdf.
Meu objetivo é o chamado myObject e é uma string.
A peça impressa pelo script python que concernes mim é:
{'/MYOBJECT': IndirectObject(584, 0)}
O arquivo pdf é esta:
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
Como posso acompanhar o valor 584
, a fim de se referir a minha string (sob pyPdf é claro) ??
Solução
cada elemento na pdf.pages
é um dicionário, por isso, assumindo que é na página 1, pdf.pages[0]['/MYOBJECT']
deve ser o elemento desejado.
Você pode tentar imprimir que individualmente ou cutucar com help
e dir
em um python prompt para mais sobre como obter a seqüência que você deseja
Editar:
depois de receber uma cópia do pdf, I o objecto em pdf.resolvedObjects[0][558]['/Resources']['/Properties']['/MC0']['/MYOBJECT']
e o valor pode ser recuperada através de getData ()
a seguinte função dá uma forma mais genérica para resolver isso de forma recursiva procurando a chave em questão
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()
Outras dicas
Um IndirectObject refere-se a um objeto real (é como um link ou um alias para que o tamanho total do PDF pode ser reduzido quando os mesmos aparece conteúdo em vários lugares). O método getObject lhe dará o objeto real.
Se o objeto é um objeto de texto, em seguida, basta fazer um str () ou unicode () sobre o objeto deverá fazê-lo dentro de dados do mesmo.
Como alternativa, lojas pyPdf os objetos nos resolvedObjects atributo. Por exemplo, um PDF que contém esse objeto:
13 0 obj
<< /Type /Catalog /Pages 3 0 R >>
endobj
Pode ser lido com isso:
>>> 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)}
O método de Jeías é bom se olhando em todos os lugares para o objeto. Meu palpite (olhando para o PDF) é que ele está sempre no mesmo lugar (a primeira página, na propriedade 'mc0'), e por isso um método muito mais simples de encontrar a seqüência seria:
import pyPdf
pdf = pyPdf.PdfFileReader(open("file.pdf"))
pdf.getPage(0)['/Resources']['/Properties']['/MC0']['/MYOBJECT'].getData()