I'm looking for a way to let a ring server - by request - grab an image from an URL, process it and serve the modified version.
This is how I got so far:
(require '[clj-http.client :as client]
'[ring.adapter.jetty :refer [run-jetty])
(import javax.imageio.ImageIO)
(def handler (-> (client/get "http://.../some-img.jpg" {:as :stream})
:body
ImageIO/read
.. ;; do some processing with the BufferedImage here
.. ;; and serve the modified version))
(run-jetty handler {:port 55555})
Especially I'm having troubles performing the last step inside the threading macro.
To return bytes as the response in Ring you need to provide either java.io.File
or java.io.InputStream
as the body content:
(defn jpeg-response [image-data]
(-> image-data
(ring.util.response/response)
(ring.util.response/content-type "image/jpeg")))
I haven't found a way to obtain an InputStream
from BufferedImage
directly without creating an intermediate byte arrays. Maybe this is a limitation of the Java Image API due to complexity required to implement a "pull" approach to get a stream of image bytes in the desired format.
Instead there is a "push" API where ImageIO.write
method requires some kind of output for image bytes. It might be a java.io.File
or java.io.OutputStream
. Thus you need to first store the bytes somewhere (java.io.File
or java.io.ByteArrayOutputStream
) and then use them as your response body:
With file (so storing the image on the disk first - you need to remember to clean it up):
(let [image (ImageIO/read "...")
image-file (java.io.File. "...")]
(ImageIO/write image "jpg" image-file)
(jpeg-response image-file))
In-memory byte array:
(let [image (ImageIO/read "...")
image-output-stream (ByteArrayOutputStream.)]
(ImageIO/write image "jpg" image-output-stream)
(jpeg-response (ByteArrayInputStream. (.toByteArray image-output-stream))))