I occasionally need to get the creation date of a JPG image made with a digital camera, and this is not always the simple task it might seem. The most accurate creation date can be obtained from the image’s Exif and Spotlight metadata, but the former may be missing and the latter is not available if the volume containing the file is not indexed. So, I wrote a script that returns the Exif creation date if one is available and a file system creation date otherwise.
use framework "AppKit" -- required by NSBitmapImageRep
use framework "Foundation"
use scripting additions
set theFile to POSIX path of (choose file of type {"public.jpeg"})
set theDate to getDate(theFile)
on getDate(theFile) -- theFile requires POSIX path
set theFile to current application's |NSURL|'s fileURLWithPath:theFile
set imageRep to current application's NSBitmapImageRep's imageRepWithContentsOfURL:theFile
set dateString to (imageRep's valueForProperty:(current application's NSImageEXIFData))'s valueForKey:"DateTimeOriginal"
if dateString is not missing value then return dateString as text
set {theResult, theDate} to (theFile's getResourceValue:(reference) forKey:"NSURLCreationDateKey" |error|:(missing value))
set dateFormatter to current application's NSDateFormatter's new()
dateFormatter's setDateFormat:"yyyy:MM:dd' 'HH:mm:ss" -- user set as desired
return ((dateFormatter's stringFromDate:theDate) as text)
end getDate
Image Events has a creation date property, but it is the file system creation date. You can get metadata tags with Image Events, but they do not appear to include a creation date.
set theFile to (choose file of type "public.image") as text
tell application "Image Events"
launch
set theDate to creation date of file theFile -- file system creation date
set theImage to open file theFile
set theTags to metadata tags of theImage -- no date tag found
end tell
I guess I was stating the obvious
Just to clarify one point, the Spotlight metadata contains a creation date, which is normally the date from an image’s Exif metadata. If an Exif date does not exist for a particular image, the file system creation date is used instead. At least that’s how it seems to work in my testing.
use framework "Foundation"
use scripting additions
set theFile to POSIX path of (choose file of type {"public.image"})
set theFile to current application's |NSURL|'s fileURLWithPath:theFile
set theMetadata to (current application's NSMetadataItem's alloc()'s initWithURL:theFile)
set theDate to (theMetadata's valueForAttribute:"kMDItemContentCreationDate") -- an NSDate object
BTW, just for the sake of completeness, I should add ExifTool:
set theFile to POSIX path of (choose file of type {"public.image"})
set theDate to do shell script "/usr/local/bin/exiftool -DateTimeOriginal " & quoted form of theFile -- verify path
It’s as simple as „PNG does not contain any Exif data. At all“. The whole Exif thing was built around images taken with a camera, so basically jpg and raw data.
If you need a „creation date“ for any „image“ in a broad sense, your approach with kMDitem… is probably the best.
It’s been a while, I guess. On my mac (Sierra), GetFileInfo and SetFile reside in /usr/bin/, not in /Developer/Tools/ as the man page suggests. At some point, it must have changed but while I vaguely recall that I had to do something, I’ve forgotten any and all details about getting them.
There’s some (JavaScript) code that first retrieves the EXIF data and then the stuff from Image Events. All data are converted to strings, IIRC. There’s also sample code to retrieve IPTC data.
All of that is JXAObjC, so it should be more or less easily be convertible to AppleScript. Except for all the mapping stuff and functions as objects, maybe
There is a GetFileInfo utility in the /usr/bin folder, but when I run the utility I get the following dialog message (on my Ventura computer):
The “GetFilelnfo” command requires the command
line developer tools. Would you like to install the tools
now? Choose Install to download and install the command line
developer tools now.
That’s a bold statement There’s an NSImageEXIFData key for NSImage objects, and that dictionary contains everything you can read with exiftool (another bold statement – exiftool can also read IPTC and GPS metadata, for which one needs another approach with AS/JXAObjC).
exiftool is a brilliant thing, but it’s an external tool that has to be installed. If one doesn’t want to do that, getting at image data is perfectly possible with on-board facilities.
Which approach is best probably depends on many factors. Most significantly, the Spotlight metadata script will not work if the files are on a drive that is not indexed. Anyways, this thread contains many different approaches and almost certainly one will fit most users’ needs.
FWIW, the following is the Spotlight metadata script but with a localized and formatted date.
use framework "Foundation"
use scripting additions
set theFile to POSIX path of (choose file of type {"public.image"})
set theDate to getDate(theFile)
on getDate(theFile) -- theFile requires POSIX path
set theFile to current application's |NSURL|'s fileURLWithPath:theFile
set theMetadata to (current application's NSMetadataItem's alloc()'s initWithURL:theFile)
if theMetadata is not missing value then
set theDate to (theMetadata's valueForAttribute:"kMDItemContentCreationDate")
set dateFormatter to current application's NSDateFormatter's new()
dateFormatter's setDateFormat:"yyyy:MM:dd' 'HH:mm:ss" -- user edit as desired
return ((dateFormatter's stringFromDate:theDate) as text)
else
return "Spotlight metadata not found"
end if
end getDate
If you mean xattr as in “pre-installed command line tool for extended attributes” – no. EXIF data is not stored in extended attributes (which are file-system dependent). They are stored inside the image file, completely independent of the file system (of course, since they come from cameras using (Ex)FAT, which has no extended attributes).
Well … if we’re talking photos, ie jpg or raw data, EXIF is just fine. It is what the camera writes into the image, and nothing can be better than that, can it? OTOH, if we’re talking PNG/GIF and perhaps TIFF, i.e. screenshots or programmatically generated images, the filesystem date is the easiest to get at, and it’s no different than any other creation date out there (hopefully), because there is no EXIF data.
Which, in my mind, boils down to
if there’s EXIF data, use it (because that even works with images on an SD card that’s not spotlighted)
else use file system data.
Going through all the loops with NSURL, kMDItemContentCreationDate and whatnot will not give you another date (hopefully) than creationDate from Finder or standard additions.
That’s exactly how my script in post 1 works, and it’s the only script in this thread that works in this manner.
But that is exactly what happens. In my testing, kMDItemContentCreationDate returns the Exif creation date if one is available and, if not, returns the file system creation date.
I ran some timing tests with one JPG file that contained an EXIF creation date, and the results on my 2023 Mac mini were as follows. This assumes that the required ASObjC frameworks are in memory.
All of the above are probably OK with one file, but performance can become an issue if the ExifTool script is used with a large number of image files. The ExifTool site contains some approaches to improve performance, but in this particular case the other scripts seem a better choice IMO.
I think that all this probably works as you say when you run it on images on your local disk, where Spotlight is indexing everything.
If I run it on an image stored on a NAS, I simply get missing value from getDate() (which shouldn’t happen, I think). The reason is that kMDMetadataItem does not contain a key for kMDItemContentCreationDate, but only those:
Perhaps these are created on the fly by using attributes of the remote file, and mdls does not return any metadata for this file.
OTOH, info for from standard additions gives me the creation date just fine.
Long story short: Checking for the existence of metadata is not sufficient in all cases, you must also check if the attribute kMDItemContentCreationDate is available. If it’s not, use the file system creation date.