Automatizar marcas-d’água em PDFs com Ghostscript
Adicione um rótulo diagonal CONFIDENTIAL a cada página de um PDF, incluindo páginas
com tamanhos e rotações diferentes. O script abaixo grava uma cópia com marca-d’água e uma versão
candidata comprimida separada em um novo diretório. Ele preserva o arquivo de entrada e se recusa a
substituir resultados anteriores.
Use isso para criar uma cópia para compartilhamento cuja aparência você possa inspecionar. O Ghostscript reescreve o PDF: assinaturas digitais se tornam inválidas, e formulários, anotações, marcadores de acessibilidade e cores podem mudar. O rótulo é cinza-claro e opaco, então confira se não encobre conteúdo importante. Uma marca-d’água visível não criptografa o documento nem impede que ele seja copiado.
Instalar e configurar o Ghostscript
Você precisa do Bash, do gs do Ghostscript, do
pdfinfo e do pdftoppm do Poppler e de um visualizador de
PDF. No Ubuntu ou Debian, instale pacotes com manutenção ativa:
sudo apt-get update && sudo apt-get install ghostscript poppler-utils
Verifique estas ferramentas, instaladas separadamente, antes de salvar os arquivos de exemplo:
bash --version && gs --version && pdfinfo -v && pdftoppm -v
Os comandos foram testados no Ubuntu 24.04 com Bash 5.2, Ghostscript 10.02.1 e Poppler 24.02.0, e no Linux com Bash 5.3, Ghostscript 10.07.1 e 10.08.0 e Poppler 26.08.0. Essas são versões testadas, não versões mínimas exigidas pelas ferramentas. Use pacotes com manutenção ativa da sua distribuição ou da página de versões do Ghostscript e inspecione os resultados após uma atualização. Este guia não cobre a execução nativa no Windows ou no macOS.
Trabalhe em um diretório que contenha seu arquivo de origem como input.pdf.
Salve os dois arquivos abaixo nesse mesmo diretório; o script procura
watermark.ps no diretório em que você o executa.
Criar uma marca-d’água com um procedimento EndPage
Salve este conteúdo como watermark.ps. EndPage desenha o
rótulo após o conteúdo existente da página. Ele retorna false na
desativação do dispositivo, para que esse evento não gere uma página extra:
%!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 redefine o estado gráfico da página antes de posicionar o rótulo.
Os limites dos glifos o centralizam nos dois eixos; o cálculo da escala deixa espaço para o rótulo
rotacionado completo em páginas estreitas. Garanta que este arquivo PostScript seja confiável:
ele contém código executável. Não insira no rótulo dados fornecidos pelo usuário sem o devido
escape.
Salvar o script de automação de PDF
Salve este conteúdo como process.sh. Ele carrega o procedimento de marca-d’água
antes do PDF de origem e então passa o arquivo efetivamente gerado com a marca-d’água para a
etapa de compressão:
#!/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 a região recortada visível do PDF como página de saída, em vez de
centralizar o rótulo em uma área maior e oculta. Isso preserva o tamanho e a orientação exibidos,
ao mesmo tempo que normaliza as caixas de página e, possivelmente, os metadados de rotação. Use
outro fluxo de trabalho se precisar da área original maior da página. Consulte a
opção CropBox do Ghostscript.
-dAutoRotatePages=/None vem após cada predefinição para desativar sua heurística de
orientação baseada em texto. Em particular, sem essa opção, /ebook
seleciona /All, o que pode girar páginas quando o texto predominante
está na lateral. A tabela de predefinições
e os controles de orientação
documentam esse comportamento. Limpar GS_OPTIONS em cada execução impede que
opções herdadas, como tamanho fixo do papel ou seleção de páginas, alterem a saída deste exemplo.
Aplicar marca-d’água com segurança
Execute o script salvo no Bash:
bash process.sh input.pdf new-results
Uma execução bem-sucedida cria new-results/stamped.pdf e new-results/compressed.pdf.
O primeiro é a cópia com marca-d’água; o segundo é uma versão candidata comprimida que contém o
mesmo rótulo. O diretório de saída deve ser novo. Para repetir a operação, escolha outro nome de
diretório e mantenha os resultados anteriores para comparação.
Se um comando de conversão falhar, o script remove seus dois arquivos de saída e o diretório que acabou de criar. Ele mantém intactos o arquivo de origem e qualquer diretório de resultados preexistente. Corrija o problema informado e execute novamente o mesmo comando. Ferramentas ausentes, arquivos ausentes e PDFs que não podem ser lidos são rejeitados antes da criação do diretório.
pdfinfo verifica se o Poppler consegue abrir o arquivo de entrada, e
-dPDFSTOPONERROR interrompe o Ghostscript diante de erros no PDF, em vez de permitir
sua recuperação habitual. Nenhum deles é um validador completo de PDF; uma conversão bem-sucedida
não comprova que um arquivo de origem danificado foi reconstruído corretamente. Leia os avisos e
inspecione a saída. Mantenha o Ghostscript atualizado com as correções e
-dSAFER ativado. Seus
controles de acesso a arquivos
não substituem um sandbox do sistema operacional para documentos não confiáveis.
Otimizar a compressão de PDF
Use stamped.pdf se não precisar da versão candidata comprimida.
/ebook define uma resolução-alvo de 150 dpi para a redução de resolução de
imagens coloridas e em tons de cinza, sujeita a um limiar de resolução; também altera outras
configurações. /prepress, usado na primeira etapa, não garante que a qualidade
permaneça inalterada. Nenhuma das predefinições garante um arquivo menor.
Compare as contagens reais de bytes:
wc -c input.pdf new-results/stamped.pdf new-results/compressed.pdf
Renderize o arquivo de origem e as duas saídas com o Poppler, usando suas regiões CropBox visíveis. Execute o bloco inteiro, incluindo os parênteses, para que um comando que falhe interrompa esse bloco sem alterar seu 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
)
Abra os PNGs correspondentes lado a lado. Confira a orientação, as dimensões, o texto e as imagens
de origem de cada página, além da presença de um rótulo diagonal completo e centralizado. Abra
também os PDFs no seu visualizador com o nível de zoom ou tamanho de impressão pretendido. O
bloco de pré-visualização se recusa a usar um diretório previews existente;
preserve-o ou renomeie-o antes de gerar outro conjunto.
Escolha a versão candidata comprimida somente se o tamanho e a aparência forem adequados ao seu documento. Para saber mais sobre como comparar predefinições e verificar recursos de PDF, consulte Otimização de PDF com a CLI do Ghostscript.
