#!/usr/bin/env bash # Regenerates everything under output/. Needs JDK 25, Maven, curl, poppler (pdftoppm, pdftotext, pdffonts), # python3 with Pillow built with libraqm. Network is needed once for Maven and for 00-versions-and-licences.txt. set -euo pipefail cd "$(dirname "$0")/.." mkdir -p output/pdf output/png JAR=target/pdf-invoice-1.0.0.jar HOST="$(java -version 2>&1 | grep -v JAVA_TOOL | head -1) | $(nproc) vCPU | $(awk '/MemTotal/ {printf "%d MB RAM", $2/1024}' /proc/meminfo)" scripts/licences.sh > output/00-versions-and-licences.txt || echo "licence check skipped (offline?)" mvn -q -B test # writes output/01, 04, 05 mvn -q -B -DskipTests package serve() { # serve : start the packaged jar, wait until it answers setsid nohup java -jar "$JAR" --server.port="$1" > "target/app-$1.log" 2>&1 < /dev/null & echo $! > "target/app-$1.pid" for _ in $(seq 1 60); do curl -s -o /dev/null "localhost:$1/invoices/openpdf.pdf" && return 0; sleep 1; done echo "app did not start" >&2; return 1 } stop() { kill "$(cat "target/app-$1.pid")" 2>/dev/null || true; } P=$((20000 + RANDOM % 10000)) serve "$P" ENGINES="openpdf itext flyingsaucer openpdf-jdk openpdf-jdk-actualtext flyingsaucer-shaped" for e in $ENGINES; do curl -s -o "output/pdf/$e.pdf" "localhost:$P/invoices/$e.pdf" curl -s -o "output/pdf/probe-$e.pdf" "localhost:$P/invoices/$e.pdf?probe=true" done { echo "# HTTP: status and headers per engine (curl -D -), then streaming vs buffered, then a failure after rendering" echo "# $HOST" for e in $ENGINES; do echo "--- GET /invoices/$e.pdf" curl -s -D - -o /dev/null "localhost:$P/invoices/$e.pdf" | tr -d '\r' | grep -i -E '^HTTP|^content-type|^content-disposition|^content-length|^transfer-encoding' done echo "--- GET /invoices/openpdf.pdf?mode=buffered" curl -s -D - -o /dev/null "localhost:$P/invoices/openpdf.pdf?mode=buffered" | tr -d '\r' | grep -i -E '^HTTP|^content-length|^transfer-encoding' echo "--- GET /invoices/openpdf.pdf?disposition=inline" curl -s -D - -o /dev/null "localhost:$P/invoices/openpdf.pdf?disposition=inline" | tr -d '\r' | grep -i -E '^HTTP|^content-disposition' echo "--- GET /invoices/nope.pdf" curl -s -D - -o /dev/null "localhost:$P/invoices/nope.pdf" | tr -d '\r' | grep -i -E '^HTTP' echo "--- GET /invoices/openpdf.pdf?failAtEnd=true (streamed: headers are already gone when the failure happens)" curl -s -D - -o target/fail-stream.pdf -w "curl exit=%{exitcode} bytes_received=%{size_download}\n" "localhost:$P/invoices/openpdf.pdf?failAtEnd=true" 2>&1 | tr -d '\r' | grep -i -E '^HTTP|^content-length|^transfer-encoding|curl exit' || true echo "--- GET /invoices/openpdf.pdf?failAtEnd=true&mode=buffered (rendered into memory first)" curl -s -D - -o target/fail-buffered.bin -w "curl exit=%{exitcode} bytes_received=%{size_download}\n" "localhost:$P/invoices/openpdf.pdf?failAtEnd=true&mode=buffered" 2>&1 | tr -d '\r' | grep -i -E '^HTTP|^content-length|curl exit' || true } > output/02-endpoints.txt { echo "# pdffonts per engine (poppler): name, type, embedded, subset" for e in $ENGINES; do echo "--- $e ($(stat -c %s "output/pdf/$e.pdf") bytes)"; pdffonts "output/pdf/$e.pdf"; done echo; echo "# Producer/Creator lines the libraries write into the PDF (pdfinfo)" for e in openpdf itext flyingsaucer; do echo "--- $e"; pdfinfo "output/pdf/$e.pdf" | grep -E '^(Title|Creator|Producer)'; done } > output/03-pdffonts-and-producer.txt stop "$P" # the FOP variant needs Apache FOP (121 jars with Batik) on the classpath: Maven profile fop mvn -q -B -Pfop -DskipTests package P2=$((20000 + RANDOM % 10000)) serve "$P2" curl -s -o output/pdf/openpdf-fop.pdf "localhost:$P2/invoices/openpdf-fop.pdf" curl -s -o output/pdf/probe-openpdf-fop.pdf "localhost:$P2/invoices/openpdf-fop.pdf?probe=true" stop "$P2" mvn -q -B -DskipTests package # back to the default jar for e in openpdf itext flyingsaucer openpdf-jdk-actualtext flyingsaucer-shaped openpdf-fop; do pdftoppm -r 110 -png -singlefile -H 800 "output/pdf/$e.pdf" "output/png/invoice-$e" done python3 scripts/compare.py output/pdf output/png src/main/resources/fonts/NotoSansDevanagari-Regular.ttf { echo "# in-process timing, $HOST" echo "# indicative: shared sandbox, one JVM, one run per line" java -jar "$JAR" --spring.profiles.active=bench --spring.main.web-application-type=none \ --bench.n="${BENCH_N:-500}" --bench.engines=openpdf,itext,flyingsaucer,openpdf-jdk-actualtext,flyingsaucer-shaped 2>/dev/null | grep -E '^#|^[a-z]' } > output/06-bench.txt echo done