Keynote、Pages、NumbersのiWorkアプリがバージョン14にアップデートされました。
本バージョンはmacOS 13以降に対応しています。
各アプリのAppleScript用語辞書に変更はありません。Pagesで見られている、ウィンドウで表示されていないページ上のオブジェクトからの情報取得ができない(正確にいえば、表示中の見開き+2見開き分まで取得可能)という挙動は変わっていません。どうも処理速度向上のための仕様のようなので、この部分はこのままだと思います。
Keynote、Pages、NumbersのiWorkアプリがバージョン14にアップデートされました。
本バージョンはmacOS 13以降に対応しています。
各アプリのAppleScript用語辞書に変更はありません。Pagesで見られている、ウィンドウで表示されていないページ上のオブジェクトからの情報取得ができない(正確にいえば、表示中の見開き+2見開き分まで取得可能)という挙動は変わっていません。どうも処理速度向上のための仕様のようなので、この部分はこのままだと思います。
GUIアプリケーションの操作において、若干の不満を覚えつつもmacOS上のGUIアプリケーションの操作を行えてきました。
ただ、「次」の段階が見えているのに、GUIアプリケーション側の機能がそれに追いついていなかったり、未実装の部分があったりで、GUIアプリケーション側が足を引っ張っているように見える今日このごろです。
たとえばKeynoteにおいて、特定のグラフィックだけを削除したい(会社ロゴなど)という場合に、メニューに「この部品に近似する部品を削除」といった機能が実装されていてもよさそうな昨今ですが、それはありません。「類似画像を削除」「類似部品を削除」といった処理はやりたくなる部分だと(勝手に)考えるものです。だいたい、OS内の機能を見ても容易に実装できそうに見えます。
Keynote書類にはimageオブジェクトが用意されており、さまざまなプロパティを取得できるようになっていますが、file nameは取得できても、
file属性を取得できない状態です。
AppleScript名:画像からfile属性を取得(できない).scpt |
tell application "Keynote" tell front document set aSel to selection set aaSel to first item of aSel set aFile to file of aaSel –> error "Keynoteでエラーが起きました: AppleEventのハンドラで誤りが起きました。" number -10000 end tell end tell |
iCloud上に存在するKeynote書類の内部ファイルに対してのパスを表現しづらい、といった理由は理解できるかもしれませんが、用語辞書にfile属性が取れると明記してある以上、file属性は(ローカルに書類が存在するなどの条件下では)取得できるべきだと考えます。
そして、file属性(おそらく、file pathをalias形式で取得できる)を取れれば、画像の「内容」にもアクセスして、「指定の画像に近似するものを削除」といった処理はできるはずです(画像のハッシュ値を計算する処理は別途する必要はあるわけですが)。
このあたりの処理が、そろそろできてもいいんですが、いろいろ邪魔が入ってできないのが残念な感じがします。
iWork……という言葉は最近はあまり使われないようなので、Keynote、Pages、Numbersと呼びますが……これらのアップデート版v13.2が公開されました。AppleScript用語辞書の修正、追加はありません(作成できるグラフ形式が増えているのですが、ASから作成できるようにはなっていません)。
メジャーアップデートのv14.0などではないので、本バージョンは堅実で小刻みな機能アップデート版といえるでしょう。
3Dオブジェクトを格納するUSDZファイルをデータとして挿入できたりアニメーション表示(Keynote)できたり、新しいテーマが追加されたり、その他SVG画像を素材として利用できるようになったもようです。
USDZ形式のファイルを扱えるのは、いまのところ手元のアプリケーションではXcodeとPreview.appのみ。
SVGについては、いろいろ増えてきています。
こうした各種書類形式をキーにして、さまざまなアプリケーションを連携させられるという情報を提供する件をAppleのWWDRに提案したことがありましたが、どこのチームも興味を持たなかったとのこと。
USDZ形式データについては、数年前からこの形式データの利用を広めたいという「意図」が見えたので、いろいろ情報収集はすすめてきました。iWork Appsでサポートするということで、1段階利用が広がったというところですが、たとえばKeynoteで3Dを前提としたアニメーションやトランジッションが実装される、という機能が整備されるまでは単なる素材が1つ増えたぐらいでしょう。
Keynoteに3Dトランジッションや3Dアニメーションを追加するぐらいのことは、とっくの昔から検討されていたと思われますが、おそらく実装してみると「思ったよりも効果的ではない」という結論になったのでしょう。Vision ProのようなxRデバイスで閲覧するという「ブラウズ環境」を整備できたことにより、USDZ形式のデータを広くサポートする「価値」が生まれると踏んだのでしょう。
Vision Proが成功を収めるか、誰もが記憶から追い出したくなるような失敗として記録されるかは不明ですが、USDZ形式の利用が広くサポートされれば、それは多くの人々に役立つものとなることでしょう。
Keynote, Pages, Numbersのバージョン13.0がリリースされました。AppleScript用語辞書的な変更点はありません。
Keynote v11からずっと、新規書類を保存するとエラーになる。Full Disk Accessの権限をKeynoteに与えていてもエラーになる、という重大な問題が解消されないままである、という認識でおりました。状況はKeynote v13.0でも変わりません。
これは、Apple側が問題として認識していないのではないか? という仮説を立て、いろいろ試してみました。
まずは、v12から継続している状況についての説明。Keynoteで新規書類を保存する際に「as Keynote」という、明らかに「指定してくださいね」というオプションがAppleScript用語辞書の中にあるので、指定したくなるところですが
AppleScript名:Keynoteで書類を新規保存(A).scpt |
set newFile to ((path to desktop) as string) & "newDoc1111.key"
tell application "Keynote" set newDoc to make new document save document 1 in file newFile as Keynote end tell |
これを指定するとエラーになります。これが、Keynote v12.0から続いており、1年以上継続している状況です。以前のバージョンで通っていた記述がエラーを出すようになった、というものです。
ふとここで、「as Keynote」というオプション指定をはずしてみると…….
AppleScript名:Keynoteで書類を新規保存(A).scpt |
set newFile to ((path to desktop) as string) & "newDoc1111.key"
tell application "Keynote" set newDoc to make new document save document 1 in file newFile end tell |
エラーが出なくなりました!!!(^ー^;;;; ファイル保存もできました。
なんなんでしょう、これは、、、、
Piyomaru Software Booksの66冊目。「AppleScript基礎テクニック集(28)アプリケーションとの対話」を発売しました。PDF 35ページ+サンプルScriptZipアーカイブ で構成されています。
→ 販売ページ
AppleScriptの文法をひととおり知っていて、実際に書くことができたとしても、それだけで何かをできるというものでもありません。各種GUIアプリケーションなりOSの機能を呼び出して、なにがしかの作業を自動化できなければ意味がありません。
ここで、いきなり「いつも行っている仕事をまるごと自動化しよう!」といった壮大な野望を目指しても失敗します。マウスやトラックパッドでGUIアプリケーションを操作するのと、AppleScriptで操作するのとでは「やりかた」や「方法」は若干異なります。そこには明確に「慣れ」が必要です。
その最初の第一歩が、アプリケーションとの間の「対話」です。対話してみて、様子を見て、それでアプリケーション操作の挙動を確認していきます。対話の仕方を知ることは、自動化を行うために必須の第一関門をクリアするためのノウハウなのです。
書く前にアプリケーションとの対話が欠かせない
対話の第一歩は、正確なアプリケーション名の指定から
参考資料:名前がローカライズされているアプリケーション
最初の会話「あなたの名前は?」
最初の会話「あなたの年齢は?」
AppleScript用語辞書で会話できる言葉を調査
選択中のオブジェクトを示すselectionを調査
「selection」の意味を調べる
オブジェクト選択してselectionの動作を調査
「selection range」の意味を調べる
表を選択してselection rangeの動作を調査
選択中のオブジェクトが「何か」を尋ねる
選択中のオブジェクトが「どうか」を尋ねる
書類上のオブジェクトを作成できないか?
audio clipを作成できないか?①
audio clipを作成できないか?②
対象オブジェクトに実行できるコマンドは?①
対象オブジェクトに実行できるコマンドは?②
対象オブジェクトに実行できるコマンドは?③
処理を組み立てるには「対話」が欠かせない
macOS 13がリリースされた翌日に、iWork(Keynote、Pages、Numbers) v12.2がリリースされました。
本バージョンで、AppleScriptから新規iWork書類を作成して保存させられないバグは修正されていません。
Keynote v12.2:
フォントサイズ指定が整数値(integer)から実数値(real)が指定できるように変更された
Pages v12.2:
フォントサイズ指定が整数値(integer)から実数値(real)が指定できるように変更された
AppleScript用語辞書掲載サンプルScriptで、Word書類への書き出しで「.doc」の指定が削除された(.docxのみ掲載)
→ Pages 12.2+macOS 13.1betaで連続してPages書類をオープンしてPDFを書き出していたら、どうもPDF書き出しできない場合があるようで(再起動で回復)。オープン後に少しウェイトを入れてからPDF書き出しするなど、様子を見ているところです。ファイルオープン後にASで後続のコマンドを受け付けるまでにアプリケーション内/書類内の初期化が間に合っていないのでは? と疑っています。
Numbers v12.2:
フォントサイズ指定が整数値(integer)から実数値(real)が指定できるように変更された
AppleScript用語辞書掲載サンプルScriptで、Excel書類への書き出しで「.xls」の指定が削除された(.xlsxのみ掲載)
Keynoteでオープン中の書類すべてをPDF書き出しして、各PDFの最初のページをJPEG画像に書き出すAppleScriptです。書き出し先はデスクトップフォルダです。Keynote v12.1+macOS 12.6.1で動作確認しています。
それぞれ、PDF書き出しするScriptと、PDFをJPEGに変換するAppleScriptは個別に書いて使っていたのですが、処理数が増えるといちいち複数のScriptをかわるがわる実行するのも面倒に。
そこで、PDF書き出し→JPEG変換を行うものを作ってみました。作ったみたといっても、部品はすでに存在していたので繋ぎ合わせただけです。
AppleScript名:すべてデスクトップ上にPDF出力し、最初のページをJPEG出力.scptd |
— – Created by: Takaaki Naganoya – Created on: 2022/10/14 — – Copyright © 2022 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use scripting additions property NSString : a reference to current application’s NSString property NSFileManager : a reference to current application’s NSFileManager property NSOrderedSame : a reference to current application’s NSOrderedSame set outPathList to {} tell application "Keynote" set allDocs to every document if allDocs = {} then return repeat with i in allDocs set j to contents of i set dRes to exportKeynoteDocToPDF(j) of me set pdfPath to (POSIX path of dRes) set pdfPath to chkExistPOSIXpathAndIncrementChildNumberFull(pdfPath) of me set jRes to (my jpegFromPath:(pdfPath) compressFactor:1.0) set the end of outPathList to jRes end repeat end tell return outPathList –Keynote書類からPDF書き出し on exportKeynoteDocToPDF(targKeynoteDoc) tell application "Keynote" set dCount to count every document if dCount = 0 then –オープン中のKeynote書類がない場合はリターン return false end if set aPath to file of targKeynoteDoc end tell set tmpPath to (path to desktop) as string set curPath to (NSString’s stringWithString:(POSIX path of aPath))’s lastPathComponent()’s stringByDeletingPathExtension()’s stringByAppendingString:".pdf" set outPath to (tmpPath & curPath) set outPath to chkExistPOSIXpathAndIncrementChildNumberFull(outPath) of me –do shell script "touch " & quoted form of POSIX path of outPath –Error 6を回避するための記述 tell application "Keynote" –set anOpt to {class:export options, export style:IndividualSlides, all stages:false, skipped slides:true, PDF image quality:Good} –set anOpt to {class:export options, export style:IndividualSlides, all stages:false, skipped slides:true, PDF image quality:Better} set anOpt to {class:export options, export style:IndividualSlides, all stages:false, skipped slides:true, PDF image quality:Best} export targKeynoteDoc to POSIX file outPath as PDF with properties anOpt end tell return ((POSIX file outPath) as alias) end exportKeynoteDocToPDF on jpegFromPath:imagePath compressFactor:compFactor — 0.0 = max compression, 1.0 = none — build destination path set pathNSString to current application’s NSString’s stringWithString:imagePath set destPath to pathNSString’s stringByDeletingPathExtension()’s stringByAppendingPathExtension:"jpg" — load the file as an NSImage set theImage to current application’s NSImage’s alloc()’s initWithContentsOfFile:imagePath if theImage = missing value then return false set theData to theImage’s TIFFRepresentation() set newRep to current application’s NSBitmapImageRep’s imageRepWithData:theData set theData to (newRep’s representationUsingType:(current application’s NSJPEGFileType) |properties|:{NSImageCompressionFactor:compFactor, NSImageProgressive:false}) set theResult to (theData’s writeToFile:destPath atomically:true) as boolean return destPath as string end jpegFromPath:compressFactor: –POSIX path stringを与えると、ファイル名の重複を検出して、ファイル名の名称回避を行って、ファイル名のみを返す on chkExistPOSIXpathAndIncrementChildNumberFull(a) set aa to POSIX path of a set aStr to NSString’s stringWithString:aa set bStr to aStr’s lastPathComponent() set cStr to (bStr’s pathExtension()) as string set dStr to (bStr’s stringByDeletingPathExtension()) as string set eStr to (aStr’s stringByDeletingLastPathComponent()) as string set aManager to NSFileManager’s defaultManager() set aRes to (aManager’s fileExistsAtPath:aStr) as boolean if aRes = false then return aa set hitF to false repeat with i from 1 to 65535 set tmpPath to (eStr & "/" & dStr & "_" & (i as string) & "." & cStr) set tmpStr to (NSString’s stringWithString:tmpPath) set aRes to (aManager’s fileExistsAtPath:tmpStr) as boolean set bRes to ((tmpStr’s caseInsensitiveCompare:eStr) is not equal to (NSOrderedSame)) as boolean if {aRes, bRes} = {false, true} then set hitF to true exit repeat end if end repeat if hitF = false then return false –ファイルパス(フルパス)を返す return (tmpStr as string) end chkExistPOSIXpathAndIncrementChildNumberFull |
Piyomaru Software Booksの60冊目。GUIアプリケーションを強引に動かす「GUI Scripting」について動作原理から気をつけるべき点、実戦レベルのScriptで注意している点やサンプルなどをまとめた「AppleScript実践的テクニック集(1)GUI Scripting」を発売しました。本文283ページとなっています。
→ 販売ページ
「AppleScript実践的テクニック集」とは、従来の「基礎テクニック集」の枠組みでは収まりきらないテーマを扱う新シリーズです。基礎テクニック集は32ページ前後のコンパクトな構成にするために、いろいろ省略した部分もありましたが、この枠組みに入り切らないテーマを別枠でご紹介することにしたものです。
ページ数の上限をとくに設けず、徹底的に情報を入れる設計です。それでいて、「基礎テクニック集」ゆずりの図や表を多用した構成はそのままです。
使い所さえ間違えなければ強力な武器になるGUI Scriptingについて、動作原理からノウハウ、注意すべきポイントや実戦レベルのScriptで気をつけていること、さまざまな「ありがちな処理」のサンプルなどを紹介する1冊です。
AS用語辞書にすべての機能は掲載されていません①
AS用語辞書にすべての機能は掲載されていません②
AppleScript非対応機能を呼ぶGUI Scripting
GUI Scriptingとは?
GUI ScriptingはSystem Eventsごしに操作
操作対象のアプリケーション①
操作対象のアプリケーション②
KeynoteでASから利用できない機能を呼ぶ
GUIアプリケーションの挙動確認が欠かせません
メニュー項目操作の実例
実行結果のリストアップ①
実行結果のリストアップ②
デフォルト状態だとGUI Scriptingは無効
AppleScript実行アプリケーションを登録
設定するとGUI Scriptingが有効に
スクリプトメニューも登録必須
資料:macOS上のAppleScript実行環境①
資料:macOS上のAppleScript実行環境②
メニュー項目:メニューを頂点としたツリー
ウィンドウ上のオブジェクト:ウィンドウが基準
簡単なGUI部品の求め方
GUI Scriptingの有効チェック
属性値の取得(properties)
属性値の取得(AX-attributes)
GUI部品のクリック
指定座標のクリック
参考資料:GUI Scriptingの座標系
ポップアップメニューの項目選択
キー入力操作
項目選択
コンテクストメニューの表示
スクロール操作
ファイル保存/書き出し
自分で発生させたモーダルなダイアログのクリック
ドラッグ&ドロップ操作
日本語IMの文字入力モード取得/設定
マウスカーソルを移動させる必要性
マウスカーソルの強制移動とクリック
指定フォルダ以下のPagesなどをPDF出力して連結
実際のメインScript部分
generatePDFLibの当該箇所
本プログラムが環境の影響を受けた点
参考資料:デスクトップの表示/非表示切り替え
Xcodeに入っているGUI部品探索ツール
Accessibility Inspectorの画面構成①
Accessibility Inspectorの画面構成②
プロセス一覧から対象を選択してInspection
指定プロセスのGUI部品の追跡中の画面表示
GUI部品の追跡ポーズ中の画面表示
OSアップデートごとにGUI構成は変わる
GUI Scripting処理部分だけをサブルーチンに分離
GUI Scripting処理部分をライブラリに分離
OSアップデートの影響を受けにくい構造に
GUI Scriptingの信頼性は?
一般的な信頼性の計測方法
経験に基づく傾向と対策
GUI Scriptingで直面した問題とその解決策
指定した処理の終了前に次の処理が行われる
同じ名前のプロセスが存在していると名称衝突①
同じ名前のプロセスが存在していると名称衝突②
指定のアプリケーションの全メニュータイトルを取得
選択中のテキストを取得
選択中のテキストを書き換え
Safariの最前面のウィンドウへの参照を得る
GUI部品への参照から所属するアプリケーション名を取得
Dockに登録されているアイコンの情報を取得
Keynoteで選択中のテキストを縦書きに
CotEditorで最前面のウィンドウを縦書きに
click【クリック】コマンド
key code【キーコード】コマンド
keystroke【キーストローク】コマンド
perform【パフォーム】コマンド
select【セレクト】コマンド
application【アプリケーション】クラス
action【アクション】クラス
application process【アプリケーションプロセス】クラス
attribute【アトリビュート】クラス
browser【ブラウザ】クラス
busy indicator【ビジーインディケータ】クラス
button【ボタン】クラス
checkbox【チェックボックス】クラス
color well【カラーウェル】クラス
column【カラム】クラス
combo box【コンボボックス】クラス
desk accessory process【デスクアクセサリプロセス】クラス
drawer【ドロワー】クラス
group【グループ】クラス
grow area【グローエリア】クラス
image【イメージ】クラス
incrementor【インクリメンタ】クラス
list【リスト】クラス
menu【メニュー】クラス
menu bar【メニューバー】クラス
menu bar item【メニューバーアイテム】クラス
menu button 【メニューボタン】クラス
menu item 【メニューアイテム】クラス
outline 【アウトライン】クラス
pop over 【ポップオーバー】クラス
pop up button 【ポップアップボタン】クラス
process 【プロセス】クラス
progress indicator 【プログレスインジケータ】クラス
radio button 【ラジオボタン】クラス
radio group【ラジオグループ】クラス
relevance indicator【レレベンスインジケータ】クラス
row【ロー】クラス
scroll area【スクロールエリア】クラス
scroll bar 【スクロールバー】クラス
sheet 【シート】クラス
slider【スライダ】クラス
splitter【スプリッタ】クラス
splitter group【スプリッタグループ】クラス
static text【スタティックテキスト】クラス
tab group【タブグループ】クラス
table【テーブル】クラス
text area【テキストエリア】クラス
text field【テキストフィールド】クラス
toolbar【ツールバー】クラス
UI element【ユーアイエレメント】クラス
value indicator【バリューインディケータ】クラス
window【ウインドウ】クラス
macOSバージョンとAppleScriptの動向
macOSとAppleScriptの要素技術史
各macOSごとのAppleScript解説
macOS内AppleScript補助ツールの歴史
System EventsのAppleScript用語辞書変更点
AppleScript 各ランタイム環境情報
AppleScript予約語一覧
AppleScriptのエラーコード
あとがき
奥付
Keynote v12.1書類の現在のスライドにあるdefault title itemに入っている改行コード(?)を除去するAppleScriptです。
結論から言うと、これが改行コード(LFとかCRとか)ではなく、Unicode特殊文字の「LINE SEPARATOR」(U+2028)であることが、データをhexdumpしてわかりました(AppleScript書いてるだけなのに、hexdumpのお世話になることの多いこと、多いこと)。なので、文字コードをUTF-16(AppleScript側の文字コード)で指定して置換を行なっています。
# AppleScriptのネイティブ文字コードはUTF-16BEです
Keynote書類の各Slideに存在しているdefault title itemから文字列(object text)を取得し、改行コードを除去する処理を行います。
AppleScript名:default title item部分に入った改行コードを除去する.scptd |
— – Created by: Takaaki Naganoya – Created on: 2022/10/09 — – Copyright © 2022 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use scripting additions tell application "Keynote" tell front document tell current slide set jj to object text of default title item –https://www.fileformat.info/info/unicode/char/2028/index.htm –Unicode Character ’LINE SEPARATOR’ (U+2028) –UTF-16 (decimal) 8,232 set kk to repCharByID(jj, 8232, "") of me log kk end tell end tell end tell –文字置換 on repCharByID(origText as string, targCharID as number, repChar as string) set targChar to string id targCharID 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 repCharByID |
Piyomaru Software Booksの59冊目。Keynote、Pages、Numbersの3つのアプリケーションのScriptingについて、共通する部分に着目して3つとも解説するScripting本、「iWork Scripting Book with AppleScript」を発売しました。本文239ページ、資料編198ページの合計437ページの大ボリウムです。
→ 販売ページ
スクリプトエディタを起動しよう
スクリプトエディタを起動しよう!
スクリプトエディタのヘルプ
色設定を変えてみよう!
スクリプトを入力してみよう
スクリプトを保存しよう
スクリプトを実行しよう(1/3)
スクリプトを実行しよう(2/3)
スクリプトを実行しよう(3/3)
セキュリティとプライバシー
セキュリティとプライバシー>プライバシー
iWork appsを起動しよう
Keynote/Pages/Numbersを指定
Keynote/Pages/Numbersを起動
Keynote/Pages/Numbersを終了
Mail.appのAppleScript用語辞書の調べ方
メニュー項目や画面強制操作の調べ方
各iWork appsの詳細仕様について
iWork appsの情報を取得しよう
アプリケーションの名前を取得
アプリケーションの情報を一括取得
アプリケーションのプロパティ項目と内容
新規書類の作成
新規書類の作成
テーマ/テンプレート名の取得
テーマ/テンプレートを指定しつつ新規書類作成①
テーマ/テンプレートを指定しつつ新規書類作成②
参考資料:テーマ/テンプレート名
Keynote:SD/HD、他のサイズの書類の指定
新規スライド/ページ/シートの作成
各iWork appsにおける新規ページの作成
Keynote:レイアウト名の取得とスライド追加
Pages:ページ追加
Numbers:シート追加
書類情報の取得
書類からの各種情報取得
書類名(name)はFinder設定と連動
書類のパスワード保護状態を取得
書類保存
書類を保存(保存ずみ書類に上書き保存)
書類を新規保存①
書類を新規保存(A.)
書類を新規保存(B.)
書類を新規保存(C.)
コラム「iWork appsが使用するパス表現」
書類へのパスワード
設定と解除
iWork書類へのパスワード設定
パスワード設定されたiWork書類のオープン
書類へのパスワード設定と解除
通常書類とパスワード保護された書類の比較
書類上の座標系
書類上の座標系
Pages書類の座標系
現在表示中のページ
書類上の現在表示中のページ番号を取得
選択中のアイテムの取得
selectionで取得できる選択中のオブジェクト
Numbersで取得できる表オブジェクト情報
デフォルトタイトル
アイテムへの文字設定(Keynote)
デフォルトタイトルアイテムのオブジェクト
デフォルトタイトルアイテムのテキストを取得
デフォルトタイトルアイテムにテキストを設定
Pagesの本文作成
書類タイプ別のPages本文の作り方
Pagesの文章の本文(body text)の操作
Pagesの文章の本文(body text)の色指定
Pagesの文章の本文(body text)のフォント指定
Pagesの文章の本文(body text)の単語にアクセス
Pagesの文章のページにアクセス(追加)
Pagesの文章のページにアクセス(削除①)
Pagesの文章のページにアクセス(削除②)
Pagesの文章のセクションにアクセス
Pagesの文章のセクションにアクセス
選択中の表からのデータ取得/設定
選択範囲(selection range)へのアクセス
選択範囲のセルの取得
選択範囲のセルのデータの取得
指定セルのデータの取得①
指定セルのデータの取得②
指定範囲のセルのデータの取得
カラム名の数値からの変換
指定範囲のセルのデータを2次元配列で取得①
指定範囲のセルのデータを2次元配列で取得②
指定範囲のセルのデータを2次元配列で取得③
指定セルにデータを設定①
指定セルにデータを設定②
指定範囲のセルへの配列データの設定
表にクリップボード経由で大量の2次元配列データを設定
テキストボックスの作成
テキストボックスのオブジェクト
テキストボックスの作成
表の作成
表の作成
表の作成+データ設定
表のソート、
セルの結合と分離
表の昇順(A→Z)ソート
表の降順(Z→A)ソート
表セルの結合
結合セルの解除
画像(image)の挿入
指定画像の挿入
Keynote:イメージスライドの作成
shape, lineの作成
shape/lineの分類
shapeの識別
shapeの作成
放射状にラインを引く(Keynote)
放射状にラインを引く(Pages)
放射状にラインを引く(Numbers)
audio clip, movieの作成
音声トラックのaudio clipの作成
ムービー(movie)の作成
プレースホルダへのデータさしこみ(Pages)
プレースホルダとは?
Pagesのテキストプレースホルダの作成①
Pagesのテキストプレースホルダの作成②
Pagesのテキストプレースホルダを利用
Pagesのメディアプレースホルダの作成
Keynoteのテキストプレースホルダ
グループへのアクセス
Keynote:グループ内のオブジェクトにアクセス
Pages:グループ内のオブジェクトにアクセス
Numbers:グループ内のオブジェクトにアクセス
Keynote:グループ内のオブジェクトの親にアクセス
シート処理(Numbers)
Numbers:シートの新規追加
Numbers:シートの削除、表示切り替え
Numbers:シートの名称変更
Numbers:現在表示中のシートのIDを返す
Numbers:シートの名称による検索
スライドの追加と順次ループ(Keynote)
Keynote:スライドの追加
Keynote:スライドの順次ループアクセス
Keynote:スライドの順次追加
スライド間の表示切り替えエフェクト指定(Keynote)
Keynote:スライド切り替え効果一覧
Keynote:スライド切り替えを設定
発表者ノート(Keynote)を記入
Keynote:発表者ノートとは?
Keynote:発表者ノートの操作
表への計算式の代入
iWork appsで共通して利用できる関数
表のセルに計算式を代入
表のセルの計算結果(値)を取得
表のセルの計算式を取得
グラフ作成(Keynote)
Keynoteで扱えるグラフの一覧
Keynote:2D横/縦棒グラフ
Keynote:3D横/縦棒グラフ
Keynote:2D/3D面グラフ
Keynote:2D/3D円グラフ
Keynote:2D散布図グラフ
Keynote:2D積み重ね縦/横棒グラフ
Keynote:3D積み重ね縦/横棒グラフ
Keynote:2D/3D階層グラフ
Keynote:2D/3D折れ線グラフ
データの書き出し(エクスポート)
各iWork appsが書き出し可能なフォーマット
書き出し用ファイルパスの組み立て
PDF書き出し
Microsoft Office書類として書き出し
Keynote:HTML書き出し
Keynote:QuickTimeムービー書き出し
Keynote:イメージ書き出し
Keynote:Keynote 09形式書き出し
Pages:EPUB形式書き出し
Pages:テキスト書き出し
Pages:Pages 09形式書き出し
Pages:リッチテキストフォーマットで書き出し
Numbers:Numbers 09形式で書き出し
Numbers:CSV形式で書き出し
印刷
iWork appsから印刷出力
AppleScriptによるプリントアウト
Keynote:印刷オプションの指定
Pages:印刷オプションの指定
Numbers:印刷オプションの指定
書式付きテキストへのアクセス
Keynoteでobject textの書式属性設定
Pagesでobject textの書式属性設定
Numbersでobject textの書式属性設定
Keynoteでobject textの文字色、フォント置換
Pagesでobject textの文字色、フォント置換
Numbersでobject textの文字色、フォント置換
書式付きテキストの幅に応じたtext item自体のリサイズ
Text itemの枠の幅を文字内容でリサイズ①
Text itemの枠の幅を文字内容でリサイズ②
Text itemの枠の幅を文字内容でリサイズ①
Text itemの枠の幅を文字内容でリサイズ②
Text itemの枠の幅を文字内容でリサイズ①
Text itemの枠の幅を文字内容でリサイズ②
text item内のテキストの使用言語の自動推定
Keynote:書類中のtext itemの使用言語を推定①
Keynote:書類中のtext itemの使用言語を推定②
Pages:書類中のtext itemの使用言語を推定①
Pages:書類中のtext itemの使用言語を推定②
Numbers:書類中のtext itemの使用言語を推定①
Numbers:書類中のtext itemの使用言語を推定②
指定行列ヘッダによる表セルへのアクセス
Keynote:指定行列ヘッダによる表セルへのアクセス
Keynote:指定行列ヘッダによる表セルへのアクセス
Pages:指定行列ヘッダによる表セルへのアクセス
Pages:指定行列ヘッダによる表セルへのアクセス
Numbers:指定行列ヘッダによる表セルへのアクセス
Numbers:指定行列ヘッダによる表セルへのアクセス
汎用オブジェクト(iWork item)によるアクセス
汎用クラスiWork itemで取得できるオブジェクト
Keynote:iWork itemでアクセス
Pages:iWork itemでアクセス
Numbers:iWork itemでアクセス
オブジェクトの重なり検出(Keynote)
Keynote:テキストとshapeの重なり検出①
Keynote:テキストとshapeの重なり検出②
書類内部データへのアクセス
iWork app書類の構造
通常書類とパスワード保護された書類の比較
Keynote固有のプレゼン系操作について
Keynote:プレゼン再生コントロール
Keynote書類のプレゼン関連情報
Keynote:プレゼン再生関連の属性値
Keynote:transitionサンプル書類作成&再生
Bundle IDで指定したアプリケーションのSDEF(AppleScript定義辞書)を、Xincludeを考慮しつつparseして、XPathで指定したクラスにアクセスするAppleScriptです。
KeynoteのAppleScript用語辞書の「open」コマンド、
を指定して本Scriptでデータを取り出すと、
のような出力が得られます。まだちょっと、属性値を取り出すところまで行っていませんが、つまり…指定コマンドのパラメータや、指定クラスがどのようなコマンドに応答するかなど、プログラム側からわかるようになることでしょう(多分)。
AppleScript名:Bundle IDで指定したアプリケーションのSDEFからXPathで指定したClassにアクセス v2.scptd |
— – Created by: Takaaki Naganoya – Created on: 2022/08/2 — – Copyright © 2022 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use framework "AppKit" use scripting additions set targAppBundleID to "com.apple.iWork.Keynote" –SDEFを取り出すターゲットのアプリケーションのBundle ID –set commandXPath to "//class[@name=’application’]/property" –set commandXPath to "//command[@name=’open’]/direct-parameter" –set commandXPath to "//class[@name=’document’]/property" –set commandXPath to "//class[@name=’document’]/responds-to" –set commandXPath to "//command[@name=’open’]" –Open Command–Open コマンド set commandXPath to "//command[@name=’open’]/direct-parameter/type" –Open Command–Open コマンド set aRes to parseSDEFandRetXPathData(targAppBundleID, commandXPath) of me return aRes –SDEFをXincludeを考慮しつつ展開 on parseSDEFandRetXPathData(targAppBundleID, commandXPath) set thePath to POSIX path of (path to application id targAppBundleID) set aSDEFname to retAppSdefNameFromBundleIPath(thePath, "OSAScriptingDefinition") of me if aSDEFname = false then return if aSDEFname does not end with ".sdef" then set aSDEFname to aSDEFname & ".sdef" set sdefFullPath to thePath & "Contents/Resources/" & aSDEFname set sdefAlias to (POSIX file sdefFullPath) as alias –sdefのフルパスを求める –SDEF読み込み(Xincludeの展開が必要な状態) tell current application set theXML to read sdefAlias as «class utf8» end tell –NSXMLDocumentの生成、Xincludeを有効に set {theXMLDoc, theError} to current application’s NSXMLDocument’s alloc()’s initWithXMLString:theXML options:(current application’s NSXMLDocumentXInclude) |error|:(reference) –XMLを文字データ化 set aDocStr to (theXMLDoc’s XMLData) set aDocStr2 to (current application’s NSString’s alloc()’s initWithData:(aDocStr) encoding:(current application’s NSUTF8StringEncoding)) as string set dRes to my extractFrom:theXMLDoc matchingXPath:commandXPath return dRes end parseSDEFandRetXPathData –指定のNSXMLDocumentから、指定のXPathでアクセスして内容を返す on extractFrom:theNSXMLDocument matchingXPath:theQuery set attStrings to {} — where attributes will be stored set theXMLOutput to current application’s NSXMLElement’s alloc()’s initWithName:"output" — found nodes added to this set {theResults, theNSError} to (theNSXMLDocument’s nodesForXPath:theQuery |error|:(reference)) — query if theResults is not missing value then repeat with anNSXMLNode in (theResults as list) anNSXMLNode’s detach() — need to detach first if anNSXMLNode’s |kind|() as integer = current application’s NSXMLAttributeKind then — see if it’s an attribute or node set end of attStrings to (anNSXMLNode’s stringValue()) as {text, list, record} else (theXMLOutput’s addChild:anNSXMLNode) — add node end if end repeat return (theXMLOutput’s XMLStringWithOptions:(current application’s NSXMLNodePrettyPrint)) as {text, list, record} else return missing value end if end extractFrom:matchingXPath: –指定パスからアプリケーションのInfo.plist中の属性値を返す on retAppSdefNameFromBundleIPath(appPath as string, aKey as string) set aDict to (current application’s NSBundle’s bundleWithPath:appPath)’s infoDictionary() set aRes to aDict’s valueForKey:(aKey) if aRes = missing value then return false set asRes to aRes as string return asRes as string end retAppSdefNameFromBundleIPath |
Keynoteの最前面の書類で表示中のスライド中の表で、選択中の各セルの内容の文字列の長さを表インタフェースで一覧表示するAppleScriptです。
こんなKeynote書類上の表があったとして、その選択中の各セルに入っている文字列の長さを、AppleScriptライブラリ「display table by list」を用いて一覧表示します。実行には同ライブラリのインストールが必要です。
実行の前提として、Keynoteで書類をオープンしてあり、書類上の表の集計対象のセルを選択しておくことが必要です。
文字列長と元の文字列を一覧表示します。
AppleScript名:Keynoteの表で選択中のセルの文字列長さを一覧表で表示.scpt |
— – Created by: Takaaki Naganoya – Created on: 2022/07/04 — – Copyright © 2022 Piyomaru Software, All Rights Reserved — use AppleScript version "2.5" — El Capitan (10.11) or later use framework "Foundation" use scripting additions use easyTable : script "display table by list" tell application "Keynote" tell front document tell current slide try set theTable to first table whose class of selection range is range on error display notification "Numbers: There is no selection" return end try tell theTable set aRes to value of cells of selection range end tell end tell end tell end tell set fLabels to {"文字列長", "文字列"} set newList to {} repeat with i in aRes set j to contents of i if j is not equal to missing value then set aLen to length of j set the end of newList to {aLen, j} end if end repeat tell current application set aRes to (display table by list newList main message "テキストの文字列長" sub message "Keynoteの表で選択中のテキストの各セルの文字列長" size {800, 400} labels fLabels icon "") end tell |
Keynoteの最前面の書類で表示中のスライド(ページ)で選択中の表の、指定行のテキストのセルの文字列長の分布をグラフ出力するAppleScriptです。
# Blogの英訳本の企画を動かしていますが、たしかに日本語のタイトルを(日本人が)見てもけっこうわかりにくいのかも?
# タイトルをGoogle翻訳に突っ込むと、それなりに「そんな感じじゃね?」という英語が出てきますが、、、
こういう、電子書籍の紹介文を掲載しているページがあって、そこに書いてある紹介文の長さの分布を計算してみるために、ありものの部品を組み合わせて作ったものです。
「だいたい3行ぐらい」というふんわりとしたルールのもとに18冊分ほど書いてきましたが、本の冊数が増えてページを追加するにあたって、文字列長の分布を計算してみようと思い立ってScriptを書いてみました。
043 # 044 ## 045 046 ### 047 048 ## 049 ### 050 # 051 # 052 # 053 054 # 055 056 # 057 # 058 059 060 061 062 063 064 065 066 067 068 #
分布はわかりましたが、似たような処理を行うことが多いので、何か簡単なGUIをつけておいたほうがいいような気がするような、、、
AppleScript名:選択中の表のデータを取得して、特定の行のデータの文字列長を集計.scpt |
— – Created by: Takaaki Naganoya – Created on: 2022/07/04 — – Copyright © 2022 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" use scripting additions use framework "Foundation" property NSMutableArray : a reference to current application’s NSMutableArray set aList to get2DListFromKeynoteTableSelection() of me if aList = "" then return false –取得した各セルの文字列長をすべて取得する set aLen to length of aList set aaLen to length of item 1 of aList set nList to {} repeat with i from 3 to (aLen) by 3 repeat with ii from 1 to aaLen set the end of nList to length of (contents of item ii of item i of aList) end repeat end repeat –文字列長の度数分布を計算 set minRes to calcMin(nList) of me set maxRes to calcMax(nList) of me set itemCount to maxRes – minRes set n2List to makeBlankListByItem(itemCount + 1, 0) of me repeat with i in nList set j to contents of i set tmpNum to contents of item (j – minRes + 1) of n2List set tmpNum to tmpNum + 1 set item (j – minRes + 1) of n2List to tmpNum end repeat –文字列長の度数分布のグラフを文字出力 set tList to {} set aCount to minRes repeat with i in n2List set gText to returnRepeatedText(i, "#") of me set tNumStr to makeFN(aCount, 3) of me set totalText to tNumStr & " " & gText set the end of tList to totalText set aCount to aCount + 1 end repeat return retArrowText(tList, return) of me –リストを任意のデリミタ付きでテキストに on retArrowText(aList, aDelim) set aText to "" set curDelim to AppleScript’s text item delimiters set AppleScript’s text item delimiters to aDelim set aText to aList as text set AppleScript’s text item delimiters to curDelim return aText end retArrowText on returnRepeatedText(aNum, aChar) set aText to "" repeat aNum times set aText to aText & aChar end repeat return aText end returnRepeatedText on makeBlankListByItem(itemNum, blankItem) set tmpList to {} repeat itemNum times set the end of tmpList to blankItem end repeat return tmpList end makeBlankListByItem on calcMin(aList as list) set tmpFItem to first item of aList set aClass to class of tmpFItem set nArray to (NSMutableArray’s arrayWithArray:aList) if aClass = real then set maxRes to (nArray’s valueForKeyPath:"@min.self")’s doubeValue() else set maxRes to (nArray’s valueForKeyPath:"@min.self")’s intValue() end if return maxRes end calcMin on calcMax(aList as list) set tmpFItem to first item of aList set aClass to class of tmpFItem set nArray to (NSMutableArray’s arrayWithArray:aList) if aClass = real then set maxRes to (nArray’s valueForKeyPath:"@max.self")’s doubeValue() else set maxRes to (nArray’s valueForKeyPath:"@max.self")’s intValue() end if return maxRes end calcMax on makeFN(aNum, aDigit) set aText to "00000000000" & (aNum as text) set aLen to length of aText set aRes to text (aLen – aDigit + 1) thru -1 of aText return aRes end makeFN –Keynoteで選択中の表のすべてのセルのデータを2Dで返す on get2DListFromKeynoteTableSelection() tell application "Keynote" tell front document tell current slide try set theTable to first table whose class of selection range is range on error return "" –何も選択されてなかった場合 end try tell theTable set selList to value of every cell –すべてののデータを取得 set selHeight to count every row set selWidth to count every column end tell end tell end tell end tell set aLen to length of selList set aaLen to selHeight set bList to {} repeat with i from 1 to aaLen set aHoriList to {} repeat with ii from 1 to selWidth set j1 to ii + (i – 1) * selWidth set tmpCon to contents of item j1 of selList set aClass to class of tmpCon if aClass = number or aClass = integer or aClass = real then set tmpCon to tmpCon as integer end if set the end of aHoriList to tmpCon end repeat set the end of bList to aHoriList end repeat return bList end get2DListFromKeynoteTableSelection –テキストを指定デリミタでリスト化 on parseByDelim(aData, aDelim) set aText to current application’s NSString’s stringWithString:aData set aList to aText’s componentsSeparatedByString:aDelim return aList as list end parseByDelim –1D/2D Listのユニーク化 on uniquifyList(aList as list) set aArray to current application’s NSArray’s arrayWithArray:aList set bArray to aArray’s valueForKeyPath:"@distinctUnionOfObjects.self" return bArray as list end uniquifyList |
Keynoteでオープン中の最前面の書類の現在のスライド(ページ)の上で3重のshapeオブジェクトを下に敷いているテキストアイテムを検出し、文字色を変更するAppleScriptです。
macOS 12.5beta+Keynote v12.1の組み合わせで作成・チェックしてみましたが、Keynote v12.xの固有の機能などは使っていないので、もっと古い環境でも動くはずです。
▲処理後 右側のテキストの色まで変わってしまっているのは意図しなかった処理(わかってたけど)
Keynote書類上でshapeオブジェクトを重ねて何かを表現することはよくありますが、重ねた場所の上に置いてある文字色だけ変更したい場合が往々にしてあります。
さっさと動かすことだけ考えて、ありものの「オブジェクトの重ね合わせ検出」Scriptを使い回しました。そのため、本当に入れ子状態の3つのオブジェクトを検出しているわけではなく、重ね合わせが3回発生しているテキストアイテムを検出しています。
もうちょっと凝った処理を行えば、本当に3階層の入れ子状態のshapeを検出できそうな気はしますが、さすがに使い捨てレベルのScriptにそんなに手間暇をかけるわけにもいかないので、現状ではこんなものでしょう。
Keynoteのselectionがまともに動くようになったので、いろいろ実践的なレベルのScriptを書けるようになりましたが、オブジェクトの重ね合わせ順なども取れたりすると、もっといろいろ書けそうです。
オブジェクトのposition、width、heightを取得する処理は、もうちょっと高速に実行できるように書けそうです(まだまだ、安全第一の処理内容)。
あとは、imageオブジェクトのpathとかイメージデータそのものを取得して、各種画像フィルタをかけてKeynote書類に書き戻せるとよさそうな気がします。
AppleScript名:テキストアイテムと1重のシェープの重なり検出 v2.scptd |
— – Created by: Takaaki Naganoya – Created on: 2022/06/25 — – Copyright © 2022 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use scripting additions set collisonNum to 1 set targPointSize to 32.0 set targColList to {0, 0, 0} –Black set tList to {} –text items set trList to {} set sList to {} –shapes set srList to {} –set bgColList to {} –background color set colList to choose color tell application "Keynote" tell front document tell current slide –text itemの情報抽出ループ set allTList to every text item repeat with i in allTList set j to contents of i tell j set {xPos, yPos} to position set aWidth to width set aHeight to height set aRect to makeRect(xPos, yPos, aWidth, aHeight) of me end tell set the end of tList to j set the end of trList to aRect end repeat –shapeの情報抽出ループ set allSList to every shape repeat with i in allSList set j to contents of i tell j set {xPos, yPos} to position set aWidth to width set aHeight to height –set aBGCol to background color set aRect to makeRect(xPos, yPos, aWidth, aHeight) of me end tell set the end of sList to j set the end of srList to aRect set the end of bgColList to aBGCol end repeat set atLen to length of trList set arLen to length of srList set outTlist to {} –shapeと重ね合わせが発生しているtext itemの検出ループ repeat with i from 1 to atLen set atRec to contents of item i of trList set atObj to contents of item i of tList set collisionC to 0 set tmpCSize to point of first character of object text of atObj –当該text itemに対して、shapeオブジェクトとのNSRectの重ね合わせが指定数発生しているかをチェック repeat with ii from 1 to arLen set tmpRect to contents of item ii of srList set aF to detectRectanglesCollision(atRec, tmpRect) of me –背景色(background color)のリストを確認 set aBG to contents of item ii of bgColList –if {aF, aBG, tmpCSize} = {true, targColList, targPointSize} then set collisionC to collisionC + 1 if {aF, tmpCSize} = {true, targPointSize} then set collisionC to collisionC + 1 end repeat –オブジェクトのRectangleが重なり合っている「回数」で判定 if collisionC = collisonNum then set the end of outTlist to atObj end if end repeat end tell end tell end tell –文字色を塗り替えるループ tell application "Keynote" tell front document tell current slide repeat with i in outTlist set j to contents of i ignoring application responses set color of object text of j to colList end ignoring end repeat end tell end tell end tell on makeRect(xPos, yPos, aWidth, aHeight) return current application’s NSMakeRect(xPos, yPos, aWidth, aHeight) end makeRect –NSRect同士の衝突判定 on detectRectanglesCollision(aRect, bRect) set a1Res to (current application’s NSIntersectionRect(aRect, bRect)) as {record, list} set tmpClass to class of a1Res if tmpClass = record then –macOS 10.10, 10.11, 10.12 return not (a1Res = {origin:{x:0.0, y:0.0}, |size|:{width:0.0, height:0.0}}) else if tmpClass = list then –macOS 10.13 or later return not (a1Res = {{0.0, 0.0}, {0.0, 0.0}}) end if end detectRectanglesCollision –1から任意の数までのアイテムで、2個ずつの組み合わせのすべての順列組み合わせパターンを計算して返す –ただし、1×1とか2×2などの同一アイテム同士の掛け合わせを除去するものとする on retPairPermutationsWithoutSelfCollision(aMax) set aList to {} repeat with x from 1 to aMax repeat with xx from 1 to aMax if x is not equal to xx then set tmpItem to {x, xx} set a2List to sort1DNumList(tmpItem, true) of me if {a2List} is not in aList then set the end of aList to a2List end if end if end repeat end repeat return aList end retPairPermutationsWithoutSelfCollision –1D List(数値)をsort / ascOrderがtrueだと昇順ソート、falseだと降順ソート on sort1DNumList(theList as list, aBool as boolean) tell current application’s NSSet to set theSet to setWithArray_(theList) tell current application’s NSSortDescriptor to set theDescriptor to sortDescriptorWithKey_ascending_(missing value, aBool) set sortedList to theSet’s sortedArrayUsingDescriptors:{theDescriptor} return (sortedList) as list end sort1DNumList |
v12で発生していた、新規書類をAppleScriptから保存できないバグは修正されていません。
Keynote書類中の各スライド(ページ)のベースレイアウト(テンプレート)の名称から、トビラのページを推測するAppleScriptです。
まずは、なんでトビラのページを特定する必要があるのかといえば、TOC(Table Of Contents)つきでPDFに書き出す際に必要だからです。
トビラのページとは、
こういうものです。記事の開始ページに入っており、記事と記事の区切りをわかりやすくするために入れるものです。
そして、TOCはこういうものです。
目下、このTOCにおける階層をベースレイアウト名から推測するロジックをAppleScriptで組んでいますが、ざっくり言って「ベースレイアウト名」から推測している状態です。
もともと、Keynote書類からAppleScriptで各スライドの階層(Level)を取得できるとか、そもそもKeynote自体にTOCつきPDFを書き出す機能がついていれば、外部からScriptで操作しなくても済むわけですが、バージョンアップを繰り返してもそんな便利な機能がつく気配すらありません。Appleに機能追加のリクエストを出して、それが実装されるまで気長に待つよりも、今日すぐにでもScriptから実装したほうがよほど建設的です。また余計なことをされて機能不全を起こされても迷惑ですし。
なので、非常に遠回りな方法ではあるものの、ベースレイアウト(テンプレート)の名称からレベルを推測せざるを得ないというのが現状です。
ただ、これにも限界があります。「だいたい扉のページにはこのベースレイアウト(テンプレート)を使うよね」という「お約束」をベースに、処理を組み立てることになります。
扉のページにつかいがちなベースレイアウト(テンプレート)をあらかじめリストアップしておいて、該当するものを一律に「扉」とみなしてもいいはずです。
ただ、これもいまひとつ信用できないので、もう1手間かけておきたいところです。
Keynote書類のすべてのスライドからベースレイアウト(テンプレート)名を取得し、出現頻度やスライドの傾向から扉ページを特定したいところでもあります。
まずは、ベースレイアウト名一覧を取得し、ユニーク化(重複削除)。それぞれのベースレイアウト名でループして、書類中における出現頻度を求めます。
出現頻度については、1回ということはないでしょうし(規模によってはあるかもしれない)、全ページが該当するものでもないでしょう。また、表紙(最初のページ)、裏表紙(最後のページ)も異なります。
さらに、扉ページについていえば、ページ内に存在する文字アイテム(text item)が少ないことが期待されます。少なくとも自分が作るようなコンテンツではそうした傾向があります。
とりあえず、AppleScriptでKeynote書類からさまざまな情報を取得し、統計的なデータを取得(ページ上に存在するtext item数の標準偏差)するなどして、全体的な傾向を把握して検討するところでしょう。
あまりやりたくはないものの、完全な一括処理(ユーザーにどれが扉ページかを問い合わせない)を行うのではなく、ユーザー(自分)に扉ページのベーススライド名を確認する処理を追加することになるでしょうか。
--> {{baseLayoutName:"タイトルのみ", itemNumList:{10, 3, 3, 7, 14, 16, 10, 8, 6, 17, 9, 11, 16, 17, 11, 3, 3, 3, 15, 7, 16, 7, 3, 8, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 12, 12, 10, 3, 3, 3, 13}, stdDev:4.939129779062}, {baseLayoutName:"タイトル(上)広告用", itemNumList:{56, 22}, stdDev:17.0}, {baseLayoutName:"セクション", itemNumList:{4, 3, 2, 2, 2, 2, 2}, stdDev:0.728431359085}}
AppleScript名:各ベースレイアウト出現頻度およびレイアウト上のアイテム数の分布から扉を推測するテスト.scptd |
— – Created by: Takaaki Naganoya – Created on: 2022/06/04 — – Copyright © 2022 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use scripting additions property NSExpression : a reference to current application’s NSExpression property NSMutableArray : a reference to current application’s NSMutableArray tell application "Keynote" tell front document set themeNames to name of base layout of every slide set themeList to items 2 thru -2 of themeNames –> {"タイトルのみ", "タイトル(上)_飾りなし", "タイトル(上)広告用", "タイトル(上)広告用", "セクション", "タイトルのみ", "タイトルのみ", "セクション", "タイトルのみ", "タイトルのみ", "セクション", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "セクション", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "セクション", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "セクション", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "セクション", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ"} set uniList to uniquify1DList(themeList) of me –> {"タイトルのみ", "タイトル(上)_飾りなし", "タイトル(上)広告用", "セクション"} set tobiraKouhoList to {} repeat with i in uniList set j to contents of i set tmpSList to (every slide whose name of base layout is equal to j) if length of tmpSList ≥ 2 then set tRatioList to {} repeat with ii in tmpSList set jj to contents of ii tell jj set aList to (every iWork item) set the end of tRatioList to length of aList end tell end repeat set d1Res to calcStddev(tRatioList) of me set the end of tobiraKouhoList to {baseLayoutName:j, itemNumList:tRatioList, stdDev:d1Res} end if end repeat return tobiraKouhoList –> {{baseLayoutName:"タイトルのみ", itemNumList:{10, 3, 3, 7, 14, 16, 10, 8, 6, 17, 9, 11, 16, 17, 11, 3, 3, 3, 15, 7, 16, 7, 3, 8, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 12, 12, 10, 3, 3, 3, 13}, stdDev:4.939129779062}, {baseLayoutName:"タイトル(上)広告用", itemNumList:{56, 22}, stdDev:17.0}, {baseLayoutName:"セクション", itemNumList:{4, 3, 2, 2, 2, 2, 2}, stdDev:0.728431359085}} end tell end tell –標準偏差を計算する on calcStddev(aList) –https://nshipster.com/nsexpression/ set anArray to NSMutableArray’s arrayWithArray:aList set anExp to NSExpression’s expressionForFunction:"stddev:" arguments:{(NSExpression’s expressionForConstantValue:anArray)} set valList to anExp’s expressionValueWithObject:(missing value) context:(missing value) return valList as real end calcStddev on uniquify1DList(theList as list) set theSet to current application’s NSOrderedSet’s orderedSetWithArray:theList return (theSet’s array()) as list end uniquify1DList |
オープンソースの「RectangleBinPack」を用いて2D Bin Packagingを解き、Keynote上の汎用オブジェクト(iWork item)を指定矩形内に詰め込むAppleScriptです。
2D Bin Packは、指定のオブジェクトを面積で評価して、ターゲットの領域に「詰め込む」(オブジェクト回転あり)という処理で、ワードクラウドであるとか、記事レイアウト時の最適化配置といった用途に用いられます。
さまざまなアルゴリズムが提唱され、コンピュータの登場初期からどえらい先人たちが攻めまくった分野であるため、ありがたく、その成果をいただいているという用途でもあります。
よく、ゲームのテクスチャ画像を1枚の画像ファイルに詰め込む際に2D Bin Packの処理を用いている例を見かけます。なんでファイルごとに分けないのかはわかりませんけれども(ファイル容量の節約???)。
–> Download Script bundle with RectangleBinPack in its bundle + sample Keynote document
# This AppleScript requires RectangleBinPack executable in its bundle. So, download the whole AppleScript bundle archive from the link above (↑)
オープン中のKeynote書類の表示中のスライド(ページ)上にある矩形オブジェクト(Shape)を指定の矩形エリア内に2D Packingします。エリアの大きさが小さすぎると正常にPackingされなかったり、false(エラー)を返したりします。
変更履歴:
v2.1: BinPackTestをIntel x64とARM binaryのそれぞれのバイナリでビルドしてバンドルに入れた(Makeを書き換えて直接Universalバイナリに仕立てられるといいのに)
v2.2: BridgePlusがなくても動くように書き換えた(ないと動かないのはいろいろ運用上問題がある)
v2.3: shapeに対してBinPackしていたのを、Keynote上の汎用オブジェクトへのアクセス予約語iWork itemでアクセスするように変更した
AppleScript名:rectBinPack v2.3_Universal.scptd |
— – Created by: Takaaki Naganoya – Created on: 2022/05/31 — – Copyright © 2019-2022 Piyomaru Software, All Rights Reserved — — 2D Bin Packing by juj https://github.com/juj/RectangleBinPack — v2.1: BinPackTestをIntel x64とARM binaryのそれぞれのバイナリでビルドしてバンドルに入れた(Universalバイナリに仕立てられるといいのに) — v2.2: BridgePlusを外した(ないと動かないのはいろいろ運用上問題がある) — v2.3: shapeに対してBinPackしていたのを、Keynote上の汎用オブジェクトへのアクセス予約語iWork itemでアクセスするように変更した use AppleScript version "2.4" use framework "Foundation" use scripting additions –Packaging Target Area set binSizeX to 600 set binSizeY to 600 set packRes to packKeynoteObjectsOnCurrentSlide(binSizeX, binSizeY) of me on packKeynoteObjectsOnCurrentSlide(binSizeX, binSizeY) set {tList, a0List} to retRectsFromKeynote() of me set aList to sortList2DDecending(a0List, {"myWidth", "myHeight", "myArea"}) of me –Sorting key is Width(main) and Area(sub) and Height(sub) set aRes to twoDBinPacking(binSizeX, binSizeY, aList) of me if aRes = false then return false tell application "Keynote" tell front document tell current slide repeat with i in aRes set {posX, posY} to myPos of i set itemIndex to myID of i set aDeg to myDegree of i –sample data {itemCounter:5, myWidth:573, myHeight:52, myArea:29796} set anObjID to itemCounter of (item itemIndex of aList) set rotation of iWork item anObjID to aDeg set position of iWork item anObjID to {posX, posY} end repeat end tell end tell end tell return true end packKeynoteObjectsOnCurrentSlide on twoDBinPacking(binSizeX as integer, binSizeY as integer, boxList as list) set aParamList to {binSizeX, binSizeY} repeat with i in boxList –copy i to {tmpID, tmpX, tmpY, tmpArea} — {itemCounter:iCount, myWidth:aWidth, myHeight:aHeight, myArea:anArea} set tmpID to itemCounter of i set tmpX to myWidth of i set tmpY to myHeight of i set tmpArea to myArea of i set aParamList to aParamList & tmpX set aParamList to aParamList & tmpY end repeat set aParam to retDelimitedText(aParamList, " ") of me –> "800 800 340 243 340 73 340 73 155 240 147 125 147 125 147 125 147 125" –Parameters for result parsing set s1Str to "Packed to (x,y)=(" set s2Str to ")" set s3Str to "," set cpuRes to CPU type of (system info) if cpuRes begins with "ARM" then set exName to "arm" else if cpuRes begins with "Intel" then set exName to "x86" end if set binName to "BinPackTest_" & exName set aPath to POSIX path of (path to resource binName) try set aRes to do shell script quoted form of aPath & " " & aParam on error return false end try if aRes does not end with "Done. All rectangles packed." then return false set aList to paragraphs of aRes set bList to {} set aCount to 1 repeat with i in aList set j to contents of i if j begins with "Packing rectangle of size " and j does not contain "Failed!" then set xyRes to pickUpFromToStrAndParse(j, s1Str, s2Str, s3Str) of me –RectangleBinPackがオブジェクトの回転をサポートしているため、その対処 if xyRes is not equal to false then set s11Str to "(w,h)=(" set s12Str to ")" set s13Str to "," set whRes to pickUpFromToStrAndParse(j, s11Str, s12Str, s13Str) of me set tmpBox to item aCount of boxList — {itemCounter:5, myWidth:573, myHeight:52, myArea:29796} –copy tmpBox to {tmpID, tmpX, tmpY, tmpArea} set tmpID to itemCounter of tmpBox set tmpX to myWidth of tmpBox set tmpY to myHeight of tmpBox set tmpArea to myArea of tmpBox if whRes = {tmpX, tmpY} then set aDeg to 0 else if whRes = {tmpY, tmpX} then set aDeg to 90 else return false end if set the end of bList to {myPos:xyRes, myID:aCount, myDegree:aDeg} end if set aCount to aCount + 1 end if end repeat return bList end twoDBinPacking on pickUpFromToStrAndParse(aStr as string, s1Str as string, s2Str as string, s3Str as string) set a1Offset to offset of s1Str in aStr if a1Offset = 0 then return false set bStr to text (a1Offset + (length of s1Str)) thru -1 of aStr set a2Offset to offset of s2Str in bStr if a2Offset = 0 then return false set cStr to text 1 thru (a2Offset – (length of s2Str)) of bStr set {x, y} to parseByDelim(cStr, s3Str) of me return {x as integer, y as integer} end pickUpFromToStrAndParse on parseByDelim(aData, aDelim) set curDelim to AppleScript’s text item delimiters set AppleScript’s text item delimiters to aDelim set dList to text items of aData set AppleScript’s text item delimiters to curDelim return dList end parseByDelim –リストを指定デリミタでテキスト化 on retDelimitedText(aList, aNewDelim) set aText to "" set curDelim to AppleScript’s text item delimiters set AppleScript’s text item delimiters to aNewDelim set aText to aList as text set AppleScript’s text item delimiters to curDelim return aText end retDelimitedText on retRectsFromKeynote() tell application "Keynote" tell front document tell current slide set tList to every iWork item set bList to {} set iCount to 1 repeat with i in tList set aWidth to width of i set aHeight to height of i set {xPos, yPos} to position of i set anArea to aWidth * aHeight set the end of bList to {itemCounter:iCount, myWidth:aWidth, myHeight:aHeight, myArea:anArea} set iCount to iCount + 1 end repeat return {tList, bList} end tell end tell end tell end retRectsFromKeynote –入れ子のリストを降順ソート on sortList2DDecending(a, keyLabelList) set fLen to length of keyLabelList set fList to {} repeat fLen times set the end of fList to false end repeat return cocoaSortListAscending(a, keyLabelList, fList) of me end sortList2DDecending –Cocoaで入れ子のリストをソート true:昇順、false:降順 on cocoaSortListAscending(theList as list, keyLabelList as list, ascendingF as list) set anArray to current application’s NSMutableArray’s arrayWithArray:(theList) set sortDesc to {} set dLen to length of keyLabelList repeat with i from 1 to dLen set tmpKeyLabel to contents of item i of keyLabelList set tmpSortF to contents of item i of ascendingF set theDescriptor to (current application’s NSSortDescriptor’s sortDescriptorWithKey:(tmpKeyLabel) ascending:(tmpSortF)) set the end of sortDesc to theDescriptor end repeat set sortedList to anArray’s sortedArrayUsingDescriptors:(sortDesc) return sortedList as list end cocoaSortListAscending |
Keynoteの最前面の書類(現在の書類)と同じ階層に没スライドを入れるゴミ箱用のスライドを、編集中の現在のスライドと同じサイズ(Normal/HD)で同じテーマで作成するAppleScriptです。
ふだん、Keynoteで作業をしているときに、不要になったスライド(ページ)を完全削除せず、別書類に移動させて復活させられるようにしているのですが、その作業が煩雑だったのでScriptで自動化したものです。
同階層にゴミ箱用のスライド書類が存在していたら、それをオープンします。存在していなければ、新規作成して指定ファイル名で保存….というところで、v12のバグに遭遇してしまったわけです。
AppleScript名:Keynoteの現在の書類と同じ階層に没スライド入れを作成.scpt |
— – Created by: Takaaki Naganoya – Created on: 2022/05/29 — – Copyright © 2022 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" use scripting additions use framework "Foundation" property newFileName : "没.key" —"trash.key" tell application "Keynote" tell front document set dName to getCurThemeName() of me set curFile to (file of it) as alias set myHeight to height of it set myWidth to width of it end tell end tell –書類の親フォルダを取得(POSIX path) set parentFol to getParentFol(curFile) of me set newKeynoteFile to parentFol & "/" & newFileName –ファイルの存在確認 set exRes to chkFileExistence(newKeynoteFile) of me if exRes = true then –すでに存在している場合はそれをオープン set newKeynoteFileAlias to (POSIX file newKeynoteFile) as alias tell application "Keynote" open newKeynoteFileAlias end tell return else –まだ存在していない場合、最前面の書類と同じテーマ、縦横比(SD、HD)の新規書類を作成する set parentFolAlias to (POSIX file parentFol) as alias as string –POSIX path to HFS path string set saveFilePathStr to (parentFolAlias as string) & newFileName tell application "Keynote" set newDoc to make new document with properties {document theme:theme dName, width:myWidth, height:myHeight} –save newDoc in file saveFilePathStr as Keynote–Keynote v12のバグに遭遇したため機能オフに end tell end if –ファイルの存在確認 on chkFileExistence(aFilePathStr) set fileManager to current application’s NSFileManager’s defaultManager() set aRes to fileManager’s fileExistsAtPath:aFilePathStr return aRes as boolean end chkFileExistence on getParentFol(anAlias) set aPath to POSIX path of anAlias set pathString to current application’s NSString’s stringWithString:aPath set newPath to pathString’s stringByDeletingLastPathComponent() return newPath as string end getParentFol on getCurThemeName() tell application "Keynote" set dCount to count every document if dCount = 0 then error "No Document" tell front document set aTheme to document theme set atThemeName to name of aTheme end tell end tell end getCurThemeName |
Keynote v12.0以降で、最前面の書類で選択中のスライド(複数可)にある表のすべての文字色を「黒」に変更するAppleScriptです。
Keynote v12.0で「selection」がまともに機能するようになったので、Keynote用Scriptの実用性がたいへんに高まっています。
# ファイル保存できないとかいうバグが一刻も早く治ることを希望しています。とくに、Pages!
もともと、複数ページにわたって掲載している「表」の中に赤字でマークした箇所があって、そのマークの意図とは別の赤字を入れたかったので、いったんすべて書式をリセットしたかったので書いたものです。
もうちょっと長いScriptを書かなければならないかと思っていたのですが、ことのほかシンプルに書けました。
もっとシンプルに書けるか(everyを使ってスライドごと指定するとか)も試してみたのですが、どうやらこのあたりが限界のようです。
Keynoteのselectionを活かしたScriptでいまいちばん活躍しているのは、Keynoteのテキストアイテム(text item)から内容を取得して、メモリ上でAppleScriptとしてコンパイルし、構文色分けを反映させたスタイル付きテキストを取得して、テキストアイテムに書式を反映させるものです。実に、Keynote上にテキストで書いておいたAppleScriptのリストを構文色分けを反映させた掲載リストに変換できるので便利です。
AppleScript名:Keynoteで選択中のスライドのすべての表のセル内文字色を黒にする.scpt |
— – Created by: Takaaki Naganoya – Created on: 2022/05/27 — – Copyright © 2022 Piyomaru Software, All Rights Reserved — tell application "Keynote" set aVer to version considering numeric strings if aVer < 12.0 then return –Keynote v12.0より以前のバージョンでは実行できない end considering tell front document set aaSel to selection set selClass to class of contents of first item of aaSel if selClass is not equal to slide then return –選択中のオブジェクトがslide(ページ)でなければ処理終了 repeat with i in aaSel set j to contents of i tell j –現在のスライド上のすべての表のすべてのセルの文字色を黒 {0, 0, 0}に set text color of every cell of every table to {0, 0, 0} end tell end repeat end tell end tell |
Apple iWorkアプリケーション(Keynote、Pages、Numbers)の最新バージョンv12.0において、共通のバグがあるのではないか? と見ています。もちろん、見ているだけでなくAppleにバグレポートもしています。
症状は、新規作成した書類を「保存できない」というものです。
以前にも、PDFをexportできないという致命的なバグが発生していましたが、今回のも同様のメカニズムで発生しているものと見ています。つまり、「Appleが自社OSに設定したセキュリティ機能によって、自社アプリであるKeynote、Pages、Numbersが自家中毒を起こしている」という状態です。
自分の勘違いだとよいのですが….
あとは、Numbersのsaveコマンドをよく見てみると、書類フォーマットに「as Numbers」というenumがあるのですが、これはAppleScriptの処理系では「number」の複数形として認識されてしまうので、この予約語自体に無理があります。ここは、「as Numbers format」といった予約語に変えるべきです。
AppleScript名:Keynoteで新規書類作成して指定名称で新規保存.scpt |
set dtPath to (path to documents folder) as string set uuidStr to (do shell script "uuidgen") & ".key" set savePath to dtPath & uuidStr tell application "Keynote" set nDoc to make new document with properties {document theme:theme id "Application/21_BasicWhite/Standard", width:1024, height:768} save nDoc in file savePath as Keynote end tell |
AppleScript名:Pagesで新規書類を作成して指定名称で新規保存.scpt |
set dtPath to (path to documents folder) as string set uuidStr to (do shell script "uuidgen") & ".pages" set savePath to dtPath & uuidStr tell application "Pages" set nDoc to make new document with properties {document template:template id "Application/Blank/ISO"} save nDoc in file savePath as Pages Format end tell |
AppleScript名:Numbersで新規書類作成して指定名称で新規保存.scpt |
set dtPath to (path to documents folder) as string set uuidStr to (do shell script "uuidgen") & ".numbers" set savePath to dtPath & uuidStr tell application "Numbers" set nDoc to make new document save nDoc in file savePath as numbers –change "Numbers" word into "numbers format" because "numbers" is alredy registered as "list of number" or "every number" end tell |