## Espaço de Tecnologias e Artes - Sesc Avenida Paulista
### `hackmd.io/@sesc-av-paulista/estudos-em-python-14-maio`
# Grupo de estudos em Python
## 14/5 Manipulando arquivos PDF
### O que eu preciso para começar?
- Vamos usar o **Thonny IDE**, que é livre já com um interpretador Python, você pode baixar em https://thonny.org
- Como instalar bibliotecas no Thonny?
- **Usando a interface gráfica** menu *Tools/Ferramentas > Manage Packages/Gerenciar Pacotes*
- **Usando o shell aberto pelo Thonny** em *Tools > Open System Shell*
- Como se faz em geral no Python: `pip install <nome da lib>`, mas idealmente você deve usar um "virtual environment" antes, só que no caso do Thonny provê já esse env
### Algumas bibliotecas
- **pdfrw2**
- https://github.com/sarnold/pdfrw
- **PyMuPDF** (the "fitz" engine)
- https://github.com/pymupdf/PyMuPDF
- https://pymupdf.readthedocs.io/en/latest/
- Fontes tipograficas extra: https://pypi.org/project/pymupdf-fonts/
### Script para concatenar (juntar) vários PDFs
- Roda no **Thonny**, precisa ter a lib **pdfrw2** instalada!
```python!
from pathlib import Path
# requer pdfrw2 - https://pypi.org/project/pdfrw2/
from pdfrw import PdfReader, PdfWriter
# TROQUE O STRING DE pasta_entrada PELO CAMINHO DA SUA PASTA!
pasta_entrada = '/home/villares/Desktop/meus-pdfs'
# garante pasta entrada que é um objeto pathlib.Path
pasta_entrada = Path(pasta_entrada)
# prepara path do arquivo_saida, nome da pasta_entrada + extensao
arquivo_saida = pasta_entrada.parent / (pasta_entrada.name + '.pdf')
try:
writer = PdfWriter(arquivo_saida) # cria gerador do novo PDF
# percorre a pasta_entrada
for arquivo in sorted(pasta_entrada.iterdir()):
if arquivo.suffix.lower() == '.pdf': # convere se é PDF
for pagina in PdfReader(arquivo).pages: # pega paginas
writer.addpage(pagina) # escreve no arquivo novo
writer.write() # salva o arquivo novo de saida
print(f'Fusão de PDFs em {arquivo_saida} concluída')
except Exception as erro:
print(erro)
```
### Script de fazer zines
- Requer a lib **PyMuPDF**
- [Código que reordena páginas de um PDF](https://gist.github.com/villares/0402a1c9033e6f4baf55554c16d25f4e)
- Confira como executar o script com argumentos na linha de comando a partir do Thonny em https://hackmd.io/@sesc-av-paulista/programazine#Script-que-faz-a-re-ordena%C3%A7%C3%A3o-das-p%C3%A1ginas-de-um-PDF
### Script para sobrepor um PDF em todas as páginas de outro
- [Overlay: usando um PDF sobreposto em várias páginas de outro](https://gist.github.com/villares/f99229fd8a3c7b8c51d8b480c93f19ad#file-multiple_page_pdf_py5_module_mode-py)
### Juntando páginas de dois PDFs lado a lado
- Este script encolhe fazendo caber quatro páginas por página, duas de cada arquivo original, em colunas paralelas
- Precisa da lib `pdfrw2`
- Feito para a linha de comando (rola no Thonny)
```python!
#! python
import sys
# Requires pdfrw2 - https://pypi.org/project/pdfrw2/
from pdfrw import PdfReader, PdfWriter, PdfDict, PdfName, PageMerge
def write_side_by_side(input_a, input_b, output_file):
"""
Write to the output file a PDF with the combined contents of 2
input files. Each page gets 2 pages from each of the input files,
scaled down by a factor of 0.5, side by side in a 4 pages up layout.
"""
# Retrieves pagas from both source PDF files
left_pages = PdfReader(input_a).pages
right_pages = PdfReader(input_b).pages
# Fill with blank pages if one source is shorter
# and make sure there is an even number of pages
while (len(left_pages) % 2 != 0 or
len(right_pages) > len(left_pages)):
left_pages.append(blank_page(left_pages[0]))
while len(right_pages) < len(left_pages):
right_pages.append(blank_page(right_pages[0]))
# Creates final PDF writer object
writer = PdfWriter(output_file)
# Loops over the number of pages index, stepping every 2
for index in range(0, len(left_pages), 2):
left_slice = left_pages[index:index + 2] # 2 from L
right_slice = right_pages[index:index + 2] # 2 from R
new_page = render4(left_slice, right_slice) # merge 4
writer.addpage(new_page) # add merged page to result
writer.write()
def blank_page(template):
"""Create a blank page from example (to get size)"""
p = PdfDict()
p.Type = PdfName.Page
p.Contents = PdfDict(stream="")
p.MediaBox = template.inheritable.MediaBox
return p
def render4(srcleft, srcright):
"""
Create a page with 4 scaled down pages,
2 from "left" and to from "right"
"""
scale = 0.5
srcpages = PageMerge() + srcleft + srcright
x_increment, y_increment = (scale * i for i in srcpages.xobj_box[2:])
for i, page in enumerate(srcpages):
page.scale(scale)
page.x = x_increment if i > 1 else 0
page.y = 0 if i % 2 else y_increment
return srcpages.render()
if __name__ == '__main__':
# Command Line Interface
try:
args = sys.argv
input_a, input_b = args[1:3]
if len(args) == 4:
output = args[3]
else:
output = 'output.pdf'
except:
print('Needs 2 PDF files as input arguments. Output name optional.')
exit()
write_side_by_side(input_a, input_b, output)
```
- Se quiser rodar com os paths dos arquivos no código direto, mudar a parte final do `if __name__ == '__main__':`:
```python!
if __name__ == '__main__':
input_a = 'arquivo_a.pdf'
input_b = 'arquivo_b.pdf'
output = 'resultado.pdf'
write_side_by_side(input_a, input_b, output)
```