render basic page/pdf options as css so they take effect in output pdfs

This commit is contained in:
Gered 2017-04-02 12:07:00 -04:00
parent 0b3ba9ccce
commit 48354a2ce9
2 changed files with 88 additions and 16 deletions

View file

@ -1,13 +1,18 @@
(ns clj-htmltopdf.core
(:require
[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
[java.io OutputStream]
[com.openhtmltopdf DOMBuilder]
[com.openhtmltopdf.pdfboxout PdfRendererBuilder]
[com.openhtmltopdf.util XRLog]
[org.jsoup Jsoup]))
[org.jsoup Jsoup]
[org.jsoup.nodes Document Element]
[org.jsoup.parser Tag]))
(defn- read-html
[in]
@ -29,35 +34,36 @@
(catch Exception ex
(throw (Exception. "Error preparing an OutputStream from output given." ex)))))
(defn- parse-html5
(defn- parse-jsoup-html
[^String html]
(try
(let [parsed-doc (Jsoup/parse html)]
(DOMBuilder/jsoup2DOM parsed-doc))
(Jsoup/parse html)
(catch Exception ex
(throw (Exception. "Error parsing input as HTML5." ex)))))
(throw (Exception. "Error parsing input HTML to Jsoup Document." ex)))))
(def default-options
{:logging? false
:base-uri ""
:include-base-css? true
:page {:size :letter
:orientation :portrait}})
(defn- set-jsoup-html-doc
[^PdfRendererBuilder builder jsoup-doc base-uri]
(try
(let [doc (DOMBuilder/jsoup2DOM jsoup-doc)]
(.withW3cDocument builder doc base-uri))
(catch Exception ex
(throw (Exception. "Error setting org.w3c.dom.Document HTML." ex)))))
(defn ->pdf
[in out & [options]]
(let [options (merge default-options options)
(let [options (merge o/default-options options)
builder (PdfRendererBuilder.)
base-uri (str (:base-uri options))
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)]
html-doc
(if (:logging? options)
(let [logger (:logger options)]
(if logger (XRLog/setLoggerImpl logger))
(XRLog/setLoggingEnabled true))
(XRLog/setLoggingEnabled false))
(.withW3cDocument builder html-doc base-uri)
(set-jsoup-html-doc builder html-doc (o/->base-uri options))
(with-open [os output]
(.toStream builder os)
(try

View 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))