diff --git a/src/clj_htmltopdf/watermark.clj b/src/clj_htmltopdf/watermark.clj
index 941b27f..3d66d0e 100644
--- a/src/clj_htmltopdf/watermark.clj
+++ b/src/clj_htmltopdf/watermark.clj
@@ -2,7 +2,7 @@
(:require
[clojure.java.io :as io])
(:import
- [java.io InputStream OutputStream]
+ [java.io File InputStream OutputStream]
[org.apache.pdfbox.pdmodel PDDocument PDPage PDPageContentStream PDPageContentStream$AppendMode]
[org.apache.pdfbox.pdmodel.common PDRectangle]
[org.apache.pdfbox.pdmodel.font PDType1Font PDFont]
@@ -10,6 +10,24 @@
[org.apache.pdfbox.pdmodel.graphics.state PDExtendedGraphicsState]
[org.apache.pdfbox.util Matrix]))
+(declare ^:dynamic *pdf-images*)
+
+(defn create-pdf-image
+ "Creates an XObject image from an image file. Caches this XObject for this particular PDF document so that if the
+ image is rendered into the PDF multiple times, the PDF will reference the same image instead of creating duplicates
+ (which would potentially bump up the file size drastically).
+ This function must only be called from within code invoked by write-watermark!."
+ ^PDImageXObject [file ^PDDocument doc]
+ (if-not *pdf-images*
+ (throw (ex-info "Could not create PDF XObject image. Image cache has not been initialized." {:file file})))
+ (let [image-file (io/file file)
+ path (.getPath image-file)]
+ (if-let [existing-image (get @*pdf-images* path)]
+ existing-image
+ (let [image (PDImageXObject/createFromFileByContent image-file doc)]
+ (swap! *pdf-images* assoc path image)
+ image))))
+
; TODO: this is a temporary measure to allow at least _some_ font customizability for watermarks
; until something more comprehensive can be implemented such as allowing loading of external
; TTF fonts via PDTrueTypeFont.loadTTF()
@@ -59,7 +77,7 @@
(defn render-image-watermark!
[^PDDocument doc ^PDPage page ^PDPageContentStream cs options]
- (let [image (PDImageXObject/createFromFileByContent (io/file (:image options)) doc)
+ (let [image (create-pdf-image (:image options) doc)
image-width (.getWidth image)
image-height (.getHeight image)
rotation (float (or (:rotation options) 0))
@@ -90,11 +108,12 @@
(defn write-watermark!
[^InputStream pdf ^OutputStream out {:keys [watermark] :as options}]
(with-open [doc (PDDocument/load pdf)]
- (doseq [^PDPage page (.getPages doc)]
- (let [cs (PDPageContentStream. doc page PDPageContentStream$AppendMode/APPEND true true)]
- (with-open [cs cs]
- (if (map? watermark)
- (render-watermark! doc page cs watermark)
- (watermark doc page cs)))))
+ (binding [*pdf-images* (atom {})]
+ (doseq [^PDPage page (.getPages doc)]
+ (let [cs (PDPageContentStream. doc page PDPageContentStream$AppendMode/APPEND true true)]
+ (with-open [cs cs]
+ (if (map? watermark)
+ (render-watermark! doc page cs watermark)
+ (watermark doc page cs))))))
(.save doc out)
out))