Plain-data PDF extraction for Clojure. Pull text, words, characters, geometric
objects, and tables out of digitally generated PDFs as EDN/JSON-friendly maps and
vectors — the Clojure counterpart to Python's pdfplumber,
built on Apache PDFBox.
Early release (0.5.0). The extraction API (text, words, chars, objects,
tables, crop) is in place and validated against the Python pdfplumber corpus;
it may still evolve before 1.0.
deps.edn
net.clojars.savya/pdfplumber-clj {:mvn/version "0.5.0"}
Leiningen
[net.clojars.savya/pdfplumber-clj "0.5.0"]
Requires JDK 17+.
(require '[pdfplumber.core :as pdf])
(pdf/with-pdf [doc "statement.pdf"]
(pdf/text doc {:page 1})) ; => "Account statement\n..."
(pdf/with-pdf [doc "statement.pdf"]
(pdf/words doc {:page 1})) ; => [{:text "Account" :x0 .. :top .. :x1 .. :bottom ..} ...]
(pdf/with-pdf [doc "invoice.pdf"]
(pdf/extract-table doc {:page 1 :strategy :lines}))
The reducible-* functions on pdfplumber.core return IReduceInit streams
that extract one page at a time. Transducers terminate early without extracting
later pages. They are re-exported from pdfplumber.reducible.
(into []
(comp (filter #(> (:size %) 10)) (take 100))
(pdf/reducible-chars doc))
(transduce (take 20) conj [] (pdf/reducible-words doc))
extract-tables returns every independent table region on a page, ordered
top-to-bottom then left-to-right. extract-table returns only the first region.
Configure each axis independently with :vertical-strategy and
:horizontal-strategy; each accepts :lines, :lines-strict, :text, or
:explicit. The legacy :strategy option sets both axes.
(pdf/extract-tables doc
{:page 1
:vertical-strategy :explicit
:horizontal-strategy :lines
:explicit-vertical-lines [70 170 260]
:snap-tolerance 3.0
:join-tolerance 3.0
:edge-min-length 3.0
:intersection-tolerance 3.0
:min-words-vertical 3
:min-words-horizontal 1})
Use :explicit-horizontal-lines with :horizontal-strategy :explicit.
Explicit lines may be coordinates or maps with bounded line coordinates.
table->maps converts an extracted table or raw rows to a sequence of
header-keyed maps.
(-> (pdf/extract-table doc {:page 1})
pdf/table->maps)
The result feeds tech.v3.dataset/->dataset directly with no added dependency.
Use :keywordize? true for keyword keys. Set :header to :first (the
default), an explicit key vector, or false for integer keys.
pdfplumber.core/to-image renders a page through PDFBox and returns a
PageImage; pdfplumber.core/page-image? identifies one. Overlay, reset/copy,
save, and display verbs live in pdfplumber.image.
(require '[pdfplumber.image :as image])
(pdf/with-pdf [doc "invoice.pdf"]
(-> (pdf/to-image doc {:page 1 :resolution 144})
(image/outline-words)
(image/draw-rect [72 72 240 160])
(image/save "debug.png")))
(pdf/with-pdf [doc "invoice.pdf"]
(-> (pdf/to-image doc {:page 1})
(image/debug-tablefinder {:vertical-strategy :lines})
(image/save "tables.png")))
Other overlays: draw-line, draw-vline, draw-hline, draw-rects,
draw-circle, draw-circles, and outline-chars. reset, copy, save, and
show manage the rendered image.
structure-tree returns a tagged PDF's nested logical structure.
page-structure-tree restricts it to a 1-based page. Untagged PDFs return [].
(pdf/structure-tree doc)
(pdf/page-structure-tree doc 1)
Widget entries returned by annots include :field-name, :field-value, and
:field-type. Other annotations are unchanged.
(pdf/annots doc {:page 1})
Dump selected PDF objects as CSV or JSON:
clojure -M -m pdfplumber.cli statement.pdf \
--format json --pages 1,2 --types char,line,rect,curve,image,annot \
--precision 2 --indent 2
images returns drawn image objects. Images also appear as :image entries in
objects. Each image includes its bbox, pixel :width and :height,
:colorspace, :bits, :mask?, and :smask?. Decoded PNG bytes are omitted
by default.
(pdf/images doc {:page 1})
(pdf/images doc {:page 1 :include-image-data? true}) ; adds :bytes
Public coordinates use a top-left origin (matching pdfplumber), with bounding
boxes as [x0 top x1 bottom] in PDF user-space points. PDFBox's native bottom-left
coordinates are converted internally.
In: text/word/char and image extraction, page geometry, crop/filter, multi-table extraction from ruling lines, text alignment, or explicit lines, visual debugging, tagged-PDF structure trees, widget form-field values, command-line CSV/JSON export, and deterministic plain-data output.
Not in scope (same as Python pdfplumber): PDF generation, OCR, scanned/image
PDFs, and layout ML. Widget annotations surface AcroForm field values, but there
is no dedicated form API. Table :text strategy is heuristic and intended for
digitally generated PDFs.
Copyright © 2026 Savyasachi.
Distributed under the Eclipse Public License 2.0.
Can you improve this documentation? These fine people already did:
Savyasachi & Savyasachi JagadeeshanEdit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |