画像ファイルを読み込んで、クリップボードに設定するAppleScriptです。
標準のAppleScriptの命令だけで割と簡潔に書けることに驚きます。
AppleScript名:画像ファイルを読み込んでクリップボードに設定する |
set aFile to choose file of type {"public.image"} set anImage to read aFile as TIFF picture set the clipboard to anImage |
画像ファイルを読み込んで、クリップボードに設定するAppleScriptです。
標準のAppleScriptの命令だけで割と簡潔に書けることに驚きます。
AppleScript名:画像ファイルを読み込んでクリップボードに設定する |
set aFile to choose file of type {"public.image"} set anImage to read aFile as TIFF picture set the clipboard to anImage |
安全策の上に安全策を講じた、心配性のファイル名称変更AppleScriptです。
基本的にはファイルのリネームプログラムであり、Finder上で選択中のファイルについてリネームを行います。
ただし、ファイルのリネーム時に同じファイル名のファイルがすでに存在していて、普段であれば衝突回避のために子番号を振るなどの対処を行うところが、そういう対応が許されていないようなケースに直面しました。
同じフォルダ内にある3つの画像ファイルを、名称が衝突するような他の名称に変更するようなケースです。
1.jpg --> 2.jpg(すでに2.jpgが存在) 2.jpg --> 3.jpg(すでに3.jpgが存在) 3.jpg --> 1.jpg
少々、頭を抱えてしまいました。
そこで、テンポラリフォルダをファイル1つごとに作成し、テンポラリフォルダにファイルを移動。
1.jpg --> /temp/uuid0001/1.jpg
そのタコツボ的なテンポラリフォルダの中でリネームを実施。
/temp/uuid0001/1.jpg --> /temp/uuid0001/2.jpg
リネームしたファイルを元のフォルダに戻すというリネームルーチンを作成した次第です。もちろん、作成したテンポラリフォルダは削除しておきます。
/temp/uuid0001/2.jpg --> 2.jpg
最近はこのAppleScriptのように、ファイル操作処理はNSFileManagerで実行し、Finderには「選択中のファイルの情報を取得」ぐらいしか行わせていません。そのため、ファイル処理が従来よりもはるかに高速に行えて、ちょっと楽しいぐらいです。
数千ファイルのコピー(込み入ったルールに従いJANコードなどのデータを参照して名前を決定したり、フォルダ名を製品名で作成したりとか)が1・2秒というオーダーで終わってしまうのは、SSD上で処理しているせいもありますが、NSFileManager経由でのファイル処理を行っているおかげです(64bit化したCocoa Finderはとにかく処理が遅いのでAppleScriptからのファイル操作用に使うとダメ)。
AppleScript名:tempフォルダに移動しつつリネームして、終了後に元フォルダに戻す v2.scptd |
— Created 2018-08-14 by Takaaki Naganoya — 2018 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" 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 property tResList : {} property tFol : "" property newNameTemplate : "test_" set tResList to {} set tFol to POSIX path of (path to temporary items) tell application "Finder" set aSel to selection as alias list if aSel = {} then display notification "No Selection" return end if end tell –コピー元ファイルの親フォルダを求める(リネーム後に戻す) set origFol to POSIX path of (contents of first item of aSel) set origFolStr to ((NSString’s stringWithString:origFol)’s stringByDeletingLastPathComponent()) as string –一時フォルダに移動してリネーム set aCount to 1 repeat with i1 in aSel set j1 to POSIX path of (contents of i1) set newName to newNameTemplate & (aCount as string) set j1Res to renameSafely(j1, newName) of me set the end of tResList to (j1Res as string) set aCount to aCount + 1 end repeat –元のフォルダに戻して一時フォルダ削除 repeat with i2 in tResList set j2 to contents of i2 set j2Res to (my moveFileAt:j2 toFolder:origFolStr) set j2Res to deleteParentFol(j2) of me end repeat –安全なリネーム(個別のテンポラリフォルダに移動してリネーム) on renameSafely(aFile, newName) –set tFol to POSIX path of (path to temporary items) set aUUIDstr to ((NSUUID’s UUID()’s UUIDString()) as string) set aTmpFol to tFol & aUUIDstr set dRes to makeDirAbsolutely(aTmpFol) of me set mRes to my moveFileAt:aFile toFolder:aTmpFol set aStr to (NSString’s stringWithString:aFile) set newFullPath to aTmpFol & "/" & aStr’s lastPathComponent() set aExt to aStr’s pathExtension() set fRes to renameFileItem(newFullPath, newName) of me set renamedPath to aTmpFol & "/" & newName & "." & aExt return renamedPath end renameSafely –指定パスににフォルダを作成する on makeDirAbsolutely(dirStr) set fileManager to NSFileManager’s defaultManager() set aRes to fileManager’s createDirectoryAtPath:dirStr withIntermediateDirectories:true attributes:(missing value) |error|:(reference) copy aRes to {aFlag, aError} return aFlag as boolean end makeDirAbsolutely on moveFileAt:POSIXPath toFolder:folderPOSIXPath set POSIXPath to NSString’s stringWithString:POSIXPath set theName to POSIXPath’s lastPathComponent() set folderPOSIXPath to NSString’s stringWithString:folderPOSIXPath set theNewPath to folderPOSIXPath’s stringByAppendingPathComponent:theName set fileManager to NSFileManager’s defaultManager() set theResult to fileManager’s moveItemAtPath:POSIXPath toPath:theNewPath |error|:(missing value) return theNewPath end moveFileAt:toFolder: on renameFileItem(aPOSIXpath as string, newName as string) set theNSFileManager to NSFileManager’s defaultManager() set POSIXPathNSString to NSString’s stringWithString:(aPOSIXpath) –Make New File Path set anExtension to POSIXPathNSString’s pathExtension() set newPath to (POSIXPathNSString’s stringByDeletingLastPathComponent()’s stringByAppendingPathComponent:newName)’s stringByAppendingPathExtension:anExtension –Rename if theNSFileManager’s fileExistsAtPath:newPath then return false else set theResult to theNSFileManager’s moveItemAtPath:POSIXPathNSString toPath:newPath |error|:(missing value) if (theResult as integer = 1) then return (newPath as string) else return false end if end if end renameFileItem on deleteParentFol(aPOSIX) set aStr to NSString’s stringWithString:aPOSIX set parentFol to aStr’s stringByDeletingLastPathComponent() set aRes to deleteItemAt(parentFol) of me return aRes end deleteParentFol on deleteItemAt(aPOSIX) set theNSFileManager to NSFileManager’s defaultManager() set theResult to theNSFileManager’s removeItemAtPath:(aPOSIX) |error|:(missing value) return (theResult as integer = 1) as boolean end deleteItemAt |
指定のCSVファイルを読み込んで、表インタフェースで表示確認するAppleScriptです。
Numbers.appから文字コードにUTF-8を指定して書き出したCSVファイルを想定しています。CSVデータのparseにはBridgePlusを、表UIの表示にはMyriad Tables Libを利用しています。
ほぼ、テンプレートともいえるような定型処理ですが、巨大なAppleScriptに入れたときにはusing terms from句がないとアプレットとして動作中にクラッシュが発生する可能性があります。
CSVデータの処理はありふれたありきたりの内容で、本来は処理内容にはほとんど関係ない表示・確認を行わせるとユーザーの反応がいいようです。
あとは、CSVデータ中にカラムヘッダーが存在するかどうかをCSVデータからでは検出できないことが問題です。せめて、メタデータ中にでもカラムヘッダーの有無を(Export時に)書いておいてくれるとよいのですが。あとは、CSV1行目のデータと他の行との文字コードの分布状況を比較して統計処理すると、相関性を数値化してヘッダーかどうかを計算できそうですが、、、そこまでやるのは「やりすぎ」でしょう。
ユーザーにヘッダーの有無を確認するとか、そのぐらい?
_kMDItemOwnerUserID = 504 kMDItemAlternateNames = ( "2010_index.csv" ) kMDItemContentCreationDate = 2018-08-14 00:51:24 +0000 kMDItemContentModificationDate = 2018-08-14 00:51:24 +0000 kMDItemContentType = "public.comma-separated-values-text" kMDItemContentTypeTree = ( "public.comma-separated-values-text", "public.data", "public.delimited-values-text", "public.plain-text", "public.item", "public.content", "public.text" ) kMDItemDateAdded = 2018-08-14 00:51:24 +0000 kMDItemDisplayName = "2010_index" kMDItemFSContentChangeDate = 2018-08-14 00:51:24 +0000 kMDItemFSCreationDate = 2018-08-14 00:51:24 +0000 kMDItemFSCreatorCode = "" kMDItemFSFinderFlags = 16 kMDItemFSHasCustomIcon = (null) kMDItemFSInvisible = 0 kMDItemFSIsExtensionHidden = 1 kMDItemFSIsStationery = (null) kMDItemFSLabel = 0 kMDItemFSName = "2010_index.csv" kMDItemFSNodeCount = (null) kMDItemFSOwnerGroupID = 80 kMDItemFSOwnerUserID = 504 kMDItemFSSize = 7746 kMDItemFSTypeCode = "" kMDItemKind = "Comma Separated Spreadsheet (.csv)" kMDItemLogicalSize = 7746 kMDItemPhysicalSize = 8192 kMDItemUserCreatedDate = ( "2018-08-14 00:51:24 +0000" ) kMDItemUserCreatedUserHandle = ( 504 )
▲ここ(メタデータ)にCSVのヘッダーの有無の情報が入っているといいのに、、、、にしても、メタデータに大昔のResource Forkよろしくいろんなデータが突っ込まれるようになってきました
▲CSVファイルの選択
▲CSVファイル内容の表示
▲CSV内のカラム数が合っていた場合の動作
▲CSV内のカラム数が合っていない場合の動作(データ確認表示)
▲CSV内のカラム数が合っていない場合の動作(ダイアログ表示)
AppleScript名:CSVデータを読み込んで表インタフェースで表示確認 v2.scptd |
— – Created by: Takaaki Naganoya – Created on: 2018/08/10 — – Copyright © 2018 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 tableLib : script "Myriad Tables Lib" –https://www.macosxautomation.com/applescript/apps/Script_Libs.html#MyriadTablesLib –Numbersから書き出したUTF-8のCSVを読み取る set someString to read (choose file of type {"public.comma-separated-values-text"}) as «class utf8» –読み込んだテキストをParseして、ヘッダーとデータ本体に分離 set {theHeader, origList} to readCSVAndParse(someString) of me –Table UIを表示して内容を確認 set colMax to 3 –あらかじめ期待しているカラム数 set {dRes, tRes} to dispTableUI(theHeader, origList, colMax) of me if dRes = false then display dialog "データ不全のため処理を終了します" with title "CSVデータエラー" return else display dialog "CSVデータの処理を続行します" with title "CSVデータOK" end if on readCSVAndParse(someString) load framework using terms from script "BridgePlus" set theData to current application’s SMSForder’s arrayFromCSV:someString commaIs:"," set origList to (current application’s SMSForder’s subarraysIn:theData paddedWith:"" |error|:(missing value)) as list end using terms from set theHeader to contents of first item of origList –Header Row set origList to rest of origList –Data return {theHeader, origList} end readCSVAndParse on dispTableUI(theHeader, origList, colMax) set {curDispW, curDispH} to (current application’s NSScreen’s mainScreen()’s frame()’s |size|()) as list set curLen to length of first item of origList set dRes to (curLen = colMax) as boolean if dRes = true then set aMessage to "問題がなければ「OK」をクリックして実行してください" –Normal message set aTitle to "CSVファイルの内容確認" else set aMessage to "CSVファイルのカラム数が期待どおりではありません。「Cancel」をクリックして実行を停止してください" –Error Message set aTitle to "CSVファイルに異常あり" end if using terms from script "Myriad Tables Lib" tell script "Myriad Tables Lib" set aDispBounds to my makeInitialBounds:(curDispW – 100) withHeight:(curDispH – 100) set theTable to make new table with data origList column headings theHeader with title aTitle with prompt aMessage with row numbering, empty selection allowed and multiple lines allowed modify table theTable initial position aDispBounds –表を表示 set tRes to (display table theTable) return {dRes, tRes} end tell end using terms from end dispTableUI on makeInitialBounds:(aTWidth as integer) withHeight:(aTHeight as integer) set aDispBounds to current application’s NSScreen’s mainScreen()’s frame() set aWidth to (width of |size| of aDispBounds) set aHeight to (height of |size| of aDispBounds) set xPos to (aWidth div 2) – (aTWidth div 2) set yPos to (aHeight div 2) – (aTHeight div 2) return {xPos, yPos, aTWidth, aTHeight} end makeInitialBounds:withHeight: |
Adobe Illustrator CC 2018(バージョン22.1)で、複数のアートボードを持つAdobe Illustrator書類をアートボードごとに分割保存するAppleScriptです。
オプションの指定方法にものすごく納得しづらいものを感じるものの、これで動くので仕方ないだろうかというところ。
AppleScript名:複数のアートボードを持つAI書類を、デスクトップにアートボードごとに分割して保存.scptd |
use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use scripting additions set dtPath to ((path to desktop) as string) & "template.ai" tell application "Adobe Illustrator" tell front document set aCount to (count every artboard) as string set sOpt to {class:Illustrator save options, save multiple artboards:true, artboard range:"1-" & aCount} save as Illustrator in file dtPath with options sOpt end tell end tell |
Adobe Illustrator CC 2018(バージョン22.1)で、オープン中の(複数のアートボードを持つ)書類を、アートボード単位で別書類に分けるAppleScriptの改修版です。
書類は(とりあえず)デスクトップに書き込まれます。前バージョンのように、アートボード外のオブジェクトが残るといったことはありません。
「exportSelectedArtwork」という長いコマンドを見つけて、ためしてみたら期待どおりの挙動であったために使ってみました。
……すると、なおのことAppleScriptからartworkのselectができないのか?(実行すると100% Illustratorがクラッシュする) artworkからnameの取得ができないのか?(実行するとエラーになる)というあたりが謎です。
artboardも選択状態になっている(はず)だと思って、そのまま実行してみたところ、artboardのサイズでは書き出されていないようです。少し別の方法を試す必要があり、自分は前バージョンのScriptにもどって作業を行っています。
AppleScript名:オープン中のIllustrator書類をartboardごとに分割 v3.scptd |
— – Created by: Takaaki Naganoya – Created on: 2018/08/07 – Modified on: 2018/08/09 – Copyright © 2018 Piyomaru Software, All Rights Reserved — use AppleScript version "2.5" — El Capitan (10.11) or later use framework "Foundation" use scripting additions set dPath to (path to desktop) as string set namesList to {} tell application "Adobe Illustrator" tell front document set aCount to count every artboard set aPath to (file path) as string end tell repeat with i from 1 to aCount set aName to getArtboardName(i – 1) of me –index base correction (1 –> 0) set outPath to dPath & aName & ".ai" selectArtboard(i – 1) of me –index base correction (1 –> 0) tell front document selectobjectsonactiveartboard exportSelectedArtwork to file outPath end tell end repeat end tell –https://lists.apple.com/archives/applescript-users/2015/Jul/msg00104.html on selectArtboard(theArtboardIndex as string) tell application "Adobe Illustrator" tell front document –Index is 0 based do javascript ("app.activeDocument.artboards.setActiveArtboardIndex(" & theArtboardIndex & ")") end tell end tell end selectArtboard on getArtboardName(theArtboardIndex as string) tell application "Adobe Illustrator" tell front document –Index is 0 based do javascript ("app.activeDocument.artboards[" & theArtboardIndex & "].name") end tell end tell end getArtboardName |
Adobe Illustrator CC 2018(バージョン22.1)で、オープン中の(複数のアートボードを持つ)書類を、アートボード単位で別書類に分けるAppleScriptです。
書類は(とりあえず)デスクトップに書き込まれます。
こういうコマンドが最初からあってもおかしくないところですが、存在していないようなので書いてみました。まずは、オープン中の書類のパスを取得し、各アートボードの名称を取得して書き出し時のファイル名として使用します。
元ファイルをクローズしては、デスクトップに新規名称でコピーし、コピーした書類をオープン、書き出し対象外のアートボードを順次選択してはアートボード上のオブジェクトを削除してアートボード自体も削除、すべて削除したら保存してクローズという動作を行います。
本来であれば高速化のために複数のアートボードを一括で削除することを考えるところですが、アートボードの削除だけであればできるものの、アートボード上のオブジェクトの削除が行えなくなってしまうので、順次削除に落ち着きました。また、本Scriptが本気でスピードを求められるようなハードな用途ではなく、文字や画像の流し込みテンプレートのメンテナンス用という「平和な用途」のために作成したものであるため、高速化処理については考慮していません。
最初からアートボード外に置かれたオブジェクトについては削除していません。あくまで自分用のツールなので作り込む必要性を感じません。気が向いたら削除するのではないでしょうか。
本Scriptの作成中にも、単にAppleScriptで命令を出しただけで派手にクラッシュしまくるAdobe Illustrator。バージョンが上がって見た目が変わっても、あの出来の悪いIllustratorであることに変わりはないのだと思い知らされました。
AppleScript名:オープン中のIllustrator書類をartboardごとに分割 v2.scptd |
— – Created by: Takaaki Naganoya – Created on: 2018/08/07 — – Copyright © 2018 Piyomaru Software, All Rights Reserved — use AppleScript version "2.5" — El Capitan (10.11) or later use framework "Foundation" use scripting additions set dPath to (path to desktop) as string set namesList to {} tell application "Adobe Illustrator" tell front document set aCount to count every artboard set aPath to (file path) as string end tell repeat with i from 1 to aCount set aName to getArtboardName(i – 1) of me –index base correction (1 –> 0) set the end of namesList to aName end repeat close every document saving no end tell repeat with i from 1 to aCount set aRes to retSerialListWithExclusion(1, aCount, i) of me set aaRes to reverse of aRes –artboardをIndex値で指定するため、先頭から削除するとIndex値が変わる。そのため逆順に処理 set tmpName to contents of item i of namesList set fromFile to POSIX path of aPath set fromFilePOSIX to quoted form of POSIX path of fromFile set toFile to (dPath & tmpName & ".ai") set toFilePOSIX to quoted form of POSIX path of toFile set shText to "cp " & fromFilePOSIX & " " & toFilePOSIX do shell script shText tell application "Adobe Illustrator" open file toFile tell front document repeat with ii in aaRes set jj to ii as integer selectArtboard(jj – 1) of me –index base correction (1 –> 0) selectobjectsonactiveartboard delete selection delete artboard jj end repeat close with saving end tell end tell end repeat –https://lists.apple.com/archives/applescript-users/2015/Jul/msg00104.html on selectArtboard(theArtboardIndex as string) tell application "Adobe Illustrator" tell front document –Index is 0 based do javascript ("app.activeDocument.artboards.setActiveArtboardIndex(" & theArtboardIndex & ")") end tell end tell end selectArtboard on getArtboardName(theArtboardIndex as string) tell application "Adobe Illustrator" tell front document –Index is 0 based do javascript ("app.activeDocument.artboards[" & theArtboardIndex & "].name") end tell end tell end getArtboardName on retSerialListWithExclusion(aFromNum as integer, aToNum as integer, anEXnum as integer) set outList to {} repeat with i from aFromNum to aToNum if i = anEXnum then — else set the end of outList to i end if end repeat return outList end retSerialListWithExclusion |
Google Drive File Stream上でSpotlight Indexを生成するAppleScriptです。
Google Driveには、Gmailのオマケでついてくる個人のデバイス間で情報のシンクロを行う目的のPersonal版(DropboxのGoogle版的なもの)と、企業内やグループ内でファイル共有を行うG SuiteのGoodle Drive File Streamがあり、後者についてはGoogleによる「Google Drive File Stream」ツールが提供され、GoogleDriveをデスクトップにマウントできます。
実際にGoogle Drive File Streamを使ってみたところ、デフォルト状態だとSpotlight検索が効きませんでした。
そこで、Index生成してみたものの…既存のファイルについてはSpotlight検索できませんでした。Index生成後に、新規追加したファイルについてはSpotlight検索が有効でした。
後日談:ただ、Google Drive File Streamに対してSpotlight Indexを常時生成するようにすると、CPUに対する負荷が大きくなるため、実際の運用ではSpotlightを無効にして運用するようにしました。
AppleScript名:Google Drive File Streamでインデックス生成 |
do shell script "mdutil -E /Volumes/GoogleDrive/" with administrator privileges |
自分が試したのは、Google Drive File Stream内の「マイドライブ」領域のみで、
「グループドライブ」領域についてはまだテストできていません。
既存のファイルについては、mdimportコマンドでインデックス作成すれば大丈夫だと思っていますが、実際に試してみると予想外の挙動を行うのかもしれません。
AppleScript名:GDFS上でSpotlight検索 |
— Created 2016-06-17 by Takaaki Naganoya — 2016 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" property NSArray : a reference to current application’s NSArray property NSPredicate : a reference to current application’s NSPredicate property NSSortDescriptor : a reference to current application’s NSSortDescriptor property NSMetadataQuery : a reference to current application’s NSMetadataQuery property NSNotificationCenter : a reference to current application’s NSNotificationCenter property NSMetadataQueryDidUpdateNotification : a reference to current application’s NSMetadataQueryDidUpdateNotification property NSMetadataQueryDidFinishGatheringNotification : a reference to current application’s NSMetadataQueryDidFinishGatheringNotification property searchRes : {} set origPath to POSIX path of (choose folder) set aList to spotlightSearch(origPath, "kMDItemContentType == ’public.png’") of me on spotlightSearch(origPath, aMDfindParam) set my searchRes to {} –initialize initiateSearchForFullPath(aMDfindParam, origPath) –Predicate & Scope Directory –Waiting for the result repeat while my searchRes = {} delay 0.01 end repeat set anObj to my searchRes’s firstObject() –Pick up the first one for test if anObj = missing value then return {} –No Result set resArray to {} repeat with anItem in my searchRes set j to contents of anItem set aPath to (j’s valueForAttribute:"kMDItemPath") as string set the end of resArray to aPath end repeat return resArray end spotlightSearch on initiateSearchForFullPath(aQueryStrings, origPath) set aSearch to NSMetadataQuery’s alloc()’s init() NSNotificationCenter’s defaultCenter()’s addObserver:(me) selector:"queryDidUpdate:" |name|:(NSMetadataQueryDidUpdateNotification) object:aSearch NSNotificationCenter’s defaultCenter()’s addObserver:(me) selector:"initalGatherComplete:" |name|:(NSMetadataQueryDidFinishGatheringNotification) object:aSearch set aPredicate to NSPredicate’s predicateWithFormat:aQueryStrings aSearch’s setPredicate:aPredicate set aScope to NSArray’s arrayWithObjects:{origPath} aSearch’s setSearchScopes:aScope set sortKeys to NSSortDescriptor’s sortDescriptorWithKey:"kMDItemFSName" ascending:true aSearch’s setSortDescriptors:(NSArray’s arrayWithObject:sortKeys) aSearch’s startQuery() end initiateSearchForFullPath on queryDidUpdate:sender log sender –> (NSConcreteNotification) NSConcreteNotification 0x7fa618450820 {name = NSMetadataQueryDidFinishGatheringNotification; object = <NSMetadataQuery: 0x7fa6172c6ca0>} end queryDidUpdate: on initalGatherComplete:sender set anObject to sender’s object anObject’s stopQuery() NSNotificationCenter’s defaultCenter()’s removeObserver:me |name|:(NSMetadataQueryDidUpdateNotification) object:anObject NSNotificationCenter’s defaultCenter()’s removeObserver:me |name|:(NSMetadataQueryDidFinishGatheringNotification) object:anObject set my searchRes to anObject’s results() end initalGatherComplete: |
Finderで選択中の画像のうち、最小のものに合わせて各画像の左上を原点にサイズを統一するAppleScriptです。
Finderで選択中のファイルから画像のみ抽出し、そのうちサイズが最小のものに合わせて他の画像をトリミングし、変更したものをデスクトップフォルダに出力します。
▲大きさを揃える画像をFinder上で選択
▲処理前の画像。大きさがまちまち
▲処理後の画像。大きさが最小の画像に合わせてそろっている
スクリーンショット画像を複数撮った場合に、厳密に同じサイズに固定することは(各種スクリーンショット作成ユーティリティを使わないと)行いづらいところです。
そこで、最小の画像を計算で求めて、それに合わせて自動トリミングするようにしてみました。Cocoaの機能を用いて画像処理しているため、Photoshopは必要ありません。
最小の画像を求めるのに、幅+高さの値でソートして最小のものを求めています(widthとheightによる2 key sortではなく1 Keyで済ませたかったので)。
Blogや書籍用の掲載画面図の作成用、といったところでしょうか。Retina画面で撮ったスクリーンショットと非Retina画面のスクリーンショットが混在するとうまく動きません(スクリーンショット画像からはRetina環境で撮った画像であるかどうかを取得できません)。
スクリーンショットの画像からRetina/非Retina環境で撮ったかを判定するのは、(Retina対応機であるかをMachine IDから取得したあとで)Syslogにアクセスしてスクリーンが接続されたか、取り外されたかといった状態を追っていくしかないのかも。
本ScriptをmacOS 10.13.6上で動作確認して驚いたのですが、いままでRecordが返ってくるべき箇所でlistが返ってくる盛大なバグが直って、本ScriptがmacOS 10.13用に書き換えずに動きました(動かないことを確認しようとして動いたので驚いた)。
AppleScript名:Finder上で選択中の画像のうち、最小のものに合わせて各画像の左上を原点にサイズ統一 v2 |
— Created 2018-07-23 by Takaaki Naganoya — 2018 Piyomaru Software use AppleScript version "2.5" use scripting additions use framework "Foundation" use framework "AppKit" use framework "QuartzCore" property |NSURL| : a reference to current application’s |NSURL| property NSUUID : a reference to current application’s NSUUID property NSArray : a reference to current application’s NSArray property NSString : a reference to current application’s NSString property NSImage : a reference to current application’s NSImage property NSScreen : a reference to current application’s NSScreen property NSZeroRect : a reference to current application’s NSZeroRect property NSPredicate : a reference to current application’s NSPredicate property NSPNGFileType : a reference to current application’s NSPNGFileType property NSMutableArray : a reference to current application’s NSMutableArray property NSCompositeCopy : a reference to current application’s NSCompositeCopy property NSGraphicsContext : a reference to current application’s NSGraphicsContext property NSBitmapImageRep : a reference to current application’s NSBitmapImageRep property NSURLTypeIdentifierKey : a reference to current application’s NSURLTypeIdentifierKey property NSCalibratedRGBColorSpace : a reference to current application’s NSCalibratedRGBColorSpace tell application "Finder" set selList to selection as alias list end tell –指定のAlias listのうち画像のみ抽出 set filRes1 to filterAliasListByUTI(selList, "public.image") of me if filRes1 = {} then tell current application –Error Message (No Selection) display dialog "Finder上で選択されているファイルはありません。" buttons {"OK"} default button 1 with icon 1 with title "画像リサイズ処理できません" end tell return end if –各種情報を入れたArrayを作成 set anArray to NSMutableArray’s new() repeat with i in selList set imgPath to (POSIX path of i) set aImage to makeNSImageFromFile(i) of me set sizeInfo to |size|() of aImage set sizeInfo to sizeInfo & {aImg:aImage, total:(width of sizeInfo) + (height of sizeInfo), myPath:imgPath} (anArray’s addObject:sizeInfo) end repeat –最小のサイズの画像の算出 set aRes to anArray’s valueForKeyPath:("@min.total") set bRes to first item of (filterRecListByLabel(anArray, "total == " & aRes as string) of me) –最小サイズの画像 –最小サイズ画像のwidthとheight set minWidth to bRes’s width set minHeight to bRes’s height –環境情報の取得 set aPath to POSIX path of (path to desktop) set retinaF to (NSScreen’s mainScreen()’s backingScaleFactor()) as real –> 2.0 (Retina) / 1.0 (Non Retina) set cRes to filterRecListByLabel(anArray, "total != " & aRes as string) of me –最小サイズ以外の画像 repeat with i in cRes set j to contents of i set anImage to aImg of j set fRes to myPath of j set cropedImage to (my cropNSImageBy:{0, 0, minWidth, minHeight} fromImage:anImage) –v1で間違っていた –Retina環境対策 if retinaF > 1.0 then set cropedImage to (my resizedImage:cropedImage toScale:(1.0)) end if –ファイル書き込み set fRes to retUUIDfilePathFromDir(aPath, "png") of me set sRes to saveNSImageAtPathAsPNG(cropedImage, fRes) of me end repeat –リストに入れたレコードを、指定の属性ラベルの値で抽出 on filterRecListByLabel(aRecList as list, aPredicate as string) –ListからNSArrayへの型変換 set aArray to NSArray’s arrayWithArray:aRecList –抽出 set aPredicate to NSPredicate’s predicateWithFormat:aPredicate set filteredArray to aArray’s filteredArrayUsingPredicate:aPredicate –NSArrayからListに型変換して返す set bList to filteredArray as list return bList end filterRecListByLabel –Alias listから指定UTIに含まれるものをPOSIX pathのリストで返す on filterAliasListByUTI(aList, targUTI) set newList to {} repeat with i in aList set j to POSIX path of i set tmpUTI to my retUTIfromPath(j) set utiRes to my filterUTIList({tmpUTI}, targUTI) if utiRes is not equal to {} then set the end of newList to j end if end repeat return newList end filterAliasListByUTI –指定のPOSIX pathのファイルのUTIを求める on retUTIfromPath(aPOSIXPath) set aURL to |NSURL|’s fileURLWithPath:aPOSIXPath set {theResult, theValue} to aURL’s getResourceValue:(reference) forKey:NSURLTypeIdentifierKey |error|:(missing value) if theResult = true then return theValue as string else return theResult end if end retUTIfromPath –UTIリストが指定UTIに含まれているかどうか演算を行う on filterUTIList(aUTIList, aUTIstr) set anArray to NSArray’s arrayWithArray:aUTIList set aPred to NSPredicate’s predicateWithFormat_("SELF UTI-CONFORMS-TO %@", aUTIstr) set bRes to (anArray’s filteredArrayUsingPredicate:aPred) as list return bRes end filterUTIList on cropNSImageTo:{x1, y1, x2, y2} fromImage:theImage set newWidth to x2 – x1 set newHeight to y2 – y1 set theSize to (theImage’s |size|()) as record set oldHeight to height of theSize — transpose y value for Cocoa coordintates set y1 to oldHeight – newHeight – y1 set newRect to {{x:x1, y:y1}, {width:newWidth, height:newHeight}} theImage’s lockFocus() set theRep to NSBitmapImageRep’s alloc()’s initWithFocusedViewRect:newRect theImage’s unlockFocus() set outImage to NSImage’s alloc()’s initWithSize:(theRep’s |size|()) outImage’s addRepresentation:theRep return outImage end cropNSImageTo:fromImage: on makeNSImageFromFile(anAlias) set imgPath to (POSIX path of anAlias) set aURL to (|NSURL|’s fileURLWithPath:(imgPath)) return (NSImage’s alloc()’s initWithContentsOfURL:aURL) end makeNSImageFromFile –NSImageを指定の大きさでトリミング on cropNSImageBy:{x1, y1, newWidth, newHeight} fromImage:theImage set theSize to (theImage’s |size|()) as record set oldHeight to height of theSize — transpose y value for Cocoa coordintates set y1 to oldHeight – newHeight – y1 set newRect to {{x:x1, y:y1}, {width:newWidth, height:newHeight}} theImage’s lockFocus() set theRep to NSBitmapImageRep’s alloc()’s initWithFocusedViewRect:newRect theImage’s unlockFocus() set outImage to NSImage’s alloc()’s initWithSize:(theRep’s |size|()) outImage’s addRepresentation:theRep return outImage end cropNSImageBy:fromImage: on retUUIDfilePathFromDir(aPath, aEXT) set aUUIDstr to (NSUUID’s UUID()’s UUIDString()) as string set aPath to ((NSString’s stringWithString:aPath)’s stringByAppendingPathComponent:aUUIDstr)’s stringByAppendingPathExtension:aEXT return aPath end retUUIDfilePathFromDir –NSImageを指定パスにPNG形式で保存 on saveNSImageAtPathAsPNG(anImage, outPath) set imageRep to anImage’s TIFFRepresentation() set aRawimg to NSBitmapImageRep’s imageRepWithData:imageRep set pathString to NSString’s stringWithString:outPath set newPath to pathString’s stringByExpandingTildeInPath() set myNewImageData to (aRawimg’s representationUsingType:(NSPNGFileType) |properties|:(missing value)) set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean return aRes –true/false end saveNSImageAtPathAsPNG on resizedImage:aSourceImg toScale:imgScale if (aSourceImg’s isValid()) as boolean = false then error "Invalid NSImage" set aSize to aSourceImg’s |size|() –> {width:32.0, height:32.0} set aWidth to (aSize’s width) * imgScale set aHeight to (aSize’s height) * imgScale set aRep to NSBitmapImageRep’s alloc()’s initWithBitmapDataPlanes:(missing value) pixelsWide:aWidth pixelsHigh:aHeight bitsPerSample:8 samplesPerPixel:4 hasAlpha:true isPlanar:false colorSpaceName:(NSCalibratedRGBColorSpace) bytesPerRow:0 bitsPerPixel:0 set newSize to {width:aWidth, height:aHeight} aRep’s setSize:newSize NSGraphicsContext’s saveGraphicsState() NSGraphicsContext’s setCurrentContext:(NSGraphicsContext’s graphicsContextWithBitmapImageRep:aRep) aSourceImg’s drawInRect:(current application’s NSMakeRect(0, 0, aWidth, aHeight)) fromRect:(NSZeroRect) operation:(NSCompositeCopy) fraction:(1.0) NSGraphicsContext’s restoreGraphicsState() set newImg to NSImage’s alloc()’s initWithSize:newSize newImg’s addRepresentation:aRep return newImg end resizedImage:toScale: |
指定画像を任意の色で単色化し、指定色名をファイル名に反映させてファイル出力するAppleScriptです。
もとは、「色付き単色画像を作成する」AppleScriptに、
・choose colorによるユーザー選択色を反映
・choose colorで指定した色のざっくりとした色名検出
などの機能をつなぎ合わせたものです。
日本地図の白地図からカラーバリエーション画像を出力する際に作成しました。線が黒で書かれている白地図(白地図というのはそういうものですが)から、さまざまな色のバリエーションを作成。その際に、どのような色を指定したかをファイル名に反映させておいたほうが便利だったので、そのようにしてみました。
GPUImage.frameworkを利用しています。
–> GPUImage.framework (To ~/Library/Frameworks/)
色名推定のロジックもけっこうしっくりきていますが、明度も反映して、明るいものは「light-」、暗いものは「dark-」と出力させてもいいような気がします。ただし、「dark-orange」はBrownのことですし、ほかにも色名を別途振り直したほうがいいパターンもあるように思われます。
AppleScript名:色付き単色画像を作成する(自由色指定&色名推定) |
— Created 2017-02-11 by Takaaki Naganoya — Modified 2018-07-15 by Takaaki Naganoya — 2017-2018 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" use framework "AppKit" use framework "GPUImage" –https://github.com/BradLarson/GPUImage property NSUUID : a reference to current application’s NSUUID property NSColor : a reference to current application’s NSColor property NSString : a reference to current application’s NSString property NSImage : a reference to current application’s NSImage property NSBezierPath : a reference to current application’s NSBezierPath property NSPNGFileType : a reference to current application’s NSPNGFileType property GPUImagePicture : a reference to current application’s GPUImagePicture property NSBitmapImageRep : a reference to current application’s NSBitmapImageRep –Select Image File set aFile to POSIX path of (choose file of type {"public.image"} with prompt "Select image") –Select Color set {rCol, gCol, bCol} to choose color set fillColorR to makeNSColorFromRGBAval(rCol, gCol, bCol, 65535, 65535) of me set fillColorRName to retColorDomainNameFromNSColor(fillColorR) of me –だいたいの色名称を計算 set imgRes to makeMonoColoredImage(aFile, fillColorR) of me set fRes to retUUIDandKeyfilePath(aFile, fillColorRName, "png") of me set bRes to saveNSImageAtPathAsPNG(imgRes, fRes) of me — return "UUID_aKey.aEXT" full path on retUUIDandKeyfilePath(aPath, aKey, aEXT) set aUUIDstr to ((NSUUID’s UUID()’s UUIDString()) as string) & "_" & aKey set aPath to ((NSString’s stringWithString:aPath)’s stringByDeletingLastPathComponent()’s stringByAppendingPathComponent:aUUIDstr)’s stringByAppendingPathExtension:aEXT return aPath end retUUIDandKeyfilePath on makeMonoColoredImage(aFile, NScolorObj) set aImage to NSImage’s alloc()’s initWithContentsOfFile:aFile return makeColoredNSImageWithColor(aImage, NScolorObj) of me –色付き単色画像を作成する end makeMonoColoredImage on makeColoredNSImageWithColor(aImage, fillColor) set aSize to aImage’s |size|() set aWidth to width of aSize set aHeight to height of aSize set newNSImage to makeNSImageWithFilledWithColor(aWidth, aHeight, fillColor) set grayImage to filterWithNSImage(aImage, "GPUImageGrayscaleFilter") of me set compImage to composeImageWithBlendFilter(grayImage, newNSImage, "GPUImageScreenBlendFilter") of me return compImage end makeColoredNSImageWithColor on filterWithNSImage(aNSImage, filterName as string) set aClass to current application’s NSClassFromString(filterName) set aImageFilter to aClass’s alloc()’s init() set aProcImg to (aImageFilter’s imageByFilteringImage:aNSImage) return aProcImg end filterWithNSImage on composeImageWithBlendFilter(aImage, bImage, filterName) set aClass to current application’s NSClassFromString(filterName) set blendFilter to aClass’s alloc()’s init() set pictureA to GPUImagePicture’s alloc()’s initWithImage:aImage pictureA’s addTarget:blendFilter pictureA’s processImage() set imgRes to blendFilter’s imageByFilteringImage:bImage return imgRes end composeImageWithBlendFilter –指定サイズの画像を作成し、指定色で塗ってNSImageで返す on makeNSImageWithFilledWithColor(aWidth, aHeight, fillColor) –Imageの作成 set curSize to current application’s NSMakeSize(aWidth, aHeight) set anImage to NSImage’s alloc()’s initWithSize:curSize anImage’s lockFocus() –描画開始 set theRect to {{x:0, y:0}, {height:aHeight, width:aWidth}} set theNSBezierPath to NSBezierPath’s bezierPath theNSBezierPath’s appendBezierPathWithRect:theRect fillColor’s |set|() –色設定 theNSBezierPath’s fill() –ぬりつぶし anImage’s unlockFocus() –描画ここまで –生成した画像のRaw画像を作成 set imageRep to anImage’s TIFFRepresentation() set aRawimg to NSBitmapImageRep’s imageRepWithData:imageRep set newImg to NSImage’s alloc()’s initWithSize:curSize newImg’s addRepresentation:aRawimg return newImg end makeNSImageWithFilledWithColor –NSImageを指定パスにPNG形式で保存 on saveNSImageAtPathAsPNG(anImage, outPath) set imageRep to anImage’s TIFFRepresentation() set aRawimg to NSBitmapImageRep’s imageRepWithData:imageRep set pathString to NSString’s stringWithString:outPath set newPath to pathString’s stringByExpandingTildeInPath() set myNewImageData to (aRawimg’s representationUsingType:(NSPNGFileType) |properties|:(missing value)) set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean return aRes –true/false end saveNSImageAtPathAsPNG –NSColor(内容はRGBAカラー)からだいたいの色名を推測 on retColorDomainNameFromNSColor(aCol) set hueVal to aCol’s hueComponent() set satVal to aCol’s saturationComponent() set brightVal to aCol’s brightnessComponent() if satVal ≤ 0.01 then set satVal to 0.0 set colName to "" if satVal = 0.0 then if brightVal ≤ 0.2 then set colName to "black" else if (brightVal > 0.95) then set colName to "white" else set colName to "gray" end if else if hueVal ≤ (15.0 / 360) or hueVal ≥ (330 / 360) then set colName to "red" else if hueVal ≤ (45.0 / 360) then set colName to "orange" else if hueVal < (70.0 / 360) then set colName to "yellow" else if hueVal < (150.0 / 360) then set colName to "green" else if hueVal < (190.0 / 360) then set colName to "green(cyan)" else if (hueVal < 250.0 / 360.0) then set colName to "blue" else if (hueVal < 290.0 / 360.0) then set colName to "purple" else set colName to "red(magenta)" end if end if return colName end retColorDomainNameFromNSColor on makeNSColorFromRGBAval(redValue as integer, greenValue as integer, blueValue as integer, alphaValue as integer, aMaxVal as integer) set aRedCocoa to (redValue / aMaxVal) as real set aGreenCocoa to (greenValue / aMaxVal) as real set aBlueCocoa to (blueValue / aMaxVal) as real set aAlphaCocoa to (alphaValue / aMaxVal) as real set aColor to NSColor’s colorWithCalibratedRed:aRedCocoa green:aGreenCocoa blue:aBlueCocoa alpha:aAlphaCocoa return aColor end makeNSColorFromRGBAval |
PDFから指定ページ以降を削除するAppleScriptです。
こんな(↑)418ページもあるPDFから、おためし版の、冒頭から40ページだけ抽出したPDFを作成する際に使用したものです。
もともとは418ページありましたが、、、
実行後は40ページに、、、
AppleScript名:PDFから指定ページ以降を削除 |
— Modified 2018-07-08 by Takaaki Naganoya –Original By Shane Stanley use AppleScript version "2.4" use scripting additions use framework "Foundation" use framework "AppKit" use framework "QuartzCore" use aBplus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html property NSSet : a reference to current application’s NSSet property |NSURL| : a reference to current application’s |NSURL| property NSArray : a reference to current application’s NSArray property SMSForder : a reference to current application’s SMSForder property NSIndexSet : a reference to current application’s NSIndexSet property PDFDocument : a reference to current application’s PDFDocument property NSSortDescriptor : a reference to current application’s NSSortDescriptor load framework set sPage to 41 –ここから末尾までのページを削除 set inFile to (choose file of type {"pdf"} with prompt "Choose your PDF files:") set pRes to removePDFPageAfter(inFile, sPage) of me –指定パスのPDFの指定ページ以降をすべて削除 on removePDFPageAfter(inFile, sPage) set pCount to pdfPageCount(inFile) of me set eCount to pCount – sPage + 1 set aindexSet to NSIndexSet’s indexSetWithIndexesInRange:(current application’s NSMakeRange(sPage, eCount)) set targPageList to (SMSForder’s arrayWithIndexSet:aindexSet) as list return removeSpecificPagesFromPDF(inFile, targPageList) of me end removePDFPageAfter –指定PDF書類の複数ページの一括削除 on removeSpecificPagesFromPDF(inFileAlias, targPageNumList as list) set inNSURL to |NSURL|’s fileURLWithPath:(POSIX path of inFileAlias) set theDoc to PDFDocument’s alloc()’s initWithURL:inNSURL –削除対象ページリストをユニーク化して降順ソート(後方から削除) set pRes to theDoc’s pageCount() set t3List to relativeToAbsNumList(targPageNumList, pRes) of me repeat with i in t3List copy i to targPageNum (theDoc’s removePageAtIndex:(targPageNum – 1)) end repeat –Overwrite Exsiting PDF set aRes to (theDoc’s writeToURL:inNSURL) as boolean return aRes end removeSpecificPagesFromPDF –絶対ページと相対ページが混在した削除対象ページリストを絶対ページに変換して重複削除して降順ソート on relativeToAbsNumList(aList, aMax) set newList to {} repeat with i in aList set j to contents of i if i < 0 then set j to aMax + j end if if (j ≤ aMax) and (j is not equal to 0) then set the end of newList to j end if end repeat set t1List to uniquify1DList(newList, true) of me set t2List to sort1DNumListWithOrder(t1List, false) of me return t2List end relativeToAbsNumList –1D/2D Listをユニーク化 on uniquify1DList(theList as list, aBool as boolean) set aArray to NSArray’s arrayWithArray:theList set bArray to aArray’s valueForKeyPath:"@distinctUnionOfObjects.self" return bArray as list end uniquify1DList –Sort 1-Dimension List(String Number List) on sort1DNumListWithOrder(theList as list, aBool as boolean) tell NSSet to set theSet to setWithArray_(theList) tell NSSortDescriptor to set theDescriptor to sortDescriptorWithKey_ascending_("floatValue", aBool) set sortedList to theSet’s sortedArrayUsingDescriptors:{theDescriptor} return (sortedList) as list end sort1DNumListWithOrder –指定PDFのページ数をかぞえる(10.9対応。普通にPDFpageから取得) –返り値:PDFファイルのページ数(整数値) on pdfPageCount(aFile) set aFile to POSIX path of aFile set theURL to |NSURL|’s fileURLWithPath:aFile set aPDFdoc to PDFDocument’s alloc()’s initWithURL:theURL set aRes to aPDFdoc’s pageCount() return aRes as integer end pdfPageCount |
Finder上で選択中のMarkdown書類を取得し、ファイル名で昇順ソート(A→Z)して、各Markdown書類中のタイトルのうち最もレベルの高い(重要な)ものを抽出し、まとめてテキストにしてクリップボードに転送するAppleScriptです。
大量にあるMarkdown書類の本文中から一番重要なタイトルを抽出する作業を……さすがに手作業で行うわけには行かなかったので、AppleScriptを書いて処理してみました。ただし、新規に書いた処理はほとんどなく、既存のルーチンの寄せ合わせで構成しています。
Finder上でMarkdown書類を選択した状態で本Scriptを実行すると(Markdown書類以外は除外して)、AppleScriptでMarkdown書類を読み込んで(Markdown書類がUTF-8固定なのでUTF-8を指定して読み込み)、正規表現で書類中のタイトルを抽出し、重要なタイトル(#の個数が少ない)をピックアップ。これをすべての書類について行います。
処理結果をクリップボードに転送します。
最終的には、(手作業で加工して)このようになります。
若干の手作業は発生してしまいますが、このScriptを組まなかったら、とてもその手作業を行う気も起こらなかったわけで、、、
AppleScript名:Finder上で選択中のMarkdown書類をファイル名で昇順ソート(A→Z)して、各書類のタイトル見出しを取得する |
— Created 2018-06-26 by Takaaki Naganoya — 2018 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" use framework "Quartz" use mdLib : script "Metadata Lib" version "1.0.0" use bPlus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html property |NSURL| : a reference to current application’s |NSURL| property NSArray : a reference to current application’s NSArray property NSString : a reference to current application’s NSString property SMSForder : a reference to current application’s SMSForder property NSIndexSet : a reference to current application’s NSIndexSet property NSPredicate : a reference to current application’s NSPredicate property NSMutableSet : a reference to current application’s NSMutableSet property NSFileManager : a reference to current application’s NSFileManager property NSCountedSet : a reference to current application’s NSCountedSet property NSURLPathKey : a reference to current application’s NSURLPathKey property NSMutableArray : a reference to current application’s NSMutableArray property NSURLNameKey : a reference to current application’s NSURLNameKey property NSSortDescriptor : a reference to current application’s NSSortDescriptor property NSURLIsPackageKey : a reference to current application’s NSURLIsPackageKey property NSRegularExpression : a reference to current application’s NSRegularExpression property NSURLIsDirectoryKey : a reference to current application’s NSURLIsDirectoryKey property NSURLTypeIdentifierKey : a reference to current application’s NSURLTypeIdentifierKey property NSURLContentModificationDateKey : a reference to current application’s NSURLContentModificationDateKey property NSRegularExpressionAnchorsMatchLines : a reference to current application’s NSRegularExpressionAnchorsMatchLines property NSDirectoryEnumerationSkipsHiddenFiles : a reference to current application’s NSDirectoryEnumerationSkipsHiddenFiles property NSRegularExpressionDotMatchesLineSeparators : a reference to current application’s NSRegularExpressionDotMatchesLineSeparators load framework –set inFiles to (choose file of type {"pdf"} with prompt "Choose your PDF files:" with multiple selections allowed) tell application "Finder" set inFiles to selection as alias list end tell if inFiles = {} then return –指定のAlias listのうちMarkdown書類のみ抽出 set filRes1 to filterAliasListByUTI(inFiles, "net.daringfireball.markdown") of me –指定のPOSIX path listから、各Markdown書類中の一番重要な見出しを抽出して返す set tRes to listTitlesFromMarkdownDocPathList(filRes1) of me –取得したタイトル一覧リストをテキストに変換 set t2Res to retStrFromArrayWithDelimiter(tRes, return) of me –クリップボードに結果を転送 set the clipboard to t2Res on listTitlesFromMarkdownDocPathList(inFiles) set outList to {} set inFilesSorted to my filesInListSortAscending(inFiles) repeat with i in inFilesSorted –POSIX pathからaliasにパス変換してテキスト読み込み set j to POSIX file (contents of i) set jj to j as alias set aStr to (read jj as «class utf8») set aList to retHeaders(aStr) of me –Markdown書類中の見出しをリストアップ –> {{1, " 2008/3/9 5桁の乱数を生成"}} if aList is not equal to {} then –2D Listの昇順ソート set sortIndexes to {0} –Key Item id: begin from 0 set sortOrders to {true} –ascending = true set sortTypes to {"compare:"} set resList to (current application’s SMSForder’s subarraysIn:(aList) sortedByIndexes:sortIndexes ascending:sortOrders sortTypes:sortTypes |error|:(missing value)) as list set aCon to contents of second item of first item of resList set the end of outList to aCon end if end repeat return outList end listTitlesFromMarkdownDocPathList on filesInListSortAscending(aliasList as list) set cList to {} repeat with i in aliasList set j to contents of i set aFileName to ((current application’s NSString’s stringWithString:j)’s valueForKeyPath:"lastPathComponent") set the end of cList to {fileName:aFileName, pathDat:j} end repeat set aResList to sortRecListByLabel(cList, "fileName", true) of me –昇順ソート set bResList to (aResList’s valueForKeyPath:"pathDat") as list of string or string return bResList end filesInListSortAscending –Alias listから指定UTIに含まれるものをPOSIX pathのリストで返す on filterAliasListByUTI(aList, targUTI) set newList to {} repeat with i in aList set j to POSIX path of i set tmpUTI to my retUTIfromPath(j) set utiRes to my filterUTIList({tmpUTI}, targUTI) if utiRes is not equal to {} then set the end of newList to j end if end repeat return newList end filterAliasListByUTI –指定のPOSIX pathのファイルのUTIを求める on retUTIfromPath(aPOSIXPath) set aURL to |NSURL|’s fileURLWithPath:aPOSIXPath set {theResult, theValue} to aURL’s getResourceValue:(reference) forKey:NSURLTypeIdentifierKey |error|:(missing value) if theResult = true then return theValue as string else return theResult end if end retUTIfromPath –UTIリストが指定UTIに含まれているかどうか演算を行う on filterUTIList(aUTIList, aUTIstr) set anArray to NSArray’s arrayWithArray:aUTIList set aPred to NSPredicate’s predicateWithFormat_("SELF UTI-CONFORMS-TO %@", aUTIstr) set bRes to (anArray’s filteredArrayUsingPredicate:aPred) as list return bRes end filterUTIList on returnNumberCharsOnly(aStr) set anNSString to current application’s NSString’s stringWithString:aStr set anNSString to anNSString’s stringByReplacingOccurrencesOfString:"[^0-9]" withString:"" options:(current application’s NSRegularExpressionSearch) range:{0, anNSString’s |length|()} return anNSString as text end returnNumberCharsOnly –リストに入れたレコードを、指定の属性ラベルの値でソート on sortRecListByLabel(aRecList as list, aLabelStr as string, ascendF as boolean) set aArray to current application’s NSArray’s arrayWithArray:aRecList set sortDesc to current application’s NSSortDescriptor’s alloc()’s initWithKey:aLabelStr ascending:ascendF set sortDescArray to current application’s NSArray’s arrayWithObjects:sortDesc set sortedArray to aArray’s sortedArrayUsingDescriptors:sortDescArray return sortedArray end sortRecListByLabel –見出し抽出用サブルーチン群 on retHeaders(aCon) set tList to {} set regStr to "^#{1,6}[^#]*?$" set headerList to my findPattern:regStr inString:aCon repeat with i in headerList set j to contents of i set regStr2 to "^#{1,6}[^#]*?" set headerLevel to length of first item of (my findPattern:regStr2 inString:j) set the end of tList to {headerLevel, text (headerLevel + 1) thru -1 in j} end repeat return tList end retHeaders on findPattern:thePattern inString:theString set theOptions to ((NSRegularExpressionDotMatchesLineSeparators) as integer) + ((NSRegularExpressionAnchorsMatchLines) as integer) set theRegEx to NSRegularExpression’s regularExpressionWithPattern:thePattern options:theOptions |error|:(missing value) set theFinds to theRegEx’s matchesInString:theString options:0 range:{location:0, |length|:length of theString} set theFinds to theFinds as list — so we can loop through set theResult to {} — we will add to this set theNSString to NSString’s stringWithString:theString repeat with i from 1 to count of items of theFinds set theRange to (item i of theFinds)’s range() set end of theResult to (theNSString’s substringWithRange:theRange) as string end repeat return theResult end findPattern:inString: –リストを指定デリミタをはさんでテキスト化 on retStrFromArrayWithDelimiter(aList, aDelim) set anArray to current application’s NSArray’s arrayWithArray:aList set aRes to anArray’s componentsJoinedByString:aDelim return aRes as list of string or string end retStrFromArrayWithDelimiter |
指定フォルダ(デスクトップ)内の指定拡張子のファイルのうち、ファイル名が指定キーワードではじまるものを抽出するAppleScriptです。
AppleScriptでは定番の処理ですが、Finderが10.7あたりでCocoa化されて書き直しが行われたあたりからフィルタ参照を併用した条件抽出のパフォーマンスが大幅に低下。
アプリケーション間通信でパフォーマンスを低下させないための機能であるフィルタ参照が、かえって処理速度を低下させるというたいへん皮肉な事態に。
AppleScript名:指定フォルダ内の指定拡張子のファイルのうち、指定キーワードで始まるものをaliasリストで返す(Finder Version) |
tell application "Finder" tell folder (path to desktop) set aList to (every file whose name starts with "スナップショット" and kind of it is "PNGイメージ") as alias list end tell end tell |
Finder経由で行うと、処理時間は驚愕の4.6秒(67項目から1項目を抽出するだけの処理です)。これをCocoaの機能を用いて処理すると0.002秒。同じAppleScriptなのに2,000倍以上高速。逆にいえば、現在のFinder経由でのファイル処理の速度は遅すぎです。
macOS 10.10以降では、各種ファイル処理についてはFinderではなくCocoaの機能を用いたほうがよいでしょう。
その他、Finder上で選択中のファイルの一覧を取得するとか、Finder上で選択中のフォルダを取得するといった処理であればパフォーマンスの低下はないので、使っても(処理速度上の)問題はありません。
AppleScript名:指定フォルダ内の指定拡張子のファイルのうち、指定キーワードで始まるものをPOSIX pathリストで返す |
— Created 2015-10-01 by Takaaki Naganoya — Modified 2015-10-01 by Shane Stanley–With Cocoa-Style Filtering — Modified 2018-07-03 by Takaaki Naganoya–Added filtering feature use AppleScript version "2.5" use scripting additions use framework "Foundation" property |NSURL| : a reference to current application’s |NSURL| property NSPredicate : a reference to current application’s NSPredicate property NSFileManager : a reference to current application’s NSFileManager property NSDirectoryEnumerationSkipsHiddenFiles : a reference to current application’s NSDirectoryEnumerationSkipsHiddenFiles set aExtension to "png" — no dot set aKeyword to "スナップショット" –"Snapshot" in Japanese set aTargetFolder to POSIX path of (path to desktop folder) set fList to getFilePathListByExtAndKeyword(aTargetFolder, aExtension, aKeyword) of me –> {"/Users/me/Desktop/スナップショット-2018-07-03 at 11_42_12 AM-1696613812.png"} on getFilePathListByExtAndKeyword(aFol, aExt, aKeyword) set aFM to NSFileManager’s defaultManager() set aURL to |NSURL|’s fileURLWithPath:aFol set urlArray to aFM’s contentsOfDirectoryAtURL:aURL includingPropertiesForKeys:{} options:(NSDirectoryEnumerationSkipsHiddenFiles) |error|:(missing value) set thePred to NSPredicate’s predicateWithFormat:"pathExtension == [c]%@ && lastPathComponent BEGINSWITH %@" argumentArray:{aExt, aKeyword} set anArray to (urlArray’s filteredArrayUsingPredicate:thePred) if anArray = missing value then return {} return (anArray’s valueForKeyPath:"path") as list end getFilePathListByExtAndKeyword |
Finder上で選択中のPDFのうち、ファイル名中の数字が小さいものから大きなものへソートを行うAppleScriptです。
Finder上で選択中のPDFをファイル名順でソートするような用途に使用します。選択中のファイルのうちPDFに該当しないものは無視します。
Finderで選択中の各PDFファイルに数字以外の文字がファイル名に混入していても無視します。
ファイル名はいったん数値として評価してソートするため、ファイル名にゼロパディングしてある場合には無視します。
Finder上で選択中のPDFを連結するさいに、ファイル名順で連結するScriptがあったほうが便利なので、そのために作ったものです。
ソートを行う際に、ファイル名の中の数字以外の部分をすべて無視するようにしています。そのため、Finder上の並び順と関係なく、ファイル名の中の数字部分のみをピックアップしてソートします。Finder自体にもFinderのルールでファイル名をソートして返すAppleScriptの機能がありますが、あれに甘えているとまともな処理はできません。
「test1_0004.pdf」というファイル名があった場合には10004という数値を検出するため、こうしたケースに対応する必要があるかもしれませんが、現時点では無用な数字の除去はしていません(それこそ一括処理で行うものではなくユーザーの目で見て判断してもらうような処理なので)。
AppleScript名:Finder上で選択中のPDFの数字のファイル名で小さいものから大きなものへとソート |
— Created 2018-06-26 by Takaaki Naganoya — 2018 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" use mdLib : script "Metadata Lib" version "1.0.0" –https://www.macosxautomation.com/applescript/apps/ use bPlus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html property |NSURL| : a reference to current application’s |NSURL| property NSArray : a reference to current application’s NSArray property NSPredicate : a reference to current application’s NSPredicate property NSURLTypeIdentifierKey : a reference to current application’s NSURLTypeIdentifierKey tell application "Finder" set inFiles to selection as alias list end tell if inFiles = {} then return –指定のAlias listのうちPDFのみ抽出 set filRes1 to filterAliasListByUTI(inFiles, "com.adobe.pdf") of me –ファイル名 set cList to {} repeat with i in (filRes1 as list) set j to contents of i set aFileName to ((current application’s NSString’s stringWithString:j)’s valueForKeyPath:"lastPathComponent.stringByDeletingPathExtension") set aNumF to returnNumberCharsOnly(aFileName) of me set the end of cList to {numDat:(aNumF as integer), pathDat:j} end repeat set aResList to sortRecListByLabel(cList, "numDat", true) of me –昇順ソート set bResList to (aResList’s valueForKeyPath:"pathDat") as list of string or string –> {"/Users/me/Pictures/243.pdf", "/Users/me/Pictures/244.pdf", "/Users/me/Pictures/245.pdf", "/Users/me/Pictures/246.pdf", "/Users/me/Pictures/247.pdf", "/Users/me/Pictures/248.pdf", "/Users/me/Pictures/249.pdf", "/Users/me/Pictures/250.pdf", "/Users/me/Pictures/251.pdf", "/Users/me/Pictures/252.pdf", "/Users/me/Pictures/253.pdf", "/Users/me/Pictures/254.pdf", "/Users/me/Pictures/255.pdf", "/Users/me/Pictures/256.pdf", "/Users/me/Pictures/257.pdf"} –文字列中から on returnNumberCharsOnly(aStr) set anNSString to current application’s NSString’s stringWithString:aStr set anNSString to anNSString’s stringByReplacingOccurrencesOfString:"[^0-9]" withString:"" options:(current application’s NSRegularExpressionSearch) range:{0, anNSString’s |length|()} return anNSString as text end returnNumberCharsOnly –リストに入れたレコードを、指定の属性ラベルの値でソート on sortRecListByLabel(aRecList as list, aLabelStr as string, ascendF as boolean) –ListからNSArrayへの型変換 set aArray to current application’s NSArray’s arrayWithArray:aRecList –ソート set sortDesc to current application’s NSSortDescriptor’s alloc()’s initWithKey:aLabelStr ascending:ascendF set sortDescArray to current application’s NSArray’s arrayWithObjects:sortDesc set sortedArray to aArray’s sortedArrayUsingDescriptors:sortDescArray return sortedArray end sortRecListByLabel –Alias listから指定UTIに含まれるものをPOSIX pathのリストで返す on filterAliasListByUTI(aList, targUTI) set newList to {} repeat with i in aList set j to POSIX path of i set tmpUTI to my retUTIfromPath(j) set utiRes to my filterUTIList({tmpUTI}, targUTI) if utiRes is not equal to {} then set the end of newList to j end if end repeat return newList end filterAliasListByUTI –指定のPOSIX pathのファイルのUTIを求める on retUTIfromPath(aPOSIXPath) set aURL to |NSURL|’s fileURLWithPath:aPOSIXPath set {theResult, theValue} to aURL’s getResourceValue:(reference) forKey:NSURLTypeIdentifierKey |error|:(missing value) if theResult = true then return theValue as string else return theResult end if end retUTIfromPath –UTIリストが指定UTIに含まれているかどうか演算を行う on filterUTIList(aUTIList, aUTIstr) set anArray to NSArray’s arrayWithArray:aUTIList set aPred to NSPredicate’s predicateWithFormat_("SELF UTI-CONFORMS-TO %@", aUTIstr) set bRes to (anArray’s filteredArrayUsingPredicate:aPred) as list return bRes end filterUTIList |
Finder上で選択中の画像を右に(時計回りに)90度回転させるAppleScriptです。
Finder上で選択中のファイルのうち、UTIがpublic.imageに含まれるもの(JPEGとかPNGとかTIFFとか)を指定の角度に回転させます。
もともと、選択中のアイテムからファイル種別でオブジェクトを抽出する機能はFinderのものを利用していたのですが、最近のFinderは応答速度が下がっているため、選択中のファイルの取得以外は極力Finderを利用しないのが(macOS 10.10以降の)おすすめです。
macOS標準搭載のScript Menu(フォルダ構造がそのままメニューになり、Scriptをメニューから実行できる)に登録して実行しています。
AppleScript名:Finderで選択中の画像を右に90度回転 |
— Created 2017-11-21 by Takaaki Naganoya — Modified 2018-04-06 by Takaaki Naganoya — 2018 Piyomaru Software use AppleScript version "2.5" — El Capitan (10.11) or later use framework "Foundation" use scripting additions property |NSURL| : a reference to current application’s |NSURL| property NSArray : a reference to current application’s NSArray property NSString : a reference to current application’s NSString property NSPredicate : a reference to current application’s NSPredicate property NSFileManager : a reference to current application’s NSFileManager property NSURLTypeIdentifierKey : a reference to current application’s NSURLTypeIdentifierKey set targDegree to 90 — targDegree have to be in {0, 90, 180, 270, 360} in clockwise tell application "Finder" set inFiles to selection as alias list end tell if inFiles = {} then return –指定のAlias listのうち画像のみ抽出 set filRes1 to filterAliasListByUTI(inFiles, "public.image") of me if filRes1 = {} then return –選択中のファイルのうちの1つから親フォルダを求め、出力先ファイルパスを組み立てる set outPathTarg to POSIX path of (first item of filRes1) set pathString to current application’s NSString’s stringWithString:outPathTarg set newPath to (pathString’s stringByDeletingLastPathComponent()) as string repeat with i in filRes1 rotateImageandSaveIt(i, targDegree) of me end repeat –指定角度に画像を回転させて上書き保存 on rotateImageandSaveIt(this_file, aTargerRect) tell application "Image Events" launch set this_image to open this_file rotate this_image to angle aTargerRect save this_image with icon close this_image end tell end rotateImageandSaveIt –Alias listから指定UTIに含まれるものをPOSIX pathのリストで返す on filterAliasListByUTI(aList, targUTI) set newList to {} repeat with i in aList set j to POSIX path of i set tmpUTI to my retUTIfromPath(j) set utiRes to my filterUTIList({tmpUTI}, targUTI) if utiRes is not equal to {} then set the end of newList to j end if end repeat return newList end filterAliasListByUTI –指定のPOSIX pathのファイルのUTIを求める on retUTIfromPath(aPOSIXPath) set aURL to |NSURL|’s fileURLWithPath:aPOSIXPath set {theResult, theValue} to aURL’s getResourceValue:(reference) forKey:NSURLTypeIdentifierKey |error|:(missing value) if theResult = true then return theValue as string else return theResult end if end retUTIfromPath –UTIリストが指定UTIに含まれているかどうか演算を行う on filterUTIList(aUTIList, aUTIstr) set anArray to NSArray’s arrayWithArray:aUTIList set aPred to NSPredicate’s predicateWithFormat_("SELF UTI-CONFORMS-TO %@", aUTIstr) set bRes to (anArray’s filteredArrayUsingPredicate:aPred) as list return bRes end filterUTIList |
Finder上で選択中のPDFを反時計方向に90°回転(=時計方向に270°回転)させるAppleScriptです。
Finder上で選択中の項目の中にPDF以外のものがあった場合には処理をスキップし、選択中のアイテムがない場合には処理を行いません。
実際には、macOS標準装備のScript Menuに、それぞれの角度(90°、180°、270°)への回転Scriptを個別に入れて使っています。1本のScriptで角度入力を行って回転させるよりも、あらかじめ固定の角度に回転させるものを複数用意しておいたほうが使い勝手がよいためです。
ドキュメントスキャナで紙の資料をPDFにスキャンするような時に、紙がヨレていて1枚ずつでないとスキャンできないような場合で、さらに穴が空いていたりヨレていて通常方向に紙を入れられなかった場合に、他の方向に入れてスキャンしておき、本Scriptのようなプログラムであとでまとめて回転させるなどの処理をよく行っています。
AppleScript名:Finderで選択中のPDFを反時計方向に90°回転させる |
— Created 2018-05-26 by Takaaki Naganoya — Modified 2018-06-02 by Takaaki Naganoya — 2018 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" use framework "Quartz" property |NSURL| : a reference to current application’s |NSURL| property NSUUID : a reference to current application’s NSUUID property NSArray : a reference to current application’s NSArray property NSString : a reference to current application’s NSString property NSPredicate : a reference to current application’s NSPredicate property PDFDocument : a reference to current application’s PDFDocument property NSFileManager : a reference to current application’s NSFileManager property NSURLPathKey : a reference to current application’s NSURLPathKey property NSMutableArray : a reference to current application’s NSMutableArray property NSSortDescriptor : a reference to current application’s NSSortDescriptor property NSURLIsPackageKey : a reference to current application’s NSURLIsPackageKey property NSURLIsDirectoryKey : a reference to current application’s NSURLIsDirectoryKey property NSURLTypeIdentifierKey : a reference to current application’s NSURLTypeIdentifierKey property NSURLContentModificationDateKey : a reference to current application’s NSURLContentModificationDateKey property NSDirectoryEnumerationSkipsHiddenFiles : a reference to current application’s NSDirectoryEnumerationSkipsHiddenFiles set targDegree to 270 — targDegree have to be in {0, 90, 180, 270, 360} in clockwise –set inFiles to (choose file of type {"pdf"} with prompt "Choose your PDF files:" with multiple selections allowed) tell application "Finder" set inFiles to selection as alias list end tell if inFiles = {} then return –指定のAlias listのうちPDFのみ抽出 set filRes1 to filterAliasListByUTI(inFiles, "com.adobe.pdf") of me if filRes1 = {} then return –選択中のファイルのうちの1つから親フォルダを求め、出力先ファイルパスを組み立てる set outPathTarg to POSIX path of (first item of filRes1) set pathString to NSString’s stringWithString:outPathTarg set newPath to (pathString’s stringByDeletingLastPathComponent()) as string repeat with i in filRes1 set destPosixPath to newPath & "/" & ((NSUUID’s UUID()’s UUIDString()) as string) & ".pdf" rotatePDFandSaveAt(i, destPosixPath, targDegree) of me end repeat –与えられたPOSIX pathのPDFを指定の角度に回転させて新規指定パスに書き出す on rotatePDFandSaveAt(oldPath as string, newPath as string, aDegree as integer) –Error Check if aDegree is not in {0, 90, 180, 270, 360} then error "Wrong Degree" set aURL to current application’s |NSURL|’s fileURLWithPath:oldPath set aPDFdoc to PDFDocument’s alloc()’s initWithURL:aURL set pCount to aPDFdoc’s pageCount() –count pages –Make Blank PDF set newPDFdoc to PDFDocument’s alloc()’s init() –Rotate Each Page repeat with i from 0 to (pCount – 1) set aPage to (aPDFdoc’s pageAtIndex:i) –Set Degree set curDegree to aPage’s |rotation|() –Get Current Degree (aPage’s setRotation:(aDegree + curDegree)) –Set New Degree (newPDFdoc’s insertPage:aPage atIndex:i) end repeat set aRes to newPDFdoc’s writeToFile:newPath return aRes as boolean end rotatePDFandSaveAt –Alias listから指定UTIに含まれるものをPOSIX pathのリストで返す on filterAliasListByUTI(aList, targUTI) set newList to {} repeat with i in aList set j to POSIX path of i set tmpUTI to my retUTIfromPath(j) set utiRes to my filterUTIList({tmpUTI}, targUTI) if utiRes is not equal to {} then set the end of newList to j end if end repeat return newList end filterAliasListByUTI –指定のPOSIX pathのファイルのUTIを求める on retUTIfromPath(aPOSIXPath) set aURL to |NSURL|’s fileURLWithPath:aPOSIXPath set {theResult, theValue} to aURL’s getResourceValue:(reference) forKey:NSURLTypeIdentifierKey |error|:(missing value) if theResult = true then return theValue as string else return theResult end if end retUTIfromPath –UTIリストが指定UTIに含まれているかどうか演算を行う on filterUTIList(aUTIList, aUTIstr) set anArray to NSArray’s arrayWithArray:aUTIList set aPred to NSPredicate’s predicateWithFormat_("SELF UTI-CONFORMS-TO %@", aUTIstr) set bRes to (anArray’s filteredArrayUsingPredicate:aPred) as list return bRes end filterUTIList |
Finder上で選択中の画像をアンチエイリアスなしで200%にリサイズするAppleScriptです。
よく使う拡大/縮小倍率のScriptを用意してmacOS標準装備のScript Menuに入れておき、Menuから呼び出して使っています。
AppleScript名:Finder上で選択中の画像をアンチエイリアスなしで200%にリサイズ |
— Created 2014-02-21 Shane Stanley — Modified 2018-06-01 Takaaki Naganoya use AppleScript version "2.5" use scripting additions use framework "Foundation" use framework "AppKit" property |NSURL| : a reference to current application’s |NSURL| property NSArray : a reference to current application’s NSArray property NSPredicate : a reference to current application’s NSPredicate property NSURLTypeIdentifierKey : a reference to current application’s NSURLTypeIdentifierKey set zoomPercent to 2.0 tell application "Finder" set inFiles to selection as alias list end tell –指定のAlias listのうち画像のみ抽出 set filRes1 to filterAliasListByUTI(inFiles, "public.image") of me if filRes1 = {} then return –選択中のファイルのうちの1つから親フォルダを求め、出力先ファイルパスを組み立てる set outPathTarg to POSIX path of (first item of filRes1) set pathString to current application’s NSString’s stringWithString:outPathTarg set newPath to (pathString’s stringByDeletingLastPathComponent()) as string repeat with i in filRes1 set outPOSIXpath to newPath & "/" & (current application’s NSUUID’s UUID()’s UUIDString()) as string set aNSImage to (current application’s NSImage’s alloc()’s initWithContentsOfFile:(i)) set theImage to (my resizeNSImageWithoutAntlialias:aNSImage toScale:zoomPercent) –ファイルパスの拡張子を取得する set pathString to (current application’s NSString’s stringWithString:i) set fileExt to (pathString’s pathExtension()) as string set newPath to outPOSIXpath & "." & fileExt –元画像のファイルファイルフォーマットに合わせて同じフォーマットに if fileExt is in {"png", "PNG"} then my saveNSImageAtPathAsPNG(theImage, newPath) else if fileExt is in {"jpg", "jpeg"} then my saveNSImageAtPathAsJPG(theImage, newPath, 1.0 as real) else if fileExt is in {"tif", "tiff"} then my saveNSImageAtPathAsTIFF(theImage, newPath) else if fileExt is in {"bmp"} then my saveNSImageAtPathAsBMP(theImage, newPath) end if end repeat –NSImageを指定倍率で拡大(アンチエイリアス解除状態で) on resizeNSImageWithoutAntlialias:aSourceImg toScale:imgScale set aSize to aSourceImg’s |size|() set aWidth to (aSize’s width) * imgScale set aHeight to (aSize’s height) * imgScale set aRep to current application’s NSBitmapImageRep’s alloc()’s initWithBitmapDataPlanes:(missing value) pixelsWide:aWidth pixelsHigh:aHeight bitsPerSample:8 samplesPerPixel:4 hasAlpha:true isPlanar:false colorSpaceName:(current application’s NSCalibratedRGBColorSpace) bytesPerRow:0 bitsPerPixel:0 set newSize to {width:aWidth, height:aHeight} aRep’s setSize:newSize current application’s NSGraphicsContext’s saveGraphicsState() set theContext to current application’s NSGraphicsContext’s graphicsContextWithBitmapImageRep:aRep current application’s NSGraphicsContext’s setCurrentContext:theContext theContext’s setShouldAntialias:false theContext’s setImageInterpolation:(current application’s NSImageInterpolationNone) aSourceImg’s drawInRect:(current application’s NSMakeRect(0, 0, aWidth, aHeight)) fromRect:(current application’s NSZeroRect) operation:(current application’s NSCompositeCopy) fraction:(1.0) current application’s NSGraphicsContext’s restoreGraphicsState() set newImg to current application’s NSImage’s alloc()’s initWithSize:newSize newImg’s addRepresentation:aRep return newImg end resizeNSImageWithoutAntlialias:toScale: –Alias listから指定UTIに含まれるものをPOSIX pathのリストで返す on filterAliasListByUTI(aList, targUTI) set newList to {} repeat with i in aList set j to POSIX path of i set tmpUTI to my retUTIfromPath(j) set utiRes to my filterUTIList({tmpUTI}, targUTI) if utiRes is not equal to {} then set the end of newList to j end if end repeat return newList end filterAliasListByUTI –指定のPOSIX pathのファイルのUTIを求める on retUTIfromPath(aPOSIXPath) set aURL to |NSURL|’s fileURLWithPath:aPOSIXPath set {theResult, theValue} to aURL’s getResourceValue:(reference) forKey:NSURLTypeIdentifierKey |error|:(missing value) if theResult = true then return theValue as string else return theResult end if end retUTIfromPath –UTIリストが指定UTIに含まれているかどうか演算を行う on filterUTIList(aUTIList, aUTIstr) set anArray to NSArray’s arrayWithArray:aUTIList set aPred to NSPredicate’s predicateWithFormat_("SELF UTI-CONFORMS-TO %@", aUTIstr) set bRes to (anArray’s filteredArrayUsingPredicate:aPred) as list return bRes end filterUTIList –NSImageを指定パスにJPEG形式で保存、qulityNumは0.0〜1.0。1.0は無圧縮 on saveNSImageAtPathAsJPG(anImage, outPath, qulityNum as real) set imageRep to anImage’s TIFFRepresentation() set aRawimg to current application’s NSBitmapImageRep’s imageRepWithData:imageRep set pathString to current application’s NSString’s stringWithString:outPath set newPath to pathString’s stringByExpandingTildeInPath() set myNewImageData to (aRawimg’s representationUsingType:(current application’s NSJPEGFileType) |properties|:{NSImageCompressionFactor:qulityNum}) set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean return aRes –true/false end saveNSImageAtPathAsJPG –NSImageを指定パスにTIFF形式で保存 on saveNSImageAtPathAsTIFF(anImage, outPath) set imageRep to anImage’s TIFFRepresentation() set aRawimg to current application’s NSBitmapImageRep’s imageRepWithData:imageRep set pathString to current application’s NSString’s stringWithString:outPath set newPath to pathString’s stringByExpandingTildeInPath() set myNewImageData to (aRawimg’s representationUsingType:(current application’s NSTIFFFileType) |properties|:(missing value)) set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean return aRes –true/false end saveNSImageAtPathAsTIFF –NSImageを指定パスにPNG形式で保存 on saveNSImageAtPathAsPNG(anImage, outPath) set imageRep to anImage’s TIFFRepresentation() set aRawimg to current application’s NSBitmapImageRep’s imageRepWithData:imageRep set pathString to current application’s NSString’s stringWithString:outPath set newPath to pathString’s stringByExpandingTildeInPath() set myNewImageData to (aRawimg’s representationUsingType:(current application’s NSPNGFileType) |properties|:(missing value)) set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean return aRes –true/false end saveNSImageAtPathAsPNG –NSImageを指定パスにBMP形式で保存 on saveNSImageAtPathAsBMP(anImage, outPath) set imageRep to anImage’s TIFFRepresentation() set aRawimg to current application’s NSBitmapImageRep’s imageRepWithData:imageRep set pathString to current application’s NSString’s stringWithString:outPath set newPath to pathString’s stringByExpandingTildeInPath() set myNewImageData to (aRawimg’s representationUsingType:(current application’s NSBMPFileType) |properties|:(missing value)) set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean return aRes –true/false end saveNSImageAtPathAsBMP |
Finder上で選択中の画像をアンチエイリアスありで50%にリサイズするAppleScriptです。
よく使う拡大/縮小倍率のScriptを用意してmacOS標準装備のScript Menuに入れておき、Menuから呼び出して使っています。
AppleScript名:Finder上で選択中の画像をアンチエイリアスありで50%にリサイズ |
— Created 2014-02-21 Shane Stanley — Modified 2018-06-01 Takaaki Naganoya use AppleScript version "2.5" use scripting additions use framework "Foundation" use framework "AppKit" property |NSURL| : a reference to current application’s |NSURL| property NSArray : a reference to current application’s NSArray property NSPredicate : a reference to current application’s NSPredicate property NSURLTypeIdentifierKey : a reference to current application’s NSURLTypeIdentifierKey set zoomPercent to 0.5 tell application "Finder" set inFiles to selection as alias list end tell –指定のAlias listのうち画像のみ抽出 set filRes1 to filterAliasListByUTI(inFiles, "public.image") of me if filRes1 = {} then return –選択中のファイルのうちの1つから親フォルダを求め、出力先ファイルパスを組み立てる set outPathTarg to POSIX path of (first item of filRes1) set pathString to current application’s NSString’s stringWithString:outPathTarg set newPath to (pathString’s stringByDeletingLastPathComponent()) as string repeat with i in filRes1 set outPOSIXpath to newPath & "/" & (current application’s NSUUID’s UUID()’s UUIDString()) as string set fRes1 to resizeImage(i, outPOSIXpath, zoomPercent) of me end repeat on resizeImage(imagePath, newPath, aZoom as real) –ファイルパスの拡張子を取得する set pathString to current application’s NSString’s stringWithString:imagePath set fileExt to (pathString’s pathExtension()) as string –画像ファイルをNSImageに読み込み set theImage to current application’s NSImage’s alloc()’s initWithContentsOfFile:imagePath — load the file as an NSImage — calculate required sizes set theSize to (theImage’s |size|()) as record set oldWidth to width of theSize set oldHeight to height of theSize set theWidth to oldWidth * aZoom set theHeight to oldHeight * aZoom set newImage to current application’s NSImage’s alloc()’s initWithSize:(current application’s NSMakeSize(theWidth, theHeight)) newImage’s lockFocus() theImage’s drawInRect:{origin:{x:0, y:0}, |size|:{width:theWidth, height:theHeight}} fromRect:(current application’s NSZeroRect) operation:(current application’s NSCompositeSourceOver) fraction:1.0 newImage’s unlockFocus() set theData to newImage’s TIFFRepresentation() set newRep to current application’s NSBitmapImageRep’s imageRepWithData:theData –元画像のファイルファイルフォーマットに合わせて同じフォーマットに if fileExt is in {"png", "PNG"} then set theData to (newRep’s representationUsingType:(current application’s NSPNGFileType) |properties|:{NSImageGamma:1.0}) else if fileExt is in {"jpg", "jpeg"} then set theData to (newRep’s representationUsingType:(current application’s NSJPEGFileType) |properties|:{NSImageCompressionFactor:1.0}) else if fileExt is in {"tif", "tiff"} then set theData to (newRep’s representationUsingType:(current application’s NSTIFFFileType) |properties|:(missing value)) else if fileExt is in {"bmp"} then set theData to (newRep’s representationUsingType:(current application’s NSBMPFileType) |properties|:(missing value)) end if set newPath to newPath & "." & fileExt return (theData’s writeToFile:newPath atomically:true) end resizeImage –Alias listから指定UTIに含まれるものをPOSIX pathのリストで返す on filterAliasListByUTI(aList, targUTI) set newList to {} repeat with i in aList set j to POSIX path of i set tmpUTI to my retUTIfromPath(j) set utiRes to my filterUTIList({tmpUTI}, targUTI) if utiRes is not equal to {} then set the end of newList to j end if end repeat return newList end filterAliasListByUTI –指定のPOSIX pathのファイルのUTIを求める on retUTIfromPath(aPOSIXPath) set aURL to |NSURL|’s fileURLWithPath:aPOSIXPath set {theResult, theValue} to aURL’s getResourceValue:(reference) forKey:NSURLTypeIdentifierKey |error|:(missing value) if theResult = true then return theValue as string else return theResult end if end retUTIfromPath –UTIリストが指定UTIに含まれているかどうか演算を行う on filterUTIList(aUTIList, aUTIstr) set anArray to NSArray’s arrayWithArray:aUTIList set aPred to NSPredicate’s predicateWithFormat_("SELF UTI-CONFORMS-TO %@", aUTIstr) set bRes to (anArray’s filteredArrayUsingPredicate:aPred) as list return bRes end filterUTIList |
指定の画像から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情報から撮影日付を取得し、画像ファイルの作成日付に反映させる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 |
指定ファイルのFinderタグを取得/設定/追加を行うAppleScriptです。
もともとはShane Stanleyが数年前に書いたScriptですが、Cocoaっぽいハンドラ記述だと慣れていないScripterには敷居が高いので、OLD Style AppleScript風のハンドラに書き換えたものです。
AppleScript名:Finderファイルタグの設定や取得 |
–Created By Shane Stanley use AppleScript version "2.4" use scripting additions use framework "Foundation" property |NSURL| : a reference to current application’s |NSURL| property NSOrderedSet : a reference to current application’s NSOrderedSet property NSURLTagNamesKey : a reference to current application’s NSURLTagNamesKey set anAlias to (choose file) set aRes to getTagsForPath(anAlias) of me — get the tags on getTagsForPath(anAlias) set aURL to |NSURL|’s fileURLWithPath:(POSIX path of anAlias) set {theResult, theTags} to aURL’s getResourceValue:(reference) forKey:(NSURLTagNamesKey) |error|:(missing value) if theTags = missing value then return {} — because when there are none, it returns missing value return theTags as list end getTagsForPath — set the tags, replacing any existing on setTagsForPath(tagList, anAlias) set aURL to |NSURL|’s fileURLWithPath:(POSIX path of anAlias) aURL’s setResourceValue:tagList forKey:(NSURLTagNamesKey) |error|:(missing value) end setTagsForPath — add to existing tags on addTagsForPath(tagList, anAlias) set aURL to |NSURL|’s fileURLWithPath:(POSIX path of anAlias) — get existing tags set {theResult, theTags} to aURL’s getResourceValue:(reference) forKey:(NSURLTagNamesKey) |error|:(missing value) if theTags ≠ missing value then — add new tags set tagList to (theTags as list) & tagList set tagList to (NSOrderedSet’s orderedSetWithArray:tagList)’s allObjects() — delete any duplicates end if aURL’s setResourceValue:tagList forKey:(NSURLTagNamesKey) |error|:(missing value) end addTagsForPath |