Descripción: Se ha realizado una refactorización mayor del sistema de notificaciones y generación de comprobantes para eliminar dependencias legacy (Imagick/FTP) y modernizar la arquitectura. 🚀 Nuevas Características (Features) Microservicio PDF (pdf-cropper): Nuevo servicio en Python (FastAPI + Poppler) desplegado en Docker (Puerto 8050) para la conversión de PDF a Imagen. Reemplaza la librería Imagick de PHP, aislando el procesamiento pesado fuera del plugin. Modo Full: Garantiza la conversión del PDF completo respetando su relación de aspecto original (sin recortes ni "square crop"). Overlay de Texto: Capacidad nativa en el backend para sobreescribir texto dinámicamente (ej. cambiar "Tarjeta de crédito Stripe" por "OXXO Pay") basado en parámetros. Integración S3 / MinIO: Implementación de MinioStorageService . Los comprobantes (JPG) y Vouchers OXXO se suben automáticamente a MinIO en lugar de usar FTP. Generación de URLs públicas seguras. 🧹 Mantenimiento y Limpieza (Chores/Refactor) Limpieza Automática (Cleanup): Se implementó lógica para eliminar archivos temporales locales (PDFs descargados, JPGs generados) inmediatamente después de una subida exitosa a MinIO. Aplica tanto para comprobantes de pago como para Vouchers OXXO. Refactor ClientCallBellAPI : Eliminación de código muerto relacionado con FTP de WordPress. Implementación de cliente HTTP Guzzle para comunicación con pdf-cropper. Cache Busting: Se añade Timestamp al nombre de archivo (_time()) para evitar caché agresivo en WhatsApp/Navegadores. Detección de Método: Lógica preliminar para detectar "OXXO" o "Transferencia" en notas de pago y aplicar Overlay. Docker Infraestructura: Actualización de docker-compose.yml para incluir pdf-cropper. Instalación de fuentes (fonts-dejavu-core) para renderizado correcto de texto. 🐛 Correcciones (Bug Fixes) Fix Recorte de Imagen: Se eliminó la restricción de relación de aspecto 1:1 (cuadrado) que cortaba headers y footers en documentos rectangulares. Standardización de Notas: Actualización de AbstractStripeOperationsFacade para incluir explícitamente "OXXO" o "Transferencia" en las notas de pago de UCRM (preparación para lógica de plantillas).
175 lines
5.0 KiB
Plaintext
175 lines
5.0 KiB
Plaintext
|
|
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
|
|
|
|
<?php
|
|
|
|
$pdfPath = 'documento.pdf';
|
|
$outputPath = 'resultado.jpg';
|
|
|
|
// URL de tu microservicio docker
|
|
$url = 'http://localhost:8080/process';
|
|
|
|
$curl = curl_init();
|
|
|
|
$fields = [
|
|
'file' => 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. |