Uma extensão da maravilhosa biblioteca PDFRW que adiciona manuseio de fluxos de conteúdo (e todos os objetos referenciados nele, por exemplo, imagens, fontes etc.), mantendo -as o mais simples possível.
Então, por que estender o PDFRW quando há bibliotecas PDF completas como PypDF? Pense desta maneira: a maioria das bibliotecas PDF tenta fornecer funções que simplificam tarefas comuns de processamento de PDF. Essas bibliotecas são muito boas no que fazem, mas de vez em quando surge uma tarefa que requer uma nova função. Agora, se você é um desenvolvedor que está em tal situação, deve começar a cavar grandes quantidades de código -fonte dessas bibliotecas.
A abordagem do PDFRW é diferente: vamos analisar o PDF o máximo possível, mantendo o resultado o mais simples possível. Não é uma má idéia, especialmente devido ao fato de o modelo de objeto PDF (que é apenas um monte de dicionários, com alguns de seus valores sendo referências a outros dicionários) é muito adequado para mapear os dicionários Python padrão. Além disso, o PDFRW implementa uma idéia por trás de outro maravilhoso pacote atribuído para tornar ainda mais simples os objetos de PDF de atravessar: o acesso a fontes da página, por exemplo, agora pode ser feito assim:
for fontName , fontDict in page . Resources . Font . items ():
( do something )O próximo passo é tentar analisar os fluxos de dicionário-essas são entradas especiais nos dicionários que contêm as coisas interessantes: texto, imagens, gráficos vetoriais etc. O PDFRW não faz nada, e não faz isso de propósito: de acordo com sua filosofia do tipo Unix, faz o que faz muito bem e não faz um pouco mais. A estrutura de dados que produz está completa: contém todo o PDF, o suficiente para qualquer tarefa de processamento possível. E é simples o suficiente para que o desenvolvedor possa começar a codificar imediatamente, gastando mais tempo desfrutando das passagens na magnum opus do Adobe e nenhuma - aprendendo outra biblioteca complicada. E, de fato, o PDFRW é uma ferramenta ideal para ajudar a aprender a sintaxe do PDF brincando com ele!
Ok, se você chegou a esse ponto, então é provável que você esteja se perguntando: então, para onde eu vou daqui? Especificamente: como analiso os fluxos de dicionário? É aqui que o PDFRWX pode ajudar: pode analisar fluxos de dicionário e fazer outras coisas úteis. Mas as primeiras coisas primeiro:
O PDFRWX, em primeiro lugar, tenta manter a filosofia do PDFRW descrita acima. Para isso, acrescenta uma observação de que, em muitas tarefas de processamento de PDF, é gasto, a maior parte do tempo é gasta no desenvolvimento de uma solução de software e não na execução. Isso leva às opções de design:
Agora estamos prontos para ver o que o PDFRWX faz e como isso o alcança:
Aqui estão exemplos/exemplo-pdfstream.py , que lê exemplo.pdf, remove todo o conteúdo de texto de todas as páginas e grava o resultado para exemplo-out.pdf:
from pdfrw import PdfReader , PdfWriter , PdfArray
from pdfrwx . pdffilter import PdfFilter
from pdfrwx . pdfstreamparser import PdfStream
toArray = lambda obj : obj if isinstance ( obj , PdfArray )
else PdfArray ([ obj ]) if obj != None else PdfArray ()
pdfIn = PdfReader ( 'example.pdf' )
pdfOut = PdfWriter ( 'example-out.pdf' )
for page in pdfIn . pages :
contentsArray = toArray ( page . Contents )
for contents in contentsArray :
stream = PdfFilter . uncompress ( contents ). stream
treeIn = PdfStream . stream_to_tree ( stream )
treeOut = []
for leaf in treeIn :
cmd , args = leaf [: 2 ]
if cmd != 'BT' : treeOut . append ( leaf )
contents . stream = PdfStream . tree_to_stream ( treeOut )
contents . Filter = None
pdfOut . addPage ( page )
pdfOut . write ()Como você pode ver, o código é executado sobre as páginas e, em seguida, sobre o conteúdo de todas as páginas e descreve o conteúdo, pois pode ser comprimido, analisa o conteúdo de uma árvore, remove os blocos de texto BT/ET e analisa a árvore resultante de volta ao fluxo. O significado de cada linha de código acima deve ficar claro, possivelmente, a função ToArray Lambda: está lá porque uma página no PDF pode ter mais de um conteúdo dicionário; nesse caso, a página. E assim, a função Toarray Lambda torna a situação com o conteúdo da página mais uniforme, transformando a página. Conteúdo que não são matrizes em pdFarray com um elemento.
Algumas outras coisas precisam ser observadas também. Primeiro, observe que, para comparar a tarefa, o código usa apenas duas novas classes do PDFRWX : pdffilter e pdfstream, com uma/duas chamadas de função de cada uma. Segundo, a árvore analisada eu apenas uma lista padrão de Python aninhada do seguinte formato trivial:
[
['q', []],
['cm', ['1','0','0','1','0','0']],
...
['BT', [], [ /a tree list of text operators/ ]],
...
['Q', []]
]
Portanto, cada folha (elemento) da lista de árvores é uma lista de 2 ou 3 elementos: os dois primeiros elementos são o comando e a lista de argumentos (uma lista vazia se o comando não tiver argumentos), enquanto o terceiro argumento opcional está presente no caso em que o folha é um bloco de comandos, nesse caso, é a lista de árvores dos comandos que compõem o bloco. Por design, existem apenas dois tipos de blocos: o bloco de texto BT/ET, que usa o nome do comando 'BT' na árvore analisada e o bloco de imagem embutido bi/id/ei, que usa o nome do comando 'bi' na árvore analisada. Observe que no fluxo PDF original há apenas uma sequência de comandos; É o analisador PDFstream que cria esses blocos em sua saída por conveniência. Para se familiarizar ainda mais com a estrutura da saída do analisador de fluxo, tente inserir um comando como Pprint (Treein) logo após a chamada para o analisador.
Observe também que a função Toarray , por mais útil, não foi implementada no módulo e, portanto, você deve codificá -la toda vez que faz a análise. Isso pode parecer estranho, mas é o resultado dos mesmos princípios de design: o módulo apenas analisa o fluxo; Cabe ao desenvolvedor codificar todo o resto.
A classe de analisador PDFstream é implementada em python puro usando apenas cerca de 300 linhas de código com a ajuda do popular (e puro python!) Para os curiosos: o analisador usa dois estados de analisador (ou seja, dois analisadores diferentes com gramáticas diferentes que alternam entre si enquanto operam), uma para analisar as cordas literais do PDF (ou seja, cordas que estão entre parênteses) e a outra - para todo o resto. Sim, para que as cordas literais suportem codificação de parênteses como parte da corda, o formato das cordas literais do PDF foi tão intrincado que exigia um analisador separado apenas para analisá -los. Então, se, por algum motivo (velocidade?) Você desejará implementar o analisador de fluxo usando outra biblioteca de geradores de analisador, verifique se ele suporta uma pilha para os estados do analisador.
Resolve o inferno das fontes. Docos em breve, fique atento.
Filtros suportados:
Cansado dos próprios produtos da Adobe Bugs quando se trata de precisão de cores na exportação de imagens? Então você veio ao lugar certo! Com o objetivo de ser a classe de manipulação de imagem em PDF mais precisa de todos. Docos em breve, fique atento.
Codecs suportados (codificar/decodificar):
Espaços de cores suportadas:
Mais:
O módulo é perfeitamente utilizável neste momento e foi executado em uma infinidade de testes para garantir que faça o que promete fazer corretamente. No entanto, não está de forma alguma perto do alfa: as interfaces ainda não estão totalmente finalizadas. Além disso, o manuseio de erros é quebrado (provavelmente será corrigido em breve e é semelhante ao modo como os erros são tratados no PDFRW ). Então, Jogue por sua conta e risco Sem nenhum risco, apenas não espere que seja de qualidade de produção ainda.