En este artículo te voy a enseñar a usar una herramienta para estampar HTML en un PDF. Con este software vas a ser capaz de enviar HTML, convertirlo a imagen y estamparlo sobre el PDF.
Básicamente será poner una marca de agua HTML en PDF con todo el proceso automatizado.
Herramientas necesarias
Esta herramienta es una modificación a mi plugin para imprimir PDF así que debes contar con:
- pdftoprinter.exe, que se debe llamar exactamente así:
PDFtoPrinter.exe - El plugin ya descargado e iniciado
- Navegador chrome portable (no el que usas para navegar), descargado de: https://download-chromium.appspot.com/ en una carpeta hermana del plugin llamada
chrome-win
Solo como referencia para que te quede claro lo de la carpeta y Chrome, aquí te dejo un árbol:
C:\Users\parzibyte\Desktop\plugin_listo>tree /f
Listado de rutas de carpetas
│ PDFtoPrinter.exe
│ plugin_pdf.exe
│
└───chrome-win
│ chrome.dll
│ chrome.exe
| Aquí muchas otras carpetas y archivos que no colocaré por simplicidad
La herramienta en mi caso se llama plugin_pdf.exe. Junto a ella (es decir, en la misma carpeta)
existe una carpeta llamada chrome-win y dentro de ésta última existe chrome.exe junto con
todas sus dependencias.
Parámetros
El plugin inicia un servidor en localhost:8080 y acepta
el parámetro grados para rotar el PDF así como html para enviar
el HTML codificado. Si envías html también debes enviar ancho y alto que representan
el tamaño de la ventana de Chrome.
También puedes enviar texto para poner texto plano en lugar de HTML. El parámetro texto
tiene prioridad sobre html, por lo que si envías ambos entonces html será ignorado.
Además de todos los parámetros mencionados, debes indicar impresora. Si haces la petición a /url debes
indicar urlPdf. Si lo haces a la raíz (/) debes indicar nombrePdf
Por cierto, por defecto el navegador tiene fondo transparente. Es responsabilidad tuya indicar el color de fondo.
Mis pruebas
Como siempre, aquí dejo las pruebas para mi yo del futuro. Como es un PDF voy a usar la impresora Microsoft print to PDF para no desperdiciar papel.
Tengo un ticket local llamado ticket.pdf:
http://localhost:8080/?nombrePdf=ticket.pdf&impresora=Microsoft%20print%20To%20PDF
Para probar, voy a invocar a la siguiente URL enviando el HTML:
http://localhost:8080/?nombrePdf=l.pdf&impresora=Microsoft%20print%20To%20PDF&html=AQUÍ_EL_HTML
Debo codificar el HTML. Para mis pruebas hice un script de Python que lee el HTML y hace la petición. Esto de enviar el HTML a través de la URL es por compatibilidad, aunque lo mejor sería usar JSON y/o peticiones POST pero el plugin está programado de esta manera y debo mantener la compatibilidad.
import requests
contenido = ""
with open("index.html", encoding="utf-8") as f:
contenido = f.read()
parametros = {
"nombrePdf": "ticket.pdf",
"impresora": "Microsoft Print to PDF",
"html": contenido,
"ancho": "800",
"alto":"600",
}
response = requests.get("http://localhost:8080", params=parametros)
print(response.text)
Prueba básica y mínima con un HTML que creo que ni siquiera es legal pero igualmente será renderizado:
<p>Hola mundo</p>
Para hacer la petición quiero imprimir ticket.pdf en Microsoft print To PDF así que la URL sin codificar
se ve así:
http://localhost:8080/?nombrePdf=ticket.pdf&impresora=Microsoft print To PDF&html=Hola mundo&ancho=400&alto=200
En este ejemplo voy a usar JavaScript en el navegador web para mostrarte cómo codificar la URL y cómo enviar el HTML.
Básicamente lo que necesitamos hacer es invocar a encodeURI con la URL y el HTML sin codificar:
await fetch(encodeURI("http://localhost:8080/?nombrePdf=ticket.pdf&impresora=Microsoft print To PDF&html=<p>Hola mundo</p>&ancho=400&alto=200"))
Si yo inspecciono la consola de depuración la URL se ha convertido en la siguiente. Recomiendo usar esta URL de prueba (cambiando el nombre del pdf y la impresora si es necesario) para que pruebes por ti mismo, ya que puedes poner la URL directamente en el navegador web.
http://localhost:8080/?nombrePdf=ticket.pdf&impresora=Microsoft%20print%20To%20PDF&html=%3Cp%3EHola%20mundo%3C/p%3E&ancho=400&alto=200
Este paso es importante porque si no codificamos el HTML puede que el servidor ni siquiera termine leyendo la marca de agua.
Entonces los siguientes ejemplos los coloco en HTML sin codificar, pero debes codificarlo al enviarlo según las condiciones y lenguaje de programación en los que estés.
Para probar el fondo transparente:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
body { background-color: transparent; }
</style>
</head>
<body>
<p style="color: green; background-color: transparent;">Hola mundo 🤖</p>
<h1>Soy un header amigo</h1>
<p style="font-size:4rem;">Párrafo con fuente 4 rem</p>
<p>Soy un párrafo<br>con saltos<br> de línea</p>
</body>
</html>
Un simple texto blanco sobre un fondo negro:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
body { background-color: black; }
</style>
</head>
<body>
<p style="color: white;">Hola mundo 🤖</p>
</body>
</html>
Probando CSS moderno:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<style>
:root {
--bg: #0f172a;
--glass: rgba(255, 255, 255, 0.05);
--accent: fuchsia;
}
body {
background: var(--bg);
font-family: 'Segoe UI', system-ui, sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
overflow: hidden;
color: white;
}
.blob {
position: absolute;
width: 300px;
height: 300px;
background: conic-gradient(from 180deg, #ff0080, #7928ca, #ff0080);
filter: blur(80px);
border-radius: 50%;
z-index: -1;
animation: move 10s infinite alternate;
}
@keyframes move {
from {
transform: translate(-50%, -50%);
}
to {
transform: translate(50%, 50%);
}
}
.card {
background: var(--glass);
backdrop-filter: blur(15px);
-webkit-backdrop-filter: blur(15px);
border: 1px solid rgba(255, 255, 255, 0.1);
padding: 2rem;
border-radius: 20px;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
display: grid;
grid-template-columns: auto 1fr;
gap: 20px;
transform: perspective(1000px) rotateX(5deg);
}
.stats {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 10px;
}
.stat-box {
background: rgba(0, 0, 0, 0.2);
padding: 10px;
border-radius: 8px;
text-align: center;
}
.emoji-header {
font-size: 3rem;
margin: 0;
text-shadow: 0 0 20px rgba(255, 0, 255, 0.5);
}
.badge {
background: linear-gradient(90deg, #4facfe 0%, #00f2fe 100%);
padding: 4px 12px;
border-radius: 20px;
font-size: 0.8rem;
font-weight: bold;
}
</style>
</head>
<body>
<div class="blob"></div>
<div class="card">
<div class="emoji-header">🤖</div>
<div>
<span class="badge">PRO RENDER</span>
<h1 style="margin: 10px 0 5px 0;">Chromium Test</h1>
<p style="color: #94a3b8; margin-bottom: 15px;">Probando transparencia y CSS moderno.</p>
<div class="stats">
<div class="stat-box"><strong>DPI</strong><br>Alta</div>
<div class="stat-box"><strong>CSS</strong><br>Grid</div>
</div>
</div>
</div>
</body>
</html>
Imágenes
También podemos imprimir imágenes codificadas en base64, aquí tengo un ejemplo de imagen redimensionada para que ocupe poco espacio:
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
En HTML se vería así:
<p>Una imagen:</p>
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAbCAMAAABY1h8eAAADAFBMVEVHcEzkzOPb4uvTQGC+z/+dR0/83tj6l7+1we3++emyNkfnlKaodqnmp7GgqeDXe43n///Pv/Dcg23eeHnZndDwk4eaquCpkcXtRmhsQFZwMEhwYZ7YvtSEESZbERCVh9zGamxscLnkfpHPjradXHrdhKbbo75QLmTQfI6/ZW+9bXrEcHDOfoj4yLrZqrvfkX7+8ML4xeL96sxsNkT95rrjUlj++upQJGWVc7nvjIuXJjKTo+DShYaCY5OdaJpyT3ZwS3jNi5x2TXd3MTqOZpHVl7irnMdqP2eNvfOBSG2nc39jRnTDeYXmVS7wVDXFdYH948X1z8qFl9fevsLLe2XdiqpiMV3Xd4a1X3pnLKZ6WofMboDCiobkm9acga6tXG2pQE20mbhukdtzJiL87N+OFiDSHSvLcVp7eMBxmOXdeI7qSB+4CRL63tO3bHTRgqHNZWGuSVYkov+IX5GFVVX+7uTyNDjesKNfSJLODgiUQWZdGD/MiLDfoLrQXnmiZ7/9+OX1iYnkmHv9+uH83rjYgGPNZmn3sqPce3t+QG+XaMZBeOguIq/jepvHnObkjbSzZL/aU6XMZHnNgHTioZ7XgZUxBglGFCXPenwiAwX1roZVJz6vX2E4CQnOc2VPHx7LelxyLSmZVEdmGyGJSDuoYEzIcXFMIDOGRERADRKaWmP80MpHExKxkK76t4alV1WiSkj1uo3z1LX+16LQo57YfWsmEBTppr6wq9bDfo3voXaMUlLQj4rWk6XciYX0w8/Hcl63c1GPRjLAcGKFOEm4WlTvqZPDaFq2dXLGhKLkxL7mxc7cpIuxWkz9wJPCkX7qxJtzQzW6f3BHBQfBjYTCfmTPlJj8y59eMDBzGhavaV6sbIiwYVekeIyAQCfikGvfm6qOlNK2gYbgjmPqlpDDa16Sfa7mzp1QUpPYnYHGn63l09ePd2t5OyjEZHCtb1C3aXyXQDv/zZbqZx5NMWWoZXLCh2zNnnvIhYT7xZKCNizVdIatLGKygoh0XHZQRrw6DSu0AAAAlnRSTlMAEQoMAi4BDkQefxsQInqJAyn9sF5zh0Qf/tNpqej9JirrJkZweXLfa6vy4b76/fX8L9H4+DU+94/Lo02nnazgvsvrsvYv1Oo+5+f7u4hp+vDQob7+91xE3hTy89jKrtn9dbrcePmi5Mzwsp/WuYP0Zc8awf6LWty96Z+QaczZokJOsU/uXuh12pphyrTSO6rX5Pzf0MX1AlHCAAACJklEQVQoz2NgYGBg5Gwwa+ZkAAEOGXYGJCBgVmpkZNJikGsI5BR1K0qzIkmmBOhev27y02B1rAijgMX/ngopVk4mmGTgulnnzm1et3n19lA1+Yl/1M3NM2R4YZLBu3bNmrXusdCx/TN6+ybc/ndj/hdpuLFqIQcWHJh39ujWTdcm9VvobflrXB0Jl+TV8V82Z86hewc3ntnwe+oUzeJOZiQXCbqtWrFo0dIF9w8fOXp2smFXPbJfmMRcZu+ec2fpkvmLF/661VFXW6OhgvAOE5/T9G3bZs6cO3flmpu7f9z+un6FM8JoAXFbe8nZy1fOnHn55tUFl84vWZiMHBICgiJ27sunzVz4bdP3i+/fyhXyqyojhSMbY9KL5WuubNn0/M2lg4c+rj+Zn6WEkPXIfLZo1enXpzZfOL90w/yFqz68E2aES/I9PLn+xOlTrzZ+OnNx7rQbK25daTOFGyu2Y/vTw3pb1u6ZtfHq5eklF2at1m2ESbIE7dj/ZN7OvY/WXtPXqVIpfzlH/1g7TJJDce2DffvmzVh2QqvANLtMNE/7+IImWEDEzZbcO2PZjHnHN6TmVH72Y2DQ0E5vhWmMmr7yiFa88ez506bJpvlKAIWUFNigktbe0xcnaCqEqU8HSkpA3QizUt5BKiI6nFHcc81cOS4WBjTAw+OqmhjjdXfJYitmBmxA2WfnHiEu7HIMDNyOMyzZccgxsNlsFWXAKckvzI3MBwAzxNdqcX1LNwAAAABJRU5ErkJggg==" />
Con Python funciona bien con el script previamente mostrado, pero en JS tuve que hacer el código más elegante:
const base64Image = "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";
const params = new URLSearchParams({
nombrePdf: 'ticket.pdf',
impresora: 'Microsoft print To PDF',
html: `<p>Una imagen:</p><img src="data:image/png;base64,${base64Image}" />`,
ancho: 400,
alto: 200
});
await fetch(`http://localhost:8080/?${params.toString()}`);
Por si te interesa, la URL codificada se ve así:
http://localhost:8080/?nombrePdf=ticket.pdf&impresora=Microsoft+print+To+PDF&html=%3Cp%3EUna+imagen%3A%3C%2Fp%3E%3Cimg+src%3D%22data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAABwAAAAbCAMAAABY1h8eAAADAFBMVEVHcEzkzOPb4uvTQGC%2Bz%2F%2BdR0%2F83tj6l7%2B1we3%2B%2BemyNkfnlKaodqnmp7GgqeDXe43n%2F%2F%2FPv%2FDcg23eeHnZndDwk4eaquCpkcXtRmhsQFZwMEhwYZ7YvtSEESZbERCVh9zGamxscLnkfpHPjradXHrdhKbbo75QLmTQfI6%2FZW%2B9bXrEcHDOfoj4yLrZqrvfkX7%2B8ML4xeL96sxsNkT95rrjUlj%2B%2BupQJGWVc7nvjIuXJjKTo%2BDShYaCY5OdaJpyT3ZwS3jNi5x2TXd3MTqOZpHVl7irnMdqP2eNvfOBSG2nc39jRnTDeYXmVS7wVDXFdYH948X1z8qFl9fevsLLe2XdiqpiMV3Xd4a1X3pnLKZ6WofMboDCiobkm9acga6tXG2pQE20mbhukdtzJiL87N%2BOFiDSHSvLcVp7eMBxmOXdeI7qSB%2B4CRL63tO3bHTRgqHNZWGuSVYkov%2BIX5GFVVX%2B7uTyNDjesKNfSJLODgiUQWZdGD%2FMiLDfoLrQXnmiZ7%2F9%2BOX1iYnkmHv9%2BuH83rjYgGPNZmn3sqPce3t%2BQG%2BXaMZBeOguIq%2FjepvHnObkjbSzZL%2FaU6XMZHnNgHTioZ7XgZUxBglGFCXPenwiAwX1roZVJz6vX2E4CQnOc2VPHx7LelxyLSmZVEdmGyGJSDuoYEzIcXFMIDOGRERADRKaWmP80MpHExKxkK76t4alV1WiSkj1uo3z1LX%2B16LQo57YfWsmEBTppr6wq9bDfo3voXaMUlLQj4rWk6XciYX0w8%2FHcl63c1GPRjLAcGKFOEm4WlTvqZPDaFq2dXLGhKLkxL7mxc7cpIuxWkz9wJPCkX7qxJtzQzW6f3BHBQfBjYTCfmTPlJj8y59eMDBzGhavaV6sbIiwYVekeIyAQCfikGvfm6qOlNK2gYbgjmPqlpDDa16Sfa7mzp1QUpPYnYHGn63l09ePd2t5OyjEZHCtb1C3aXyXQDv%2FzZbqZx5NMWWoZXLCh2zNnnvIhYT7xZKCNizVdIatLGKygoh0XHZQRrw6DSu0AAAAlnRSTlMAEQoMAi4BDkQefxsQInqJAyn9sF5zh0Qf%2FtNpqej9JirrJkZweXLfa6vy4b76%2FfX8L9H4%2BDU%2B94%2FLo02nnazgvsvrsvYv1Oo%2B5%2Bf7u4hp%2BvDQob7%2B91xE3hTy89jKrtn9dbrcePmi5Mzwsp%2FWuYP0Zc8awf6LWty96Z%2BQaczZokJOsU%2FuXuh12pphyrTSO6rX5Pzf0MX1AlHCAAACJklEQVQoz2NgYGBg5Gwwa%2BZkAAEOGXYGJCBgVmpkZNJikGsI5BR1K0qzIkmmBOhev27y02B1rAijgMX%2FngopVk4mmGTgulnnzm1et3n19lA1%2BYl%2F1M3NM2R4YZLBu3bNmrXusdCx%2FTN6%2Bybc%2Fndj%2FhdpuLFqIQcWHJh39ujWTdcm9VvobflrXB0Jl%2BTV8V82Z86hewc3ntnwe%2BoUzeJOZiQXCbqtWrFo0dIF9w8fOXp2smFXPbJfmMRcZu%2Bec2fpkvmLF%2F661VFXW6OhgvAOE5%2FT9G3bZs6cO3flmpu7f9z%2Bun6FM8JoAXFbe8nZy1fOnHn55tUFl84vWZiMHBICgiJ27sunzVz4bdP3i%2B%2FfyhXyqyojhSMbY9KL5WuubNn0%2FM2lg4c%2Brj%2BZn6WEkPXIfLZo1enXpzZfOL90w%2FyFqz68E2aES%2FI9PLn%2BxOlTrzZ%2BOnNx7rQbK25daTOFGyu2Y%2FvTw3pb1u6ZtfHq5eklF2at1m2ESbIE7dj%2FZN7OvY%2FWXtPXqVIpfzlH%2F1g7TJJDce2DffvmzVh2QqvANLtMNE%2F7%2BIImWEDEzZbcO2PZjHnHN6TmVH72Y2DQ0E5vhWmMmr7yiFa88ez506bJpvlKAIWUFNigktbe0xcnaCqEqU8HSkpA3QizUt5BKiI6nFHcc81cOS4WBjTAw%2BOqmhjjdXfJYitmBmxA2WfnHiEu7HIMDNyOMyzZccgxsNlsFWXAKckvzI3MBwAzxNdqcX1LNwAAAABJRU5ErkJggg%3D%3D%22+%2F%3E&ancho=400&alto=200
Recuerda: el servidor (herramienta para marca de agua) va a decodificar el HTML, y si lo encuentra malformado simplemente no lo va a imprimir, por eso es importante ir haciendo pruebas paso por paso, poco a poco y asegurarte de codificar correctamente el HTML.
Imprimiendo por URL
En los ejemplos de arriba estoy imprimiendo un PDF local pero también se puede hacer esto con un PDF a través de su URL de internet o URL local. Aquí un ejemplo con JavaScript listo para ser pegado en la consola de depuración:
const base64Image = "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";
const params = new URLSearchParams({
urlPdf: 'https://parzibyte.github.io/plugin-silent-pdf-print-examples/ticket.pdf',
impresora: 'Microsoft print To PDF',
html: `<p>Una imagen:</p><img src="data:image/png;base64,${base64Image}" />`,
grados: 0,
ancho: 400,
alto: 200
});
const respuestaHttp = await fetch(`http://localhost:8080/url?${params.toString()}`);
console.log(await respuestaHttp.text())
Algunos errores
El plugin va a devolver una cadena. Si la cadena no está vacía entonces es porque hubo un error y la misma cadena te dirá el error. Aquí he documentado algunos:
- “exec: "./chrome-win/chrome.exe": file does not exist” es porque no configuraste chrome correctamente
- “exit status 7”: (o cualquier otro número) es porque Chrome falló al renderizar el HTML ya sea porque algún parámetro es incorrecto o porque falta alguna DLL (zip mal extraído, ubicación mal colocada, etcétera)