Clojureでイメージファイルのリサイズ
思ったより処理速度早かった。リアルタイムな処理中でも使えそう。
出力はJpegだけですが、ちょっといじれば拡張できます。ImageIOが対応している形式なら出力できると思う。
(ns resize-image (:import [java.awt.image BufferedImage] [java.awt Image] [javax.imageio IIOImage ImageIO ImageWriteParam] [javax.imageio.plugins.jpeg JPEGImageWriteParam])) (defn- read-image [file-path] (ImageIO/read (java.io.File. file-path))) (defn- get-jpeg-param [] (doto (JPEGImageWriteParam. (java.util.Locale/getDefault)) (.setCompressionMode ImageWriteParam/MODE_EXPLICIT) (.setCompressionQuality 1.0))) (defn- get-jpeg-writer [] (.. (ImageIO/getImageWritersByFormatName "jpg") next)) (defn- write-jpeg-image [file-path image] (let [param (get-jpeg-param) file (java.io.File. file-path) out (ImageIO/createImageOutputStream file)] (doto (get-jpeg-writer) (.setOutput out) (.write nil (IIOImage. image nil nil) param) (.dispose)) (doto out (.flush) (.close)) file)) (defn #^{:doc "イメージデータのリサイズ. アスペクト比を保ったままリサイズを行う. src-image: リサイズ対象のImageオブジェクト. rate: 拡大縮小率."} resize-image [src-image rate] (let [width (* rate (.getWidth src-image)) height (* rate (.getHeight src-image)) dest-image (BufferedImage. width height (.getType src-image)) scaled-image (.getScaledInstance src-image width height Image/SCALE_AREA_AVERAGING)] (doto (.getGraphics dest-image) (.drawImage scaled-image 0 0 width height nil)) dest-image)) (defn #^{:doc "イメージデータのリサイズ及び、ファイルへの書き出し. イメージの長辺を基準にリサイズを行う.幅方向の方が長ければ out-width, 高さ方向の方が長ければ out-height にあわせてイメージのリサイズを行い, out-fileへ書き出す。評価値はイメージを書き出したFileオブジェクト."} resize-image-file [src-file out-file out-width out-height] (let [[out-width out-height] (map float [out-width out-height]) image (read-image src-file) [width height] ((juxt #(.getWidth %) #(.getHeight %)) image) rate (if (< width height) (/ out-height height) (/ out-width width)) resized-image (resize-image image rate)] (write-jpeg-image out-file resized-image)))
余談だけど、emacs + clojure-mode で関数のメタデータ書くとその後に続く「関数名」と「関数内の最初のS式」のインデントが同じ高さになってしまうな。ちょっと気持ち悪い。