render basic page/pdf options as css so they take effect in output pdfs
This commit is contained in:
parent
0b3ba9ccce
commit
48354a2ce9
|
@ -1,13 +1,18 @@
|
||||||
(ns clj-htmltopdf.core
|
(ns clj-htmltopdf.core
|
||||||
(:require
|
(:require
|
||||||
[clojure.java.io :as io]
|
[clojure.java.io :as io]
|
||||||
[hiccup.page :as h])
|
[clojure.string :as string]
|
||||||
|
[hiccup.page :as h]
|
||||||
|
[clj-htmltopdf.css :as css]
|
||||||
|
[clj-htmltopdf.options :as o])
|
||||||
(:import
|
(:import
|
||||||
[java.io OutputStream]
|
[java.io OutputStream]
|
||||||
[com.openhtmltopdf DOMBuilder]
|
[com.openhtmltopdf DOMBuilder]
|
||||||
[com.openhtmltopdf.pdfboxout PdfRendererBuilder]
|
[com.openhtmltopdf.pdfboxout PdfRendererBuilder]
|
||||||
[com.openhtmltopdf.util XRLog]
|
[com.openhtmltopdf.util XRLog]
|
||||||
[org.jsoup Jsoup]))
|
[org.jsoup Jsoup]
|
||||||
|
[org.jsoup.nodes Document Element]
|
||||||
|
[org.jsoup.parser Tag]))
|
||||||
|
|
||||||
(defn- read-html
|
(defn- read-html
|
||||||
[in]
|
[in]
|
||||||
|
@ -29,35 +34,36 @@
|
||||||
(catch Exception ex
|
(catch Exception ex
|
||||||
(throw (Exception. "Error preparing an OutputStream from output given." ex)))))
|
(throw (Exception. "Error preparing an OutputStream from output given." ex)))))
|
||||||
|
|
||||||
(defn- parse-html5
|
(defn- parse-jsoup-html
|
||||||
[^String html]
|
[^String html]
|
||||||
(try
|
(try
|
||||||
(let [parsed-doc (Jsoup/parse html)]
|
(Jsoup/parse html)
|
||||||
(DOMBuilder/jsoup2DOM parsed-doc))
|
|
||||||
(catch Exception ex
|
(catch Exception ex
|
||||||
(throw (Exception. "Error parsing input as HTML5." ex)))))
|
(throw (Exception. "Error parsing input HTML to Jsoup Document." ex)))))
|
||||||
|
|
||||||
(def default-options
|
(defn- set-jsoup-html-doc
|
||||||
{:logging? false
|
[^PdfRendererBuilder builder jsoup-doc base-uri]
|
||||||
:base-uri ""
|
(try
|
||||||
:include-base-css? true
|
(let [doc (DOMBuilder/jsoup2DOM jsoup-doc)]
|
||||||
:page {:size :letter
|
(.withW3cDocument builder doc base-uri))
|
||||||
:orientation :portrait}})
|
(catch Exception ex
|
||||||
|
(throw (Exception. "Error setting org.w3c.dom.Document HTML." ex)))))
|
||||||
|
|
||||||
(defn ->pdf
|
(defn ->pdf
|
||||||
[in out & [options]]
|
[in out & [options]]
|
||||||
(let [options (merge default-options options)
|
(let [options (merge o/default-options options)
|
||||||
builder (PdfRendererBuilder.)
|
builder (PdfRendererBuilder.)
|
||||||
base-uri (str (:base-uri options))
|
|
||||||
html (read-html in)
|
html (read-html in)
|
||||||
html-doc (parse-html5 html)
|
html-doc (parse-jsoup-html html)
|
||||||
|
html-doc (o/inject-options-into-html html-doc options)
|
||||||
output (->output-stream out)]
|
output (->output-stream out)]
|
||||||
|
html-doc
|
||||||
(if (:logging? options)
|
(if (:logging? options)
|
||||||
(let [logger (:logger options)]
|
(let [logger (:logger options)]
|
||||||
(if logger (XRLog/setLoggerImpl logger))
|
(if logger (XRLog/setLoggerImpl logger))
|
||||||
(XRLog/setLoggingEnabled true))
|
(XRLog/setLoggingEnabled true))
|
||||||
(XRLog/setLoggingEnabled false))
|
(XRLog/setLoggingEnabled false))
|
||||||
(.withW3cDocument builder html-doc base-uri)
|
(set-jsoup-html-doc builder html-doc (o/->base-uri options))
|
||||||
(with-open [os output]
|
(with-open [os output]
|
||||||
(.toStream builder os)
|
(.toStream builder os)
|
||||||
(try
|
(try
|
||||||
|
|
66
src/clj_htmltopdf/options.clj
Normal file
66
src/clj_htmltopdf/options.clj
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
(ns clj-htmltopdf.options
|
||||||
|
(:require
|
||||||
|
[clojure.java.io :as io]
|
||||||
|
[clojure.string :as string]
|
||||||
|
[clj-htmltopdf.css :as css])
|
||||||
|
(:import
|
||||||
|
[org.jsoup.nodes Document Element]
|
||||||
|
[org.jsoup.parser Tag]))
|
||||||
|
|
||||||
|
(def default-options
|
||||||
|
{:logging? false
|
||||||
|
:base-uri ""
|
||||||
|
:include-base-css? true
|
||||||
|
:page {:size :letter
|
||||||
|
:orientation :portrait
|
||||||
|
:margin "1.0in"}})
|
||||||
|
|
||||||
|
(defn ->base-uri
|
||||||
|
[options]
|
||||||
|
(str (:base-uri options)))
|
||||||
|
|
||||||
|
(defn ->page-size-css
|
||||||
|
[{:keys [size orientation] :as page-options}]
|
||||||
|
(if (or size orientation)
|
||||||
|
(string/trim
|
||||||
|
(str
|
||||||
|
(cond
|
||||||
|
(keyword? size) (name size)
|
||||||
|
(sequential? size) (string/join " " size)
|
||||||
|
:else size)
|
||||||
|
" "
|
||||||
|
(if (keyword? orientation)
|
||||||
|
(name orientation)
|
||||||
|
orientation)))))
|
||||||
|
|
||||||
|
(defn page-options->css
|
||||||
|
[page-options]
|
||||||
|
(let [styles (->> [[:size (->page-size-css page-options)]]
|
||||||
|
(into [])
|
||||||
|
(remove #(nil? (second %)))
|
||||||
|
(reduce #(assoc %1 (first %2) (second %2)) {}))]
|
||||||
|
[["@page" styles]]))
|
||||||
|
|
||||||
|
(defn append-page-options-style-tag
|
||||||
|
^Element [^Element parent options]
|
||||||
|
(let [styles (-> (:page options)
|
||||||
|
(page-options->css)
|
||||||
|
(css/css->str))
|
||||||
|
element (.appendElement parent "style")]
|
||||||
|
(.attr element "type" "text/css")
|
||||||
|
(.text element styles)))
|
||||||
|
|
||||||
|
(defn append-base-css-link-tag
|
||||||
|
^Element [^Element parent]
|
||||||
|
(let [element (.appendElement parent "link")]
|
||||||
|
(.attr element "type" "text/css")
|
||||||
|
(.attr element "rel" "stylesheet")
|
||||||
|
(.attr element "href" (str (io/resource "htmltopdf-base.css")))))
|
||||||
|
|
||||||
|
(defn inject-options-into-html
|
||||||
|
[^Document doc options]
|
||||||
|
(let [base-uri (->base-uri options)
|
||||||
|
head-tag (-> doc (.select "head") (.first))]
|
||||||
|
(append-page-options-style-tag head-tag options)
|
||||||
|
(if (:include-base-css? options) (append-base-css-link-tag head-tag))
|
||||||
|
doc))
|
Loading…
Reference in a new issue