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

(import
  '(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)
      (do 
        (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)) 
            (do 
              (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*)))
(do
  (let [file (new File (first *command-line-args*))]
    (println (str "file: " (. file getPath)))
    (readexif file)))
   

Brian Schlining

Developer

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

0 comments: