カテゴリー: exif

Photosで選択中の写真をKeynoteの現在の書類の現在のスライド以降に配置 v2

Photosで選択中の写真をKeynoteで現在オープン中の書類の現在のスライド(ページ)以降に配置していくAppleScriptの改良版です。

作業の過程をiPhoneで写真撮影。撮影した写真を写真.app(Photos.app)経由でKeynote書類にまとめる作業を行なっていました。作業工程を時間こみで表示できないとわかりにくかったので、Keynoteの各スライドに時刻を入れるようにAppleScriptを書いておきました。

初版では写真.app(Photos)上の選択項目を一切ソートなどしなかったため、exifから取得した撮影日付で昇順ソートしています。


さんかく写真.app(Photos)上でKeynoteに配置したい写真を選択


さんかくあらかじめKeynote上でマスタースライド「画像(横長)」上のアイテムを編集しておくといいかも


さんかくAppleScriptによって写真.app上の写真をKeynote書類上に順次割り付け。タイトル部分にexifに記録されていた撮影時刻が入る


さんかく実行結果。写真.appから割り付けた写真は撮影日時でソートされている

AppleScript名:Photosで選択中の写真をKeynoteの現在の書類の現在のスライド以降に配置 v2

– Created by: Takaaki Naganoya
– Created on: 2019年05月26日

– Copyright © 2019 Piyomaru Software, All Rights Reserved

use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use BPlus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html
use mdLib : script "Metadata Lib" version "2.0.0" –https://www.macosxautomation.com/applescript/apps/Script_Libs.html#Metadata_Lib

property NSUUID : a reference to current application’s NSUUID
property NSString : a reference to current application’s NSString
property SMSForder : a reference to current application’s SMSForder
property NSFileManager : a reference to current application’s NSFileManager

tell application "Keynote"
if (count every document) = 0 then return
end tell

–Photosで選択中の写真をすべて書き出してalias listを取得する
set aList to exportSelectedPhotoOnPhotos() of me
if aList = {} or aList = false then return

set aLen to length of aList

–書き出した画像の親フォルダを求めておく(あとで削除するため)
tell application "Finder"
set parentFol to parent of (item 1 of aList)
end tell

–exifから撮影日時を取得して2D List化
set aaList to {}
repeat with i in aList
set j to contents of i
set exifDate to readExifDateTimeOriginal(j) of me
set the end of aaList to {j, exifDate, (time string of exifDate)}
end repeat

–撮影日時で昇順ソート
set aaaList to sortList2DAscending(aaList, {2}) of me

tell application "Keynote"
tell front document
tell current slide
set curNum to slide number –現在表示中のスライドの番号(ページ数)を取得する
end tell

–Photosから取得した写真のアイテム数でループ
repeat with i from 1 to aLen
copy (item i of aaaList) to {aPhoto, aDateObj, creTime}

set newSlide to make new slide at slide (curNum + i) with properties {base slide:master slide "画像(横長)"} –This item is localized!! Maybe a "Photo"

tell newSlide
set object text of default title item to creTime
set file name of image 1 to aPhoto –place an image to image placeholder
end tell

–配置画像を削除
tell application "Finder"
delete aPhoto –配置した写真を削除
end tell
end repeat
end tell
end tell

–あとしまつ
tell application "Finder"
delete parentFol –画像のダウンロードフォルダを削除
end tell

–Photosで選択中のファイルをtmporaryフォルダに書き出してalias listで返す
on exportSelectedPhotoOnPhotos()
set dtPath to (path to temporary items) as text
set aUUID to NSUUID’s UUID()’s UUIDString() as text

set dirPath to ((POSIX path of dtPath) & aUUID)
set fileManager to NSFileManager’s defaultManager()
set aRes to (fileManager’s createDirectoryAtPath:dirPath withIntermediateDirectories:true attributes:(missing value) |error|:(reference))
set dtPath to dtPath & aUUID

tell application "Photos"
set a to selection
if a = {} then return {}
set aRes to (export a to file dtPath)
end tell

tell application "Finder"
tell folder dtPath
set fList to (every file) as alias list
end tell
end tell

if fList = {} then return false
return fList
end exportSelectedPhotoOnPhotos

–指定JPEG画像のExif情報からDateTimeOriginalを取得してAS dateオブジェクトに変換して返す
on readExifDateTimeOriginal(aTargFileAlias)
set theMetadata to readMetadataFrom(aTargFileAlias) of me
if theMetadata = false then return false

set keysList to theMetadata’s allKeys()

if "{Exif}" is not in (keysList as list) then return false

set exifDate to theMetadata’s valueForKeyPath:"{Exif}.DateTimeOriginal"
if exifDate = missing value then return false

set a to NSString’s stringWithString:exifDate
set {aDateStr, aTimeStr} to (a’s componentsSeparatedByString:" ") as list
set bDateStr to repChar(aDateStr, ":", "/") of me
set fullDate to date (bDateStr & " " & aTimeStr)

return fullDate
end readExifDateTimeOriginal

–指定のファイルからメタデータを取得する
on readMetadataFrom(imageFile)
load framework
set {theRecord, theError} to SMSForder’s metadataFromImage:imageFile |error|:(reference)
if theRecord = missing value then — there was a problem, so extract the error description
error false
else
return theRecord
end if
end readMetadataFrom

–文字置換
on repChar(origText as string, targChar as string, repChar as string)
set curDelim to AppleScript’s text item delimiters
set AppleScript’s text item delimiters to targChar
set tmpList to text items of origText
set AppleScript’s text item delimiters to repChar
set retText to tmpList as string
set AppleScript’s text item delimiters to curDelim
return retText
end repChar

–入れ子のリストを昇順ソート
on sortList2DAscending(a, keyItem)
return sort2DList(a, keyItem, {true}) of me
end sortList2DAscending

–入れ子のリストを降順ソート
on sortList2DDecending(a, keyItem)
return sort2DList(a, keyItem, {false}) of me
end sortList2DDecending

–2D Listをソート
on sort2DList(aList as list, sortIndexes as list, sortOrders as list)
load framework

–index値をAS流(アイテムが1はじまり)からCocoa流(アイテムが0はじまり)に変換
set newIndex to {}
repeat with i in sortIndexes
set j to contents of i
set j to j – 1
set the end of newIndex to j
end repeat

set sortTypes to {}
repeat (length of sortIndexes) times
set the end of sortTypes to "compare:"
end repeat

set resList to (SMSForder’s subarraysIn:(aList) sortedByIndexes:newIndex ascending:sortOrders sortTypes:sortTypes |error|:(missing value)) as {missing value, list}

return resList
end sort2DList

Photosで選択中の写真をKeynoteの現在の書類の現在のスライド以降に配置

Photosで選択中の写真をKeynoteで現在オープン中の書類の現在のスライド(ページ)以降に配置していくAppleScriptです。

作業の過程をiPhoneで写真撮影。撮影した写真を写真.app(Photos.app)経由でKeynote書類にまとめる作業を行なっていました。作業工程を時間こみで表示できないとわかりにくかったので、Keynoteの各スライドに時刻を入れるようにAppleScriptを書いておきました(同じ作業が二度あるかは不明ですが、二度目からは明らかに時間の節約。つまり時間の貯金ができることになります)。

写真.app(Photos)上でKeynoteに配置したい写真を選択しておき、本Scriptを実行します。

Keynote書類上に新規スライドを追加し、撮影時刻と写真を配置していきます。

実行直後にPhotosで選択中の写真をファイルに書き出すため、若干待たされます。

# 複数のマシンでiCloudを介して写真を同期した場合に、写真.appのライブラリの写真の並び順は撮影日時どおりにならないようなので、明示的にソートしておく必要があるようです

ちなみに、写真の自作キーボードキットはこの後フットペダルにつなぎなおして、PPSSPP用の足踏みコントローラー化する予定です(「戦場の絆ポータブル」用)。

AppleScript名:Photosで選択中の写真をKeynoteの現在の書類の現在のスライド以降に配置

– Created by: Takaaki Naganoya
– Created on: 2019年05月26日

– Copyright © 2019 Piyomaru Software, All Rights Reserved

use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use BPlus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html
use mdLib : script "Metadata Lib" version "2.0.0" –https://www.macosxautomation.com/applescript/apps/Script_Libs.html#Metadata_Lib

property NSUUID : a reference to current application’s NSUUID
property NSString : a reference to current application’s NSString
property NSFileManager : a reference to current application’s NSFileManager

tell application "Keynote"
if (count every document) = 0 then return
end tell

–Photosで選択中の写真をすべて書き出してalias listを取得する
set aList to exportSelectedPhotoOnPhotos() of me
if aList = {} or aList = false then return

set aLen to length of aList

–書き出した画像の親フォルダを求めておく(あとで削除するため)
tell application "Finder"
set parentFol to parent of (item 1 of aList)
end tell

tell application "Keynote"
tell front document
tell current slide
set curNum to slide number –現在表示中のスライドの番号(ページ数)を取得する
end tell

–Photosから取得した写真のアイテム数でループ
repeat with i from 1 to aLen
set aPhoto to contents of item i of aList
set newSlide to make new slide at slide (curNum + i) with properties {base slide:master slide "画像(横長)"} –This item is localized!! Maybe a "Photo"
set creTime to getCreationTime(aPhoto) of me
tell newSlide
set object text of default title item to creTime
set file name of image 1 to aPhoto –place an image to image placeholder
end tell

–配置画像を削除
tell application "Finder"
delete aPhoto –配置した写真を削除
end tell
end repeat
end tell
end tell

–あとしまつ
tell application "Finder"
delete parentFol –画像のダウンロードフォルダを削除
end tell

–指定のaliasからExif情報の作成日の時刻情報を返す
on getCreationTime(anAlias)
set exifDate to readExifDateTimeOriginal(anAlias) of me
return time string of exifDate
end getCreationTime

–Photosで選択中のファイルをtmporaryフォルダに書き出してalias listで返す
on exportSelectedPhotoOnPhotos()
set dtPath to (path to temporary items) as text
set aUUID to NSUUID’s UUID()’s UUIDString() as text

set dirPath to ((POSIX path of dtPath) & aUUID)
set fileManager to NSFileManager’s defaultManager()
set aRes to (fileManager’s createDirectoryAtPath:dirPath withIntermediateDirectories:true attributes:(missing value) |error|:(reference))
set dtPath to dtPath & aUUID

tell application "Photos"
set a to selection
if a = {} then return {}
set aRes to (export a to file dtPath)
end tell

tell application "Finder"
tell folder dtPath
set fList to (every file) as alias list
end tell
end tell

if fList = {} then return false
return fList
end exportSelectedPhotoOnPhotos

–指定JPEG画像のExif情報からDateTimeOriginalを取得してAS dateオブジェクトに変換して返す
on readExifDateTimeOriginal(aTargFileAlias)
set theMetadata to readMetadataFrom(aTargFileAlias) of me
if theMetadata = false then return false

set keysList to theMetadata’s allKeys()

if "{Exif}" is not in (keysList as list) then return false

set exifDate to theMetadata’s valueForKeyPath:"{Exif}.DateTimeOriginal"
if exifDate = missing value then return false

set a to NSString’s stringWithString:exifDate
set {aDateStr, aTimeStr} to (a’s componentsSeparatedByString:" ") as list
set bDateStr to repChar(aDateStr, ":", "/") of me
set fullDate to date (bDateStr & " " & aTimeStr)

return fullDate
end readExifDateTimeOriginal

–指定のファイルからメタデータを取得する
on readMetadataFrom(imageFile)
load framework
set {theRecord, theError} to current application’s SMSForder’s metadataFromImage:imageFile |error|:(reference)
if theRecord = missing value then — there was a problem, so extract the error description
error false
else
return theRecord
end if
end readMetadataFrom

–文字置換
on repChar(origText as string, targChar as string, repChar as string)
set curDelim to AppleScript’s text item delimiters
set AppleScript’s text item delimiters to targChar
set tmpList to text items of origText
set AppleScript’s text item delimiters to repChar
set retText to tmpList as string
set AppleScript’s text item delimiters to curDelim
return retText
end repChar

指定の画像からEXIFの撮影日付(DateTimeOriginal)を取得 v2

指定の画像からEXIF情報を取得し、撮影日付(DateTimeOriginal)を取得するAppleScriptです。

Image Eventsで取得するよりも、BridgePlusで取得するほうが高速だったので差し替えてみました。

AppleScript名:指定の画像からEXIFの撮影日付(DateTimeOriginal)を取得 v2
— Created 2014年12月14日 by Takaaki Naganoya
— 2014 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use BPlus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html

property NSString : a reference to current application’s NSString
property NSLocale : a reference to current application’s NSLocale
property SMSForder : a reference to current application’s SMSForder
property NSDateFormatter : a reference to current application’s NSDateFormatter

set aTargFile to choose file of type {"public.image"}
set exifRes to readExifDateTimeOriginal(aTargFile) of me

–指定ファイルからのExifデータを取得し撮影日付を取得する
on readExifDateTimeOriginal(aTargFileAlias)
set theMetadata to readMetadataFrom(aTargFileAlias) of me
set keysList to theMetadata’s allKeys()

if "{Exif}" is not in (keysList as list) then return false

set exifDate to theMetadata’s valueForKeyPath:"{Exif}.DateTimeOriginal"
if exifDate = missing value then return false

set fullDate to dateFromStringWithDateFormat(exifDate, "yyyy:MM:dd HH:mm:ss") of me

return fullDate
end readExifDateTimeOriginal

–指定ファイルからのメタデータ読み込み
on readMetadataFrom(imageFile)
load framework
set {theRecord, theError} to SMSForder’s metadataFromImage:imageFile |error|:(reference)
if theRecord = missing value then — there was a problem, so extract the error description
error (theError’s localizedDescription() as text) — number (theError’s code())
else
return theRecord
end if
end readMetadataFrom

–日付文字列を形式指定しつつdate objectに変換
on dateFromStringWithDateFormat(dateString, dateFormat)
set dStr to NSString’s stringWithString:dateString
set dateFormatStr to NSString’s stringWithString:dateFormat

set aDateFormatter to NSDateFormatter’s alloc()’s init()
aDateFormatter’s setDateFormat:dateFormatStr
aDateFormatter’s setLocale:(NSLocale’s alloc()’s initWithLocaleIdentifier:"en_US_POSIX")

set aDestDate to (aDateFormatter’s dateFromString:dStr)

return aDestDate as list of string or string
end dateFromStringWithDateFormat

指定フォルダ内のJPEGファイルのEXIFから撮影日付を取得してファイルの作成日付に反映させる v2

指定フォルダ内のすべてのJPEGファイルのEXIF情報から撮影日付を取得し、画像ファイルの作成日付に反映させるAppleScriptです。

写真.app(Photos.app)内で管理している大量の写真ファイルをいったんファイルに書き出して、DVD-Rにコピーして人に渡すときに、写真の作成日付が撮影日になっておらず、Finderなどのファイラー上で整理するのが大変でした。

ファイル書き出しなので仕方のないことですが、この仕様はいただけません。

かようにファイル作成日付が正しくない写真でも、EXIFに正しい撮影日付が保存されているケースが多い(ただし、完全にすべてではない)ため、EXIFの日付をAppleScriptで読み取ってファイル作成日付に反映させてみました。

写真.appなどのアプリケーションにインポートしてしまえばEXIF日付でソートされるので、あまり意味があるとも思えませんが、Finder上での写真整理のために実行してとりあえず走らせてみました。

AppleScript名:EXIFから撮影日付を取得してファイルの作成日付に反映させる v2
— Created 2018年05月30日 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"

script spd
property fList : {}
end script

set renCount to 0

set (fList of spd) to {}

set aFolder to (choose folder)

set aDate to current date

set (fList of spd) to getFilePathList(aFolder, "JPG") of me

repeat with i in (fList of spd)
set j to contents of i
chkCreationDateAsExif(j) of me
set renCount to renCount + 1
end repeat

set bDate to current date

return {bDate – aDate, renCount}

on chkCreationDateAsExif(aFile)
tell application "Image Events"
launch
set this_image to open (aFile as alias)

try
tell this_image
set aVal to (value of metadata tag "creation")
end tell
on error
return
end try

close this_image
end tell

set a to current application’s NSString’s stringWithString:aVal
set {aDateStr, aTimeStr} to (a’s componentsSeparatedByString:" ") as list
set bDateStr to repChar(aDateStr, ":", "/") of me
set fullDate to date (bDateStr & " " & aTimeStr)

set aDic to current application’s NSMutableDictionary’s dictionaryWithObject:fullDate forKey:(current application’s NSFileModificationDate)
set aFM to current application’s NSFileManager’s defaultManager()’s setAttributes:aDic ofItemAtPath:(POSIX path of aFile) |error|:(missing value)
end chkCreationDateAsExif

–文字置換
on repChar(origText as string, targChar as string, repChar as string)
set curDelim to AppleScript’s text item delimiters
set AppleScript’s text item delimiters to targChar
set tmpList to text items of origText
set AppleScript’s text item delimiters to repChar
set retText to tmpList as string
set AppleScript’s text item delimiters to curDelim
return retText
end repChar

on getFilePathList(aFol, aExt)
set aFol to current application’s |NSURL|’s fileURLWithPath:(POSIX path of aFol)

set aFM to current application’s NSFileManager’s defaultManager()
set urlArray to aFM’s contentsOfDirectoryAtURL:aFol includingPropertiesForKeys:{} options:(current application’s NSDirectoryEnumerationSkipsHiddenFiles) |error|:(missing value)
set thePred to current application’s NSPredicate’s predicateWithFormat:"pathExtension == [c]%@" argumentArray:{aExt}
set anArray to urlArray’s filteredArrayUsingPredicate:thePred
return anArray as list — URLs pre-10.11, files under 10.11
end getFilePathList