Add pdf-invoice module: one invoice in OpenPDF 3.0.5, iText Core 9.8.0 and Flying Saucer 10.7.0, Devanagari shaping checked by rendering, streamed vs buffered download, subset sizes and timings
Co-Authored-By: Claude Sonnet 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_017ic4b6Kg9RWSTJzyz6KP9X
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
# pdf-invoice
|
||||
|
||||
Companion code for **[Generate PDF Invoices in Spring Boot: OpenPDF vs iText vs Flying Saucer (HTML to PDF)](https://ankurm.com/spring-boot-generate-pdf-invoice-openpdf-itext-flying-saucer/)**.
|
||||
|
||||
Spring Boot 4.1.2, JDK 25, OpenPDF 3.0.5, iText Core 9.8.0 (AGPL 3 or commercial), Flying Saucer 10.7.0, Thymeleaf 3.1.5, Apache PDFBox 3.0.8 (tests only). No database, no Docker.
|
||||
|
||||
One invoice, rendered by three libraries, with Marathi and Hindi text in Noto Sans Devanagari (SIL OFL 1.1) embedded:
|
||||
|
||||
| Engine name | Code | What it is |
|
||||
|---|---|---|
|
||||
| `openpdf` | `OpenPdfInvoiceWriter` | (a) OpenPDF's programmatic API, defaults |
|
||||
| `itext` | `ITextInvoiceWriter` | (b) iText Core 9.8.0, programmatic API, defaults |
|
||||
| `flyingsaucer` | `FlyingSaucerInvoiceWriter`, `templates/invoice.html` | (c) Thymeleaf template to XHTML to Flying Saucer, defaults |
|
||||
| `openpdf-jdk`, `openpdf-jdk-actualtext` | `OpenPdfInvoiceWriter` with `Shaping.JDK` | OpenPDF's `GlyphLayoutManager`: text laid out by the JDK's own shaper |
|
||||
| `openpdf-fop` | `OpenPdfInvoiceWriter` with `Shaping.FOP` | OpenPDF's optional Apache FOP glyph engine (only with `mvn -Pfop`) |
|
||||
| `flyingsaucer-shaped` | `FlyingSaucerInvoiceWriter` with `shaped=true` | Flying Saucer with OpenPDF's static `LayoutProcessor` switched on |
|
||||
|
||||
`InvoiceController` serves `GET /invoices/{engine}.pdf` with `StreamingResponseBody` (default) or a buffered `byte[]` (`?mode=buffered`), a Marathi
|
||||
`Content-Disposition` file name, `?probe=true` for an invoice that is only a shaping test string, and `?failAtEnd=true` to see what a failure after rendering looks like.
|
||||
`Bench` (profile `bench`) times N invoices per engine in one JVM.
|
||||
|
||||
```bash
|
||||
export JAVA_HOME=/path/to/jdk-25
|
||||
mvn -DskipTests package
|
||||
java -jar target/pdf-invoice-1.0.0.jar # then: curl -o invoice.pdf localhost:8080/invoices/openpdf.pdf
|
||||
./scripts/run-all.sh # tests + every capture below; rewrites output/ (about 4 minutes)
|
||||
```
|
||||
|
||||
`scripts/run-all.sh` needs poppler (`pdftoppm`, `pdftotext`, `pdffonts`, `pdfinfo`) and Python with Pillow built with libraqm (for the reference line in the comparison image).
|
||||
Everything in `output/` was produced by that script; the numbers in `06-bench.txt` are indicative (shared 2-vCPU sandbox, one run per line).
|
||||
|
||||
## Captured output
|
||||
|
||||
| File | What it holds |
|
||||
|---|---|
|
||||
| `output/00-versions-and-licences.txt` | licence declarations read from the POMs, sentences from iText's AGPL page, latest GA versions |
|
||||
| `output/01-text-extraction.txt` | PDFBox text extraction of each engine's invoice (`PdfContentTest`) |
|
||||
| `output/02-endpoints.txt` | status and headers for every engine, streamed vs buffered, a failure after rendering |
|
||||
| `output/03-pdffonts-and-producer.txt` | `pdffonts` per engine and the Producer line each library writes |
|
||||
| `output/04-glyph-counts.txt` | glyph codes written into the page, per engine (`GlyphCountTest`) |
|
||||
| `output/05-layoutprocessor-trap.txt` | what the static `LayoutProcessor` does to other OpenPDF writers in the same JVM |
|
||||
| `output/06-bench.txt` | time per invoice, PDF size, subset vs whole font |
|
||||
| `output/png/shaping-comparison.png` | the probe string drawn by each engine under a Pillow/libraqm reference line |
|
||||
| `output/png/invoice-*.png` | the first 800 pixel rows of each engine's invoice at 110 dpi |
|
||||
| `output/pdf/*.pdf` | the PDFs themselves (`probe-*.pdf` are the shaping probe invoices) |
|
||||
|
||||
## Not covered here
|
||||
|
||||
iText's pdfCalligraph add-on (proprietary licence, needs a licence key, so it was not run), PDF/A and PDF/UA conformance, digital signatures, multi-page invoices and page headers/footers,
|
||||
and Microsoft Word / Adobe Acrobat / mobile viewers (rendering was checked with poppler's `pdftoppm` only).
|
||||
|
||||
## Fonts
|
||||
|
||||
`src/main/resources/fonts/` holds static Regular and Bold instances of Noto Sans Devanagari, cut from the variable font with `scripts/make_fonts.py`
|
||||
(source and licence in the script's header and in `OFL.txt`).
|
||||
Reference in New Issue
Block a user