diff --git a/src/clj_htmltopdf/core.clj b/src/clj_htmltopdf/core.clj index e4f9fef..8f85d0a 100644 --- a/src/clj_htmltopdf/core.clj +++ b/src/clj_htmltopdf/core.clj @@ -2,6 +2,7 @@ (:require [clojure.java.io :as io] [hiccup.page :as h] + [clj-htmltopdf.objects :as obj] [clj-htmltopdf.options :as o] [clj-htmltopdf.watermark :as w]) (:import @@ -45,15 +46,20 @@ html-doc)) (defn write-pdf! - ^InputStream [^Document html-doc ^String base-uri] - (let [builder (PdfRendererBuilder.)] + ^InputStream [^Document html-doc options] + (let [builder (PdfRendererBuilder.) + base-uri (o/->base-uri options)] + (obj/set-object-drawer-factory builder options) (.withW3cDocument builder (DOMBuilder/jsoup2DOM html-doc) base-uri) (let [piped-in (PipedInputStream.) piped-out (PipedOutputStream. piped-in)] (future - (with-open [os piped-out] - (.toStream builder os) - (.run builder))) + (try + (with-open [os piped-out] + (.toStream builder os) + (.run builder)) + (catch Exception ex + (println "Exception while rendering PDF" ex)))) piped-in))) (defn ->pdf @@ -61,7 +67,7 @@ (let [options (o/get-final-options options) html-doc (prepare-html in options)] (configure-logging! options) - (let [pdf (write-pdf! html-doc (o/->base-uri options)) + (let [pdf (write-pdf! html-doc options) out (->output-stream out)] (if (:watermark options) (w/write-watermark! pdf out options) diff --git a/src/clj_htmltopdf/objects.clj b/src/clj_htmltopdf/objects.clj new file mode 100644 index 0000000..86e6c89 --- /dev/null +++ b/src/clj_htmltopdf/objects.clj @@ -0,0 +1,47 @@ +(ns clj-htmltopdf.objects + (:require + [clojure.string :as string]) + (:import + [com.openhtmltopdf.extend FSObjectDrawer FSObjectDrawerFactory OutputDevice OutputDeviceGraphicsDrawer] + [com.openhtmltopdf.pdfboxout PdfRendererBuilder] + [org.w3c.dom Element NamedNodeMap])) + +(defn element-attrs->map + [^Element element] + (let [attributes (.getAttributes element)] + (reduce + (fn [m idx] + (let [node (.item attributes (int idx)) + name (.getNodeName node) + value (.getNodeValue node)] + (assoc m (keyword name) value))) + {} + (range (.getLength attributes))))) + +(defn ->object-drawer-by-id + ^FSObjectDrawer [f] + (reify FSObjectDrawer + (drawObject [_ element x y width height output-device rendering-context dots-per-pixel] + (.drawWithGraphics + ^OutputDevice output-device + (float x) + (float y) + (float (/ width dots-per-pixel)) + (float (/ height dots-per-pixel)) + (reify OutputDeviceGraphicsDrawer + (render [_ graphics2d] + (f (element-attrs->map element) graphics2d))))))) + +(defn ->object-drawer-by-id-factory + ^FSObjectDrawerFactory [options] + (reify FSObjectDrawerFactory + (^FSObjectDrawer createDrawer [_ ^Element element] + (if (.hasAttribute element "id") + (let [element-id (.getAttribute element "id")] + (if-let [f (get-in options [:objects :by-id element-id])] + (->object-drawer-by-id f))))))) + +(defn set-object-drawer-factory + [^PdfRendererBuilder builder options] + (let [factory (->object-drawer-by-id-factory options)] + (.useObjectDrawerFactory builder factory)))