mojipoji.dev / Posts / BAPDFer

BAPDFer: I Built a Desktop PDF Assembly Tool in an Afternoon

Someone at work said the tools for assembling PDF documents aren't good enough. I agreed, so I used Claude to build one — JavaFX, Swing, Apache PDFBox, a couple of hours. Something old, something new.

BAPDFer — Bad-Ass PDFer desktop application

The complaint was offhand, the kind of thing someone says at the end of a meeting. Assembling a PDF from multiple source documents — pulling specific pages, rotating a few, scaling others down, dropping the ones you don't need — is still genuinely annoying. Preview handles basic merges. Acrobat costs money and buries the controls. The open-source options tend to be command-line tools that require you to remember flags. Nobody said "someone should build a better one," but the gap was obvious.

So I did. Meet BAPDFer — the Bad-Ass PDFer.

Something old, something new

The tech stack here is a deliberate mix. On the "old" side: JavaFX and Swing. Swing has been around since 1997. JavaFX is its spiritual successor, still kicking at version 21. Desktop Java UI frameworks have a reputation — not all of it fair — as relics of a different era. On the "new" side: Claude, doing what it does best, turning a clear description of what I wanted into working code fast.

The pairing is the point. Swing and JavaFX are niche enough that most developers have never touched them, and that reputation keeps people away. But the capability is real — a desktop app with full file system access, no browser sandbox, no Electron overhead. Claude knows these APIs well, and with good prompting it can build production-quality Swing/JavaFX UIs in a session. The "old" framework stops being a liability when you're not writing it yourself from scratch.

What it does

BAPDFer takes one or more source PDF documents and lets you compose a new output document with full control over what happens to each page:

The workflow is drag-and-drop friendly. Load your sources, work through the pages, configure each one, export. The output is a single assembled PDF.

Under the hood

The PDF heavy lifting is done by Apache PDFBox 3.0.3. PDFBox is mature, well-documented, and handles the full range of operations BAPDFer needs — page extraction, rotation transforms, scaling, and final document assembly — without requiring a commercial license. The UI is JavaFX 21 with the Swing bridge module, which lets you embed Swing components where JavaFX doesn't have a native equivalent.

JavaFX 21.0.6 javafx.controls javafx.fxml javafx.swing pdfbox 3.0.3 Gradle

The Gradle build keeps it simple. No spring, no ORM, no server — just a desktop tool that does one thing well.

The build session

The whole thing came together in a couple of hours in Claude Code. The session started with describing the problem: a GUI app that loads multiple PDFs and gives the user per-page control over append, rotate, scale, and ignore. From there, Claude scaffolded the project structure, wired up the PDFBox integration, built the page list UI, and handled the file I/O for export.

The part that would have taken the most time manually — and probably the part most developers have never written — is the PDFBox transform pipeline. Getting rotation, scaling, and page ordering to compose correctly in the output document isn't hard once you know the API, but it's tedious to figure out from scratch. Claude had it right the first time.

The other thing worth noting: the Swing/JavaFX bridge. Mixing the two toolkits in a single app has real gotchas around threading (Swing has the EDT; JavaFX has its own application thread). Claude flagged this proactively and handled it correctly without me having to ask. That kind of thing — knowing the domain well enough to anticipate the subtle problems — is where the speed really adds up.

See it in action

Loading multiple PDF sources, configuring pages, and exporting the assembled output.

The takeaway

The gap in PDF tooling is real — and it's closable in an afternoon. That's the story here. Not that Swing is back, or that Claude writes perfect code, but that the combination lets you move from "someone should build this" to a working app faster than anyone expects. The old framework gets the job done. The new tool makes the old one viable again.

Next time someone at work says a tool isn't good enough, I'm going to keep saying yes.

Find this useful? Share the link