3

I'd like to go through a directory and pick out all the images and then do some things based on their dimensions. What libraries are available for me to do this?

I'm working in Clojure but anything available on the JVM is fair game.

Thanks in advance!

Tim Visher
  • 12,786
  • 16
  • 58
  • 66

3 Answers3

8
(with-open [r (java.io.FileInputStream. "test.jpeg")]
  (let [image (javax.imageio.ImageIO/read r)]
    [(.getWidth image) (.getHeight image)]))

You can use with-open to have the stream closed automatically.

Here is an example of using to iterate through some number of files in a directory. It assumes all the files in the directory are images. The example directory only contains your stackoverflow avatar.

(defn files-in-dir [dir]
  (filter #(not (.isDirectory %))
          (.listFiles (java.io.File. dir))))

(defn figure-out-height-width
  [files]
  (map (fn [file]
         (with-open [r (java.io.FileInputStream. file)]
           (let [img (javax.imageio.ImageIO/read r)]
             [file (.getWidth img) (.getHeight img)])))
       files))

user>(figure-out-height-width (files-in-dir "/home/jmccrary/Downloads/pics/"))
([#<File /home/jmccrary/Downloads/pics/test.jpeg> 32 32])
Jake McCrary
  • 1,180
  • 9
  • 8
3

Package javax.io is what you're looking for.

(import 'java.io.File)
(import 'java.io.FileInputStream)
(import 'javax.imageio.ImageIO)

(def img  (ImageIO/read (FileInputStream. (File. "myfile.png"))))

[ (.getWidth img) (.getHeight img)]
  • Works for both png and jpg files.
  • This was posted in a hurry. There are more more idiomatic ways to open a file and get an InputStream in Clojure.
Leonel
  • 28,541
  • 26
  • 76
  • 103
  • Thank you. That's exactly what I was looking for. Could you provide the more idiomatic ways to accomplish this? I'm running into Heap issues with fairly small numbers of files, I suspect because streams aren't getting closed. – Tim Visher Nov 18 '10 at 19:35
0

Perhaps a more efficient answer could be

(ns common.image
  (:require [clojure.java.io :as io])
  (:import (javax.imageio ImageIO)))

(defn dimensions [src]
  (let [res (if (string? src) (io/file (io/resource src)) src)]
    (if res
      (let [image-input-stream (ImageIO/createImageInputStream res)
            readers (ImageIO/getImageReaders image-input-stream)]
        (if-let [r (and (.hasNext readers) (.next readers))]
          (try
            (.setInput r image-input-stream)
            [(.getWidth r 0) (.getHeight r 0)]
            (finally
              (.dispose r)))))
      [0 0])))

This doesn't require to read the whole image into memory.

Adapted from https://stackoverflow.com/a/1560052

Light-wharf
  • 147
  • 1
  • 7
  • I could not get your initial version to work (https://gist.github.com/timvisher/f1a92e005fd70cdf4ece3f7bd5b0e306#file-original-version-clj). I think this is because it assumes that a string arg is a resource. This version works (for my use case at least) https://gist.github.com/timvisher/f1a92e005fd70cdf4ece3f7bd5b0e306#file-working-version-clj – Tim Visher Jun 28 '19 at 12:37