Keynote v10.3.8がリリースされました。対象OSはmacOS 10.15以降です。exportコマンドでCodec指定のEnum「h.264」はそのままで、AppleScriptの言語処理系では構文確認も実行もできないままです。「h.264」→「h264」に修正してほしいんですけどー。
タグ: Keynote
Apple iWork Appsがv10.3.5にアップデート
AppleのiWork Appsがv10.3.5にアップデートしました。対象OSはmacOS 10.15以降です。
Keynote v10.3.5のAppleScript用語辞書のexport optionのmovie codecに「H.264」を指定するための定数が前バージョンから引き続き「h.264」になっています。バグ未修正状態です。
これでは、AppleScriptの構文確認をパスできません。AppleScriptの予約語としてこのような記号を途中に入れられないのですが、まるっきり動作確認もバグの所在も認識していない様子です。
みんながUIのお手本にしてきたKeynoteも、今回の10.3.5でこの体たらく。とくにツールバーアイコン。いきなり無色アイコンに変えられて(しかも小さい)、とても使いにくいというか、見えません。
まるでAppleから嫌がらせをされているかのようです。KeynoteのUIをまともにした互換アプリケーションでも誰か出さないだろうかと考えてしまいます。
iWork Appsのv10.2アップデートが公開される
AppleがKeynote/Pages/Numbersのv10.2アッップデートを公開しました。このv10.2から対象OSがmacOS 10.15以降になり、macOS 10.14では最新のKeynote v10.2を使えなくなったことになります。
Keynote v10.2のAppleScript系の機能の差分チェックを(sdefファイルベースで)行ってみたところ、iWorkアプリケーション中でKeynoteのみ機能追加されたことがわかりました。
Keynoteにムービー書き出し機能のAppleScriptオプション機能が追加される
exportコマンドのexport optionsで「movie codecs」と「movie framerates」の指定ができるように機能追加されています。
movie codecs enum h.264 : H.264 AppleProRes422 : Apple ProRes 422 AppleProRes4444 : Apple ProRes 4444 AppleProRes422LT : Apple ProRes 422LT AppleProRes422HQ : Apple ProRes 422HQ AppleProRes422Proxy : Apple ProRes 422Proxy HEVC : HEVC movie framerates enum FPS12 : 12 FPS FPS2398 : 23.98 FPS FPS24 : 24 FPS FPS25 : 25 FPS FPS2997 : 29.97 FPS FPS30 : 30 FPS FPS50 : 50 FPS FPS5994 : 59.94 FPS FPS60 : 60 FPS
風の噂によるとどうもARM Macはムービー書き出しが高速なようなので、そのあたりをアピールするためにもムービー書き出し系の機能の拡充は必要ということなのでしょう。
KeynoteのAppleScript用語辞書に構文確認をパスできないバグ持ち予約語が存在
同時に、「こんなんAppleScriptの処理系でコンパイル(構文確認)通るわけないやん、メーカーが何やってますのん?」という予約語がsdef内に書かれていることが一目でわかりました。
「h.264?」
この「h.264」の予約語はexportコマンドのexport optionsのmovie codecsのEnum内に書かれています。
<enumeration name="movie codecs" code="Knmc"> <enumerator name="h.264" code="Kmc1" description="H.264"> <cocoa string-value="AVVideoCodecTypeH264" /> </enumerator>
macOS 10.15.6上で確認したところ、見事に構文確認時にエラーになります。
Apple製のアプリケーションのAppleによるスクリプティング定義内容がまともに動きません。こうした事態は理解に苦しむものがあります。100%動作確認していないとしか思えません。
ここは、記号入りの予約語では言語処理系的に構文確認すらパスできないので、「h.264」ではなく記号を含まない「h264」ないし「H264」という予約語にすべきです。AppleScript系の機能を追加していただくのは前向きでよいと思いますが、メーカーとして一度も動作確認しないで機能をリリースするというのはいかがなものでしょう?
そんなところに凝っていないで、選択中のオブジェクトを取れる属性「selected objects」とか、テキストオブジェクトの縦書き制御属性「vertical」などをつけたほうが実用性があって助かります。機能追加自体はたいした作業ではありませんが、ぜひ動作確認した上でリリースしていただきたいところです。
AppleScript名:keynote movie export test |
–Works with Keynote v10.2 or later set aTagFile to ((path to desktop) as string) & "testOut.m4v" tell application "Keynote" set exOpt to {compression factor:1.0, movie format:native size, class:export options} –set exOpt to {compression factor:1.0, movie format:native size, movie codec:h.264, class:export options}–this cause error export document 1 to file aTagFile as QuickTime movie with properties exOpt end tell |
日頃からMac App Storeのレビューアーの血も涙もない(でも、ツッコミどころ満載の)リジェクトに遭っている身からすれば、こんなのリジェクト案件です。
個人的には信頼度の問題からmacOS 10.15は「パス」なので、macOS 11.0 Big SurがRelease時にコケないことを祈るのみです(メールが消えるとかいう話が一番OSの信頼度を下げる)。macOS 10.13, “Vista”という史上最悪・最低の大失敗をやらかして以来、「Release版のOSがBetaよりも低品質」という昨今のmacOS。10.13もBetaの時にはよかったのに、Release版で大崩壊を起こして見るも無残な姿に成り果てました。10.14もBetaの段階でGUI Scriptingの認証系でひどいバグがあって、「とても使えない」と判断。10.14.6まで待ってようやく手を出す気になったほど。
macOS 11.0, Big SurはBeta段階でも珍しく好印象で(GUIまわりの仕様はコロコロ変わるけど)、macOS 10.15みたいにBeta段階で「もう、これはダメ!」という話も聞きません(Relase時に紹介記事を書かなかったOSは10.15がはじめてです。10.15の崩壊度はひどかった)。macOS 11.0, Big Surには、macOS 10.13のような「Release版の大崩壊」を起こしてほしくないものです。
現在のスライドと次のスライドでオーバーラップしている画像とグループを検出して位置をそろえる
Keynoteの最前面の書類で、現在表示中のスライドと次のスライドの間で、矩形座標が重なっている「画像」と「グループアイテム」(複数のオブジェクトをグループ化したアイテム)を検出して、現在のスライドの開始位置に場所をそろえるAppleScriptです。
# 最初掲載したもの(v1)は、動作しているものの処理内容に誤りがあったので修正しました(v2)
連続したスライド上に画面図を配置して、その画面図の位置をそろえるためのものです。何回か書いたような気がします。見た目より書くのが大変ではないので、ついつい書いてしまう処理です。
単にそれぞれの対象候補のオブジェクトの矩形開始座標と幅&高さをリスト化して、それをNSRectに変換して重ね合わせが発生していないかをCocoaの機能で判定しているだけです。この、一番めんどくさい部分をCocoaに丸投げしているので、おおよそ知性というものを感じさせないレベルのScriptです。
画像やグループアイテム 以外の表オブジェクト同士の重なりあいの検出を行うものに書き換えるのは簡単ですが、複数のオブジェクトの重なり合いが発生している場合には対処できません。
AppleScript名:現在のスライドと次のスライドでオーバーラップしている画像とグループを検出して位置をそろえる v2.scpt |
— – Created by: Takaaki Naganoya – Created on: 2020/09/10 — – Copyright © 2020 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" use scripting additions use framework "Foundation" tell application "Keynote" set dCount to count every document if dCount = 0 then return –ドキュメントがオープンしていないと処理終了 tell front document set allNum to count every slide if allNum < 2 then return –slideの枚数が少なかった場合に処理終了 set curSlide to current slide if allNum = curSlide then return –current slideが末尾だった場合処理終了 set sNum to slide number of curSlide set nextSlide to slide (sNum + 1) –最初のページ(スライド)からオブジェクトを収集 tell current slide set curObj1 to every image set curObj2 to every group set curObjList to curObj1 & curObj2 if curObjList = {} then return end tell –次のページ(スライド)からオブジェクトを収集 tell nextSlide set nextObj1 to every image set nextObj2 to every group set nextObjList to nextObj1 & nextObj2 if nextObjList = {} then return end tell set nexObjRes to calcOverlappedObj(curObjList, nextObjList) of me repeat with i in nexObjRes copy i to {origID, targID} set aOrigObj to contents of item origID of curObjList set aTargObj to contents of item origID of nextObjList set origPos to position of aOrigObj set position of aTargObj to origPos end repeat set current slide to slide sNum end tell end tell –与えられた2つのリストに入っているKeynoteオブジェクトの矩形座標が重なっているものをIDペアで出力する –同時に複数のオブジェクトが重なっていないことが前提 on calcOverlappedObj(objList1, objList2) tell application "Keynote" –最初のページのオブジェクトからオブジェクトIDとNSRectからなるリストを作成 set objRecList1 to {} set aCount to 1 repeat with i in objList1 if contents of i is not equal to {} then set {x1, y1} to position of i set aRect to {origin:{x:x1, y:y1}, |size|:{|width|:(width of i), |height|:(height of i)}} set the end of objRecList1 to {objID:aCount, rect:aRect} end if set aCount to aCount + 1 end repeat –次のページのオブジェクトからオブジェクトIDとNSRectからなるリストを作成 set objRecList2 to {} set aCount to 1 repeat with i in objList2 if contents of i is not equal to {} then set {x1, y1} to position of i set aRect to {origin:{x:x1, y:y1}, |size|:{|width|:(width of i), |height|:(height of i)}} set the end of objRecList2 to {objID:aCount, rect:aRect} end if set aCount to aCount + 1 end repeat –最初のページのオブジェクトと次のページのオブジェクトで矩形エリアが重なっているオブジェクトを抽出してそれぞれのIDをペアにしたリストを作成 set matchList to {} repeat with i in objRecList1 set origRect to rect of i set origID to objID of i repeat with ii in objRecList2 set targRect to rect of ii set targID to objID of ii set tRes to detectRectanglesCollision(origRect, targRect) of me if tRes = true then set the end of matchList to {origID, targID} end if end repeat end repeat return matchList end tell end calcOverlappedObj –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 |
iWork Appがv10.1にアップデートし、Movie書き出しバグの修正とPDF書き出し属性を追加
iWorkアプリケーション(Keynote、Numbers、Pages)がアップデートされてv10.1になりました。対象はmacOS 10.14/10.15。
AppleScript系ではバグ修正1点と、機能追加が1点あります。
Keynoteのムービー書き出しオプション(native size)バグ修正
Keynote v10.0の際のアホなバグ(native size指定時にエラー)が修正されました。
AppleScript名:native sizeでムービー書き出し |
set outFile to (path to desktop as string) & (do shell script "uuidgen") & ".m4v"
tell application "Keynote" tell front document export to file outFile as QuickTime movie with properties {class:export options, movie format:native size} end tell end tell |
PDF書き出しオプション(include comments)を追加
また、3アプリケーション共通でPDF書き出し時に「include comments」オプションが指定できるようになりました。
▲KeynoteのGUI上で指定する「コメントを含める」チェックボックス
▲上がinclude comments:falseで書き出したPDF、下がinclude comments:trueで書き出したPDF
AppleScript名:Keynote書類からPDF書き出し v3(10.10対応) |
— Created 2017-01-21 by Takaaki Naganoya — Modified 2020-07-10 by Takaaki Naganoya — 2017-2020 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" set tmpPath to (path to desktop) as string set aRes to exportKeynoteDocToPDF(tmpPath) –Keynote書類からPDF書き出し on exportKeynoteDocToPDF(targFolderPath as string) tell application "Keynote" set dCount to count every document if dCount = 0 then return false end if set aPath to file of document 1 end tell set curPath to (current application’s NSString’s stringWithString:(POSIX path of aPath))’s lastPathComponent()’s stringByDeletingPathExtension()’s stringByAppendingString:".pdf" set outPath to (targFolderPath & curPath) tell application "Keynote" –v10.10で追加されたinclude comments属性の指定を追加してみた set anOpt to {class:export options, export style:IndividualSlides, all stages:false, skipped slides:true, PDF image quality:Best, include comments:false} export document 1 to file outPath as PDF with properties anOpt end tell return (outPath as alias) end exportKeynoteDocToPDF |
iWorkアプリケーションのAppleScript系機能に望むこと
・slide上の選択中のオブジェクトを扱えるようにしてほしい(selected itemといった予約語で)
・縦書きテキストの制御機能がほしい(強引に作ったけど)
・TOCつきPDFが直接書き出せるように(自分で作ったけど)
・Pagesをなんとかして。レイアウトをScriptから再現できない
Keynote書類上の画像を実パスを求めてアーカイブ展開してオープン
Keynote書類上の指定画像のアーカイブ中のパスを求め、指定画像のファイル名と照合し、当該画像ファイルのみアーカイブ展開してからPreview.appでオープンするAppleScriptです。
Keynote書類には2つの形式(パッケージ形式、フラット形式)があり、現在のデフォルトはフラット形式です。
パッケージ形式についてはFinder上でパッケージバンドルを表示させて、内部データ構造を実際に見られるようになっています。
では、フラット形式はどうかといえば、上記のパッケージ形式データをZip圧縮して拡張子を「.key」に変更したものです。
そのため、拡張子を「.key」から「.zip」に付け替えて、アーカイブ展開すると、実際にパッケージ内部のファイルにアクセスできます。
本Scriptは、フラット形式のKeynote書類に対して動作します。パッケージ形式は想定していません(パッケージ形式は単にファイル構造にアクセスすればよいだけなので)。
画像を貼り付けたスライドを表示した状態で本AppleScriptを実行すると、スライド上に貼り付けた画像をデスクトップフォルダに展開し、Previw.appでオープンします。1回実行するとデスクトップに画像ファイルの名前のフォルダが作られ、その中に画像が展開されています。この状態でScriptを再実行すると、フォルダ名が重複するためエラーになります。再実行したい場合にはデスクトップ上の画像名のフォルダを削除しておいてください。
指定Keynote書類の、指定スライド上にある指定イメージについては、ファイル名がわかるだけでパスやデータを取得できるわけではありません。
そこで、フラット形式のKeynote書類中の画像一覧を取得し、このファイル名と符合するものをピックアップします。ただし、ファイル名が完全一致するわけではなく、オリジナルのファイル名が「someImage.png」だった場合に、「someImage-221.png」といったファイル名が見つかります。
また、見つかるのは実ファイルだけでなくプレビュー用の「someImage-small-221.png」といったものも入っています。このプレビュー用イメージについてはスキップしています。
その後、さまざまな処理を行なってもよいでしょうけれども、とりあえず現状ではPreview.appでファイルをオープンしています。
AppleScript名:Keynote書類上の画像をアーカイブ展開して実パスを求めて展開.scptd |
— – Created by: Takaaki Naganoya – Created on: 2020/07/04 — – Copyright © 2020 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use scripting additions tell application "Keynote" set dCount to count (every document) if dCount = 0 then return tell front document set myPath to (file of it) if myPath = missing value then return false –Unsaved tell current slide tell image 1 set aFile to file name –> "switchControl.png" end tell end tell end tell end tell set myPOSIXPath to POSIX path of (myPath as alias) –Extract document internal image paths by extracting Keynote’s zip archive set dList to getInternalImagesWithinKeynote(myPath) of me –Extract file name and ext from image 1 path set pPath to POSIX path of aFile set {aName, aExt} to getExtAndFilenameFromPath(pPath) of me –Filter Keynote internal image list by image 1’s file name and ext set theArray to current application’s NSArray’s arrayWithArray:dList set thePred to current application’s NSPredicate’s predicateWithFormat_("self.pathExtension == %@ && self.lastPathComponent beginswith %@ ", aExt, aName) set bList to (theArray’s filteredArrayUsingPredicate:thePred) as list –> {"Data/switchControl-226.png", "Data/switchControl-small-227.png"} –Extrat file set exF to false repeat with i in bList set outName to getFilenameAndExtFromPath(i) of me if outName does not contain "-small-" then –Skip Preview Image set outPath to POSIX path of (path to desktop) & outName set bRes to do shell script "unzip -j " & quoted form of myPOSIXPath & " " & quoted form of i & " -d " & " " & outPath set extractPath to POSIX path of (path to desktop) & outName & "/" & outName do shell script "open " & quoted form of extractPath –Open for test set exF to true end if end repeat if exF = false then return false –Keynote書類中の画像ファイル一覧を取得 on getInternalImagesWithinKeynote(myPath) set kPath to POSIX path of myPath set aRes to do shell script "unzip -Z1 " & quoted form of kPath & " | grep ^Data/" set aList to paragraphs of aRes return aList end getInternalImagesWithinKeynote –ファイルパスからファイル名部分と拡張子を分離 on getExtAndFilenameFromPath(aPOSIXpath) set pathString to current application’s NSString’s stringWithString:aPOSIXpath set aStr to pathString’s lastPathComponent() set aExt to (aStr’s pathExtension()) set bStr to aStr’s stringByDeletingPathExtension() return {bStr as string, aExt as string} end getExtAndFilenameFromPath –ファイルパスからファイル名部分のみ取得 on getFilenameAndExtFromPath(aPOSIXpath) set pathString to current application’s NSString’s stringWithString:aPOSIXpath set aStr to pathString’s lastPathComponent() return aStr as string end getFilenameAndExtFromPath |
Finder上で「すべてのファイル名拡張子を表示」にチェックが入っているかを返す
Finderの環境設定で「すべてのファイル名拡張子を表示」にチェックが入っているかを確認するAppleScriptです。
iWorkアプリケーション(Keynote、Pages、Numbers)では、オープン中の書類名を返すときに、Finderの上記の環境設定の内容を反映して拡張子を含めたり、含めなかったりしつつ名称を返すという仕様。
「ファイル名単独で求めることなんてないでしょ?」と思いつつも、オープン中のドキュメントの存在確認を名称で行うため、けっこう左右されることになります。
AppleScript名:Finder上で「すべてのファイル名拡張子を表示」にチェックが入っているかを返す.scpt |
— – Created by: Takaaki Naganoya – Created on: 2020/05/19 — – Copyright © 2020 Piyomaru Software, All Rights Reserved — set exRes to checkDisplayTheFileExtensionsInFinder() of me –> true on checkDisplayTheFileExtensionsInFinder() try set aRes to (do shell script "/usr/bin/defaults read NSGlobalDomain AppleShowAllExtensions") as integer return aRes as boolean on error return false end try end checkDisplayTheFileExtensionsInFinder |
面積で評価して、Keynoteのメインウィンドウのうち最大のもののItem Numberを返す
ウィンドウ上に複数存在するscroll areaのうち処理対象となるべきものを面積を計算することで特定するGUI Scripting系のAppleScriptです。
どーしてもGUI Scriptingでしか操作できない機能があって、それを自動化する価値があって、大幅に発生する可能性の高い労力を削減できる見込みが立ったので、一気に自動化Scriptを作成。本Scriptはその中で作成した1つの部品です。
自分が書いた処理内容は、Keynoteで作った書類の目次ページに用意した、各スライドのタイトルに実際のスライドへのリンクを付加するもの。
本来、Keynote自体のAppleScript用語辞書に標準装備されていてほしい機能です。残念ながら標準装備されていないために、自分で組む必要があったわけです。
それを作っている途中で、このメインの(Keynoteオブジェクトを配置する中央のエリア)scroll areaのIDが起動するたびに変わるという現象に直面。初期状態(インスペクタの表示状態)をそろえてもIDが変わる。たいていこうしたGUI Scriptingがらみの「怪奇現象」に直面した場合には、スクルプトエディタやアプリケーションの再起動を行えば回避できることが多いのですが、何回かためしても回避できなかったので、scroll areaの特定をID以外で行うことに。
IDが毎回(起動ごとに)変更になるので、「最大の面積を持つもの」を計算して求めるようにしてみました。
AppleScript名:面積で評価して、Keynoteのメインウィンドウのうち最大のもののItem Numberを返す |
— – Created by: Takaaki Naganoya – Created on: 2020/05/09 — – Copyright © 2020 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use scripting additions set areaNum to getKenoteScrollAreaMax() of me –面積で評価して、Keynoteのメインウィンドウのうち最大のもののItem Numberを返す on getKenoteScrollAreaMax() tell application "System Events" tell process "Keynote" tell window 1 set sCount to count every scroll area set tmpMax to 0 set tmpMaxItem to 0 repeat with i from 1 to sCount tell scroll area i set tmpA to size copy tmpA to {tmpW, tmpH} set tmpArea to tmpW * tmpH if tmpArea > tmpMax then set tmpMax to tmpArea set tmpMaxItem to i end if end tell end repeat end tell end tell end tell return tmpMaxItem end getKenoteScrollAreaMax |
Keynoteで選択中のスライドのタイトルを取得して改行区切りテキストに変換
Keynoteのselectionを利用して、複数選択中のスライドを取得した処理を書いてみました。
ウィンドウ左側でアウトライン表示されているスライド一覧で複数選択しているものを、順次タイトルを取得して改行コードをはさんで連結したテキスト化してクリップボードに内容を転送します。内容をテキストエディタに転送して加工するために作ったものです。
Keynote用のScriptは必要に迫られて書くことが多く、本Scriptも実際に必要に迫られて書いています。ほぼ書き捨てレベルの内容でもあり、各スライドからタイトルが取得できない(タイトルが存在しない)場合には対処していません。
マスタースライドの名称を取得してタイトルオブジェクトの有無を判定するとか、各スライド上のタイトルオブジェクトにエラートラップを仕掛けつつアクセスする(存在しない場合にはエラー発生するもトラップを仕掛けてあるので処理が中断しない)、とかいった実戦レベルのScriptも(別途)書いておきたいところです。
selectionが返してくるスライド(ページ)のリストは、GUI上で後ろ(スライド番号の大きい方)から連続選択しても、前(スライド番号の小さい)のほうから連続選択しても、結果は変わりませんでした。スライド番号が小さい方から大きい方へとソートされた状態で取得されます。
AppleScript名:選択中のスライドのタイトルを取得して改行区切りテキストに変換 |
— – Created by: Takaaki Naganoya – Created on: 2020/05/08 — – Copyright © 2020 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use scripting additions set tList to {} tell application "Keynote" tell front document set aSel to selection set aLen to length of aSel if aLen < 2 then return repeat with i in aSel tell i tell default title item set aTitleStr to object text end tell set the end of tList to aTitleStr end tell end repeat end tell end tell set aStr to retArrowText(tList, return) of me set the clipboard to aStr –リストを任意のデリミタ付きでテキストに 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 |
Keynoteのselectionの使い方が判明
AppleScriptにおける「selection」という予約語は割と重要で、選択中のオブジェクトや選択中のテキストを特定したり、選択中のオブジェクトへの処理を行うといった、一歩踏み出した処理が行えます。
KeynoteのAppleScript用語辞書に「selection」が追加されたのは、2019年3月にリリースされたv9.0のこと。
「list of iWork item」を返してくると記載されていることから、スライド(ページ)上で選択中の各種iWork item(shapeとかimageとかtext itemなどの各種オブジェクト)の選択状態を取得できることが期待されたわけですが、実際に試してみるとAppleScript用語辞書のようにiWork itemsを取得できるわけではありませんでした(当時のガッカリ感が半端ない)。
ところが、些細なことからこのKeynoteのselectionが「何を」選択しているかを返すかが分かってきました。
この、ウィンドウ左側のアウトライン表示されている各スライド(ページ)。ここを複数選択した状態でselectionを実行すると、このスライドがlistで返ってくることがわかりました。
この動作を知らずに(KeynoteのAppleScriptの用語辞書を信用して)試すと、現在表示中のスライド(ページ)のオブジェクトがリストで返ってくるという動作になります。なので、このselectionは現在表示中のスライド(ページ)のオブジェクトを返す(超使えない)コマンドだと判断していました。
ウィンドウ内容の表示ポップアップから「Light Table」を選択すると、
ここで複数スライドを選択しても「selection」で選択状態を取得できるわけではないようです。
Keynoteに対するAppleScriptの処理で、スライド上の各種オブジェクトの位置やサイズを統一するようなものがありますが、そういう範囲で使うのであれば有効に使えるといったところでしょうか。
iWork Apps Update v10.0
Keynote、Pages、Numbersのv10.0が配信されました。Keynoteの前バージョンはv9.2、Pagesはv8.2、Numbersはv6.2.1でしたが、バージョン番号を別々に採番することがめんどくさくなったのか、内部のエンジンが一新されたのか、バージョン番号をそろえてきました。
おそらく、マーケティング的な要請やユーザーサポートの手間を省くために番号をそろえてきたのでしょう。
Pages/NumbersについてはmacOS 10.14以上が対象。KeynoteはmacOS 10.15.4が必要とのことですが、いろいろ致命的なバグの修正を含んでいるため、後日macOS 10.14.6向けのKeynoteアップデートが配信されることを期待したいところです。
# アップデートに出てこないだけで、Mac App Storeから個別にKeynote v10.0のダウンロードが(macOS 10.14.6上でも)できました。なんででしょう?
v10.0 UpdateのAppleScript的な変更の有無
■Numbers v10.0:変更点なし
Numbers v6.2で「特定の行数の表を作るとエラーになる」というバグがありましたが、これはv6.2.1で修正されました。これが修正されています(記憶違いだったので、記事を修正しておきます)。
Pages v10.0の変更点
documentにfacing pagesというプロパティが新設されました。見開き表示時にページの左右(奇数ページ、偶数ページ)を考慮して2ページ表示のペアを変更するという機能のようです。
AppleScript名:Pages v10.0で追加されたfacing pagesの操作を行う |
tell application "Pages" tell front document set curStat to facing pages set facing pages to not curStat –反転 delay 2 set facing pages to curStat –元に戻す end tell end tell |
全言語的に普遍的な内容ではあるのですが、日本語ユーザー的には縦書き/横書きの設定属性値を持ってくれたほうがありがたいところです。たぶん、自分は使うことはないと思います。
Keynote v10.0の変更点
Keynoteは前バージョンでかなりおかしなバグが発覚していたので、その修正が行われているかどうか、というのが見所です。
結論からいえば、バグは修正されています。macOSに関して久しぶりに前向きなニュースといえます。彼らにバグを修正する意思と能力が残されていたことについては喜びたいところです。同時に残念なニュースとして、この修正に関連して新たなバグが生まれています(このあたりがいかにもAppleらしい)。
Keynoteバグ1:表(table)作成時に行数によってはエラーになる
5行の表を作るとエラーになり、他の行数でもいろいろエラーになる組み合わせが確認されていました。テスト用のAppleScriptを書いて、行数を2〜100行で変更しつつ作成、列数を2〜30列で変更しつつ作成、行数および列数を順次ループで2〜20まで変更しつつ新規作成するなどのテストを実施。無事、修正を確認できました。
ただし、本テストは表の新規作成についてのみ確認したものであり、既存の表の行数/列数の変更を確認したものではありません。Appleの仕事に関しては、修正点の周囲に新たなバグを生む可能性が高く、修正時と修正後が一番危険な状態です。彼らに「自分の作った機能を動作確認する」という能力を期待してはいけません。信じてもいけません。つねに、疑いの目で見ることが重要です。
AppleScript名:Keynote書類上に表を作成、行数を2から100まで可変 |
tell application "Keynote" tell front document tell current slide repeat with i from 2 to 100 set aTable to make new table with properties {header column count:0, header row count:0, row count:i, column count:3} delay 1 delete aTable end repeat end tell end tell end tell |
AppleScript名:Keynote書類上に表を作成、列数を2から30まで可変 |
tell application "Keynote" tell front document tell current slide repeat with i from 2 to 30 set aTable to make new table with properties {header column count:0, header row count:0, row count:5, column count:i} delay 1 delete aTable end repeat end tell end tell end tell |
AppleScript名:Keynote書類上に表を作成、行数および列数を2から20まで可変 |
tell application "Keynote" tell front document tell current slide repeat with x from 2 to 20 repeat with y from 2 to 20 set aTable to make new table with properties {header column count:0, header row count:0, row count:y, column count:x} delay 0.01 delete aTable end repeat end repeat end tell end tell end tell |
Keynoteバグ2:書類(document)のムービーexport optionsにバグ
数値ではじまる予約語や記号を含む予約語はAppleScriptの言語処理系では宣言できません。エラーになります。それをAppleの(おそらくKeynoteの)担当者がKeynote v7.1のアップデート時に、従来の「small」「midium」「large」といったEnumによる指定から、「360p」「540p」「720p」「1080p」「2160p」という指定を行えるように変更を加えました。
より大きな解像度の書き出しに対処したことは評価できると思いますが、そもそもAppleScriptの処理系で認識できない「数字で始まる予約語」に変えたのはダメダメです(スクリプトエディタ上で構文確認を行うとエラーになる=使えない)。つまり、この担当者はsdefの改変を行なっただけで、実際にコードを書いて動作確認を行っていないことがわかります。
Appleにバグレポートを書きつつ、このような処理が必要な場合にはnative sizeで書き出して、そのあとでムービーをリサイズするような処理で回避していました(GUI Scriptingで乗り切ったScripterもいるようですが)。
Keynote v10.0では「format360p」「format540p」「format720p」「format1080p」「format2160p」と変更され、AppleScriptの構文確認時にエラーでハネられることはなくなりました。この点についてはバグ修正が行われたものと判断してよいと思われます。
ただし、従来動作していたEnum「native size」を指定するとエラーになるようになってしまいました。互換性のために残したが動作していない、といったコメントが書かれているわけでもないため、これはバグだと判断します。
■Keynote書類フォーマットとムービー書き出し時の解像度の対応表(Piyomaru Software独自調査による)
movie export formats | 標準(4:3) | ワイド(16:9) |
format360p | 480 × 360 | 640 × 360 |
format540p | 720 × 540 | 960 × 540 |
format720p | 960 × 720 | 1280 × 720 |
format1080p | 1440 × 1080 | 1920 × 1080 |
format2160p | 2880 × 2160 | 3840 × 2160 |
AppleScript名:Keynote 360p movie export test |
set targetFileHFSPath to (choose file name) as string –かならずファイル拡張子に「.m4v」を指定する必要がある if targetFileHFSPath does not end with ".m4v" then set targetFileHFSPath to targetFileHFSPath & ".m4v" end if with timeout of 3600 seconds tell application "Keynote" export front document to file targetFileHFSPath as QuickTime movie with properties {movie format:format360p} end tell end timeout |
AppleScript名:Keynote 540p movie export test |
set targetFileHFSPath to (choose file name) as string –かならずファイル拡張子に「.m4v」を指定する必要がある if targetFileHFSPath does not end with ".m4v" then set targetFileHFSPath to targetFileHFSPath & ".m4v" end if with timeout of 3600 seconds tell application "Keynote" export front document to file targetFileHFSPath as QuickTime movie with properties {movie format:format540p} end tell end timeout |
AppleScript名:Keynote 720p movie export test |
set targetFileHFSPath to (choose file name) as string –かならずファイル拡張子に「.m4v」を指定する必要がある if targetFileHFSPath does not end with ".m4v" then set targetFileHFSPath to targetFileHFSPath & ".m4v" end if with timeout of 3600 seconds tell application "Keynote" export front document to file targetFileHFSPath as QuickTime movie with properties {movie format:format720p} end tell end timeout |
AppleScript名:Keynote 1080p movie export test |
set targetFileHFSPath to (choose file name) as string –かならずファイル拡張子に「.m4v」を指定する必要がある if targetFileHFSPath does not end with ".m4v" then set targetFileHFSPath to targetFileHFSPath & ".m4v" end if with timeout of 3600 seconds tell application "Keynote" export front document to file targetFileHFSPath as QuickTime movie with properties {movie format:format1080p} end tell end timeout |
AppleScript名:Keynote 2160p movie export test |
set targetFileHFSPath to (choose file name) as string –かならずファイル拡張子に「.m4v」を指定する必要がある if targetFileHFSPath does not end with ".m4v" then set targetFileHFSPath to targetFileHFSPath & ".m4v" end if with timeout of 3600 seconds tell application "Keynote" export front document to file targetFileHFSPath as QuickTime movie with properties {movie format:format2160p} end tell end timeout |
AppleScript名:Keynote native size movie export test (Bug) |
set targetFileHFSPath to (choose file name) as string –かならずファイル拡張子に「.m4v」を指定する必要がある if targetFileHFSPath does not end with ".m4v" then set targetFileHFSPath to targetFileHFSPath & ".m4v" end if with timeout of 3600 seconds tell application "Keynote" –export front document to file targetFileHFSPath as QuickTime movie with properties {movie format:native size} end tell end timeout |
Keynoteで選択中の画像を特定する
Keynoteの書類上で選択中のオブジェクト(image)を特定するAppleScriptです。
Keynoteには、選択中のオブジェクトを求めるという重要な機能「selection」が実装されていません。一応、最新版のKeynoteには「selection」の予約語が存在しているものの、slide中の選択オブジェクトではなく「選択中のスライド」が返ってきます。current slideとほぼ同じ動作です。これでは実用性がいまひとつです。
ないと困るselection(get selected object)ですが、実装されていないのは仕方ありません。
そのものズバリの機能が存在していないものの、他のやりかたで選択中の画像を特定してみました。数が少なかったり重複するものが存在していない場合には有効のようです。
本Scriptでは、Keynote書類上で選択中の画像があるという前提の上で、GUI Scripting経由でコピーを行い、選択対象をクリップボードに入れます。このクリップボード内の画像のサイズを取得。次に、現在のKeynote書類の現在のスライド(ページ)上の画像(imageオブジェクト)のサイズを取得し、順次照合。同じサイズのものがあれば、それが選択中のオブジェクトであると類推します。
かなり穴の多いロジックですが、最初の一歩としては悪くないでしょう。とりあえずは、サイズで比較を行い、同一のものがあれば画像同士の類似性を計算するといった方法も検討できそうです。
お手上げになってしまうのは、画像サイズや内容ともに同一のものが複数あった場合です。その場合を除けば割と識別できそうに思えます。
また、ながらく調査を行なってきた「ローカライズ言語に依存しないGUI Scripting」を用いて選択中のオブジェクトのコピーができるとよさそうです。
AppleScript名:Keynoteで選択中の画像を特定する.scptd |
— – Created by: Takaaki Naganoya – Created on: 2020/01/22 — – Copyright © 2020 Piyomaru Software, All Rights Reserved — use AppleScript version "2.7" use scripting additions use framework "Foundation" use framework "AppKit" set kRes to getSelectedImage() of me –> image 3 of slide 24 of document id "534F4E65-4459-4B00-95D4-34C3E020467E" on getSelectedImage() my executeKeynoteItemCopy() –Execute Copy From Menu –クリップボードの内容をNSImageに set aNSIMage to my getClipboardASImage() if aNSIMage = false then return false end if –クリップボード中のNSImageのサイズを取得 set aSize to aNSIMage’s |size|() set selWidth to (aSize’s width) as real set selHeight to (aSize’s height) as real –Keynoteの最前面のドキュメントの現在のスライド上の画像からサイズを取得してクリップボード内の画像サイズと照合する tell application "Keynote" tell front document tell current slide set iList to every image repeat with i in iList set myHeight to (height of i) as real set myWidth to (width of i) as real if {myWidth, myHeight} = {selWidth, selHeight} then return contents of i end if end repeat end tell end tell end tell return false end getSelectedImage — クリップボードの内容をNSImageとして取り出して返す on getClipboardASImage() set theNSPasteboard to current application’s NSPasteboard’s generalPasteboard() set theAttributedStringNSArray to theNSPasteboard’s readObjectsForClasses:({current application’s NSImage}) options:(missing value) if theAttributedStringNSArray = {} then return false set theNSAttributedString to theAttributedStringNSArray’s objectAtIndex:0 return theNSAttributedString end getClipboardASImage on executeKeynoteItemCopy() activate application "Keynote" tell application "System Events" tell process "Keynote" –click menu item "Copy" of menu 1 of menu bar item "Edit" of menu bar 1 click menu item "コピー" of menu 1 of menu bar item "編集" of menu bar 1 end tell end tell end executeKeynoteItemCopy |
再帰でKeynote書類上のフォントを置換する(グループ対応)
macOS 10.15でバンドルされなくなった「ヒラギノ角ゴProN W3」「ヒラギノ角ゴProN W6」がKeynote書類中に指定されていたら、それぞれ「ヒラギノ角ゴシック W3」「ヒラギノ角ゴシック W6」に置換するAppleScriptです。
現在オープン中の最前面のKeynote書類を走査して、全スライド中のオブジェクトの内容を取得し、text item、shape、table中に指定されているフォントを置換するようになっています。また、group化されたこれらのオブジェクトを再帰で取得するようになっています。
ただし、グラフ(chart)中の文字のフォントについてはAppleScriptからアクセスできないため、フォントの置換は行えません。このあたりでミソがついて、完全自動でヒラギノ角ゴProNを置換できるわけではないので、少々残念(KeynoteのAppleScript用語辞書の仕様の問題)な結果に。
また、別にこれらのフォントを置換しなくても実害はないので、置換しても単に気分の問題だけでしょう。
AppleScript名:再帰でKeynote書類上のフォントを置換する(グループ対応) |
— Created 2019-11-14 by Takaaki Naganoya — 2019 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" property allText : {} property allShape : {} property allTable : {} set searchFont to {"HiraKakuProN-W6", "HiraKakuProN-W3"} tell application "Keynote" tell front document set sCount to count every slide repeat with ii from 1 to sCount set current slide to slide ii tell current slide getEveryTextAndShapes() of me –Text Item、Shapeのフォント置換ループ set tList to allText & allShape repeat with i in tList set aClass to class of i –if aClass is not equal to default title item then set aFont to font of object text of i set aText to (object text of i) if aFont is in searchFont and aText is not equal to "" then if aFont ends with "-W6" then set font of object text of i to "HiraginoSans-W6" else if aFont ends with "-W3" then set font of object text of i to "HiraginoSans-W3" end if end if –end if end repeat –Table内の全セルのフォント置換ループ repeat with iii in allTable tell iii set cList to every cell repeat with i in cList –Loop by cells set aFont to font name of i set aText to (value of i) if aFont is in searchFont then if aFont ends with "-W6" then set font name of i to "HiraginoSans-W6" else if aFont ends with "-W3" then set font name of i to "HiraginoSans-W3" end if end if end repeat end tell end repeat end tell end repeat end tell end tell on getEveryTextAndShapes() set allText to {} set allShape to {} set allTable to {} tell application "Keynote" tell front document tell current slide set gList to every group set i1List to every text item set i2List to every shape set i3List to every table if i1List is not equal to {} then set allText to allText & i1List if i2List is not equal to {} then set allShape to allShape & i2List if i3List is not equal to {} then set allTable to allTable & i3List prepareGroup(gList) of me end tell end tell end tell end getEveryTextAndShapes –Dig into groups by recursive call on prepareGroup(gList) tell application "Keynote" tell front document tell current slide repeat with i in gList tell i set g2List to every group set i1List to every text item set i2List to every shape set i3List to every table if i1List is not equal to {} then set allText to allText & i1List if i2List is not equal to {} then set allShape to allShape & i2List if i3List is not equal to {} then set allTable to allTable & i3List prepareGroup(g2List) of me end tell end repeat end tell end tell end tell end prepareGroup |
iWork Appsがアップデート、表の新規作成時バグは未修正
iWork Apps(Keynote、Pages、Numbers)がアップデートし、Keynote v9.2、Pages v8.2、Numbers v6.2になりました。
KeynoteとNumbersで表の新規作成時に特定のセル数でエラーになる(ほとんどのケースでエラーになる)バグが修正されていないことを確認しました。Pagesは未確認です。
Pages v8.2で表の新規作成を試してみたところ、Pagesでは行数や桁数を指定しても問題なく作成できました。
tell application "Pages"
tell front document
tell page 1
make new table at beginning with properties {row count:20, column count:5, header row count:2, header column count:2, position:{60, 80}}
end tell
end tell
end tell
★Click Here to Open This Script
Numbersでimageのposition X座標による制御ができないバグはNumbers v6.2で修正されたことを確認しました。
Keynoteに画期的なバグ〜特定のセルサイズの表を作るとエラーに
Keynote v9.1+macOS 10.14.6上でAppleScriptのプログラムを組んでいたら「行数が正しくない」といったエラーになるので、徹底的に調べてみました。
Keynote v9.2でも修正されていないことを確認しました。
Keynote v9.2.1でも修正されていないことを確認しました。
▲5行の表を作ろうとするとエラー。4行でも6行でも大丈夫なのに5行の表を作るとエラー
tell application "Keynote"
tell front document
tell current slide
set aTable to make new table with properties {header column count:0, header row count:0, row count:5, column count:3}
end tell
end tell
end tell
★Click Here to Open This Script
すると、なんと「特定のセルサイズ(行数、列数)の表を作成させた場合にのみエラーになる」ことが判明。
make new table with propertiesコマンドで行/列を指定して作成するとエラーになる組み合わせは以下のとおり。
{{xNum:2, yNum:5}, {xNum:3, yNum:5}, {xNum:4, yNum:2}, {xNum:4, yNum:3}, {xNum:4, yNum:4}, {xNum:4, yNum:5}, {xNum:4, yNum:6}, {xNum:4, yNum:7}, {xNum:4, yNum:8}, {xNum:4, yNum:9}, {xNum:4, yNum:10}, {xNum:4, yNum:11}, {xNum:4, yNum:12}, {xNum:4, yNum:13}, {xNum:4, yNum:14}, {xNum:4, yNum:15}, {xNum:4, yNum:16}, {xNum:4, yNum:17}, {xNum:4, yNum:18}, {xNum:4, yNum:19}, {xNum:4, yNum:20}, {xNum:4, yNum:21}, {xNum:4, yNum:22}, {xNum:4, yNum:23}, {xNum:4, yNum:24}, {xNum:4, yNum:25}, {xNum:4, yNum:26}, {xNum:4, yNum:27}, {xNum:4, yNum:28}, {xNum:4, yNum:29}, {xNum:4, yNum:30}, {xNum:5, yNum:5}, {xNum:6, yNum:5}, {xNum:7, yNum:5}, {xNum:8, yNum:5}, {xNum:9, yNum:5}, {xNum:10, yNum:5}}
さらに、上記サイズでエラー発生時に追試を行い、安全なサイズの表(3×3)を作成したあとにリサイズを行ってもエラーになるのが、
{xNum:3, yNum:5}, {xNum:4, yNum:3}
の組み合わせであるようです。なんでやねーん、と関西人でもないのにツッコンでしまいました。いやー、作ろうとしないとできないバグなんでは?
特定サイズの表をAppleScript側から作らせないようにしているのでしょうか? とても不思議なパターンのバグです。思わず「わざとなのか?」と思ってしまったほどです。何かのイースターエッグなんでしょうか、とても不愉快なイースターエッグですが。
Core i5のマシンでも追試を行ってみて、同様にエラーが再現することを確認しました。Xeonでのみ発生するエラーということではないようです(それはそれでちょっと見てみたい)。
追試で、Keynote v8.1+macOS 10.12.6上で同じことをやってみたら、とくにエラーにはなりませんでした。
AppleScript名:keynoteTableTest.scptd |
— – Created by: Takaaki Naganoya – Created on: 2019/08/09 — – Copyright © 2019 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later, use framework "Foundation" use scripting additions set erList1 to {} set erList2 to {} tell application "Keynote" make new document end tell repeat with x from 2 to 10 repeat with y from 2 to 30 tell application "Keynote" tell front document tell current slide delete every table set errorF to false –First trial (make new table command) try set aTable to make new table with properties {header column count:0, header row count:0, row count:y, column count:x} on error set errorF to true set the end of erList1 to {xNum:x, yNum:y} end try if errorF = true then –Second trial (Make safe size table and change its size after generation) delete every table set aTable to make new table with properties {header column count:0, header row count:0, row count:3, column count:3} try set column count of aTable to y set row count of aTable to x on error set the end of erList2 to {xNum:x, yNum:y} end try end if end tell end tell end tell end repeat end repeat return {erList1, erList2} |
Keynoteの表の内容を回転(Transpose)
Keynoteでオープン中の書類の現在表示中のページ(スライド)上にある表のデータを回転(transpose)する、行列入れ替えするAppleScriptです。
–> Download tableTransposer (Code Signed Applet)
Numbersでは、指定の表データの縦横転置のためのコマンド「行と列を転置」(transpose)がありますが、Keynoteにはありません。
Keynoteの表データをコピーしてNumbersに持って行って転置してKeynoteに戻していますが、メニュー操作で一発で転置できるようにしてみたものです。
回転(転置)前にテーブルの縦横のセル数をカウントして、高さと幅が同じでない場合には処理を行いません。ただ、これでは明らかに使い勝手がよくありません。いっそ、表のセル数を変更して転置したデータ形状に表の方を合わせるべきです。
Script Menuから実行させてみる場合には、コード署名してアプレット書き出しする必要があります。上記のリンクから、コード署名したアプレットをダウンロードして実行してみてください。
AppleScript名:表の内容を回転(Transpose) |
— – Created by: Takaaki Naganoya – Created on: 2019/05/16 — – Copyright © 2019 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use scripting additions use script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html set tName to getTargetTableName() of me if tName = false then return –Get Table Values as 2D List set t1List to getValuesOfATableBy2DList(tName) of me –Check Table width and height is same or not set tRes to countElementsOf2DList(t1List) of me if tRes = false then display notification "Table width and height is not same….." return end if –Transpose 2D List set t2List to transpose2DList(t1List) of me –Set values to a table setValuesToATableBy2DList(tName, t2List) of me –Keynoteの現在の最前面の書類の現在のスライド上の指定名称の表に2D Listの値を入れる on setValuesToATableBy2DList(tName, tList) tell application "Keynote" tell front document tell current slide tell table tName set rCount to count every row set cCount to count every column repeat with i from 1 to rCount tell row i repeat with ii from 1 to cCount tell cell ii ignoring application responses –Sync Mode set value of it to getItemByXY(ii, i, tList, "") of me end ignoring end tell end repeat end tell end repeat end tell end tell end tell end tell end setValuesToATableBy2DList –Keynoteの現在の最前面の書類の現在のスライド上の指定名称の表から2D Listで値を取り出す on getValuesOfATableBy2DList(tName) set a2Dlist to {} tell application "Keynote" tell front document tell current slide tell table tName set rCount to count every row repeat with i from 1 to rCount tell row i set tList to value of every cell end tell set the end of a2Dlist to tList end repeat end tell end tell end tell end tell return a2Dlist end getValuesOfATableBy2DList –処理対象となる表の名称を取得する on getTargetTableName() tell application "Keynote" tell front document tell current slide set tCount to count every table if tCount = 0 then display notification "There is no Table" return false else if tCount > 1 then set tList to name of every table set tRes to choose from list tList with prompt "Chose target Table" if tRes = false then return false set tName to first item of tRes else set tName to name of table 1 end if return tName end tell end tell end tell end getTargetTableName –2D ListをTransposeする on transpose2DList(aList as list) load framework return (ASify from (current application’s SMSForder’s colsToRowsIn:aList |error|:(missing value))) end transpose2DList —-リストに対して、一般的な配列添字っぽくアクセスするサブルーチン(ただし、要素は1はじまり) on getItemByXY(aX, aY, aList, aBlankItem) try set aContents to contents of (item aX of item aY of aList) on error set aContents to aBlankItem end try return aContents end getItemByXY on setItemByXY(aX, aY, aList, aContents) set (item aX of item aY of aList) to aContents return aList end setItemByXY –空白の2D Array を出力する on make2DBlankArray(curLen, curMax) set outArray to {} repeat curMax times set aList to {} repeat curLen times set the end of aList to "" end repeat set the end of outArray to aList end repeat return outArray end make2DBlankArray –配列のサイズを数えるサブルーチン –2D Listの要素数カウント on countElementsOf2DList(aList) set aDim to getDimension given tArray:aList if aDim is not equal to 2 then return false set aHeight to count every item of aList set aWidth to count every item of item 1 of aList return {xWidth:aWidth, yHeight:aHeight} end countElementsOf2DList –指定Listの次元を再帰で取得する on getDimension given tArray:aList as list : {}, curDim:aNum as integer : 1 set anItem to contents of first item of aList set aClass to class of anItem if aClass = list then set aNum to aNum + 1 set aRes to getDimension given tArray:anItem, curDim:aNum else return aNum end if end getDimension |
選択中のリストのテキスト(多分)をもとにKeynoteの表を作成 v2
Script Editor上で選択中の1D List(1次元配列)のテキストを評価してリストとして解釈し、それをもとにKeynoteの新規書類上に表を作成するAppleScriptの改良版です。
こんな感じ(↑)に、Script Editor上で1D List(1次元配列)のテキストが存在しているものを、資料化するためにKeynote上で表にすることがあり、その作業を自動化してみました。
スクリプトエディタ上の選択範囲のテキストをrun scriptコマンドで実際に実行(Evalのような使い方)して本物のAppleScriptのリストを作成して処理します。
ここがたいへんにセキュリティホールになりやすいので、実行前にテキストをAppleScriptとして構文確認を行い、危ない構文要素(コマンド類)が入っていないか、AppleScriptの構文的に中途半端でないかチェックを行います。
技術的にはMac OS X 10.4ないし10.5の時代に確立していた内容ではありますが、当時はスクリプトエディタをコントロールして構文色分け情報を取得していたので、macOS 10.10以降でCocoaの機能がAppleScriptから直接利用できるようになって、よりスマートに処理できるようになりました。
Mac OS X 10.4の時代には、plistの情報はテキストで記録されていたので、構文色分け設定を読むのは簡単でした。スクリプトエディタから書式つきテキスト情報(attribute runs)を取得して付け合わせを行っていました。途中でplistの内容がバイナリ化されてplistを読むことが難しくなったので、新規書類に「すべての構文要素が入った最低限度のAppleScript」を転送して構文確認を行い、attribute runsを取得して規定の場所の書式情報を取得することで、特定の構文要素の色分け情報を取得していました(一瞬で新規書類を作成して構文確認し、すぐに破棄するので目には見えない)。
–> Download selectedStrToKeynoteTable (Source AppleScript Bundle with Library)
–> Download selectedStrToKeynoteTableWithCodeSign(AppleScript Applet executable with Code Sign)
ただし、本ScriptをmacOS 10.14上で実行してみていろいろ問題を感じました。まずは、スクリプトエディタ/Script Debugger上で実行する分には何も問題はありません。ここは大事なので明記しておきます。
これ以外の実行環境で実行させると、とたんに首をひねりたくなるような挙動が見られます。Script Menuから実行することを前提に作ってみたわけですが………
普通にScriptとして保存して実行(署名なし、公証なし):初回実行時にオートメーション認証ダイアログが表示されて実行。数回同じScriptを実行すると実行されなくなる(!)
Appletとして保存して実行(署名なし、公証なし):実行時、毎回オートメーション認証ダイアログが表示されて実行。
Appletとして保存して実行(署名あり、公証なし):初回実行時、オートメーション認証ダイアログが表示されて実行。連続して実行するとダイアログ表示なし。しばらく時間を置いて実行するとダイアログ表示される。
macOS 10.14については2か月前から使い始めたので、公証についてもまだうまく行えていません(SD Nortaryで開発者IDが認識されない、、、)。こちら(公証)も試してみるべきなんでしょう。
公証関連については、実際に行っている方、失敗した方の意見をまとめておきたいので、本Blog併設のフォーラムにて(言語は英語でも何語でもOKなので)情報交換させてください。
AppleScript名:選択中のリストのテキスト(多分)をもとにKeynoteの表を作成 v2 |
— – Created by: Takaaki Naganoya – Created on: 2019/07/31 — – Copyright © 2019 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use scripting additions use dangerAS : script "checkDangerAS" set aTargMasterSlide to "空白" –This string is *Localized* in Japanese. This is "Blank" tell application "Script Editor" tell front document set bText to contents of selection end tell end tell if bText = "" then return –指定のテキストをAppleScriptとして評価し、指定の構文要素に該当するものが含まれているかどうかチェック set dRes to chkTargLexicalElementsFromCompiledScriptAttribute(bText, {9, 14}) of dangerAS if dRes = missing value then –The selected text contains AppleScript lexical error display dialog "選択中のテキストにAppleScriptの構文エラーが検出されました" default answer bText with title "Error" with icon 2 return end if if dRes = true then –The selected text contain danger AppleScript lexical element (maybe it is any command) display dialog "選択中のテキストは実行に危険な文字列(AppleScriptコマンド)を含んでいるため、処理しませんでした" default answer bText with title "Error" with icon 2 return end if try set aRes to run script bText –Danger!! Take Care of. set aClass to class of aRes on error –The Evaluation error (some AppleScript lexical error) display dialog "The contents of clipboard seems not to be an AppleScript list but " & (aClass as string) & return & bText with title "Error (1)" with icon 2 return end try if aClass is not equal to list then –The Evaluated result is not list display dialog "The contents of clipboard seems not to be an AppleScript list but " & (aClass as string) & return & bText with title "Error (2)" with icon 2 return end if set aLen to length of aRes set aDim to getDimension given tArray:aRes if aDim > 1 then –Check List’s dimension (the taeget dimension is 1) display dialog "選択中のテキストを評価したリスト(配列)の次元数が1ではなかったので、処理しませんでした" default answer bText with title "Dimension Error(3)" with icon 2 return end if tell application "Keynote" activate set aDoc to (make new document with properties {document theme:theme "ホワイト", width:1024, height:768}) — –This string is *Localized* in Japanese. This is "White" tell aDoc set masList to name of every master slide if aTargMasterSlide is not in masList then return –多分ないと思うが、作成予定のマスタースライドが現在有効でない場合に処理打ち切り set base slide of current slide to master slide aTargMasterSlide tell current slide set aTable to make new table with properties {header column count:0, header row count:1, row count:2, column count:aLen, name:"Test Table"} tell aTable repeat with y from 1 to 1 tell row y repeat with x from 1 to aLen tell cell x set value to (item x of aRes) as string end tell end repeat end tell end repeat end tell end tell end tell end tell –指定Listの次元を再帰で取得する on getDimension given tArray:aList as list : {}, curDim:aNum as integer : 1 set anItem to contents of first item of aList set aClass to class of anItem if aClass = list then set aNum to aNum + 1 set aRes to getDimension given tArray:anItem, curDim:aNum else return aNum end if end getDimension |
選択中のリストのテキスト(多分)をもとにKeynoteの表を作成
Script Editor上で選択中の1D List(1次元配列)のテキストを評価してリストとして解釈し、それをもとにKeynoteの新規書類上に表を作成するAppleScriptです。
こんな感じ(↑)に、Script Editor上で1D List(1次元配列)のテキストが存在しているものを、資料化するためにKeynote上で表にすることがありますが、これが個人的に超絶かったるいです。
きれいにデータになっているものを、表のセルに細切れにして突っ込む作業がかったるいので、おそらくそれを手動で行う数倍の時間をかけてAppleScriptで自動化しておきました。
(1)Script Editor上でListの箇所を選択しておく
(2)Script Menuに入れておいた本Scriptを呼び出す
(3)Keynoteで新規書類を作成し、1ページ目に表を新規作成し、(1)の内容を1行目に代入
という動作を行います。上記のとおり、Script Menuに入れて呼び出すことを前提にしています。もし、そうでなければ当該部分をコピーしておいて、クリップボード経由で受け取るようにしてみてください。
当初は本Scriptもそういう構造になっていましたが、選択部分をコピーするのを忘れることが多いため、選択箇所から取得するように変更しました。
本Scriptは自分自身で使うことを前提に作ったため(本Blogまるごとそんなもんですが)、run scriptコマンドで文字列をAppleScriptとして評価して実行して結果を取得するという、ひじょーーーーーにセキュリティホールになりやすい処理を行っています。
本来、取得した文字列をAppleScriptとして評価して、構文要素的に「コマンド類」が入っていないか(とくにdo shell script)を評価する必要があると思います。その上で、もしもコマンド類が入っていた場合にはユーザーに再考を促すようにダイアログを表示するなどの処理を行うのがまっとうなやりかたでしょう。
このあたり、ものすごくラフに作ったので、利用はあくまで自己責任で行ってください(本Blogまるごとそんなもんですが)。
AppleScript名:選択中のリストのテキスト(多分)をもとにKeynoteの表を作成 |
— – Created by: Takaaki Naganoya – Created on: 2019/07/31 — – Copyright © 2019 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use scripting additions set aTargMasterSlide to "空白" –This string is *Localized* in Japanese. This is "Blank" tell application "Script Editor" tell front document set bText to contents of selection end tell end tell if bText = "" then return try set aRes to run script bText –Danger!! Take Care of. set aClass to class of aRes on error display dialog "The contents of clipboard seems not to be an AppleScript list (1)." with title "Error" return end try if aClass is not equal to list then display dialog "The contents of clipboard seems not to be an AppleScript list (2)." with title "Error" return end if set aLen to length of aRes tell application "Keynote" activate set aDoc to (make new document with properties {document theme:theme "ホワイト", width:1024, height:768}) — –This string is *Localized* in Japanese. This is "White" tell aDoc set masList to name of every master slide if aTargMasterSlide is not in masList then return –多分ないと思うが、作成予定のマスタースライドが現在有効でない場合に処理打ち切り set base slide of current slide to master slide aTargMasterSlide tell current slide set aTable to make new table with properties {header column count:0, header row count:1, row count:2, column count:aLen, name:"Test Table"} tell aTable repeat with y from 1 to 1 tell row y repeat with x from 1 to aLen tell cell x set value to (item x of aRes) as string end tell end repeat end tell end repeat end tell end tell end tell end tell |
Keynote, Pages, Numbersがアップデート
macOS 10.13以上で動作するiWorkアプリケーションの最新版がアップデートしました。
Keynote v9.1、Pages v8.1、Numbers v6.1です。
AppleScript用語辞書を書き出して比較してみましたが、用語辞書に変更は一切ありません。
ただし、アプリケーション自体には大幅に機能追加が行われており、ちょっと前までの停滞しまくっていたiWorkアプリケーションとは思えないほどの強化ぶりです。
Photos.app以外でははじめて顔認識の機能が(Apple純正アプリでは)利用され、写真を配置する際に顔認識して配置するとか、ページ間リンクを張るさいにブックマークを挿入(他のアプリケーションで言うところの「アンカー」ですね)したりと、アプリケーションとしてまっとうな機能アップが行われたように感じられました。
Keynoteで選択中のスライドだけをデスクトップに画像で書き出す
Keynoteでオープン中の最前面の書類で、選択中のスライドだけをデスクトップにPNG画像で書き出すAppleScriptです。Keynote 9.xを必要とします(macOS 10.13以降)。
ちょっとした説明のためにKeynoteの資料の一部だけを画面上でキャプチャして、メールなどに添付して送ることはよくあります(全部送ると量がおおすぎたり、焦点がぼやけたり)。
そこで、複数枚のスライド(ページ)を選択しておくと、それらのみを画像書き出しするAppleScriptを作ってみました。Keynoteにそんな機能はないのですが、「選択中のページ番号」は取れるので、書類全体をPDF書き出ししておいて、書き出したPDFから指定ページを画像として再書き出しを行い、PDFを削除しています。
手品のように見える処理でも、実際に行える機能を組み合わせて地道に作っているだけです。問題は、「手品」が実は地道な調査と機能確認、こまごまとしたライブラリの整備の末に実現されていることが、一般の方にはわかりにくいということでしょうか(いきなり手品を求められて絶句すること多し)。
仕事の合間に作ったので、割と雑な作りです。書き出し画像のファイル名衝突チェックなどは入れていません。
それでも、スクリプトメニューに入れて利用するとなかなか便利です。
AppleScript名:Keynoteで選択中のスライドだけをデスクトップに画像で書き出す.scptd |
— – Created by: Takaaki Naganoya – Created on: 2019/06/20 — – Copyright © 2019 Piyomaru Software, All Rights Reserved — use AppleScript version "2.7" — 10.13 or later use framework "Foundation" use framework "Quartz" use framework "AppKit" use scripting additions set dtPath to (path to desktop) as string tell application "Keynote" set aVer to version considering numeric strings if aVer < "9.0" then display dialog "Too old version for this Script." buttons {"OK"} default button 1 with icon 1 return end if end considering tell front document set aSel to selection –選択中のスライドオブジェクトへの参照がリストで入る set pList to {} repeat with i in aSel set tmpPage to slide number of i set the end of pList to tmpPage end repeat end tell end tell –Keynote書類を指定フォルダにPDF書き出し(全ページ書き出し) set savedPDFPath to exportKeynoteDocToPDF(dtPath) of me if savedPDFPath = false then return –Error set aPOSIXpath to POSIX path of savedPDFPath –書き出したPDFから、部分的にPNG画像に書き出す repeat with p in pList –PDFの指定ページをNSImageとして取り出す set tmpNSImage to getNSImageFromPDFPage(aPOSIXpath, p) of me –PDFの書き出しファイル名に子番号にスライド番号をつける set bPath to addStringbeforeExtension(aPOSIXpath, "_" & (p as string)) of me –PDF書き出しファイル名に set newPath to repFilePathExtension(bPath, ".png") of me –指定のNSImageを指定のパスにPNG形式で保存 set sRes to saveNSImageAtPathAsPNG(tmpNSImage, newPath) of me end repeat –書き出したPDFを削除 tell application "Finder" delete savedPDFPath end tell –Keynote書類からPDF書き出し on exportKeynoteDocToPDF(targFolderPath as string) tell application "Keynote" set dCount to count every document if dCount = 0 then return false end if set aPath to file of document 1 end tell set curPath to (current application’s NSString’s stringWithString:(POSIX path of aPath))’s lastPathComponent()’s stringByDeletingPathExtension()’s stringByAppendingString:".pdf" set outPath to (targFolderPath & curPath) tell application "Keynote" set anOpt to {class:export options, export style:IndividualSlides, all stages:false, skipped slides:true, PDF image quality:Best} export document 1 to file outPath as PDF with properties anOpt end tell return (outPath as alias) end exportKeynoteDocToPDF –指定のPDFから、指定のページをNSImageで返す on getNSImageFromPDFPage(aPOSIX, aPage as number) set aURL to (current application’s |NSURL|’s fileURLWithPath:aPOSIX) set aPDFdoc to current application’s PDFDocument’s alloc()’s initWithURL:aURL set pCount to aPDFdoc’s pageCount() set compFactor to 1.0 –1.0 — 0.0 = max jpeg compression, 1.0 = none –Detect Retina Environment set retinaF to current application’s NSScreen’s mainScreen()’s backingScaleFactor() if retinaF = 1.0 then set aScale to 2.0 –Non Retina Env else set aScale to 1.0 –Retina Env end if set thisPage to (aPDFdoc’s pageAtIndex:(aPage – 1)) set anNSImage to (current application’s NSImage’s alloc()’s initWithData:(thisPage’s dataRepresentation())) if anNSImage = missing value then error "Error in getting imagerep from PDF" return anNSImage end getNSImageFromPDFPage –ファイル名の拡張子の直前に子番号的な文字列を入れる on addStringbeforeExtension(aPath, extraString) set pathString to current application’s NSString’s stringWithString:aPath set theExtension to pathString’s pathExtension() set thePathNoExt to pathString’s stringByDeletingPathExtension() set newPath to (thePathNoExt’s stringByAppendingString:extraString)’s stringByAppendingPathExtension:theExtension return newPath as string end addStringbeforeExtension –与えられたパスの拡張子を付け替える on repFilePathExtension(origPath, newExt) set aName to current application’s NSString’s stringWithString:origPath set theExtension to aName’s pathExtension() if (theExtension as string) is not equal to "" then set thePathNoExt to aName’s stringByDeletingPathExtension() set newName to (thePathNoExt’s stringByAppendingString:newExt) else set newName to (aName’s stringByAppendingString:newExt) end if return newName as string end repFilePathExtension –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 |