EXIF Metadata Extraction in Clojure

by 1/08/2010 12:28:00 PM 0 comments

EXIF Metadata Extraction in Clojure

Since I've been playing around with Clojure lately, I thought I'd port the Groovy and Scala versions of the EXIF metadata extraction code to Clojure. Here's some things I ran into with Clojure:
  • Have to admit, although I'm very new at the Lisp syntax, Clojure is kinda fun to work with. As with both Groovy and Scala it's nice to have a REPL to test out new ideas out. The Clojure REPL's built in help (e.g. (doc instance?) and (find-doc "instance") is a very nice touch.
  • I'm not a fan of the numerous parenthesis, I suppose I'm just used to the curly brackets. I find it's hard to visualize the scope of variables. A text editor with nice bracket matching helps though (Sorry TextMate, I had to use jEdit for Clojure work)
  • Writing a script still left me jonesing for an equivalent to Grape
  • The clj script used in the shebang line, posted on Wikibooks, was wrong. Took me a little bit to figure out what was going on. I fixed the script on Wikibooks.
  • I couldn't figure out how to neatly embed the classpath info, so I had to launch it with clj -cp /path/to/sanselan-0.97.jar readexif.clj /path/to/image.jpg
  • I have absolutely no idea how to indent Clojure/Lisp code
And the code:
#! /usr/bin/env clj

  '(java.io File)
  '(org.apache.sanselan ImageReadException Sanselan)
  '(org.apache.sanselan.common IImageMetadata, RationalNumber)
  '(org.apache.sanselan.formats.jpeg JpegImageMetadata)
  '(org.apache.sanselan.formats.tiff TiffField TiffImageMetadata)
  '(org.apache.sanselan.formats.tiff.constants ExifTagConstants GPSTagConstants TagInfo TiffConstants TiffTagConstants))
(defn print-tag-value [metadata tagInfo]
  (let [field  (. metadata findEXIFValue tagInfo)]
    (if (nil? field) 
      (println (str "        (" (. tagInfo name) " not found.)"))
      (println (str "        (" (. tagInfo name) ": " (. field getValueDescription))))))
(defn readexif [file]
  (let [metadata (Sanselan/getMetadata file)]
    (if (nil? metadata) (println "\tNo EXIF metdata was found"))
    (if (instance? JpegImageMetadata metadata)
        (println "  -- Standard EXIF Tags")
        (print-tag-value metadata (TiffTagConstants/TIFF_TAG_XRESOLUTION))
        (print-tag-value metadata (TiffTagConstants/TIFF_TAG_DATE_TIME))
        (print-tag-value metadata (ExifTagConstants/EXIF_TAG_DATE_TIME_ORIGINAL))
        (print-tag-value metadata (ExifTagConstants/EXIF_TAG_CREATE_DATE))
        (print-tag-value metadata (ExifTagConstants/EXIF_TAG_ISO))
        (print-tag-value metadata (ExifTagConstants/EXIF_TAG_SHUTTER_SPEED_VALUE))
        (print-tag-value metadata (ExifTagConstants/EXIF_TAG_APERTURE_VALUE))
        (print-tag-value metadata (ExifTagConstants/EXIF_TAG_BRIGHTNESS_VALUE))
        (print-tag-value metadata (GPSTagConstants/GPS_TAG_GPS_LATITUDE_REF))
        (print-tag-value metadata (GPSTagConstants/GPS_TAG_GPS_LATITUDE))
        (print-tag-value metadata (GPSTagConstants/GPS_TAG_GPS_LONGITUDE_REF))
        (print-tag-value metadata (GPSTagConstants/GPS_TAG_GPS_LONGITUDE_REF))
        ; simple interface to GPS data
        (println "  -- GPS Info")
        (let [exifMetadata (. metadata getExif)]
          (if (false? (nil? exifMetadata)) 
              (let [gpsInfo (. exifMetadata getGPS)]
                (if (false? (nil? gpsInfo))
                  (let [longitude (. gpsInfo getLongitudeAsDegreesEast)
                        latitude (. gpsInfo getLatitudeAsDegreesNorth)]
                    (println (str "        GPS Description: " gpsInfo))
                    (println (str "        GPS Longitude (Degrees East):" longitude))
                    (println (str "        GPS Latitude (Degrees North):" latitude))))))))
         ; Print all EXIF data
         (println "  -- All EXIF info")
         (doseq [item (. metadata getItems)]
           (println (str "        " item)))
         (println "")))))

;(readexif (new File (first *command-line-args*)))
  (let [file (new File (first *command-line-args*))]
    (println (str "file: " (. file getPath)))
    (readexif file)))

Brian Schlining


Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.