Ah, what a refreshing question! I’ve been writing shell scripts for so long that it’s burned into my brain. Not to mention that I write a column on shell script programming for Linux Journal and am the author of the best selling Wicked Cool Shell Scripts for NoStarch Press. Yeah, I’ve been exploring shell scripts for a long time now, so I’m the perfect person to ask. 🙂
As you already know, photos taken by modern cameras (and cell phones) embed extra information including film speed, lens size, date, time, geographic location of the photo and many other items of data. EXIF, in fact, stands for “EXchangeable Image Format”, if you’re curious.
Generally it’s required special third party open source programs to access EXIF information on photos from the command line, but Mac OS X includes a slick utility called “mdls” (which stands for metadata-ls). Here’s what I see when I use “mdls” on a photo sitting on my desktop:
$ mdls IMG_1331.JPG
kMDItemAcquisitionMake = "Apple"
kMDItemAcquisitionModel = "iPhone 5s"
kMDItemAltitude = 33.75805651958354
kMDItemAperture = 2.275007124536905
kMDItemBitsPerSample = 32
kMDItemColorSpace = "RGB"
kMDItemContentCreationDate = 2013-12-19 15:19:49 +0000
kMDItemContentModificationDate = 2013-12-19 15:19:49 +0000
kMDItemContentType = "public.jpeg"
kMDItemContentTypeTree = (
"public.jpeg",
"public.image",
"public.data",
"public.item",
"public.content"
)
kMDItemCreator = "7.0.4"
kMDItemDateAdded = 2013-12-30 06:19:43 +0000
kMDItemDisplayName = "IMG_1331.JPG"
kMDItemEXIFVersion = "2.2.1"
kMDItemExposureMode = 0
kMDItemExposureProgram = 2
kMDItemExposureTimeSeconds = 0.03333333333333333
kMDItemFlashOnOff = 0
kMDItemFNumber = 2.2
kMDItemFocalLength = 4.12
kMDItemFSContentChangeDate = 2013-12-19 15:19:49 +0000
kMDItemFSCreationDate = 2013-12-19 15:19:49 +0000
kMDItemFSCreatorCode = ""
kMDItemFSFinderFlags = 0
kMDItemFSHasCustomIcon = (null)
kMDItemFSInvisible = 0
kMDItemFSIsExtensionHidden = 0
kMDItemFSIsStationery = (null)
kMDItemFSLabel = 0
kMDItemFSName = "IMG_1331.JPG"
kMDItemFSNodeCount = (null)
kMDItemFSOwnerGroupID = 20
kMDItemFSOwnerUserID = 501
kMDItemFSSize = 2163587
kMDItemFSTypeCode = ""
kMDItemGPSDateStamp = "2013:12:19"
kMDItemHasAlphaChannel = 0
kMDItemImageDirection = 310.9829545454546
kMDItemISOSpeed = 80
kMDItemKind = "JPEG document"
kMDItemLatitude = 47.6087
kMDItemLogicalSize = 2163587
kMDItemLongitude = -122.3407216666667
kMDItemOrientation = 0
kMDItemPhysicalSize = 2166784
kMDItemPixelCount = 7990272
kMDItemPixelHeight = 2448
kMDItemPixelWidth = 3264
kMDItemProfileName = "sRGB IEC61966-2.1"
kMDItemRedEyeOnOff = 0
kMDItemResolutionHeightDPI = 72
kMDItemResolutionWidthDPI = 72
kMDItemTimestamp = "16:19:48"
kMDItemWhiteBalance = 0
As you can see, quite a huge amount of data is produced from the command, far more than you want, I’m betting!
To me, the most interesting parts are the camera info — camera name, focal length and ISO speed setting — the location of the photo — latitude / longitude — and the dimensions of the image.
For the first, look at kMDItemAcquisitionMake, kMDItemAcquisitionModel, kMDItemExposureTimeSeconds, kMDItemFNumber and kMDItemISOSpeed. The location is stored in kMDItemLatitude and kMDItemLongitude, and the dimensions are kMDItemPixelHeight and kMDItemPixelWidth.
From a scripting perspective, these are easily extracted and saved as named variables like this:
height=$(mdls IMG_1331.JPG | grep PixelHeight | awk '{print $3}')
Do that for the individual variables and you’ve got the values you want loaded up. Latitude and Longitude, for example? Like this:
lat=$(mdls IMG_1331.JPG | grep Latitude | awk '{print $3}')
long=$(mdls IMG_1331.JPG | grep Longitude | awk '{print $3}')
echo Photo was taken at $lat / $long
From this point I bet you can proceed with the script manipulation you seek!
7 thoughts on “Can I analyze EXIF information on the Mac OS X command line?”
In almost all cases, the use of grep and awk together is baffling. Awk has made grep obsolete pretty much as soon as it got released. If you use awk, there’s never a need to use grep.
grep foo | awk {bar}
can be replaced with
awk /foo/ {bar}
Another pet peeve of mine: using cat to feed something in a pipe. It’s not needed. Like ever. Say
cat foo | bar | baz
can be generically replaced with
bar < foo | baz
Ahh, always a purist in the group. 🙂 I am always seeking the balance between maximally efficient and maximally readable and understandable. So x < y | z might make sense to you, but for someone learning the shell that can be a bit baffling.
Cool, thanks. I am missing all of the lens info. Where is this hidden? Appreciate any help!
Not every camera or photo device records all the EXIF information. I think it’s all basically optional, so perhaps you’re missing the lens information because your camera isn’t recording it, Roland?
The kMDItemOrientation field is not to be confused with the EXIF standard orientation field (which contains a value from 1..9 if memory serves). kMDItemOrientation is 0 or 1 based on whether the image is in portrait or landscape format.
and forgotten…
mdls -raw -name kMDItemLatitude IMG_1331.JPG
will directly give the value, “47.6087” in your case.
instead of grep you can directly access the data with
mdls -name kMDItemLatitude IMG_1331.JPG