I would love to retrieve the EXIF data from an image to use in the file name. Is there any way to easily retrieve that data using Keyboard Maestro?
If you do a google on "AppleScript EXIF" you should find a number of solutions.
I don't know if KM has a native solution, but you could setup batch processing of files with KM, and call an AppleScript.
Hey Gary,
Not specifically no, however there is a great command-line tool for this:
Using that in combination with Keyboard Maestro makes such a thing a cinch.
Basic usage is:
exiftool "/posix path to file/the file.jpg"
Help is available on the site and via the Terminal using the command: exiftool -h
-Chris
And you could also do something with an Execute JavaScript action in KM.
Here are examples of:
- getting a particular EXIF value like 'DateTimeOriginal'
- Listing any EXIF value types (value keys) that are available in an image
- Getting all of the EXIF key:value pairs in an image
((function () {
'use strict';
// exifValue :: String -> String -> String
function exifValue(strPath, strKey) {
var maybeData = exifData(strPath) || {};
return maybeData[strKey];
}
// exifKeys :: String -> [String]
function exifKeys(strPath) {
var dctData = exifData(strPath) || {};
return Object.keys(
dctData
)
.sort();
}
// exifData :: String -> Dictionary
function exifData(strPath) {
ObjC.import('AppKit');
return ObjC.deepUnwrap(
$.NSBitmapImageRep.imageRepWithContentsOfFile(
$(strPath)
.stringByStandardizingPath
)
.valueForProperty($.NSImageEXIFData)
);
}
// for type strings see: Apple's 'System-Declared Uniform Type Identifiers'
// if strType is omitted, files of all types will be selectable
// filePathChoice :: String -> String -> String
function filePathChoice(strPrompt, strType) {
var a = Application.currentApplication();
return (a.includeStandardAdditions = true, a)
.chooseFile({
withPrompt: strPrompt,
ofType: strType
})
.toString();
}
var strPath = filePathChoice('Choose image file', 'public.image');
return strPath && {
// Getting a particular value from the EXIF
time: exifValue(strPath, 'DateTimeOriginal'),
// Listing all the available value types in the EXIF
sortedKeys: exifKeys(strPath),
// Getting ALL of the EXIF data into a JavaScript dictionary
allData: exifData(strPath)
}
})();
Nice.
I would have done something similar with AppleScriptObjC, except that exiftool
eats them both for lunch in terms of information returned.
-Chris
Out of interest, if one uses AppleScriptObjC to harvest the data as a record, what's the best way to get a list of the keys ?
Perhaps some method on NSDictionary ?
UPDATE
Got it, I think – looks like NSDictionary.allKeys
Yep.
-Chris
# Handlers for making a record from separate lists of keys and values,
# and for returning the keys of a record as a flat list.
--------------------------------------------------------------------------------
use framework "Foundation"
--------------------------------------------------------------------------------
set theKeys to {"fname", "lname"}
set theValues to {"Chris", "Stone"}
set theRecord to its recWithLabels:theKeys andValues:theValues
set recKeys to its returnLabelsFromRec:theRecord
--------------------------------------------------------------------------------
--» HANDLERS
--------------------------------------------------------------------------------
on recWithLabels:theKeys andValues:theValues
return (current application's NSDictionary's dictionaryWithObjects:theValues forKeys:theKeys) as record
end recWithLabels:andValues:
--------------------------------------------------------------------------------
on returnLabelsFromRec:aRecord
return (current application's NSDictionary's dictionaryWithDictionary:aRecord)'s allKeys() as list
end returnLabelsFromRec:
--------------------------------------------------------------------------------
I am keen to use this as I have hundreds of files where the Creation Date shown in Finder is no longer the same as that in the EXIF data.
Ideally I'd like to be able to iterate through a series of photos in a Folder called "Wrong Date" and update the Creation Date with the EXIF data.
I can build a KM macro that I think would do the trick—except I don't know how how to read across from KM into JXA and vice-versa. ComplexPoint's script asks for a prompt and, as shown below, I would like to read in the filename held in the variable %Photo%:
I'm guessing that this is where it's happening:
function filePathChoice(strPrompt, strType) {
var a = Application.currentApplication();
return (a.includeStandardAdditions = true, a)
.chooseFile({
withPrompt: strPrompt,
ofType: strType
})
.toString();
}
And presumably rather than have
.chooseFile({
withPrompt: strPrompt,
I need some kind of .chooseFile({ defined by this variable})
The next question is getting the EXIF data that the JXA script has pulled and putting that into the KM macro, where I have some RegEx waiting to do the next piece of work:
Thanks for any help.
Hey @Rather,
The exiftool
Unix Command-line tool makes this relatively easy to do from the Terminal.
cd "~/test_directory/exif_test/";
exiftool "-filemodifydate<datetimeoriginal" "-modifydate<datetimeoriginal" "-metadatadate<datetimeoriginal" "-historywhen<datetimeoriginal" -overwrite_original *.jpg;
Here's a relevant thread:
What kind of files are you managing? I've limited the shell script to jpegs, but that is easily altered.
Make sure you test on COPIES before working with the originals.
-Chris
Thank-you @ccstone,
I will take a look at this—and try it out on some duplicate data!