Repository: dotemacs/pdfboxing
Pull request #22 (2016-03-19 18:20:53)

Implements PDFDocument protocol to handle both PDDocument and PDF filepaths directly
As previously discussed in #19, this allows us to pass both PDDocument and PDF filepaths directly to a number of function in the API.

This PR:
- Replaces calls to `load-pdf` with calls to PDFDocument protocol's `obtain-document`.
- Updates docs to reflect changes / capability

Tests passing.

dotemacs: Hello @mil o/

Thank you for the PR, your work is greatly appreciated.

One nitpick: in your commit you misspelt `obtain-doucment`. 
Maybe you want to fix that? Not a show stopper.

The thing that I'd really like to see is some tests for this feature.
Once you add them I'll merge the PR.

Thanks again 



Patch:
diff --git a/README.md b/README.md
index c17f855..3100f5d 100644
--- a/README.md
+++ b/README.md
@@ -104,3 +104,23 @@ on which the line should be drawn
                               :x1 650
                               :y1 160})
 ```
+
+## Compatibility with Pdfbox PDDocuments
+The following functions referenced above have direct compatibility with Pdfbox's internal PDDocument type:
+- `text/extract`
+- `pdf/split-pdf`
+- `form/get-fields`
+- `form/set-fields`
+- `form/rename-fields`
+- `info/page-number`
+- `draw/draw-line`
+
+This allows you to substitute each filepath (of each function's input) referenced above with a PDDocument type.  This is helpful for example in the case that you were to want to split a PDF up by pages and then extract the text from *only* the 3rd page:
+```clojure
+(require '[pdfboxing.text :as text])
+(require '[pdfboxing.split :as split])
+(text/extract
+  (nth 
+    (split/split-pdf :input "test/pdfs/multi-page.pdf")
+    2))
+```
diff --git a/src/pdfboxing/common.clj b/src/pdfboxing/common.clj
index 4df98d9..fb4bc0b 100644
--- a/src/pdfboxing/common.clj
+++ b/src/pdfboxing/common.clj
@@ -4,7 +4,6 @@
    [org.apache.pdfbox.pdmodel PDDocument]
    [org.apache.pdfbox.preflight.parser PreflightParser]))
 
-
 (defn is-pdf?
   "Confirm that the PDF supplied is really a PDF"
   [pdf-file]
@@ -23,3 +22,18 @@
   (if (is-pdf? pdf-file)
     (PDDocument/load pdf-file)
     (throw (IllegalArgumentException. (format "%s is not a PDF file" pdf-file)))))
+
+
+(defprotocol PDFDocument
+  "return an object from which text can be extracted"
+  (obtain-document [source]))
+
+(extend-protocol PDFDocument
+  java.lang.String
+  (obtain-document [source]
+    (if (is-pdf? source)
+      (load-pdf source)))
+
+  org.apache.pdfbox.pdmodel.PDDocument
+  (obtain-document [source]
+    source))
diff --git a/src/pdfboxing/draw.clj b/src/pdfboxing/draw.clj
index deff70d..7a93d03 100644
--- a/src/pdfboxing/draw.clj
+++ b/src/pdfboxing/draw.clj
@@ -54,7 +54,7 @@
    coordinates. Where coordinates have: page-number, x, y, x1, y1
    points where the line should be drawn."
   [& {:keys [input-pdf output-pdf coordinates]}]
-  (with-open [document (common/load-pdf input-pdf)]
+  (with-open [document (common/obtain-document input-pdf)]
     (with-open [content-stream (get-content-stream document (:page-number coordinates))]
       (use-rgb-colour content-stream)
       (set-line-width content-stream)
diff --git a/src/pdfboxing/form.clj b/src/pdfboxing/form.clj
index 8677a9a..db2f2b1 100644
--- a/src/pdfboxing/form.clj
+++ b/src/pdfboxing/form.clj
@@ -9,7 +9,7 @@
 (defn get-fields
   "get all the field names and their values from a PDF document"
   [pdfdoc]
-  (with-open [doc (common/load-pdf pdfdoc)]
+  (with-open [doc (common/obtain-document pdfdoc)]
     (let [catalog (.getDocumentCatalog doc)
           form (.getAcroForm catalog)
           fields (.getFields form)]
@@ -18,7 +18,7 @@
 (defn set-fields
   "fill in the fields with the values provided"
   [input output new-fields]
-  (with-open [doc (common/load-pdf input)]
+  (with-open [doc (common/obtain-document input)]
     (let [catalog (.getDocumentCatalog doc)
           form (.getAcroForm catalog)]
       (try
@@ -34,7 +34,7 @@
   the current form field names and values as the new names, and rename
   them"
   [input output fields-map]
-  (with-open [doc (common/load-pdf input)]
+  (with-open [doc (common/obtain-document input)]
     (let [catalog (.getDocumentCatalog doc)
           form (.getAcroForm catalog)]
       (doseq [field fields-map]
diff --git a/src/pdfboxing/info.clj b/src/pdfboxing/info.clj
index 5d6f4a6..0fec663 100644
--- a/src/pdfboxing/info.clj
+++ b/src/pdfboxing/info.clj
@@ -7,7 +7,7 @@
 (defn page-number
   "return number of pages of a PDF document"
   [pdfdoc]
-  (with-open [doc (common/load-pdf pdfdoc)]
+  (with-open [doc (common/obtain-document pdfdoc)]
     (.getNumberOfPages doc)))
 
 
@@ -28,7 +28,7 @@
              :or {keys ["title" "author" "subject" "keywords"
                         "creator" "producer" "trapped" "metadata-keys"
                         "creation-date" "modification-date"]}}]
-  (with-open [doc (common/load-pdf pdfdoc)]
+  (with-open [doc (common/obtain-document pdfdoc)]
     (let [info (.getDocumentInformation doc)
           info-fields keys]
       (into {}
@@ -37,13 +37,13 @@
 (defn metadata-value
   "get the value of a custom metadata information field for the document."
   [pdfdoc field-name]
-  (with-open [doc (common/load-pdf pdfdoc)]
+  (with-open [doc (common/obtain-document pdfdoc)]
     (.. doc getDocumentInformation (getCustomMetadataValue field-name))))
 
 (defn metadata-values
   "get all values of a custom metadata information field for the document."
   [pdfdoc]
-  (with-open [doc (common/load-pdf pdfdoc)]
+  (with-open [doc (common/obtain-document pdfdoc)]
     (let [info (.. doc getDocumentInformation)]
       (into {}
             (map #(hash-map (str %1) (.. info (getCustomMetadataValue %1)))
diff --git a/src/pdfboxing/split.clj b/src/pdfboxing/split.clj
index 3d630a6..3cb264a 100644
--- a/src/pdfboxing/split.clj
+++ b/src/pdfboxing/split.clj
@@ -46,7 +46,7 @@
   "split pdf into pages"
   [& {:keys [input start end split]}]
   {:pre [(arg-check input start end split)]}
-  (let [doc (common/load-pdf input)
+  (let [doc (common/obtain-document input)
         splitter (Splitter.)]
     (when start (.setStartPage splitter start))
     (when end (.setEndPage splitter end))
diff --git a/src/pdfboxing/text.clj b/src/pdfboxing/text.clj
index 731de74..f39f3cb 100644
--- a/src/pdfboxing/text.clj
+++ b/src/pdfboxing/text.clj
@@ -5,6 +5,6 @@
 (defn extract
   "get text from a PDF document"
   [pdfdoc]
-  (with-open [doc (common/load-pdf pdfdoc)]
+  (with-open [doc (common/obtain-document pdfdoc)]
     (let [stripper (new PDFTextStripper)]
       (.getText stripper doc))))


Test patch:
diff --git a/test/pdfboxing/common_test.clj b/test/pdfboxing/common_test.clj
index b98493f..1968601 100644
--- a/test/pdfboxing/common_test.clj
+++ b/test/pdfboxing/common_test.clj
@@ -6,3 +6,15 @@
   (testing "If document supplied is a PDF"
     (is (false? (is-pdf? "test/pdfs/a.txt")))
     (is (true? (is-pdf? "test/pdfs/hello.pdf")))))
+
+(deftest obtain-document-returns-pddocument-if-provided-string-check
+  (testing "obtain-document returns a PDDocument if a string path to a PDF is a supplied"
+    (is (true?  (instance?
+                   org.apache.pdfbox.pdmodel.PDDocument
+                   (obtain-document "test/pdfs/hello.pdf"))))))
+
+(deftest obtain-document-returns-pddocument-if-provided-pddocument-check
+  (testing "obtain-document returns a PDDocument if PDDocument is provided"
+    (is (true?  (instance?
+                   org.apache.pdfbox.pdmodel.PDDocument
+                   (obtain-document (obtain-document "test/pdfs/hello.pdf")))))))