Skip to content

Початок роботи з PDF Oxide (Clojure)

PDF Oxide — це найшвидший інструментарій для роботи з PDF із вбудованим видобуванням тексту: середній час 0.8 мс та 100% успішних проходжень на 3830 PDF. Прив’язка для Clojure — це ідіоматична, тонка обгортка над зрілою Java-прив’язкою fyi.oxide:pdf-oxide, якій належить єдиний нативний міст JNI. Вона не додає жодного нативного коду: викликає Java-класи через interop і повертає зручні для Clojure значення (java.util.List → вектор, java.util.Optional → значення-або-nil).

Встановлення

Додайте Java-прив’язку до свого deps.edn. Простір імен Clojure (pdf_oxide.core) лежить у вашому дереві вихідного коду й обгортає її:

{:deps {fyi.oxide/pdf-oxide {:mvn/version "0.3.69"}}}

Типи дескрипторів (Pdf, PdfDocument, DocumentEditor) реалізують AutoCloseable, тож використовуйте with-open для детермінованого очищення ресурсів.

Швидкий старт

Зберіть PDF із Markdown, відкрийте його назад і видобудьте текст. Кожен крок повертає звичайні значення Clojure.

(require '[pdf-oxide.core :as pdf])

(with-open [p (pdf/from-markdown "# Hello\n\nbody\n")
            d (pdf/open (pdf/save p))]
  (println "pages:   " (pdf/page-count d))
  (println "producer:" (or (pdf/producer d) "(none)"))
  (println (pdf/extract-text d 0)))

Відкриття PDF

pdf/open приймає або масив байтів, або рядок зі шляхом у файловій системі, а також необов’язковий пароль для зашифрованих документів.

(require '[pdf-oxide.core :as pdf])

;; Зі шляху
(with-open [d (pdf/open "research-paper.pdf")]
  (println "pages:" (pdf/page-count d)))

;; З байтів (наприклад, завантажених із S3 або HTTP)
(with-open [d (pdf/open pdf-bytes)]
  (println (pdf/extract-text d 0)))

;; Зашифрований документ
(with-open [d (pdf/open "confidential.pdf" "secret")]
  (println (pdf/extract-text d 0)))

Також можна автентифікуватися вже після відкриття:

(with-open [d (pdf/open "confidential.pdf")]
  (when (pdf/authenticate d "secret")
    (println (pdf/extract-text d 0))))

Видобування тексту

Видобувайте звичайний текст із будь-якої сторінки за її індексом, що починається з нуля.

(require '[pdf-oxide.core :as pdf])

(with-open [d (pdf/open "report.pdf")]
  ;; Окрема сторінка
  (println (pdf/extract-text d 0))

  ;; Усі сторінки
  (doseq [i (range (pdf/page-count d))]
    (println "--- Page" (inc i) "---")
    (println (pdf/extract-text d i))))

Елементи сторінки

pdf/page повертає PdfPage. З нього можна отримати слова, рядки, символи, таблиці, зображення та анотації — кожне у вигляді вектора Clojure. Об’єкти слів/рядків/символів надають .text і .bbox через interop.

(require '[pdf-oxide.core :as pdf])

(with-open [d (pdf/open "paper.pdf")]
  (let [pg (pdf/page d 0)]
    (println "page width:" (.width pg))

    ;; Слова з їхніми обмежувальними прямокутниками
    (doseq [w (take 8 (pdf/words pg))]
      (println "  " (.text w) "@" (.bbox w)))

    ;; Інші вектори елементів
    (println "lines:      " (count (pdf/lines pg)))
    (println "chars:      " (count (pdf/chars pg)))
    (println "tables:     " (count (pdf/tables pg)))
    (println "images:     " (count (pdf/images pg)))
    (println "annotations:" (count (pdf/annotations pg)))

    ;; Звичайний текст усієї сторінки або обрізаної області (BBox)
    (println (pdf/page-text pg))))

Щоб обрізати видобування до області, передайте fyi.oxide.pdf.geometry.BBox:

(import '[fyi.oxide.pdf.geometry BBox])

(with-open [d (pdf/open "paper.pdf")]
  (let [pg (pdf/page d 0)]
    (println (pdf/page-text pg (BBox. 0.0 0.0 1000.0 1000.0)))))

Конвертація у Markdown та HTML

Конвертуйте весь документ або окрему сторінку в Markdown чи HTML.

(require '[pdf-oxide.core :as pdf])

(with-open [d (pdf/open "paper.pdf")]
  ;; Весь документ
  (println (pdf/to-markdown d))
  (println (pdf/to-html d))

  ;; Окрема сторінка (відлік із нуля)
  (println (pdf/to-markdown d 0))
  (println (pdf/to-html d 0)))

Для багатшої структури pdf/extract-structured повертає структуроване дерево елементів сторінки:

(with-open [d (pdf/open "paper.pdf")]
  (println (pdf/extract-structured d 0)))

Пошук

pdf/search сканує весь документ і повертає вектор об’єктів-збігів. Кожен збіг надає .text через interop.

(require '[pdf-oxide.core :as pdf])

(with-open [d (pdf/open "manual.pdf")]
  (doseq [m (pdf/search d "configuration")]
    (println (.text m))))

Рендеринг

Відрендерте сторінку в масив байтів PNG, за бажанням із заданою роздільною здатністю (DPI).

(require '[pdf-oxide.core :as pdf]
         '[clojure.java.io :as io])

(with-open [d (pdf/open "paper.pdf")]
  ;; Типовий DPI
  (io/copy (pdf/render d 0) (io/file "page-0.png"))

  ;; Явно заданий DPI
  (io/copy (pdf/render d 0 150) (io/file "page-0@150.png")))

Створення

Тип Pdf надає фабричні функції. pdf/save серіалізує зібраний Pdf у масив байтів.

(require '[pdf-oxide.core :as pdf]
         '[clojure.java.io :as io])

;; З Markdown
(with-open [p (pdf/from-markdown "# Hello World\n\nThis is a PDF.")]
  (io/copy (pdf/save p) (io/file "output.pdf")))

;; З HTML
(with-open [p (pdf/from-html "<h1>Invoice</h1><p>Amount: $42</p>")]
  (io/copy (pdf/save p) (io/file "invoice.pdf")))

Редагування та редагування (вилучення) даних

pdf/editor відкриває DocumentEditor (із масиву байтів або шляху) для структурних правок. Очищуйте метадані, позначайте області для вилучення даних і застосовуйте їх безповоротно, після чого серіалізуйте за допомогою pdf/editor-save.

(require '[pdf-oxide.core :as pdf]
         '[clojure.java.io :as io])
(import '[fyi.oxide.pdf.geometry BBox])

(with-open [ed (pdf/editor "form.pdf")]
  (pdf/scrub-metadata ed)
  (pdf/add-redaction ed 0 (BBox. 10.0 10.0 50.0 20.0))
  (pdf/apply-redactions ed)
  (io/copy (pdf/editor-save ed) (io/file "redacted.pdf")))

Метадані та життєвий цикл

pdf/producer і pdf/creator повертають метадані документа як значення або nil, коли їх немає (java.util.Optional розгортається за вас). Надавайте перевагу with-open; pdf/close і pdf/open? — це запасні механізми для ручного керування життєвим циклом.

(require '[pdf-oxide.core :as pdf])

(let [d (pdf/open "paper.pdf")]
  (println "open?    " (pdf/open? d))
  (println "producer:" (or (pdf/producer d) "(none)"))
  (println "creator: " (or (pdf/creator d) "(none)"))
  (pdf/close d)
  (println "open?    " (pdf/open? d)))

Наступні кроки