macOS 15.2betaにおいて「写真.app」のバージョン番号が「10.0」ではなく「1.0」になっていた件、本日配信されたmacOS 15.2beta(24C5089c)において「10.0」に修正されていました。
タグ: 15.0savvy
アプリのキーワード登録をチェック
アプリケーションフォルダ以下にあるアプリをすべてリストアップして、各アプリに「キーワード」が登録されているかをチェックするAppleScriptです。「キーワード」が設定されているものをPOSIX pathの一覧で返します。
「キーワード」というのは、Finder上で「情報を見る」コマンドで表示させたウィンドウで、「詳細情報」の下に表示される「キーワード」です。
最近、これを登録してあるアプリが出始めてきたので、全体でどの程度の数になっているのか調査すべく、書いてみました。実行には「Metadata Lib」AppleScriptライブラリを必要とします。実行環境はScript Debuggerである必要はありません。普通にスクリプトエディタで大丈夫です。
App Store申請時に記述する検索用キーワードとは異なるようです。他のアプリを検索したときにヒットすることを目的に、「iPhoto」「Aperture」などと指定してあるところが戦略的です。たしかに、Spotlightで「Aperture」をキーワードに検索するとPixelmator Proが出てきます。
AppleScript名:指定フォルダ以下のアプリケーションを取得して、アプリのキーワード登録をチェック.scptd |
— – Created by: Takaaki Naganoya – Created on: 2024/11/21 — – Copyright © 2024 Piyomaru Software, All Rights Reserved — use AppleScript use scripting additions use framework "Foundation" use framework "AppKit" use mdLib : script "Metadata Lib" version "2.0.0" –https://macosxautomation.com/applescript/apps/Script_Libs.html set origPath to {(POSIX path of (path to applications folder))} set aResList to mdLib’s searchFolders:(origPath) searchString:("kMDItemContentType == %@") searchArgs:{"com.apple.application-bundle"} set sList to {} repeat with i in aResList set j to contents of i set sRes to retAppKeywordsFromBundleIPath(j) of me if sRes ≠ "" then set the end of sList to j end if end repeat return sList –> {"/Applications/Pixelmator Pro.app", "/Applications/Dropzone 4.app", "/Applications/Spotify.app", "/Applications/MarsEdit.localized/MarsEdit.app", "/Applications/Keka.app", "/Applications/MindNode.app", "/Applications/NeoFinder.app", "/Applications/Linearity Curve.app", "/Applications/Amazon Kindle.app", "/Applications/PrimeVideo.app"} –指定パスからアプリケーションの「キーワード」メタデータを取得する on retAppKeywordsFromBundleIPath(appPath as string) set theRecord to mdLib’s fetchMetadataFor:appPath return kMDItemKeywords of theRecord end retAppKeywordsFromBundleIPath |
KGPixelBoundsClipがmacOS 15で動作しない?
画像から透過部分を周囲から切り抜く、KGPixelBoundsClipをCooca Framework化して利用していますが、macOS 15上でこれが動作しないことを確認しました。
このFrameworkをAppleScriptから呼び出せることで、Adobe PhotoshopなどのGUIアプリの併用が必要ないため、応用範囲がものすごく広くなりました。
一般向けに公開していない個人用ツールで、本フレームワークを利用しまくっていました。
しかし、macOS 15+MacBook Air M2(Retina Display)の環境では以前のように動作しません(Universal Binaryビルドずみ)。
本プログラムの動作原理はおそろしく簡単です。
周囲から1ピクセルずつ色を拾って、透明色が続く矩形エリアを検出します。CとかObjective-Cだとパフォーマンスを確保しやすい処理内容ですが(脳筋プログラミング)、インタプリタ型のAppleScriptだとこういう脳筋な処理内容だと著しく不利になります。
目下、
(1)かわりの部品をオープンソースのプロジェクトからみつくろう
(2)その後、OS内で類似の機能が追加されていないか調査する
(3)もう、あとくされないようにAppleScriptで書き換える
といった対処を検討中です。
(1)については、Image+Trim.swiftといったSwiftで書かれたプログラムが見つかっています。AppleScriptから呼び出すためには、Bridging Headerを書く必要があるので、ひたすらダルいです。
(2)については、たぶん実装されていないんでないかと(未調査)
(3)については、1ピクセルずつチェックするのでなければ作れそうです。画像の外周部を画像のサイズから計算して細分化したブロックに分割、このブロックごとに透明かどうかをチェックし、ある程度まとめて処理することで速度を稼げそうな気がします。
あとは、最初にサムネイル画像を作ってしまって、その小さくした画像で外周部から色をピックアップしていくという手段もあります。いくつかの方法を試してどれが一番速いかを調べておく必要がありそうです。
(確認中)AppleScript Dropletのバグっぽい動作が解消?
macOS 10.12で導入されたセキュリティ系の機能によって、AppleScriptドロップレットの動作が妨げられる現象が確認されてきました。
ドロップしたファイルが数回に分かれてon openハンドラに渡されたり、ドラッグ&ドロップしたファイルすべてがドロップレット側に認識されなかったりするという動作です。
これは、Gatekeeperの動作とquarantine機能(もたらされたファイルが安全かどうか確認されるまでプログラム側に引き渡されない仕組み)の相互作用によるもの、という話になっていますが……認証のためのインタフェースが用意されておらず、ユーザー側から見れば「説明もなしに動かなくなった」という状態でした。
macOS 10.12、10.13、10.14、10.15、11、12、13、14とずーーっとそのままです。レポートしても修正されず、Scripter側でも対策コードを共有するほかなく、この素朴な機能は問題を抱えたままになっていました。
一応、Shane Stanleyによる対策コードによってドロップレットが運用できていたのと、display drop dialogなどの他のドラッグ&ドロップのためのインタフェースを用意できていたのと、もともと個人的にはドロップレットが性に合わなかった(Finder上の選択中のファイルを取得したほうが事故が起こらなくて簡単)ため、対策はできていました。
ただ、初心者にこの状態をどう説明するの? Apple側で説明する気は一切ありません。完全にバグであり、不具合としかユーザーには映りません。
macOS 15betaでも問題が解決されていなかったので、この問題は放置状態のまま解決されないものとばかり思っていました。
それが、macOS 15.2betaか15.1あたりで解消されたようで(バグが出ても直してもレポートを出さないのがApple風味)、確認してみると13.7.2でもドロップしたファイルを見失うといった動作をしなくなった……ような気がします。
macOS 13/14/15と現行のmacOSに対しては同様のアップデートが行われたのではないでしょうか。
まだ確認が不十分だと感じるのと、どうせmacOSのマイナーアップデートでまた使えなくなったりするんだろうというところです。
一方で、Cocoa AppleScript AppletについてはmacOS 12.6以降ずっと動作しない状況が続いています。こちらもレポートしても一切の反応がない状態です。直す気があるのであればいいのですが、その気がないのならスクリプトエディタのテンプレートから削除するといった処置が必要(試してみて動かないというのが最悪)でしょう。
最前面のKeynote書類で選択中のshapeを一番上のガイドオブジェクトの幅をもとに、残りを等分割
Keynote書類上で複数Shapeないしtext itemが選択された状態で、一番上にあるitemの幅に、下にあるitemを等分割+位置合わせを行うAppleScriptです。
言葉で言い表すと難しいのですが、画面キャプチャで表現すると一目瞭然です。
▲処理後、上側のshapeの幅で下のshapeを等分割+ギャップ指定
電子書籍作成時によく行う作業をワンアクションで行えるようにしてみました。
2D ListのソートはVanilla AppleScriptで書かれたものを使っていますが、これはソートする対象のデータが極小なのと、本ScriptをmacOS標準搭載のScript Menuから呼び出すために作ったためです。
2D Listのソートを行うためだけに、BridgePlusを使用=Script DebuggerでEnhanced Appletに書き出す必要があるというのは面倒なので。
AppleScript名:最前面のKeynote書類で選択中のshapeを一番上のガイドオブジェクトの幅をもとに、残りを等分割 |
— – Created by: Takaaki Naganoya – Created on: 2024/11/15 — – Copyright © 2024 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use scripting additions property xGap : 8 –X軸方向のオブジェクトの隙間座標値 tell application "Keynote" tell front document set aSel to selection if aSel = {} then return set fClass to class of first item of aSel if fClass = slide then return –スライド上のオブジェクトではなく、スライドが選択されていた場合には処理しない set objList to {} set posList to {} set aCount to 1 repeat with i in aSel set j to contents of i set tmpClass to class of j –条件に合うオブジェクトのみ処理対象に if tmpClass is in {text item, shape} then set the end of objList to j set the end of posList to ((position of j) & (width of j) & aCount) set aCount to aCount + 1 end if end repeat set newPosList to shellSortListAscending(posList, 2) of sortLib –Y軸値をもとにソート set guideObj to first item of newPosList –Y軸座標が一番少ない(上)のものをガイドオブジェクトとしてみなす set newPosList to shellSortListAscending(rest of newPosList, 1) of sortLib –ガイドオブジェクト以外のオブジェクト座標値をX軸値でソート set guideWidth to contents of item 3 of guideObj set xStartPos to item 1 of item 1 of newPosList set yPos to item 2 of item 1 of newPosList set itemsCount to length of newPosList set itemWidth to (guideWidth – (xGap * (itemsCount – 1))) / itemsCount –下側オブジェクトの位置と幅修正処理 copy xStartPos to x repeat with i from 1 to itemsCount set y to item 2 of (item i of newPosList) set targObj to item (item 4 of (item i of newPosList)) of objList tell targObj set position of it to {x, y} set width of it to itemWidth end tell set x to x + itemWidth + (xGap) end repeat end tell end tell –Vanilla AppleScriptで書いた2D ListのSorting Lib script sortLib –シェルソートで入れ子のリストを昇順ソート on shellSortListAscending(aSortList, aKeyItem) script oBj property list : aSortList end script set len to count oBj’s list’s items set gap to 1 repeat while (gap ≤ len) set gap to ((gap * 3) + 1) end repeat repeat while (gap > 0) set gap to (gap div 3) if (gap < len) then repeat with i from gap to (len – 1) set temp to oBj’s list’s item (i + 1) set j to i repeat while ((j ≥ gap) and (contents of item aKeyItem of (oBj’s list’s item (j – gap + 1)) > item aKeyItem of temp)) set oBj’s list’s item (j + 1) to oBj’s list’s item (j – gap + 1) set j to j – gap end repeat set oBj’s list’s item (j + 1) to temp end repeat end if end repeat return oBj’s list end shellSortListAscending –シェルソートで入れ子のリストを降順ソート on shellSortListDescending(aSortList, aKeyItem) script oBj property list : aSortList end script set len to count oBj’s list’s items set gap to 1 repeat while (gap ≤ len) set gap to ((gap * 3) + 1) end repeat repeat while (gap > 0) set gap to (gap div 3) if (gap < len) then repeat with i from gap to (len – 1) set temp to oBj’s list’s item (i + 1) set j to i repeat while ((j ≥ gap) and (contents of item aKeyItem of (oBj’s list’s item (j – gap + 1)) < item aKeyItem of temp)) set oBj’s list’s item (j + 1) to oBj’s list’s item (j – gap + 1) set j to j – gap end repeat set oBj’s list’s item (j + 1) to temp end repeat end if end repeat return oBj’s list end shellSortListDescending end script |
ステージマネージャのON_OFF
macOS 13で搭載された「ステージマネージャ」機能のオン/オフを行うAppleScriptです。
ステージマネージャは、最前面のアプリのウィンドウだけを表示するようにする仕組みで、iPadOSに搭載されたものがそのままmacOSにも搭載されました。ドラッグ&ドロップをこのステージマネージャに対して行えるのと、表示ウィンドウを最前面のものだけに切り替えるものです。
つまり、マルチウィンドウのGUIに不慣れなユーザーのために用意された機能です。Windowsユーザー向けに用意した、ともいえるでしょう。
このステージマネージャのOn/Offを行います。動作内容はご覧のとおり、単にshellコマンドを呼び出しているだけです。現在オンになっているかどうかも、defaults readコマンドで同様に実行できることでしょう。
▲真っ先にオフにして、二度とオンにすることはなかったステージマネージャ(画面左端)
AppleScript名:ステージマネージャのON_OFF |
— – Created by: Takaaki Naganoya – Created on: 2024/11/15 — – Copyright © 2024 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use scripting additions set aBool to true stageManagerControl(aBool) of me delay 5 set aBool to false stageManagerControl(aBool) of me on stageManagerControl(aBool as boolean) set sText to "defaults write com.apple.WindowManager GloballyEnabled -bool " & (aBool as string) do shell script sText end stageManagerControl |
スクリプトエディタでFinderやスクリプトエディタ自身のAppleScript用語辞書をブラウズできない問題、解決か?
macOS 15.2 Beta(24C5079e)において、以前本BlogでレポートしていたスクリプトエディタでFinderやスクリプトエディタ自身のAppleScript用語辞書をオープンできない問題が解消されていることを確認しました。
ただし、本問題は再発する可能性が高いものと見ています。電子書籍「AppleScript最新リファレンス v2.8対応」のmacOS 15向けの改修を行なっていますが、
「macOS 15でFinderのAppleScript用語辞書を閲覧できない件」についての対処方法の追加記事が無駄になったことは、喜ばしいことなのでしょうか。きっと、再現して必要になるのでは? と思っているものです。
スクリプトエディタのコンテクストメニューに、絵文字を使ったファイル名のAppleScriptやフォルダが複数回表示されるバグの場合にも、Betaで修正を知らされてもRelease版では直っていなかったため、複数プロジェクト間で矛盾した設定や処理が行われていること自体が解消されてこなかったのでしょう。
Appleの会社組織が極度に縦割り化されているため、チーム間の連携とかチーム間にまたがる問題がいっこうに解決されないといった問題が発生しており、Aチームで修正を行っても他のBチームやCチームでは以前どおりの処理を行なってAチームの修正が無駄になるといった話を散々目撃してきました。
Apple、macOS標準搭載アプリ「写真」のバージョン表記を間違える
macOS 15.2betaにおいて、macOS標準搭載アプリ「写真」(Photos.app)の表示用バージョン番号が誤って「1.0」と記載されています。macOS 15 Betaの段階では「10.0」と記載されていたので、Release後にバージョン番号がおかしくなったのでしょう。
実際にAppleScriptからバージョンを求めても、”1.0″が返ってきます。
AppleScript名:macOS 15.2betaでPhotosのバージョンを間違っている検証 |
tell application "Photos" version –> "1.0" end tell system version of (system info) –> "15.2" |
なお、これまでの写真.appのバージョン履歴は以下のようになっています。
macOS上のアプリのバージョン記述ミスについては、これまでにも何度か発生しており、有名なところではmacOS 13上の「連絡先」(Contacts)がバージョン2539といった謎表記になっていることが知られています(おそらくこれはビルドNo.で、バージョン記述するのを忘れたままになっていたのでしょう)。
自社アプリがApp Storeの審査を通れないのでは? それ以前に、バージョン管理してるんでしょうか????
Pagesで選択中のテキストフレーム内のテキストを、指定記号の前まで太らせる
以前にKeynote用に作っておいたAppleScriptを、Pages用に書き直しました。
Pages書類、主に奥付けのテキストなどで、「項目名」「:」(セパレータ)「内容」みたいに列挙している箇所を行頭からセパレータの場所の前まで太字の書体に変更します。ヒラギノ角ゴシックでチェックしており、欧文フォントは考慮していません。
Pages v14.2+macOS 15.2Betaで実験しています。
AppleScript名:フォントを記号の前まで太らせる.scptd |
— – Created by: Takaaki Naganoya – Created on: 2024/11/01 — – Copyright © 2024 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use framework "AppKit" use scripting additions property NSFont : a reference to current application’s NSFont property NSFontManager : a reference to current application’s NSFontManager –セパレータリスト、表記ゆらぎ対応(ゆらぎ表記個数は可変) property separatorList : {{":", ":"}, {"mm", "㎜"}, {"cm", "㎝"}} tell application "Pages" tell front document set aSel to selection –Keynote上の選択中のオブジェクトでループ repeat with i in aSel set j to contents of i set tmpClass to class of j –選択中のオブジェクトがテキストアイテムの場合に……. if tmpClass = shape then set objText to object text of j set fontName to font of object text of j set fontSize to size of object text of j –フォントを太らせる(ウェイトを上げる) set fFamilyCount to countFontsInItsFamily(fontName) of me if fFamilyCount = 2 then –ヒラギノ角ゴProN W3 → ヒラギノ角ゴProN W6 set newFont to incrementFontWeight(fontName, 1) of me else if fFamilyCount > 4 then –ヒラギノ角ゴシック Wn のウェイトを上げ set newFont to incrementFontWeight(fontName, 4) of me end if set aCount to 1 set tList to splitByLInes(objText) of me –行ごとにParseした行ごとのテキストでループ repeat with ii in tList set jj to contents of ii set anOffset to 0 –セパレータでループ repeat with iii in separatorList –セパレータの「ゆらぎ」表記を考慮してループ repeat with iiii in iii set jjjj to contents of iiii set anOffset to offset of jjjj in jj if anOffset is not equal to 0 then exit repeat end if end repeat if anOffset is not equal to 0 then exit repeat end repeat if anOffset is not equal to 0 then try set font of characters 1 thru (anOffset – 1) of paragraph aCount of object text of j to newFont end try end if set aCount to aCount + 1 end repeat end if end repeat end tell end tell –テキストを行ごとにParse on splitByLInes(someText) — free to a good home set theString to current application’s NSString’s stringWithString:someText set theList to theString’s componentsSeparatedByCharactersInSet:(current application’s NSCharacterSet’s newlineCharacterSet()) return theList as list end splitByLInes –フォントを太らせる。欧文フォントは考慮していない(別の方法で行う) on incrementFontWeight(psFontName, incNum) set aFont to current application’s NSFont’s fontWithName:psFontName |size|:9.0 –> (NSCTFont) "HiraginoSans-W0 9.00 pt. P [] (0x12870af00) fobj=0x11b1e90d0, spc=1.98" set fontM to current application’s NSFontManager’s sharedFontManager() repeat incNum times set aFont to fontM’s convertWeight:true ofFont:aFont end repeat return (aFont’s fontName()) as string end incrementFontWeight –指定フォントのファミリーに属するフォント数を取得 on countFontsInItsFamily(aPSName) set aFont to current application’s NSFont’s fontWithName:(aPSName) |size|:9.0 set aFamily to aFont’s familyName() set fMan to current application’s NSFontManager’s sharedFontManager() set fList to fMan’s availableMembersOfFontFamily:aFamily return length of (fList as list) end countFontsInItsFamily |
全フォントのmostCompatibleStringEncodingを求めて集計
使用中のmacOS環境にインストールされているフォントのmostCompatibleStringEncodingを求めて、集計出力するAppleScriptです。
mostCompatibleStringEncodingはフォントが対応しているエンコーディングということで、普通そんなものはないように思えますが、EnglishなどのAscii & Numelicだけの言語用フォントであれば、「それにしか対応していない」という意味でのmostCompatibleStringEncodingはあるんじゃないかと。
一応調査するために書いてみたものです。バーコード系のフォントやドットフォントが該当しそうな感じです。
AppleScript名:全フォントのmostCompatibleStringEncodingを求める.scptd |
— – Created by: Takaaki Naganoya – Created on: 2024/11/06 — – Copyright © 2024 Piyomaru Software, All Rights Reserved — use AppleScript use scripting additions use framework "Foundation" property NSFont : a reference to current application’s NSFont property NSPredicate : a reference to current application’s NSPredicate property NSFontManager : a reference to current application’s NSFontManager script spdf property fList : {} property outList : {} end script set (outList of spdf) to {} set (fList of spdf) to getEveryFontPSName() of me repeat with i in (fList of spdf) set j to contents of i set aEnc to chkFontsCompatibleEncoding(j) of me –if aEnc is not equal to "default" then set the end of (outList of spdf) to {fontEncoding:aEnc} set the end of (outList of spdf) to {fontEncoding:aEnc} end repeat set aCountedList to countEachRecord((outList of spdf)) of me –> {{aCount:1, aData:{fontEncoding:"NSSymbolStringEncoding"}}, {aCount:860, aData:{fontEncoding:"default"}}, {aCount:1005, aData:{fontEncoding:"NSMacOSRomanStringEncoding"}}} –Rec in Listの登場頻度を集計して出力 on countEachRecord(aRecList) set theCountedSet to current application’s NSCountedSet’s |set|() repeat with i in aRecList set j to contents of i (theCountedSet’s addObject:j) end repeat set theEnumerator to theCountedSet’s objectEnumerator() set anArray to current application’s NSMutableArray’s alloc()’s init() repeat set aDict to current application’s NSMutableDictionary’s alloc()’s init() set aValue to theEnumerator’s nextObject() if aValue is missing value then exit repeat set aCount to theCountedSet’s countForObject:aValue aDict’s setObject:aCount forKey:"aCount" aDict’s setObject:aValue forKey:"aData" anArray’s addObject:aDict end repeat return anArray as anything end countEachRecord on getEveryFontPSName() script spd property aList : {} end script set aFontList to NSFontManager’s sharedFontManager()’s availableFonts() set thePred to NSPredicate’s predicateWithFormat:"NOT SELF BEGINSWITH ’.’" set aFontList to (aFontList’s filteredArrayUsingPredicate:thePred) as list set aList of spd to {} repeat with i in aFontList set aName to contents of i set the end of aList of spd to aName end repeat return aList of spd end getEveryFontPSName on chkFontsCompatibleEncoding(fontPSName as string) set aFont to current application’s NSFont’s fontWithName:(fontPSName) |size|:16 if aFont’s mostCompatibleStringEncoding() = (current application’s NSASCIIStringEncoding) then return "NSASCIIStringEncoding" else if aFont’s mostCompatibleStringEncoding() = (current application’s NSNEXTSTEPStringEncoding) then return "NSNEXTSTEPStringEncoding" else if aFont’s mostCompatibleStringEncoding() = (current application’s NSJapaneseEUCStringEncoding) then return "NSJapaneseEUCStringEncoding" else if aFont’s mostCompatibleStringEncoding() = (current application’s NSUTF8StringEncoding) then return "NSUTF8StringEncoding" else if aFont’s mostCompatibleStringEncoding() = (current application’s NSISOLatin1StringEncoding) then return "NSISOLatin1StringEncoding" else if aFont’s mostCompatibleStringEncoding() = (current application’s NSSymbolStringEncoding) then return "NSSymbolStringEncoding" else if aFont’s mostCompatibleStringEncoding() = (current application’s NSNonLossyASCIIStringEncoding) then return "NSNonLossyASCIIStringEncoding" else if aFont’s mostCompatibleStringEncoding() = (current application’s NSShiftJISStringEncoding) then return "NSShiftJISStringEncoding" else if aFont’s mostCompatibleStringEncoding() = (current application’s NSISOLatin2StringEncoding) then return "NSISOLatin2StringEncoding" else if aFont’s mostCompatibleStringEncoding() = (current application’s NSUnicodeStringEncoding) then return "NSUnicodeStringEncoding" else if aFont’s mostCompatibleStringEncoding() = (current application’s NSWindowsCP1251StringEncoding) then return "NSWindowsCP1251StringEncoding" else if aFont’s mostCompatibleStringEncoding() = (current application’s NSWindowsCP1252StringEncoding) then return "NSWindowsCP1252StringEncoding" else if aFont’s mostCompatibleStringEncoding() = (current application’s NSWindowsCP1253StringEncoding) then return "NSWindowsCP1253StringEncoding" else if aFont’s mostCompatibleStringEncoding() = (current application’s NSWindowsCP1254StringEncoding) then return "NSWindowsCP1254StringEncoding" else if aFont’s mostCompatibleStringEncoding() = (current application’s NSWindowsCP1250StringEncoding) then return "NSWindowsCP1250StringEncoding" else if aFont’s mostCompatibleStringEncoding() = (current application’s NSISO2022JPStringEncoding) then return "NSISO2022JPStringEncoding" else if aFont’s mostCompatibleStringEncoding() = (current application’s NSMacOSRomanStringEncoding) then return "NSMacOSRomanStringEncoding" else if aFont’s mostCompatibleStringEncoding() = (current application’s NSProprietaryStringEncoding) then return "NSProprietaryStringEncoding" else if aFont’s mostCompatibleStringEncoding() = (current application’s NSISO2022JPStringEncoding) then return "NSISO2022JPStringEncoding" else if aFont’s mostCompatibleStringEncoding() = (current application’s NSJapaneseEUCStringEncoding) then return "NSJapaneseEUCStringEncoding" else if aFont’s mostCompatibleStringEncoding() = (current application’s NSShiftJISStringEncoding) then return "NSShiftJISStringEncoding" else if aFont’s mostCompatibleStringEncoding() = (current application’s NSUTF16BigEndianStringEncoding) then return "NSUTF16BigEndianStringEncoding" else if aFont’s mostCompatibleStringEncoding() = (current application’s NSUTF16LittleEndianStringEncoding) then return "NSUTF16LittleEndianStringEncoding" else if aFont’s mostCompatibleStringEncoding() = (current application’s NSUTF16StringEncoding) then return "NSUTF16StringEncoding" else if aFont’s mostCompatibleStringEncoding() = (current application’s NSUnicodeStringEncoding) then return "NSUnicodeStringEncoding" else if aFont’s mostCompatibleStringEncoding() = (current application’s NSUTF32BigEndianStringEncoding) then return "NSUTF32BigEndianStringEncoding" else if aFont’s mostCompatibleStringEncoding() = (current application’s NSUTF32LittleEndianStringEncoding) then return "NSUTF32LittleEndianStringEncoding" else if aFont’s mostCompatibleStringEncoding() = (current application’s NSUTF32StringEncoding) then return "NSUTF32StringEncoding" else return "default" end if end chkFontsCompatibleEncoding |
PostScript名で指定のフォントのTraitMaskを付与する_v3
PostScript名で指定したフォントにTraitMaskを付与し、そのPostScript名の文字列を返すAppleScriptです。
指定フォントのBoldバージョンを取得する、という用途においてはこれで済むのですが、すでにBold指定されたフォントを渡したときにExtra Boldのフォントを返すという処理には使えません。
AppleScript名:PostScript名で指定のフォントのTraitMaskを付与する_v3.scptd |
— – Created by: Takaaki Naganoya – Created on: 2024/10/19 — – Copyright © 2024 Piyomaru Software, All Rights Reserved — use AppleScript use framework "Foundation" use framework "AppKit" use scripting additions property NSFont : a reference to current application’s NSFont property NSFontManager : a reference to current application’s NSFontManager set aName to "TimesNewRomanPSMT" set traitsNum to (current application’s NSBoldFontMask) set bName to getTraitedFontName(aName, traitsNum) of me –> "TimesNewRomanPS-BoldMT" on getTraitedFontName(aName, traitsNum) set bFont to getBoldFontObj(aName, traitsNum) of me return bFont’s fontName() as string end getTraitedFontName –BoldフォントのNSFontを取得 on getBoldFontObj(aName, traitsNum) set aFont to current application’s NSFont’s fontWithName:aName |size|:9.0 –> (NSCTFont) "HelveticaNeue 9.00 pt. P [] (0x4864eb0e0) fobj=0x12ee73e90, spc=2.50" set fontM to current application’s NSFontManager’s sharedFontManager() –指定のフォントがBoldのtraitを持っているかをチェック set fRes to fontM’s fontNamed:aName hasTraits:traitsNum if (fRes as boolean) = true then return aFont –すでに該当する set bFont to fontM’s convertFont:(aFont) toHaveTrait:(traitsNum) return bFont end getBoldFontObj –指定フォントのファミリーに属するフォント数を取得 on countFontsInItsFamily(aPSName) set aFont to current application’s NSFont’s fontWithName:(aPSName) |size|:9.0 set aFamily to aFont’s familyName() set fMan to current application’s NSFontManager’s sharedFontManager() set fList to fMan’s availableMembersOfFontFamily:aFamily return length of (fList as list) end countFontsInItsFamily |
全フォントから全traitsを調べる v2
macOSにインストールされているすべてのフォントに対して、すべてのtraitsを確認して、タブ区切りテキストとして出力するAppleScriptです。
実際にNumbersの表データに入力して、Numbers上のフィルタを用いてtraitsの分布状況を調べてみました。とくに問題はないようです。
AppleScript名:全フォントから全traitsを調べる v2.scptd |
— – Created by: Takaaki Naganoya – Created on: 2024/11/03 — – Copyright © 2024 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use framework "AppKit" use scripting additions property NSFont : a reference to current application’s NSFont property NSPredicate : a reference to current application’s NSPredicate property NSFontManager : a reference to current application’s NSFontManager set fontStatList to {} set fList to getEveryFontPSName() of me set fontM to NSFontManager’s sharedFontManager() repeat with i in fList set j to contents of i set f1Res to (fontM’s fontNamed:(j) hasTraits:(current application’s NSItalicFontMask)) as integer set f2Res to (fontM’s fontNamed:(j) hasTraits:(current application’s NSBoldFontMask)) as integer set f3Res to (fontM’s fontNamed:(j) hasTraits:(current application’s NSUnboldFontMask)) as integer set f4Res to (fontM’s fontNamed:(j) hasTraits:(current application’s NSNonStandardCharacterSetFontMask)) as integer set f5Res to (fontM’s fontNamed:(j) hasTraits:(current application’s NSNarrowFontMask)) as integer set f6Res to (fontM’s fontNamed:(j) hasTraits:(current application’s NSExpandedFontMask)) as integer set f7Res to (fontM’s fontNamed:(j) hasTraits:(current application’s NSCondensedFontMask)) as integer set f8Res to (fontM’s fontNamed:(j) hasTraits:(current application’s NSSmallCapsFontMask)) as integer set f9Res to (fontM’s fontNamed:(j) hasTraits:(current application’s NSPosterFontMask)) as integer set fARes to (fontM’s fontNamed:(j) hasTraits:(current application’s NSCompressedFontMask)) as integer set fBRes to (fontM’s fontNamed:(j) hasTraits:(current application’s NSFixedPitchFontMask)) as integer set fCRes to (fontM’s fontNamed:(j) hasTraits:(current application’s NSUnitalicFontMask)) as integer set the end of fontStatList to {j, f1Res, f2Res, f3Res, f4Res, f5Res, f6Res, f7Res, f8Res, f9Res, fARes, fBRes, fCRes} end repeat –結果のリストをタブ区切りテキストに set sRes to make2DList2TabSepMultilineText(fontStatList) of me –> (* 07LightNovelPOP 0 1 0 0 0 0 0 0 0 0 0 0 07YasashisaGothic 0 0 0 0 0 0 0 0 0 0 0 0 07YasashisaGothicBold 0 0 0 0 0 0 0 0 0 0 0 0 7barP 0 0 0 0 0 0 0 0 0 0 0 0 7barSP 0 0 0 0 0 0 0 0 0 0 0 0…….. *) on getEveryFontPSName() set aFontList to NSFontManager’s sharedFontManager()’s availableFonts() set thePred to NSPredicate’s predicateWithFormat:"NOT SELF BEGINSWITH ’.’" set aFontList to (aFontList’s filteredArrayUsingPredicate:thePred) as list set aList to {} repeat with i in aFontList set aName to contents of i set the end of aList to aName end repeat return aList end getEveryFontPSName on make2DList2TabSepMultilineText(aList) set aStr to "" repeat with i in aList set j to contents of i set tmpStr to list2TABseparatedText(j) of me set aStr to aStr & tmpStr & return end repeat return aStr end make2DList2TabSepMultilineText –リストをタブ区切りのテキストに変換 on list2TABseparatedText(aList) set curDelim to AppleScript’s text item delimiters set AppleScript’s text item delimiters to tab set bList to aList as string set AppleScript’s text item delimiters to curDelim return bList end list2TABseparatedText |
指定フォントの指定Traitが存在するかをチェック
欧文フォントを太らせる処理を行う下調べとして、指定PostScriptフォント名のフォントファミリーに、指定のバリエーションが存在するかどうかを調べるAppleScriptを書いてみました。
Classic MacOS時代はフォントを変形させてボールド表現を行ったり、イタリック表現を行うなどの機能が実装されていました。
一方、OPENSTEPを源流に持つmacOSは、さまざまなバリエーションのフォントをあらかじめ用意しておくことが必要です。このあたりの仕様は、なんとなく技術的な後退を感じますが、まあいいでしょう。
そして、NSFontManagerの機能を用いて、指定のフォントバリエーション(ボールド)が存在するかを確認するはずだったのが本AppleScriptです。
ただ、実際に試してみたところ、どのフォントを指定してもダメでした。「ボールド書体はない」と言われます。あれ????
そこで、macOSに入っているすべてのフォントのPostScript名を取得して、すべてのフォントのTraitsをチェック。
結果、けっこうな数のフォントがboldのTraitsを持っている、と返ってきました。名前に「Bold」と入っているフォントばかりが。
つまり、NSFontManagerのfontNamed:① hasTraits:② は、指定のフォント自体にTraitsがあるのか調べるAPIであったということです。自分が誤解していたようでした。
AppleScript名:指定フォントの指定Traitsが存在するかをチェック.scptd |
— – Created by: Takaaki Naganoya – Created on: 2024/11/02 — – Copyright © 2024 Piyomaru Software, All Rights Reserved — use AppleScript use framework "Foundation" use framework "AppKit" use scripting additions –set aName to "HelveticaNeue" –set aName to "Verdana" –set aName to "TimesNewRomanPSMT" set aName to "SFProText-Regular" –指定のフォントがBoldのtraitを持っているかをチェック set fontM to current application’s NSFontManager’s sharedFontManager() set fRes to fontM’s fontNamed:aName hasTraits:(current application’s NSBoldFontMask) –> false(みんなfalse) |
AppleScript名:全フォントからtraitsを調べる.scptd |
— – Created by: Takaaki Naganoya – Created on: 2024/11/03 — – Copyright © 2024 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use framework "AppKit" use scripting additions property NSFont : a reference to current application’s NSFont property NSPredicate : a reference to current application’s NSPredicate property NSFontManager : a reference to current application’s NSFontManager set okList to {} set fList to getEveryFontPSName() of me set fontM to NSFontManager’s sharedFontManager() repeat with i in fList set j to contents of i set fRes to (fontM’s fontNamed:(j) hasTraits:(current application’s NSBoldFontMask)) if fRes as boolean = true then set the end of okList to j end repeat return okList on getEveryFontPSName() set aFontList to NSFontManager’s sharedFontManager()’s availableFonts() set thePred to NSPredicate’s predicateWithFormat:"NOT SELF BEGINSWITH ’.’" set aFontList to (aFontList’s filteredArrayUsingPredicate:thePred) as list set aList to {} repeat with i in aFontList set aName to contents of i set the end of aList to aName end repeat return aList end getEveryFontPSName |
Keynoteで選択中のtext itemの冒頭のフォントを太くする v2
Keynote書類で選択中のテキストアイテムのうち、各行の冒頭からマークの文字までの間を太文字にするAppleScriptです。
v1を改良し、さまざまな区切り記号に対応させるべく、改修を行なってみたものです。
当初は、各テキストアイテムの内部テキストを解析して、共通記号文字を計算して自動で認識処理を行なってみようかと考えていました。統計処理を行なって共通で登場する文字をピックアップさせることを検討していました。
ただ、これだと複数の選択アイテムで別々の区切り文字を採用している場合に対応できません。
統計処理を行わず、技術的にもっとレベルを下げ、「ゆらぎ」検出のためのオーソドックスな、ゆらぎ表記列挙リストを作って、ひたすらループで処理するように改変。
▲処理後 各テキストアイテムで、指定の記号より前の部分の文字を太くした
なお、本Scriptは書式変更ターゲット文字のピックアップ性能を向上させたものであり、欧文フォントの処理を考慮したものにはなっていません。フォントファミリー内のウェイトを上げたフォントを求めるという処理を行なっています。
fFamilyCount = 2
の場合には、「ヒラギノ角ゴProN W3」を「ヒラギノ角ゴProN W6」に変更する処理を行います。
fFamilyCount > 4
の場合には、「ヒラギノ角ゴシック Wn」のウェイトを上げています。
もしも、利用中のMacにウェイトが多数含まれているフォントをインストールして、Keynote書類上でそのフォントを指定している場合には、ウェイトを上げたフォントを求める処理で、文字を太くするよう処理されることでしょう。
AppleScript名:選択中のtext itemの冒頭のフォントを太くする(フォントのWeightを変更)v2.scptd |
— – Created by: Takaaki Naganoya – Created on: 2024/11/01 — – Copyright © 2024 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use framework "AppKit" use scripting additions property NSFont : a reference to current application’s NSFont property NSFontManager : a reference to current application’s NSFontManager –セパレータリスト、表記ゆらぎ対応(ゆらぎ表記個数は可変) property separatorList : {{":", ":"}, {"mm", "㎜"}, {"cm", "cm"}} tell application "Keynote" tell front document set aSel to selection –Keynote上の選択中のオブジェクトでループ repeat with i in aSel set j to contents of i set tmpClass to class of j –選択中のオブジェクトがテキストアイテムの場合に……. if tmpClass = text item then set objText to object text of j set fontName to font of object text of j set fontSize to size of object text of j –フォントを太らせる(ウェイトを上げる) set fFamilyCount to countFontsInItsFamily(fontName) of me if fFamilyCount = 2 then set newFont to incrementFontWeight(fontName, 1) of me else if fFamilyCount > 4 then set newFont to incrementFontWeight(fontName, 4) of me end if set aCount to 1 set tList to splitByLInes(objText) of me –行ごとにParseした行ごとのテキストでループ repeat with ii in tList set jj to contents of ii set anOffset to 0 –セパレータでループ repeat with iii in separatorList –セパレータの「ゆらぎ」表記を考慮してループ repeat with iiii in iii set jjjj to contents of iiii set anOffset to offset of jjjj in jj if anOffset is not equal to 0 then exit repeat end if end repeat if anOffset is not equal to 0 then exit repeat end repeat if anOffset is not equal to 0 then try set font of characters 1 thru (anOffset – 1) of paragraph aCount of object text of j to newFont end try end if set aCount to aCount + 1 end repeat end if end repeat end tell end tell –テキストを行ごとにParse on splitByLInes(someText) — free to a good home set theString to current application’s NSString’s stringWithString:someText set theList to theString’s componentsSeparatedByCharactersInSet:(current application’s NSCharacterSet’s newlineCharacterSet()) return theList as list end splitByLInes –フォントを太らせる。欧文フォントは考慮していない(別の方法で行う) on incrementFontWeight(psFontName, incNum) set aFont to current application’s NSFont’s fontWithName:psFontName |size|:9.0 –> (NSCTFont) "HiraginoSans-W0 9.00 pt. P [] (0x12870af00) fobj=0x11b1e90d0, spc=1.98" set fontM to current application’s NSFontManager’s sharedFontManager() repeat incNum times set aFont to fontM’s convertWeight:true ofFont:aFont end repeat return (aFont’s fontName()) as string end incrementFontWeight –指定フォントのファミリーに属するフォント数を取得 on countFontsInItsFamily(aPSName) set aFont to current application’s NSFont’s fontWithName:(aPSName) |size|:9.0 set aFamily to aFont’s familyName() set fMan to current application’s NSFontManager’s sharedFontManager() set fList to fMan’s availableMembersOfFontFamily:aFamily return length of (fList as list) end countFontsInItsFamily |
macOS 15:スクリプトエディタのAppleScript用語辞書を確認できない
macOS 15になって、起動中のアプリ自身が自分のバンドル内のリソースにファイルアクセスできなくなったためか(仮説)、スクリプトエディタで自身のAppleScript用語辞書を確認できていません(macOS 15.1)。
用語辞書を読まずにAppleScriptを書くことはできないので、従来のmacOS 13や14から比べると「困った改変」です。
一応、Script Debuggerを用いてスクリプトエディタのAppleScript用語辞書をブラウズすることは可能であるため、不可能になったわけではないのですが、スクリプトエディタで用語辞書をオープンできないと、辞書内容をファイル保存して、変更点の差分を検出できなくて(私が)困っています。
スクリプトエディタのAppleScript用語辞書は、バンドル内にsdefの形式で格納されなくなったため(.scriptsuites書類?)バンドルの中身を開けてコピーというFinderのような解決策をとることができません。
Keynoteで選択中のtext itemの冒頭のフォントを太くする
Keynote書類で選択中のテキストアイテムのうち、各行の冒頭から「:」の文字までの間を太文字にするAppleScriptです。
本Scriptは、処理内容が地味な割に、処理内容(の説明)が大変です。かなり複雑な処理をやっているためです。(フォント名を文字列で組み立てるなどの)もっと乱暴な処理もできるのですが、ここはあえて丁寧な処理を行なってみました。
Keynote書類上の選択中のText item(複数の場合もある)内のObject textにアクセス。ここで、文字情報、フォント情報、フォントサイズ情報、文字色情報などが取得できます。
フォントサイズ情報を取得して(テキストアイテム内はすべて同じフォントが指定されているものと想定)、フォント名がPostScript名で返ってくるので、NSFontManagerの機能を用いて、当該フォントが所属するフォントファミリーを求めます。さらに、そのファミリーにいくつのフォントが所属しているのかを求めます。
ここで想定しているのは、ヒラギノ角ゴ W3/W6かヒラギノ角ゴシックW0〜W9です。欧文フォントでは、ボールド書体がファミリー中に存在するかをチェックし、存在すればボールド書体を指定するといったまったく別の処理が必要です。本Scriptはとりあえずやりたいことを詰め込んで動くレベルにまとめただけで、汎用性はあまりありません。
また、Keynoteのtext item中の「行」(paragraph)へのアクセスが安定していません。改行をリターンキーだけで行うか、Shift-Returnで行うか、Control-Returnで行うかといった些細な操作の違いによって行カウントできる行数に差が発生します。
安全のためには、AppleScript上でRTF(NSMutableAttributedString)を作って、そこでフォントの変更を行なってtext itemのobject textに書き戻すのが理想的です。
AppleScript名:選択中のtext itemの冒頭のフォントを太くする.scptd |
— – Created by: Takaaki Naganoya – Created on: 2024/10/19 — – Copyright © 2024 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use framework "AppKit" use scripting additions property NSFont : a reference to current application’s NSFont property NSFontManager : a reference to current application’s NSFontManager tell application "Keynote" tell front document set aSel to selection repeat with i in aSel set j to contents of i set tmpClass to class of j if tmpClass = text item then set objText to object text of j set fontName to font of object text of j set fontSize to size of object text of j –フォントを太らせる(ウェイトを上げる) set fFamilyCount to countFontsInItsFamily(fontName) of me if fFamilyCount = 2 then set newFont to incrementFontWeight(fontName, 1) of me else if fFamilyCount > 4 then set newFont to incrementFontWeight(fontName, 4) of me end if set aCount to 1 set tList to splitByLInes(objText) of me repeat with ii in tList set jj to contents of ii set anOffset1 to offset of ":" in jj set anOffset2 to offset of ":" in jj if {anOffset1, anOffset2} is not equal to {0, 0} then if anOffset1 = 0 then set offRes to anOffset2 else if anOffset2 = 0 then set offRes to anOffset1 else set offRes to anOffset1 end if try set font of characters 1 thru offRes of paragraph aCount of object text of j to newFont end try set aCount to aCount + 1 end if end repeat end if end repeat end tell end tell –テキストを行ごとにParse on splitByLInes(someText) — free to a good home set theString to current application’s NSString’s stringWithString:someText set theList to theString’s componentsSeparatedByCharactersInSet:(current application’s NSCharacterSet’s newlineCharacterSet()) return theList as list end splitByLInes –フォントを太らせる。欧文フォントは考慮していない(別の方法で行う) on incrementFontWeight(psFontName, incNum) set aFont to current application’s NSFont’s fontWithName:psFontName |size|:9.0 –> (NSCTFont) "HiraginoSans-W0 9.00 pt. P [] (0x12870af00) fobj=0x11b1e90d0, spc=1.98" set fontM to current application’s NSFontManager’s sharedFontManager() repeat incNum times set aFont to fontM’s convertWeight:true ofFont:aFont end repeat return (aFont’s fontName()) as string end incrementFontWeight –指定フォントのファミリーに属するフォント数を取得 on countFontsInItsFamily(aPSName) set aFont to current application’s NSFont’s fontWithName:(aPSName) |size|:9.0 set aFamily to aFont’s familyName() set fMan to current application’s NSFontManager’s sharedFontManager() set fList to fMan’s availableMembersOfFontFamily:aFamily return length of (fList as list) end countFontsInItsFamily |
PostScript名で指定したフォントのウェイトを上げるループ処理のテスト
NSFontManagerを用いて、指定フォントのウェイト(太さ)を上げたり下げたりする処理ができますが、実際にやってみると「見えなかったもの」が見えてきます。
macOSには「ヒラギノ角ゴシック」のW0(PostScript名:HiraginoSans-W0)からW9(PostScript名:HiraginoSans-W9)まで異なるウェイトのフォントがインストールされています。そこで、W0から順次W9までウェイトを上げる処理を行なってみると、「ヒラギノ角ゴシックW2」にウェイトが割り振られていないことがわかります。
バグなのか、意図的なものなのか……多分バグだと思うのですが……。
AppleScript名:PostScript名で指定のフォントのウェイトを上げるループ.scptd |
— – Created by: Takaaki Naganoya – Created on: 2024/10/19 — – Copyright © 2024 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use framework "AppKit" use scripting additions property NSFont : a reference to current application’s NSFont property NSFontManager : a reference to current application’s NSFontManager set aName to "HiraginoSans-W0" set aFont to current application’s NSFont’s fontWithName:aName |size|:9.0 –> (NSCTFont) "HiraginoSans-W0 9.00 pt. P [] (0x12870af00) fobj=0x11b1e90d0, spc=1.98" set fontM to current application’s NSFontManager’s sharedFontManager() set fRes to fontM’s weightOfFont:(aFont) –> 2 repeat 12 times set fRes to fontM’s weightOfFont:(aFont) log (fRes as number) set aFontName to aFont’s fontName() log aFontName (*2*) (*(NSString) "HiraginoSans-W0"*) (*3*) (*(NSString) "HiraginoSans-W1"*) — <– W2は????? (*4*) (*(NSString) "HiraginoSans-W3"*) (*5*) (*(NSString) "HiraginoSans-W4"*) (*6*) (*(NSString) "HiraginoSans-W5"*) (*8*) (*(NSString) "HiraginoSans-W6"*) (*9*) (*(NSString) "HiraginoSans-W7"*) (*10*) (*(NSString) "HiraginoSans-W8"*) (*12*) (*(NSString) "HiraginoSans-W9"*) set aFont to fontM’s convertWeight:true ofFont:aFont end repeat |
ヒラギノ角ゴシックW2のウェイトを取得したら3が返ってきました。ウェイトがW2とW3で重なっているんですね。
AppleScript名:PostScript名で指定のフォントのウェイトを取得.scptd |
— – Created by: Takaaki Naganoya – Created on: 2024/10/19 — – Copyright © 2024 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use framework "AppKit" use scripting additions property NSFont : a reference to current application’s NSFont property NSFontManager : a reference to current application’s NSFontManager set aName to "HiraginoSans-W2" set aFont to current application’s NSFont’s fontWithName:aName |size|:9.0 –> (NSCTFont) "HiraginoSans-W0 9.00 pt. P [] (0x12870af00) fobj=0x11b1e90d0, spc=1.98" set fontM to current application’s NSFontManager’s sharedFontManager() set fRes to fontM’s weightOfFont:(aFont) –> 3 |
macOS 15:スクリプトエディタでFinderのAppleScript用語辞書が閲覧できない
Betaのときには起こっていなかった現象で、macOS 15.1で確認されています。
スクリプトエディタでFinderのAppleScript用語辞書を閲覧できません。
Finderは/System/Library/CoreServicesフォルダに入っており、このフォルダへのアクセスが「より厳しく」なったのでしょう。
ただ、実際にFinderがAppleScript対応しなくなったわけでもなければ、FinderのSDEFが除去されたわけでもありません。
実際にFinderの(パッケージ内容をコンテクストメニューから表示させたうえで)SDEFをコピーして、コピーしたものをスクリプトエディタで閲覧するとよいでしょう。