Pregunta: Algún microservicio que pueda levantar con docker compose y que funcione como API para pasarle un PDF y me devuelva una imagen y recortada en ciertas coordenadas o ajustada a formato cuadrado. Respuesta: Para lo que necesitas, la mejor opción no es una herramienta genérica (como Gotenberg), ya que estas suelen convertir la página entera pero no permiten recortar por coordenadas en la misma petición. La solución más limpia y eficiente es crear un microservicio ligero en Python (usando FastAPI y pdf2image) que puedas levantar con Docker. Python tiene las mejores librerías para manipulación de PDFs e imágenes. Aquí tienes la solución completa "Copy-Paste": 1. Estructura del proyecto Crea una carpeta (ej. pdf-cropper) con estos 3 archivos: Dockerfile main.py docker-compose.yml 2. El Código (Python + FastAPI) Este script recibe el PDF, lo convierte a imagen y aplica el recorte o ajuste cuadrado según lo que le pidas. Archivo: main.py Python from fastapi import FastAPI, UploadFile, File, Form from pdf2image import convert_from_bytes from PIL import Image import io app = FastAPI() @app.post("/process") async def process_pdf( file: UploadFile = File(...), mode: str = Form("square"), # 'square' o 'coords' x: int = Form(0), y: int = Form(0), w: int = Form(500), h: int = Form(500) ): # 1. Leer el archivo PDF en memoria pdf_bytes = await file.read() # 2. Convertir la primera página a imagen # poppler_path no es necesario si se instala en el sistema (ver Dockerfile) images = convert_from_bytes(pdf_bytes, fmt="jpeg") if not images: return {"error": "No se pudo leer el PDF"} img = images[0] # Tomamos la primera página # 3. Lógica de recorte if mode == "square": # Recorte cuadrado centrado automático width, height = img.size new_dim = min(width, height) left = (width - new_dim) / 2 top = (height - new_dim) / 2 right = (width + new_dim) / 2 bottom = (height + new_dim) / 2 img = img.crop((left, top, right, bottom)) # Opcional: Redimensionar al tamaño final deseado img = img.resize((w, h)) elif mode == "coords": # Recorte por coordenadas exactas img = img.crop((x, y, x + w, y + h)) # 4. Devolver la imagen procesada img_byte_arr = io.BytesIO() img.save(img_byte_arr, format='JPEG', quality=90) img_byte_arr.seek(0) from starlette.responses import StreamingResponse return StreamingResponse(img_byte_arr, media_type="image/jpeg") 3. El Dockerfile Es crucial instalar poppler-utils, que es el motor que procesa el PDF. Archivo: Dockerfile Dockerfile FROM python:3.9-slim # Instalar poppler (necesario para pdf2image) RUN apt-get update && apt-get install -y poppler-utils && rm -rf /var/lib/apt/lists/* WORKDIR /app # Instalar dependencias de Python RUN pip install fastapi uvicorn python-multipart pdf2image Pillow COPY main.py . # Ejecutar la API CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] 4. Docker Compose Para levantarlo. Archivo: docker-compose.yml YAML services: pdf-cropper: build: . ports: - "8080:8000" restart: always Comando para iniciar: Bash docker compose up -d --build 5. Cómo usarlo desde PHP Ahora tienes una API corriendo en http://localhost:8080/process. Aquí tienes el script PHP para enviarle un PDF y guardar la imagen recortada. Archivo: cliente.php PHP new CURLFile($pdfPath, 'application/pdf', 'documento.pdf'), // OPCIÓN A: Recorte cuadrado automático (centrado) 'mode' => 'square', 'w' => 800, // Tamaño final del cuadrado (px) 'h' => 800, // OPCIÓN B: Coordenadas específicas (descomentar para usar) // 'mode' => 'coords', // 'x' => 100, // Píxeles desde la izquierda // 'y' => 200, // Píxeles desde arriba // 'w' => 500, // Ancho del recorte // 'h' => 300 // Alto del recorte ]; curl_setopt_array($curl, [ CURLOPT_URL => $url, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $fields, CURLOPT_RETURNTRANSFER => true, ]); $response = curl_exec($curl); $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); if ($httpCode == 200) { file_put_contents($outputPath, $response); echo "Imagen guardada exitosamente en $outputPath"; } else { echo "Error: " . curl_error($curl); echo "Respuesta del servidor: " . $response; } curl_close($curl); ?> ¿Por qué esta solución? Atomocidad: Hace la conversión y el recorte en un solo paso de memoria (RAM), sin guardar archivos temporales en disco. Control: Puedes ajustar la lógica de "cuadrado" (si quieres que sea centrado o desde la esquina superior) modificando fácilmente el main.py. Ligero: La imagen Docker pesará poco y consumirá memoria solo cuando procese un archivo.