Logic related to creating image bundles, and some predefined ones. An image bundle contains the data needed to
either encode the image inline in a URL (when | (ns metabase.channel.render.image-bundle (:require [clojure.java.io :as io]) (:import (java.util Arrays) (org.apache.commons.io IOUtils) (org.fit.cssbox.misc Base64Coder))) |
(set! *warn-on-reflection* true) | |
Generate a hash to be used in a Content-ID | (defn- hash-bytes [^bytes img-bytes] (Math/abs ^Integer (Arrays/hashCode img-bytes))) |
Generate a hash to be used in a Content-ID | (defn- hash-image-url [^java.net.URL url] (-> url io/input-stream IOUtils/toByteArray hash-bytes)) |
(defn- content-id-reference [content-id] (str "cid:" content-id)) | |
(defn- mb-hash-str [image-hash] (str image-hash "@metabase")) | |
(defn- write-byte-array-to-temp-file [^bytes img-bytes] (let [f (doto (java.io.File/createTempFile "metabase_channel_image_" ".png") .deleteOnExit)] (with-open [fos (java.io.FileOutputStream. f)] (.write fos img-bytes)) f)) | |
(defn- byte-array->url [^bytes img-bytes] (-> img-bytes write-byte-array-to-temp-file io/as-url)) | |
Takes a PNG byte array and returns a Base64 encoded URI | (defn render-img-data-uri [img-bytes] (str "data:image/png;base64," (String. (Base64Coder/encode img-bytes)))) |
Create an image bundle. An image bundle contains the data needed to either encode the image inline (when
| (defmulti make-image-bundle {:arglists '([render-type url-or-bytes])} (fn [render-type url-or-bytes] [render-type (class url-or-bytes)])) |
(defmethod make-image-bundle [:attachment java.net.URL] [render-type, ^java.net.URL url] (let [content-id (mb-hash-str (hash-image-url url))] {:content-id content-id :image-url url :image-src (content-id-reference content-id) :render-type render-type})) | |
(defmethod make-image-bundle [:attachment (class (byte-array 0))] [render-type image-bytes] (let [image-url (byte-array->url image-bytes) content-id (mb-hash-str (hash-bytes image-bytes))] {:content-id content-id :image-url image-url :image-src (content-id-reference content-id) :render-type render-type})) | |
(defmethod make-image-bundle [:inline java.net.URL] [render-type, ^java.net.URL url] {:image-src (-> url io/input-stream IOUtils/toByteArray render-img-data-uri) :image-url url :render-type render-type}) | |
(defmethod make-image-bundle [:inline (Class/forName "[B")] [render-type image-bytes] {:image-src (render-img-data-uri image-bytes) :render-type render-type}) | |
(def ^:private external-link-url (io/resource "frontend_client/app/assets/img/external_link.png")) (def ^:private no-results-url (io/resource "frontend_client/app/assets/img/no_results.png")) (def ^:private attached-url (io/resource "frontend_client/app/assets/img/attachment@2x.png")) | |
(def ^:private external-link-image (delay (make-image-bundle :attachment external-link-url))) | |
(def ^:private no-results-image (delay (make-image-bundle :attachment no-results-url))) | |
(def ^:private attached-image (delay (make-image-bundle :attachment attached-url))) | |
Image bundle for an external link icon. | (defn external-link-image-bundle [render-type] (case render-type :attachment @external-link-image :inline (make-image-bundle render-type external-link-url))) |
Image bundle for the 'No results' image. | (defn no-results-image-bundle [render-type] (case render-type :attachment @no-results-image :inline (make-image-bundle render-type no-results-url))) |
Image bundle for paperclip 'attachment' image. | (defn attached-image-bundle [render-type] (case render-type :attachment @attached-image :inline (make-image-bundle render-type attached-url))) |
Convert an image bundle into an email attachment. | (defn image-bundle->attachment [{:keys [render-type content-id image-url]}] (case render-type :attachment {content-id image-url} :inline nil)) |