(require '[clojure.java.io :as io])
(defn- write-jpeg-with-compression-quality
[^java.awt.image.BufferedImage image ^java.io.File output-file ^double quality]
{:pre [(<= 0.0 quality 1.0)]}
(with-open [ios (javax.imageio.ImageIO/createImageOutputStream output-file)]
(let [w (.next (javax.imageio.ImageIO/getImageWritersByFormatName "jpg"))]
(.setOutput w ios)
(.write w
nil
(javax.imageio.IIOImage. image nil nil)
;; javax.imageio.ImageIO/write でも同じ様にフォーマットを指定して書き込めるけど
;; jpeg とかフォーマット毎のパラメタの指定はできない
(doto (javax.imageio.plugins.jpeg.JPEGImageWriteParam. (java.util.Locale/getDefault))
(.setCompressionMode javax.imageio.ImageWriteParam/MODE_EXPLICIT)
(.setCompressionQuality quality)))
(.flush ios)
(.dispose w))))
(-> (java.net.URL. "https://upload.wikimedia.org/wikipedia/commons/d/de/Shanghai_montage.png")
javax.imageio.ImageIO/read
(write-jpeg-with-compression-quality (io/file "/tmp/out.jpg") 0.8))
(defn- jpeg-byte-array-output-stream-with-compression-quality
[^java.awt.image.BufferedImage image ^double quality]
{:pre [(<= 0.0 quality 1.0)]}
(let [bos (java.io.ByteArrayOutputStream.)]
(with-open [ios (javax.imageio.ImageIO/createImageOutputStream bos)]
(let [w (.next (javax.imageio.ImageIO/getImageWritersByFormatName "jpg"))]
(.setOutput w ios)
(.write w
nil
(javax.imageio.IIOImage. image nil nil)
(doto (javax.imageio.plugins.jpeg.JPEGImageWriteParam. (java.util.Locale/getDefault))
(.setCompressionMode javax.imageio.ImageWriteParam/MODE_EXPLICIT)
(.setCompressionQuality quality)))
(.flush ios)
(.dispose w)))
bos))
;;; ファイルサイズの上限を決めて画質を落す場合
(def upper-limit 500000)
;;; 画質がどこまで落るか見てみる
;;; これだと、何度も画像をダウンロードするので良くないけど、サンプルなので簡単に書いておく
;;; ディスクにあるファイルなら気にしなくていい
(->> (iterate #(- % 0.1) 0.9)
(take 5)
(keep #(let [bos (-> (java.net.URL. "https://upload.wikimedia.org/wikipedia/commons/d/de/Shanghai_montage.png")
javax.imageio.ImageIO/read
(jpeg-byte-array-output-stream-with-compression-quality %))]
(when (< (.size bos) upper-limit)
[% (.size bos)])))
first)
;; => [0.7000000000000001 444917]
;;; 書き込んでみる
(when-let [bos (->> (iterate #(- % 0.1) 0.9)
(take 5)
(keep #(let [bos (-> (java.net.URL. "https://upload.wikimedia.org/wikipedia/commons/d/de/Shanghai_montage.png")
javax.imageio.ImageIO/read
(jpeg-byte-array-output-stream-with-compression-quality %))]
(when (< (.size bos) upper-limit)
bos)))
first)]
(with-open [os (io/output-stream (io/file "/tmp/out.jpg"))]
(.writeTo bos os)))