move watermark functionality to separate namespace

This commit is contained in:
Gered 2017-08-16 18:46:31 -04:00
parent aa4a9fa302
commit 37bbe3f398
2 changed files with 74 additions and 68 deletions

View file

@ -2,18 +2,13 @@
(:require
[clojure.java.io :as io]
[hiccup.page :as h]
[clj-htmltopdf.options :as o])
[clj-htmltopdf.options :as o]
[clj-htmltopdf.watermark :as w])
(:import
[java.awt.geom Point2D$Float]
[java.io InputStream OutputStream PipedInputStream PipedOutputStream]
[com.openhtmltopdf DOMBuilder]
[com.openhtmltopdf.pdfboxout PdfRendererBuilder]
[com.openhtmltopdf.util XRLog]
[org.apache.pdfbox.pdmodel PDDocument PDPage PDPageContentStream PDPageContentStream$AppendMode]
[org.apache.pdfbox.pdmodel.common PDRectangle]
[org.apache.pdfbox.pdmodel.font PDType1Font PDFont]
[org.apache.pdfbox.pdmodel.graphics.state PDExtendedGraphicsState]
[org.apache.pdfbox.util Matrix]
[org.jsoup Jsoup]
[org.jsoup.nodes Document]))
@ -52,7 +47,7 @@
html-doc))
(defn write-pdf!
[^Document html-doc ^String base-uri]
^InputStream [^Document html-doc ^String base-uri]
(let [builder (PdfRendererBuilder.)]
(.withW3cDocument builder (DOMBuilder/jsoup2DOM html-doc) base-uri)
(let [piped-in (PipedInputStream.)
@ -63,71 +58,15 @@
(.run builder)))
piped-in)))
(def watermark-fonts
{"times-roman" PDType1Font/TIMES_ROMAN
"times-bold" PDType1Font/TIMES_BOLD
"times-italic" PDType1Font/TIMES_ITALIC
"times-bolditalic" PDType1Font/TIMES_BOLD_ITALIC
"helvetica" PDType1Font/HELVETICA
"helvetica-bold" PDType1Font/HELVETICA_BOLD
"helvetica-oblique" PDType1Font/HELVETICA_OBLIQUE
"helvetica-boldoblique" PDType1Font/HELVETICA_BOLD_OBLIQUE
"courier" PDType1Font/COURIER
"courier-bold" PDType1Font/COURIER_BOLD
"courier-oblique" PDType1Font/COURIER_OBLIQUE
"courier-boldoblique" PDType1Font/COURIER_BOLD_OBLIQUE})
(defn render-watermark!
[^PDPage page ^PDPageContentStream cs options]
(let [font (or (get watermark-fonts (:font options))
(get watermark-fonts "helvetica-bold"))
font-size (float (or (:font-size options) 36.0))
font-color (or (:color options) [0 0 0])
text (:text options)
text-width (/ (* (.getStringWidth font text) font-size) 1000.0)
text-height (/ (* (.getHeight (.getFontBoundingBox (.getFontDescriptor ^PDFont font))) font-size) 1000.0)
rotation (float (or (:rotation options) 0))
page-size (.getMediaBox page)
page-width (.getWidth page-size)
page-height (.getHeight page-size)
x (if (= :center (:x options)) (/ page-width 2) (float (:x options)))
y (if (= :center (:y options)) (/ page-height 2) (float (:y options)))
transform (doto (Matrix.)
(.translate x y)
(.rotate (Math/toRadians rotation))
(.translate (- (/ text-width 2)) (- (/ text-height 2))))]
(when (:opacity options)
(let [r0 (PDExtendedGraphicsState.)]
(.setNonStrokingAlphaConstant r0 (float (:opacity options)))
(.setGraphicsStateParameters cs r0)))
(.beginText cs)
(.setFont cs font font-size)
(.setNonStrokingColor cs (int (nth font-color 0)) (int (nth font-color 1)) (int (nth font-color 2)))
(.setTextMatrix cs transform)
(.showText cs text)
(.endText cs)))
(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! page cs watermark)
(watermark page cs)))))
(.save doc out)
out))
(defn ->pdf
[in out & [options]]
(let [options (o/get-final-options options)
html-doc (prepare-html in options)]
(configure-logging! options)
(let [result (write-pdf! html-doc (o/->base-uri options))
(let [pdf (write-pdf! html-doc (o/->base-uri options))
out (->output-stream out)]
(if (:watermark options)
(write-watermark! result out options)
(w/write-watermark! pdf out options)
(with-open [os out]
(io/copy result os)
(io/copy pdf os)
os)))))

View file

@ -0,0 +1,67 @@
(ns clj-htmltopdf.watermark
(:import
[java.io InputStream OutputStream]
[org.apache.pdfbox.pdmodel PDDocument PDPage PDPageContentStream PDPageContentStream$AppendMode]
[org.apache.pdfbox.pdmodel.common PDRectangle]
[org.apache.pdfbox.pdmodel.font PDType1Font PDFont]
[org.apache.pdfbox.pdmodel.graphics.state PDExtendedGraphicsState]
[org.apache.pdfbox.util Matrix]))
; 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()
(def watermark-fonts
{"times-roman" PDType1Font/TIMES_ROMAN
"times-bold" PDType1Font/TIMES_BOLD
"times-italic" PDType1Font/TIMES_ITALIC
"times-bolditalic" PDType1Font/TIMES_BOLD_ITALIC
"helvetica" PDType1Font/HELVETICA
"helvetica-bold" PDType1Font/HELVETICA_BOLD
"helvetica-oblique" PDType1Font/HELVETICA_OBLIQUE
"helvetica-boldoblique" PDType1Font/HELVETICA_BOLD_OBLIQUE
"courier" PDType1Font/COURIER
"courier-bold" PDType1Font/COURIER_BOLD
"courier-oblique" PDType1Font/COURIER_OBLIQUE
"courier-boldoblique" PDType1Font/COURIER_BOLD_OBLIQUE})
(defn render-watermark!
[^PDPage page ^PDPageContentStream cs options]
(let [font (or (get watermark-fonts (:font options))
(get watermark-fonts "helvetica-bold"))
font-size (float (or (:font-size options) 36.0))
font-color (or (:color options) [0 0 0])
text (:text options)
text-width (/ (* (.getStringWidth font text) font-size) 1000.0)
text-height (/ (* (.getHeight (.getFontBoundingBox (.getFontDescriptor ^PDFont font))) font-size) 1000.0)
rotation (float (or (:rotation options) 0))
page-size (.getMediaBox page)
page-width (.getWidth page-size)
page-height (.getHeight page-size)
x (if (= :center (:x options)) (/ page-width 2) (float (:x options)))
y (if (= :center (:y options)) (/ page-height 2) (float (:y options)))
transform (doto (Matrix.)
(.translate x y)
(.rotate (Math/toRadians rotation))
(.translate (- (/ text-width 2)) (- (/ text-height 2))))]
(when (:opacity options)
(let [r0 (PDExtendedGraphicsState.)]
(.setNonStrokingAlphaConstant r0 (float (:opacity options)))
(.setGraphicsStateParameters cs r0)))
(.beginText cs)
(.setFont cs font font-size)
(.setNonStrokingColor cs (int (nth font-color 0)) (int (nth font-color 1)) (int (nth font-color 2)))
(.setTextMatrix cs transform)
(.showText cs text)
(.endText cs)))
(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! page cs watermark)
(watermark page cs)))))
(.save doc out)
out))