PDF Oxide 시작하기 (Clojure)
PDF Oxide는 텍스트 추출 기능을 기본 내장한 가장 빠른 PDF 툴킷으로, 평균 0.8ms에 3,830개 PDF에서 100% 통과율을 기록합니다. Clojure 바인딩은 단일 JNI 네이티브 브리지를 담당하는 성숙한 fyi.oxide:pdf-oxide Java 바인딩 위에 얹은 관용적이고 얇은 래퍼입니다. 네이티브 코드를 전혀 추가하지 않으며, interop를 통해 Java 클래스를 호출하고 Clojure 친화적인 값을 반환합니다 (java.util.List → 벡터, java.util.Optional → 값-또는-nil).
설치
deps.edn에 Java 바인딩을 추가하세요. Clojure 네임스페이스(pdf_oxide.core)는 여러분의 소스 트리에 위치하며 이를 감쌉니다:
{:deps {fyi.oxide/pdf-oxide {:mvn/version "0.3.69"}}}
핸들 타입(Pdf, PdfDocument, DocumentEditor)은 AutoCloseable이므로, 결정적인 정리를 위해 with-open을 사용하세요.
빠른 시작
Markdown에서 PDF를 만들고, 다시 열어, 텍스트를 추출합니다. 각 단계는 평범한 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))))
텍스트 추출
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 벡터로 가져올 수 있습니다. 단어/줄/문자 객체는 interop를 통해 .text와 .bbox를 노출합니다.
(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))
;; 단일 페이지 (0부터 시작)
(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는 문서 전체를 스캔하여 일치 객체의 벡터를 반환합니다. 각 일치 항목은 interop를 통해 .text를 노출합니다.
(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")))
편집 및 교정(Redaction)
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)))