197 lines
4.9 KiB
Markdown
197 lines
4.9 KiB
Markdown
---
|
|
name: pdf
|
|
description: Processamento completo de ficheiros PDF — leitura, extraccao de texto/tabelas, merge, split, watermarks, encriptacao, OCR, criacao e preenchimento de formularios.
|
|
layer: wiki
|
|
---
|
|
|
|
# PDF Processing Guide
|
|
|
|
## Resumo
|
|
|
|
Guia completo para processamento de PDFs com bibliotecas Python e ferramentas de linha de comandos. Para formularios PDF, seguir as instruccoes na seccao "Preenchimento de formularios". Para funcionalidades avancadas e bibliotecas JavaScript, consultar a seccao "Referencia avancada".
|
|
|
|
## Quick Start
|
|
|
|
```python
|
|
from pypdf import PdfReader, PdfWriter
|
|
|
|
# Read a PDF
|
|
reader = PdfReader("/media/ealmeida/Dados/GDrive/Cloud/Descomplicar/documento.pdf")
|
|
print(f"Pages: {len(reader.pages)}")
|
|
|
|
# Extract text
|
|
text = ""
|
|
for page in reader.pages:
|
|
text += page.extract_text()
|
|
```
|
|
|
|
## Bibliotecas Python
|
|
|
|
### pypdf — operacoes basicas
|
|
|
|
#### Merge PDFs
|
|
```python
|
|
from pypdf import PdfWriter, PdfReader
|
|
|
|
writer = PdfWriter()
|
|
for pdf_file in ["doc1.pdf", "doc2.pdf", "doc3.pdf"]:
|
|
reader = PdfReader(pdf_file)
|
|
for page in reader.pages:
|
|
writer.add_page(page)
|
|
|
|
with open("merged.pdf", "wb") as output:
|
|
writer.write(output)
|
|
```
|
|
|
|
#### Split PDF
|
|
```python
|
|
reader = PdfReader("input.pdf")
|
|
for i, page in enumerate(reader.pages):
|
|
writer = PdfWriter()
|
|
writer.add_page(page)
|
|
with open(f"page_{i+1}.pdf", "wb") as output:
|
|
writer.write(output)
|
|
```
|
|
|
|
#### Extract Metadata
|
|
```python
|
|
reader = PdfReader("document.pdf")
|
|
meta = reader.metadata
|
|
print(f"Title: {meta.title}")
|
|
print(f"Author: {meta.author}")
|
|
print(f"Subject: {meta.subject}")
|
|
print(f"Creator: {meta.creator}")
|
|
```
|
|
|
|
#### Rotate Pages
|
|
```python
|
|
reader = PdfReader("input.pdf")
|
|
writer = PdfWriter()
|
|
|
|
page = reader.pages[0]
|
|
page.rotate(90) # Rotate 90 degrees clockwise
|
|
writer.add_page(page)
|
|
|
|
with open("rotated.pdf", "wb") as output:
|
|
writer.write(output)
|
|
```
|
|
|
|
### pdfplumber — extraccao de texto e tabelas
|
|
|
|
#### Extract Text with Layout
|
|
```python
|
|
import pdfplumber
|
|
|
|
with pdfplumber.open("document.pdf") as pdf:
|
|
for page in pdf.pages:
|
|
text = page.extract_text()
|
|
print(text)
|
|
```
|
|
|
|
#### Extract Tables
|
|
```python
|
|
with pdfplumber.open("document.pdf") as pdf:
|
|
for i, page in enumerate(pdf.pages):
|
|
tables = page.extract_tables()
|
|
for j, table in enumerate(tables):
|
|
print(f"Table {j+1} on page {i+1}:")
|
|
for row in table:
|
|
print(row)
|
|
```
|
|
|
|
#### Advanced Table Extraction
|
|
```python
|
|
import pandas as pd
|
|
|
|
with pdfplumber.open("document.pdf") as pdf:
|
|
all_tables = []
|
|
for page in pdf.pages:
|
|
tables = page.extract_tables()
|
|
for table in tables:
|
|
if table: # Check if table is not empty
|
|
df = pd.DataFrame(table[1:], columns=table[0])
|
|
all_tables.append(df)
|
|
|
|
# Combine all tables
|
|
if all_tables:
|
|
combined_df = pd.concat(all_tables, ignore_index=True)
|
|
combined_df.to_excel("extracted_tables.xlsx", index=False)
|
|
```
|
|
|
|
### reportlab — criacao de PDFs
|
|
|
|
#### Basic PDF Creation
|
|
```python
|
|
from reportlab.lib.pagesizes import letter
|
|
from reportlab.pdfgen import canvas
|
|
|
|
c = canvas.Canvas("hello.pdf", pagesize=letter)
|
|
width, height = letter
|
|
|
|
# Add text
|
|
c.drawString(100, height - 100, "Hello World!")
|
|
c.drawString(100, height - 120, "This is a PDF created with reportlab")
|
|
|
|
# Add a line
|
|
c.line(100, height - 140, 400, height - 140)
|
|
|
|
# Save
|
|
c.save()
|
|
```
|
|
|
|
#### Create PDF with Multiple Pages
|
|
```python
|
|
from reportlab.lib.pagesizes import letter
|
|
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak
|
|
from reportlab.lib.styles import getSampleStyleSheet
|
|
|
|
doc = SimpleDocTemplate("report.pdf", pagesize=letter)
|
|
styles = getSampleStyleSheet()
|
|
story = []
|
|
|
|
# Add content
|
|
title = Paragraph("Report Title", styles['Title'])
|
|
story.append(title)
|
|
story.append(Spacer(1, 12))
|
|
|
|
body = Paragraph("This is the body of the report. " * 20, styles['Normal'])
|
|
story.append(body)
|
|
story.append(PageBreak())
|
|
|
|
# Page 2
|
|
story.append(Paragraph("Page 2", styles['Heading1']))
|
|
story.append(Paragraph("Content for page 2", styles['Normal']))
|
|
|
|
# Build PDF
|
|
doc.build(story)
|
|
```
|
|
|
|
#### Subscripts and Superscripts
|
|
|
|
**Importante**: nunca usar caracteres Unicode subscript/superscript (subscript: 0-9, superscript: 0-9) em PDFs ReportLab. As fontes built-in nao incluem estes glifos, resultando em caixas pretas.
|
|
|
|
Usar as tags XML do ReportLab em objectos Paragraph:
|
|
```python
|
|
from reportlab.platypus import Paragraph
|
|
from reportlab.lib.styles import getSampleStyleSheet
|
|
|
|
styles = getSampleStyleSheet()
|
|
|
|
# Subscripts: use <sub> tag
|
|
chemical = Paragraph("H<sub>2</sub>O", styles['Normal'])
|
|
|
|
# Superscripts: use <super> tag
|
|
squared = Paragraph("x<super>2</super> + y<super>2</super>", styles['Normal'])
|
|
```
|
|
|
|
Para texto desenhado com canvas (nao Paragraph), ajustar manualmente o tamanho da fonte e posicao.
|
|
|
|
## Ferramentas de linha de comandos
|
|
|
|
### pdftotext (poppler-utils)
|
|
```bash
|
|
# Extract text
|
|
pdftotext input.pdf output.txt
|
|
|
|
# Extract text preserving layout
|
|
pdftotext -layout |