Convertir PDF a imágenes con Python: PyMuPDF, pdf2image y comparativa
Convertir páginas de PDF a imágenes (JPG, PNG, TIFF) es una tarea común: generar previsualizaciones de documentos para una web, extraer páginas para OCR, crear miniaturas de catálogos. Python tiene tres librerías que dominan el espacio, cada una con trade-offs distintos. Esta guía las compara y muestra el código real de cada una.
Comparativa rápida
| Librería | Velocidad | Dependencias del sistema | Calidad | Licencia |
|---|---|---|---|---|
| PyMuPDF (fitz) | Más rápida (5-10× pdf2image) | Ninguna | Excelente | AGPL (comercial requiere licencia) |
| pdf2image | Media | Requiere Poppler instalado | Excelente | MIT |
| Pillow + Wand | Más lenta | Requiere ImageMagick + Ghostscript | Excelente | LGPL / MIT |
Recomendación rápida: Si tu proyecto es open-source o personal, usa PyMuPDF (más rápida y sin headaches de dependencias). Si es comercial y AGPL te complica licensing, usa pdf2image.
Opción 1: PyMuPDF (recomendada)
PyMuPDF es un binding Python sobre MuPDF, escrito en C. Sin dependencias del sistema (todo viene en el wheel), 5-10× más rápida que pdf2image, y la API es la más limpia.
pip install pymupdf
import fitz # nombre del módulo es 'fitz' por razones históricas
doc = fitz.open("documento.pdf")
# Convertir todas las páginas a PNG
for i, page in enumerate(doc):
pix = page.get_pixmap(dpi=150)
pix.save(f"pagina_{i+1}.png")
doc.close()
Controles clave
# Resolución alta para OCR (300 DPI)
pix = page.get_pixmap(dpi=300)
# Resolución exacta vía matrix (independent del DPI metadato)
matrix = fitz.Matrix(2, 2) # 2× zoom = aprox 144 DPI
pix = page.get_pixmap(matrix=matrix)
# Solo una región (clip)
clip = fitz.Rect(0, 0, 300, 300) # x0, y0, x1, y1 en puntos
pix = page.get_pixmap(clip=clip)
# Convertir a JPG (en lugar de PNG default)
pix.pil_save("pagina.jpg", format="JPEG", quality=85)
Procesamiento batch eficiente
import fitz
from pathlib import Path
def pdf_to_images(pdf_path: Path, output_dir: Path, dpi: int = 150):
output_dir.mkdir(parents=True, exist_ok=True)
doc = fitz.open(pdf_path)
for i, page in enumerate(doc):
pix = page.get_pixmap(dpi=dpi)
pix.save(output_dir / f"{pdf_path.stem}_page{i+1:03d}.png")
doc.close()
# Procesar todos los PDFs de una carpeta
for pdf in Path("./pdfs").glob("*.pdf"):
pdf_to_images(pdf, Path(f"./output/{pdf.stem}"), dpi=200)
PyMuPDF procesa ~50-100 páginas/segundo en CPU moderna (M2, Ryzen 7), velocidad sobrada para batches de miles de PDFs.
Opción 2: pdf2image (cuando AGPL es bloqueante)
pdf2image es un wrapper sobre Poppler (las herramientas que vienen detrás de Chrome PDF viewer y Linux). Más lento que PyMuPDF pero MIT-licensed sin restricciones.
# Instalar Poppler primero (dependencia del sistema)
# macOS
brew install poppler
# Linux Debian/Ubuntu
sudo apt install poppler-utils
# Windows: descarga de github.com/oschwartz10612/poppler-windows
# y añade el bin/ al PATH
# Luego instalar el wrapper Python
pip install pdf2image
from pdf2image import convert_from_path
# Convertir PDF entero a lista de PIL Images
images = convert_from_path("documento.pdf", dpi=150)
for i, img in enumerate(images):
img.save(f"pagina_{i+1}.png", "PNG")
Controles importantes
# Solo páginas específicas
images = convert_from_path("documento.pdf", first_page=1, last_page=5)
# Formato de salida (default es ppm)
images = convert_from_path("documento.pdf", fmt="jpeg")
# Threading para acelerar PDFs grandes
images = convert_from_path("documento.pdf", dpi=200, thread_count=4)
# Modo grayscale (ahorra ~3× tamaño)
images = convert_from_path("documento.pdf", grayscale=True)
Versión streaming (no carga todo a memoria)
Para PDFs muy grandes (1000+ páginas):
from pdf2image import convert_from_path
# Streaming a disco directamente, no a memoria
convert_from_path(
"huge.pdf",
output_folder="./pages",
output_file="page",
fmt="jpeg",
dpi=150,
paths_only=True, # devuelve paths en lugar de objetos PIL
)
Opción 3: Pillow + Wand (ImageMagick)
Si ya tienes ImageMagick + Ghostscript en el sistema y prefieres no añadir más dependencias:
sudo apt install imagemagick ghostscript
pip install Wand
from wand.image import Image
with Image(filename="documento.pdf", resolution=150) as img:
for i, page in enumerate(img.sequence):
with Image(image=page) as page_img:
page_img.format = "png"
page_img.save(filename=f"pagina_{i+1}.png")
Más lenta que las otras dos, pero aprovecha herramientas que probablemente ya están en tu pipeline si trabajas con imágenes.
Decisión por caso de uso
| Tu caso | Librería |
|---|---|
| Pipeline OCR a escala (miles de PDFs/día) | PyMuPDF — más rápida |
| Generar miniaturas para web | PyMuPDF a 72 DPI con JPG quality 75 |
| Servicio comercial de SaaS | pdf2image (MIT) o licencia comercial PyMuPDF |
| Ya usas ImageMagick en el sistema | Wand para mantener un ecosistema |
| Necesitas zonas específicas del PDF (clip) | PyMuPDF — API de Rect clara |
| Streaming PDFs gigantes a disco | pdf2image con paths_only |
Pitfall — fuentes que aparecen como cuadrados
Si el PDF usa fuentes que no están embebidas y tu sistema no las tiene instaladas, los caracteres se renderizan como cuadrados o "tofu". Solución:
# Con PyMuPDF, instala las fuentes adicionales del paquete
pip install pymupdf-fonts
# Comprueba qué fuentes están embebidas en el PDF
import fitz
doc = fitz.open("documento.pdf")
for page in doc:
for font in page.get_fonts():
print(font)
Si aparecen fuentes con embedded=False, deben estar en el sistema. En servidores Linux suele faltar la familia "Times New Roman" — instala fonts-liberation o ttf-mscorefonts-installer.
Pitfall — PDFs encriptados con contraseña
import fitz
doc = fitz.open("protegido.pdf")
if doc.needs_pass:
if not doc.authenticate("mi-contraseña"):
raise ValueError("Contraseña incorrecta")
# Ahora puedes proceder normalmente
pdf2image:
images = convert_from_path("protegido.pdf", userpw="mi-contraseña")
Performance: benchmarks reales
Test: PDF de 100 páginas, A4, mezcla texto + imágenes, en MacBook Pro M2:
| Librería | Tiempo total | Páginas/segundo | RAM peak |
|---|---|---|---|
| PyMuPDF a 150 DPI | 1.8s | 56 | 280 MB |
| pdf2image a 150 DPI | 12.4s | 8 | 450 MB |
| Wand a 150 DPI | 28.7s | 3.5 | 600 MB |
PyMuPDF es la opción clara cuando la velocidad importa.
Conversiones relacionadas
- PDF a JPG — versión online sin código
- PDF a PNG — para imágenes con texto fino y máxima calidad
- PDF a TIFF — para archivado o flujos de imprenta
- JPG a PDF — operación inversa: empaquetar imágenes en un PDF
- PNG a PDF — combinar capturas en un único PDF
- PDF a HTML — alternativa para convertir contenido PDF a web