Automatiza las marcas de agua en PDF con Ghostscript
Añade una etiqueta diagonal CONFIDENTIAL a cada página de un PDF, incluidas
las páginas con distintos tamaños y rotaciones. El siguiente script genera una copia marcada y
una copia candidata comprimida en un directorio nuevo. Conserva el archivo de entrada y se niega a
reemplazar resultados anteriores.
Úsalo para crear una copia destinada a compartir cuya apariencia puedas revisar. Ghostscript reescribe el PDF: las firmas digitales dejan de ser válidas, y los formularios, las anotaciones, las etiquetas de accesibilidad y el color pueden cambiar. La etiqueta es de color gris claro opaco, así que comprueba que no oculte contenido importante. Una marca de agua visible no cifra el documento ni impide que se copie.
Instala y configura Ghostscript
Necesitas Bash, gs de Ghostscript,
pdfinfo y pdftoppm de Poppler, y un visor de PDF.
En Ubuntu o Debian, instala paquetes que reciban mantenimiento:
sudo apt-get update && sudo apt-get install ghostscript poppler-utils
Comprueba estas herramientas, que se instalan por separado, antes de guardar los archivos de ejemplo:
bash --version && gs --version && pdfinfo -v && pdftoppm -v
Los comandos se probaron en Ubuntu 24.04 con Bash 5.2, Ghostscript 10.02.1 y Poppler 24.02.0, y en Linux con Bash 5.3, Ghostscript 10.07.1 y 10.08.0, y Poppler 26.08.0. Estas son versiones probadas, no versiones mínimas intrínsecas. Usa paquetes que reciban mantenimiento de tu distribución o de la página de versiones de Ghostscript, y revisa los resultados después de una actualización. Esta guía no cubre la ejecución nativa en Windows ni macOS.
Trabaja en un directorio que contenga tu archivo de origen como input.pdf.
Guarda los dos archivos siguientes en ese mismo directorio; el script busca
watermark.ps en el directorio desde el que lo ejecutas.
Crea una marca de agua con un procedimiento EndPage
Guarda esto como watermark.ps. EndPage dibuja la
etiqueta después del contenido existente de la página. Devuelve false
para la desactivación del dispositivo, de modo que ese evento no genere una página adicional:
%!PS-Adobe-3.0
<< /EndPage {
2 eq {
pop false
} {
pop
gsave
initgraphics
12 dict begin
/size currentpagedevice /PageSize get def
/label (CONFIDENTIAL) def
/Helvetica-Bold findfont 36 scalefont setfont
newpath 0 0 moveto label true charpath pathbbox
/top exch def /right exch def /bottom exch def /left exch def
/extent right left sub top bottom sub add 0.70710678 mul def
/side size aload pop 2 copy gt { exch } if pop def
/factor side 0.8 mul extent div def
factor 1 gt { /factor 1 def } if
size 0 get 2 div size 1 get 2 div translate
45 rotate
factor dup scale
0.75 setgray
left right add -2 div bottom top add -2 div moveto
label show
end
grestore
true
} ifelse
} >> setpagedevice
initgraphics restablece el estado gráfico de la página antes de colocar la
etiqueta. Los límites de los glifos la centran en ambos ejes; el cálculo de escala deja espacio
para la etiqueta girada completa en páginas estrechas. Asegúrate de que este archivo PostScript
sea de confianza: es código ejecutable. No insertes datos de entrada de usuarios sin escapar
en la etiqueta.
Guarda el script de automatización de PDF
Guarda esto como process.sh. Carga el procedimiento de marca de agua
antes del PDF de origen y luego pasa el resultado marcado real a la etapa de compresión:
#!/bin/bash
set -euo pipefail
if [ "$#" -ne 2 ]; then
echo "Usage: $0 <input-pdf> <new-output-directory>" >&2
exit 1
fi
INPUT_FILE=$1
OUTPUT_DIR=$2
WATERMARK_FILE=$PWD/watermark.ps
STAMPED_FILE=stamped.pdf
COMPRESSED_FILE=compressed.pdf
[[ $INPUT_FILE = /* ]] || INPUT_FILE=$PWD/$INPUT_FILE
[[ $OUTPUT_DIR = /* ]] || OUTPUT_DIR=$PWD/$OUTPUT_DIR
for tool in gs pdfinfo; do
if ! command -v "$tool" >/dev/null; then
echo "Error: Install $tool before running this script" >&2
exit 1
fi
done
if [ ! -f "$INPUT_FILE" ]; then
echo "Error: Input PDF not found" >&2
exit 1
fi
if [ ! -f "$WATERMARK_FILE" ]; then
echo "Error: watermark.ps not found in the working directory" >&2
exit 1
fi
if ! pdfinfo "$INPUT_FILE" >/dev/null; then
echo "Error: Input is not a readable PDF" >&2
exit 1
fi
if ! mkdir -m 700 -- "$OUTPUT_DIR"; then
echo "Error: Use a new output directory" >&2
exit 1
fi
cleanup() {
local status=$?
if [ "$status" -ne 0 ]; then
rm -f -- "$OUTPUT_DIR/$STAMPED_FILE" "$OUTPUT_DIR/$COMPRESSED_FILE"
rmdir -- "$OUTPUT_DIR"
fi
}
trap cleanup EXIT
cd -P -- "$OUTPUT_DIR"
OUTPUT_DIR=$PWD
process_pdf() {
local output=$1
local settings=$2
shift 2
if ! GS_OPTIONS= gs -dSAFER -dBATCH -dNOPAUSE -sDEVICE=pdfwrite \
-dPDFSETTINGS="$settings" -dCompatibilityLevel=1.7 \
-dAutoRotatePages=/None -dUseCropBox -dPDFSTOPONERROR \
-sOutputFile="$output" -f "$@"; then
echo "Error: PDF processing failed" >&2
exit 1
fi
}
echo "Adding watermark…"
process_pdf "$STAMPED_FILE" /prepress "$WATERMARK_FILE" "$INPUT_FILE"
echo "Creating compression candidate…"
process_pdf "$COMPRESSED_FILE" /ebook "$OUTPUT_DIR/$STAMPED_FILE"
echo "Processing complete: $OUTPUT_DIR/$COMPRESSED_FILE"
-dUseCropBox usa la región recortada visible del PDF como página de salida,
en lugar de centrar la etiqueta en un lienzo más grande y oculto. Esto conserva el tamaño y la
orientación mostrados, a la vez que normaliza los recuadros de página y puede normalizar los
metadatos de rotación. Usa otro flujo de trabajo si necesitas el lienzo original más grande de
la página. Consulta la opción CropBox de Ghostscript.
-dAutoRotatePages=/None se coloca después de cada ajuste preestablecido para desactivar
su heurística de orientación basada en texto. En particular, /ebook
selecciona /All si no se desactiva esa heurística, lo que puede girar
las páginas cuando su texto predominante está orientado de lado. La
tabla de ajustes preestablecidos
y los controles de orientación
documentan ese comportamiento. Vaciar GS_OPTIONS en cada invocación evita
que las opciones heredadas, como el tamaño fijo del papel o la selección de páginas, cambien
el resultado de este ejemplo.
Aplica la marca de agua de forma segura
Ejecuta el script guardado en Bash:
bash process.sh input.pdf new-results
Una ejecución correcta crea los archivos new-results/stamped.pdf y
new-results/compressed.pdf. El primero es la copia marcada; el segundo es una copia
candidata comprimida que contiene la misma etiqueta. El directorio de salida debe ser nuevo.
Para repetir la operación, elige otro nombre de directorio y conserva los resultados anteriores
para compararlos.
Si falla un comando de conversión, el script elimina sus dos archivos de salida y el directorio que acaba de crear. Deja intactos el archivo de origen y cualquier directorio de resultados preexistente. Resuelve el problema indicado y vuelve a ejecutar el mismo comando. La falta de herramientas o archivos y un PDF que no se pueda leer se detectan y rechazan antes de crear el directorio.
pdfinfo comprueba que Poppler pueda abrir el archivo de entrada, y
-dPDFSTOPONERROR detiene Ghostscript ante errores del PDF en lugar de recurrir a
su recuperación habitual. Ninguno es un validador completo de PDF; una conversión correcta no
demuestra que un archivo de origen dañado se haya reconstruido correctamente. Lee las
advertencias y revisa el resultado. Mantén Ghostscript actualizado con los parches y
-dSAFER activado. Sus
controles de acceso a archivos
no sustituyen un entorno aislado del sistema operativo para documentos que no sean de confianza.
Optimiza la compresión del PDF
Usa stamped.pdf si no necesitas la copia candidata comprimida.
/ebook establece una resolución objetivo de 150 dpi para reducir el
muestreo de las imágenes en color y en escala de grises, sujeta a un umbral de resolución;
también cambia otros ajustes. /prepress, usado en la primera etapa,
no garantiza que la calidad se mantenga intacta. Ninguno de los ajustes preestablecidos garantiza
un archivo más pequeño.
Compara los tamaños reales en bytes:
wc -c input.pdf new-results/stamped.pdf new-results/compressed.pdf
Renderiza el archivo de origen y ambos resultados con Poppler, usando sus regiones CropBox visibles. Ejecuta el bloque completo, incluidos los paréntesis, para que un comando fallido detenga este bloque sin modificar tu shell:
(
set -eu
mkdir new-results/previews
pdftoppm -cropbox -r 150 -png input.pdf new-results/previews/original
pdftoppm -cropbox -r 150 -png new-results/stamped.pdf new-results/previews/stamped
pdftoppm -cropbox -r 150 -png new-results/compressed.pdf new-results/previews/compressed
)
Abre los PNG correspondientes uno al lado del otro. Comprueba la orientación, las dimensiones,
el texto y las imágenes de origen de cada página, además de que haya una etiqueta diagonal
completa y centrada. Abre también los PDF en tu visor con el nivel de zoom o el tamaño de impresión
previstos. El bloque de vista previa rechaza un directorio previews
existente; consérvalo o cámbiale el nombre antes de crear otro conjunto.
Elige la copia candidata comprimida solo si su tamaño y apariencia son adecuados para tu documento. Para obtener más información sobre cómo comparar ajustes preestablecidos y comprobar las características de los PDF, consulta Optimización de PDF con la CLI de Ghostscript.
