Archive for 2月, 2009

2009/02/28 Font Bookで指定typefaceの詳細な情報を取得する

目下、マイブームが起きているFont Book。AppleScriptから操作すると興味深い情報が山のように出てきます。本Scriptでは、PostScript nameで指定したフォントの詳細な情報を取得します。

フォント名称の取得は、通常のAppleScriptでもそうですが、AppleScript Studioのアプリケーションでフォント指定を行う場合に必要なテクノロジーです。

しかし、ここまで詳細に情報が取得できるというのは、Font Book担当者の「趣味」なのでしょうか。Apple純正アプリのAppleScript系機能が軒並み荒いことを考えると、本アプリのみ丁寧な作りになっているのは……Font Bookはサードパーティから買い取ったか、外注に作らせているアプリケーションなのかもしれません(有名なところでは「Interface Builder」を外注に作らせている、と噂で聞いたことがあります)。

スクリプト名:Font Bookで指定typefaceの詳細な情報を取得する
tell application Font Book
  set ffList to properties of first item of (every typeface whose PostScript name = HiraKakuPro-W3“)
end tell
> {{style name:”W3″, duplicated:false, typeface additional info:{|FBFaceFullName|:”ヒラギノ角ゴ Pro W3″, |FBFaceLocation|:”/Library/Fonts/ヒラギノ角ゴ Pro W3.otf”, |FBFaceManufacturerName|:”大日本スクリーン製造株式会社”, |FBFaceLanguages|:{”アイスランド語”, “アイルランド語”, “アルバニア語”, “イタリア語”, “インドネシア語”, “エストニア語”, “エスペラント語”, “オランダ語”, “オロモ語”, “ガリシア語”, “カタロニア語”, “コーンウォール語”, “スウェーデン語”, “スペイン語”, “スロバキア語”, “スロベニア語”, “スワヒリ語”, “ソマリ語”, “チェコ語”, “デンマーク語”, “ドイツ語”, “ノルウェー語 (ニーノシュク)”, “ノルウェー語 (ブークモール)”, “バスク語”, “ハワイ語”, “ハンガリー語”, “ブルガリア語”, “フィンランド語”, “フェロー語”, “フランス語”, “ポルトガル語”, “ポーランド語”, “マレー語”, “マン島語”, “ロシア語”, “日本語”, “英語”}, |FBFaceIsDuplicate|:false, |FBFaceFamilyName|:”ヒラギノ角ゴ Pro”, |FBFaceKind|:”OpenType PostScript”, |FBFaceCopyProtection|:false, |FBFaceEmbedding|:true, |FBFacePostScriptName|:”HiraKakuPro-W3″, |FBFaceUniqueName|:”大日本スクリーン製造株式会社 ヒラギノ角ゴ Pro W3″, |FBFaceDesignerName|:”有限会社 字游工房”, |FBFaceVersionName|:”7.11″, |FBFaceCopyrightName|:”ver7.11, Copyright © 1993-2002 大日本スクリーン製造株式会社. All Rights Reserved.”, |FBFaceIsEnabled|:true, |FBFaceTrademarkName|:”千都およびヒラギノは大日本スクリーン製造株式会社の登録商標です”, |FBFaceSubFamilyName|:”W3″}, displayed name:”ヒラギノ角ゴ Pro”, files:{file “Cherry:Library:Fonts:ヒラギノ角ゴ Pro W3.otf”}, font family:font family “Hiragino Kaku Gothic Pro” of application “Font Book”, font container:{font container “/Library/Fonts/ヒラギノ角ゴ Pro W3.otf” of application “Font Book”}, enabled:true, font type:”OpenType PostScript”, family name:”Hiragino Kaku Gothic Pro”, copyright:”ver7.11, Copyright © 1993-2002 大日本スクリーン製造株式会社. All Rights Reserved.”, name:”Hiragino Kaku Gothic Pro W3″, class:typeface, PostScript name:”HiraKakuPro-W3″, id:66146}}

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/02/28 diskutilitiesで起動HDDのユーザー権限修復

HDDのメンテナンスを行うMac OS X標準添付ツール「ディスクユーティリティ」はAppleScript対応ではありませんが、コマンドラインから使えるcui版の/usr/sbin/diskutilを呼び出すことで同様の機能をAppleScriptから利用できます。

diskutil.jpg

「ユーザー権限の修復」なんて、AppleScriptにはまったく関係ないのでは? といえばさにあらず。作成したAppleScript(GUIつきのAppleScript Studioアプリ)をユーザーに配布したときに、「ユーザー権限がないのでファイルを書き込めないというエラーに遭遇した」というレポートがあがってきたことがありました。

この問題をつぶさに調査したところ、ユーザーのホームディレクトリ下のtemporary itemsフォルダ(path to temporary items from user domain)に作業ファイルを書き込もうとしたところ、ユーザーがディスクユーティリティでHDDのメンテナンスをまったく行っていなかったために、ユーザー権限が正しく設定されていなかったため、と判明しました。

path to temporary items from system domainで同様の問題に遭遇したことはなかったのですが、Mac OS X 10.5からはデフォルトのtemporary items folderがpath to temporary items from user domainに変更になったため、その流儀に則ってScriptを書いたのですが……それが裏目に出たということでしょうか。

ディスクユーティリティによるHDDのメンテナンスをユーザーに強制できるものでもないので、処理が正確に行われることを期待するのであれば、AppleScript(AppleScript Studioアプリ)の初回起動時なり、インストーラー実行時にインストーラースクリプト中でdiskutilを実行しておくとよいかもしれません。

diskutilコマンドには有用な機能が多いので、man pageの内容をひととおり確認しておくことをおすすめします。

スクリプト名:diskutilitiesで起動HDDのユーザー権限修復
with timeout of 3600 seconds
  do shell script diskutil repairPermissions / with administrator privileges
end timeout

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/02/26 Font Bookですべてのfont collectionの名称を取得する

Font Bookで、フォントコレクションの名称を求めるAppleScriptです。

fontbook1.jpg

スクリプト名:Font Bookですべてのfont collectionの名称を取得する
tell application "Font Book"
  set ffList to name of every font collection
end tell
> {"Classic", "Handwriting", "PDF", "Web", "Web-safe Mac/Windows", "Windows Office Compatible", "エコフォント", "バーコード", "ファン", "モダン", "レタリング風フォント", "韓国語", "古代エジプト文字", "手書き風フォント", "中国語", "等幅", "日本語", "発音記号", "毛筆書体"}

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/02/26 Font Bookで指定フォントのファイルがどこに置かれているかを検知する

Font Bookを用いて、指定フォントが存在するパスを求めるAppleScriptです。

スクリプト名:Font Bookで指定フォントのファイルがどこに置かれているかを検知する
tell application "Font Book"
  set fList to every typeface whose displayed name begins with "ヒラギノ"
  
set tfList to {}
  
repeat with i in fList
    set j to contents of i
    
try
      set the end of tfList to (files of j)
    end try
  end repeat
end tell

tfList

>{{file "Cherry:Library:Fonts:ヒラギノ角ゴ Pro W3.otf"}, {file "Cherry:Library:Fonts:ヒラギノ角ゴ Pro W6.otf"}, {file "Cherry:System:Library:Fonts:ヒラギノ角ゴ ProN W3.otf"}, {file "Cherry:System:Library:Fonts:ヒラギノ角ゴ ProN W6.otf"}, {file "Cherry:Library:Fonts:ヒラギノ角ゴ Std W8.otf"}, {file "Cherry:Library:Fonts:ヒラギノ角ゴ StdN W8.otf"}, {file "Cherry:Library:Fonts:ヒラギノ丸ゴ Pro W4.otf"}, {file "Cherry:Library:Fonts:ヒラギノ丸ゴ ProN W4.otf"}, {file "Cherry:Library:Fonts:ヒラギノ明朝 Pro W3.otf"}, {file "Cherry:Library:Fonts:ヒラギノ明朝 Pro W6.otf"}, {file "Cherry:System:Library:Fonts:ヒラギノ明朝 ProN W3.otf"}, {file "Cherry:System:Library:Fonts:ヒラギノ明朝 ProN W6.otf"}}

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/02/26 Font Bookで指定displayed nameのフォントスタイルを取得する

Font Bookをコントロールして、フォントのdisplayed name(例:ヒラギノ明朝 Pro)を指定して、そのフォントのタイプフェイス(W3とかW6とか)を求めるAppleScriptです。

AppleScript Studioでフォントを指定する場合には、displayed nameではなくnameを指定する必要があるわけですが、普段ユーザーが接しているのはdisplayed nameなので、なかなか調べるのが大変です。

Font Bookを使用すると、こうしたMac OS Xで使われているさまざまなフォント名称を求められるので便利なのですが……Font Bookはアプリケーションなので、フォント名称の確認をおこなうたびにいちいち起動してしまうのはみっともない感じがします。

Font Sync ScriptingにFont Bookのフォント名称取得の機能を持たせたほうがいいような気がします。

スクリプト名:Font Bookで指定displayed nameのフォントスタイルを取得する
tell application "Font Book"
  set ffList to style name of every typeface whose displayed name = "ヒラギノ明朝 Pro"
end tell
> {"W3", "W6"}

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/02/26 リスト中で重複を検出する(大文字小文字を同一視)

「ABC」や「abc」など大文字小文字の記述を同一視して、リスト中の重複を検出するサブルーチンです。

Mac OS Xが標準で使用しているファイルシステム「HFS Plus」では、ファイル名/フォルダ名でアルファベットの大文字/小文字の区別を行いません。

そこで、作成しようとしているファイル名ないしフォルダの名称に対して、大文字/小文字の違いを同一視しつつ名称重複を検出します。大文字小文字が違うペアが存在するという仮定。2つより多い個数の重複があるというケースは考慮していません。

スクリプト名:リスト中で重複を検出する(大文字小文字を同一視)
set aList to {”abc“, ABC“, def“, DEF“, ab1“, AB1“, ccd“, cDc“}
set dupList to detectDuplicates(aList) of me
> {{”abc”, “ABC”}, {”def”, “DEF”}, {”ab1″, “AB1″}}

与えられたリストの中で重複しているものをピックアップ。アルファベットの大文字小文字の違いを無視
on detectDuplicates(aList)
  set newList to {}
  
repeat with i from 1 to (length of aList)
    set tmpList to {}
    
    
あえてアルファベットの大文字小文字の違いを無視(というよりも、同一視)
    
ignoring case
      set anItem to item 1 of aList
      
set aList to rest of aList
      
if {anItem} is in aList then set end of tmpList to anItem
      
repeat with j in aList
        set jj to contents of j
        
if jj = anItem then
          set end of tmpList to jj
          
exit repeat 重複は基本的にABC-abcのように1対のみという前提。フォルダ名の衝突回避が目的なので
        end if
      end repeat
    end ignoring
    
    
if tmpList is not equal to {} then
      set the end of newList to tmpList
    end if
  end repeat
  
return newList
end detectDuplicates

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/02/25 Font Bookでフォントのさまざまな名称を取得する

Mac OS X上では、フォントに3つの名前があります。「ヒラギノ明朝 Pro W3」を例にとると、

 ヒラギノ明朝 Pro W3(表示される名称)–displayed name
 Hiragino Mincho Pro W3(本当の名前)–name
 HiraMinPro-W3(PostScript名称)–postscript name

といった調子です。これをMac OS X標準装備のFont Bookを用いて求めるAppleScriptを書いてみました。

さまざまなアプリケーションの間で、フォント名の指定方法が異なることがありますが……これらの名称を自由に取得できれば、楽に作業ができることでしょう。

fontbook.jpg

スクリプト名:FontBookでフォントのさまざまな名称を取得する
tell application Font Book
  set aFont to displayed name of every typeface whose name contains Hiragino
  
> {”ヒラギノ角ゴ Pro”, “ヒラギノ角ゴ Pro”, “ヒラギノ角ゴ ProN”, “ヒラギノ角ゴ ProN”, “ヒラギノ角ゴ Std”, “ヒラギノ角ゴ StdN”, “ヒラギノ丸ゴ Pro”, “ヒラギノ丸ゴ ProN”, “ヒラギノ明朝 Pro”, “ヒラギノ明朝 Pro”, “ヒラギノ明朝 ProN”, “ヒラギノ明朝 ProN”}
  
  
set bFont to name of every typeface whose name contains Hiragino
  
> {”Hiragino Kaku Gothic Pro W3″, “Hiragino Kaku Gothic Pro W6″, “Hiragino Kaku Gothic ProN W3″, “Hiragino Kaku Gothic ProN W6″, “Hiragino Kaku Gothic Std W8″, “Hiragino Kaku Gothic StdN W8″, “Hiragino Maru Gothic Pro W4″, “Hiragino Maru Gothic ProN W4″, “Hiragino Mincho Pro W3″, “Hiragino Mincho Pro W6″, “Hiragino Mincho ProN W3″, “Hiragino Mincho ProN W6″}
  
  
set cFont to PostScript name of every typeface whose name contains Hiragino
  
> {”HiraKakuPro-W3″, “HiraKakuPro-W6″, “HiraKakuProN-W3″, “HiraKakuProN-W6″, “HiraKakuStd-W8″, “HiraKakuStdN-W8″, “HiraMaruPro-W4″, “HiraMaruProN-W4″, “HiraMinPro-W3″, “HiraMinPro-W6″, “HiraMinProN-W3″, “HiraMinProN-W6″}
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/02/22 GUI Scriptingによる記述(4)

GUI Scriptingの要となるツールはPreFab UI Growserですが、PreFab UI Browserで、カバーできない分はどうするのか? ポップアップボタンの上に出たメニューの内容はどうやって要素名を追いかけるのか?

inspector.jpg

……実は、その場合にはApple純正のツールを用いることになります。通常の用途にはあまり役立たないものの、Appleの「Accessibility Inspector」によってポップアップメニューなどの要素を追いかけることが可能です。同ツールは、AppleのXcode toolsをインストールすると一緒に入ってきます。

ただし、オブジェクトの名称はAppleScript的な名称ではないので、AppleScriptの記述のためには使いづらいシロモノです。

2009/02/21 Shade 10でsceneをDXF形式で書き出す

Shade 10でドキュメント(scene)をDXF形式で指定パスに書き出すAppleScriptです。

scene 1に対してのtellブロック内で「save DXF」を実行しても、「save DXF scene 1 in aPOSIXpath」を実行しても正常に実行されます。

確認のため、書き出したDXFファイルを現在オープン中のドキュメント内にインポートしてみましたが、tellブロック内で実行したものでも、1行にまとめて記述・実行したものでも同様の結果が得られました。

スクリプト名:Shade 10でsceneをDXF形式で書き出す
set fileName to choose file name
set aPOSIXpath to POSIX path of fileName

tell application "Shade 10"
  tell scene 1
    save DXF in aPOSIXpath
  end tell
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/02/21 Shade 10で円(disk)を作成する

Shade 10でscene上に座標{0, 0, 0}から同心円状に円(disk)を描画します。

Shadeのオンライン・フォーラムで加藤俊明さんが書かれていたものを……そのまま掲載するのは芸がないので、ちょっと応用してループで同心円を描かせてみた次第です。

shade_disk.jpg

スクリプト名:Shade 10で円(disk)を作成する
tell application "Shade 10"
  tell scene 1
    repeat with i from 100 to 1000 by 100
      create disk at {0, 0, 0} r i axis 1
    end repeat
  end tell
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/02/21 Shade 10で新規ドキュメントを作成

Shade 10で新規ドキュメントを作成するAppleScriptです。

一般的に、アプリケーションで新規ドキュメントを作成する場合には、「create new document」とか「make new document」といった記述になりますが……Shadeではこれが「new scene」という固有の命令で行うことになります。

一般的なAppleScriptのノウハウでShadeを攻略しようとしても、定石がまったく役立たずに歯が立たない感じですし、ShadeでAppleScriptによるコントロールをマスターした人がいたとしても、Shadeのなまりが強すぎて他のアプリケーションを操作することは困難でしょう。

「Shade弁」とでもいうべき強烈な方言は勘弁していただきたいものです。

スクリプト名:Shade 10で新規ドキュメントを作成
tell application "Shade 10"
  new scene
end tell
> 「名称未設定」ドキュメントが作成される

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/02/21 Shade 10でドキュメントを保存する

Shade 10でオープン中のshdファイルを指定したパスに保存するAppleScriptです。

ただし、ShadeではPOSIX pathでパスを指定する必要があるうえに、空白文字列を含むパスであることに備えて、AppleScriptで常識的に用いられる「quoted form of」の指定を行うと逆に異常動作を行ってしまいます。

miss_shade.jpg

なんと、HDDのrootディレクトリ上にフルパスの文字列をquote文字列を含んだまま保存してしまうという異常動作であり、Shadeの開発者がquoted form ofが使用されることを知らずにコーディングしていることが伺われます。

同様の異常動作はAdobeのAcrobat Distillerでも見ることができ、このようなアプリケーションの存在については注意を払う必要があります。バグといってよいでしょう。

そのうえ、scene 1に対してsave命令を実行してもファイルへの保存は行われません。「save scene」という1語を、アプリケーションに対して直接実行する必要があります。

スクリプト名:Shade 10でドキュメントを保存する
set aFile to choose file name
set aPosixFile to POSIX path of aFile
set aPosixFile to quoted form of POSIX path of aFile –quoted formを付けるとrootフォルダ上にフルパスを名称としたファイルを作ってしまう

tell application Shade 10
  save scene aPosixFile
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/02/21 pdfinfoの結果をparseするv2

フリーのxpdf-toolsに含まれるpdfinfoを呼び出して、その結果をレコードにparseするAppleScriptです。

レコードの属性ラベルにパーティカルバー(「|」)を付けているのは、AppleScript Studioアプリ内でTableViewに突っ込むことを目的として作成したからです。

これまでに作成したサブルーチンを組み合わせた程度のものですが、たいへん便利に使っています。

→ 問題点が見つかったので、新バージョン(v3)を使用してください。

スクリプト名:pdfinfoの結果をparseするv2
set aRes to Title: iPhone Coding HowTo-J
Author: Takahiro Kaneko
Creator: Pages
Producer: Mac OS X 10.5.3 Quartz PDFContext
CreationDate: Thu Jun 26 04:09:03 2008
ModDate: Thu Jun 26 04:09:03 2008
Tagged: no
Pages: 31
Encrypted: no
Page size: 595 x 842 pts (A4)
File size: 988819 bytes
Optimized: no
PDF version: 1.3

set bRes to parseInfopdfData(aRes) of me

on parseInfopdfData(aRes)
  set aList to paragraphs of aRes
  
set aRec to {|aTitle|:”", |aSubject|:”", |anAuthor|:”", |aCreator|:”", |aProducer|:”", |aCreationDate|:”", |aModDate|:”", |aTagged|:”", |aPages|:”", |anEncrypted|:”", |aPageSize|:”", |aFilesize|:”", |anOptimized|:”", |aPDFver|:”"}
  
repeat with i in aList
    set j to contents of i
    
先にデータのみにしておいて…
    
set bRes to fetchDataAfterColon(j) of me
    
レコードの中身を指定する
    
if j begins with Title: then
      set |aTitle| of aRec to bRes
    else if j begins with Subject: then
      set |aSubject| of aRec to bRes
    else if j begins with Author: then
      set |anAuthor| of aRec to bRes
    else if j begins with Creator: then
      set |aCreator| of aRec to bRes
    else if j begins with Producer: then
      set |aProducer| of aRec to bRes
    else if j begins with CreationDate: then
      set |aCreationDate| of aRec to bRes
    else if j begins with ModDate: then
      set |aModDate| of aRec to bRes
    else if j begins with Tagged: then
      set |aTagged| of aRec to bRes
    else if j begins with Pages: then
      set |aPages| of aRec to bRes
    else if j begins with Encrypted: then
      set |anEncrypted| of aRec to bRes
    else if j begins with Page size: then
      set |aPageSize| of aRec to changePTStoMM(bRes) of me
    else if j begins with File size: then
      set |aFilesize| of aRec to bRes
    else if j begins with Optimized: then
      set |anOptimized| of aRec to bRes
    else if j begins with PDF version: then
      set |aPDFver| of aRec to bRes
    end if
  end repeat
  
return aRec
end parseInfopdfData

コロンの次の文字からスペースではない文字をスキップして残りの文字を返す
on fetchDataAfterColon(aData)
  set cList to characters of aData
  
set sPos to offset of : in aData
  
set sPos to sPos + 1
  
repeat with i from sPos to (length of cList)
    if contents of item i of cList is not equal to then
      set aRes to (items i thru -1 of cList) as string
      
return aRes
    end if
  end repeat
  
return “”
end fetchDataAfterColon

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

ポイント数値のテキストをmmに書き換える
on changePTStoMM(aText)
  set wList to words of aText
  
  
set attrList to {}
  
repeat with i in wList
    set the end of attrList to numChk(i) of me
  end repeat
  
  
set aCount to count wList
  
  
set aReText to {}
  
repeat with i from 1 to (aCount - 1)
    set anItem to item i of wList
    
set anAttr to item i of attrList
    
if anAttr = true then
      set the end of aReText to (point2mm(anItem as number) of me) as string
    else
      set the end of aReText to anItem
    end if
  end repeat
  
set the end of aReText to “mm”
  
set last item of aReText to mm
  
  
set aText to makeStrFromListWithDelim(” “, aReText) of me
  
return aText
  
end changePTStoMM

リストを任意のデリミタ付きでテキストに
on makeStrFromListWithDelim(aDelim, aList)
  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 makeStrFromListWithDelim

ポイントからmmへの変換
on point2mm(a)
  return (a * 0.353) 1ポイント=0.353mm
end point2mm

数値かどうか調べる
on numChk(aNum)
  set aClass to (class of aNum) as string
  
if aClass = number or aClass = double or aClass = integer or aClass = real then
    return true
  else if aClass = string or aClass = text or aClass = unicode text then
    try
      set bNum to aNum as number
      
return true
    on error
      return false
    end try
  end if
end numChk

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/02/21 GUI Scriptingによる記述(3)

GUI Scriptingにおいて覚えておくべき重要な事項があります。それは、繰り返しになりますが……Adobeのアプリケーションの多くに、GUI Scriptingは利かないケースが多いということです。

InDesign、Photoshop、Illustrator……それらにGUI Scriptingは(ほとんど)利きません。ダイアログ上のボタンを押そうとしてもクリックできず、ダイアログ上のポップアップボタンのメニューを操作しようとしても、メニューそのものを表示させることはできません。

これは、Adobeアプリケーションの多くが、(おそらく)マルチプラットフォーム対応のためにGUI部品をプログラム側から動的に生成していることと、ポップアップメニューなどをポップアップボタンのエリア内にマウスカーソルが入ってきたときに動的に生成しているからです。

Adobeのアプリケーションにはやたらとバグが多いとか、機能を検証もせずに出荷しているとか、バグを訴えても誰もコードの内容の全貌を把握していないために直せないとか、そうした傾向はあるものの、構造的にGUI Scriptingに向いていないといった側面があるということです。

2009/02/21 GUI Scriptingによる記述(2)

GUI Scriptingを覚えたてのScripterにありがちなのは、なんでもかんでもすべてGUI Scriptingで記述しようとすることです。

GUI Scriptingは、AppleScriptによるプログラミングとしては(他に選択手段がない場合の)「最終手段」であり、GUI Scriptingは本当に必要な箇所にのみ使用する程度にとどめておくべきです。

なぜなら、GUI Scriptingはスピードが遅く、信頼性に欠けるためです。たとえば、あるボタンをクリックさせようとしたとしても、アプリケーションの状態によっては、そのボタンが表示されていなかったり、イネーブルになっていない可能性もあります。

GUI Scriptingによる記述について、スピードを向上させることはできませんが……確実性を向上させるための処理は重要です。確実性を向上させてはじめて、「最終手段」としての信頼性を確保できることになります。

たとえば、あるボタンをクリックさせるためには、ボタンの存在を確認し、そのボタンがイネーブルであるかを確認し、クリックした後にエラーのダイアログが表示されていないかを確認する……といった確認操作が必要になります。そこまで処理する慎重さが重要です。

実際には、そこまでしつこくGUI部品の状態をスキャンするよりも、失敗したときに備えてtry文でエラートラップを仕掛けておけば足りる場合が多いので、その程度でも大丈夫でしょう。

2009/02/18 Shade 10でレンダリングを行う

Shade 10で現在レンダリング中かどうかを調べ、レンダリング中でなければレンダリングを行います。

スクリプト名:Shade 10でレンダリングを行う
tell application "Shade 10"
  activate
  
set curRender to still rendering
  
if curRender = false then
    start rendering
  end if
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/02/18 Shade 10のプロパティを取得(クラッシュする可能性高し)

Shade 10 basicを購入したのでAppleScriptでコントロールしてみようと試みたのですが……ちょっとプロパティを調べてみようとしただけで、必ずクラッシュします。再現性はほぼ100%。

Shadeの用語辞書の内容を調べてみると、一般的なアプリケーションとはかけ離れた内容であり、とても手に負えない印象を受けます。自分がやりたい処理を記述できるかどうか、なかなか見えてきません。

どうも、この辞書内容からするとShadeはRecordingに対応しているようで……そのようなアプリケーションでは、素直なスクリプティングが行えないので、最近ではあまりRecordingは推奨されていません。

shade1.jpg

スクリプト名:Shade 10のプロパティを取得(クラッシュする可能性高し)
tell application Shade 10
  properties
end tell
> “Shade 10 でエラーが起きました:接続が無効です。”
100%クラッシュする

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/02/16 GUI Scriptingによる記述(1)

GUI Scripting(UI Element Scripting)によるAppleScriptをどう書くのか、という話題がUsers Groupのミーティングで出ました。

通常のAppleScriptによるScriptingでは、アプリケーションがAppleScriptに対して解放している機能の呼び出しやオブジェクトへのアクセスを行うことになります。いわば、内部からコントロールする方法です。

一方のGUI Scriptingは、メニューのどのアイテムをクリックするとか、ウィンドウの指定のボタンのタイトルを取得するとかいったように、アプリケーションを外側からコントロールする方法であり、AppleScriptに対応していない機能や、AppleScriptに対応していないアプリケーションをもコントロール可能にする技術です(ただし、プログラムで動的にGUI部品を生成しているようなものは、コントロールできないケースもあります。Adobeのアプリケーションがそれに該当します)。

多くのScripterがGUI Scriptingを「素手で書く」ものとして認識しているようなのですが、それははっきり言って大きな誤りです。GUI Scriptingは、PreFab UI Browserを使って書くものです。PreFab UI Browserを使っても、カバーできるのは90%ぐらいのGUI部品であり、そこからさらに工夫が必要になってしまうわけで……Prefab UI Browserを使わなかったら、この残り10%を攻略するレベルにはとうてい到達できないわけです。

prefab1.jpg

たった55ドルのこのアプリケーションが、どれだけ生産性の向上に寄与してくれるかということを考えれば、それは決して無駄な投資にはならないことでしょう。まして、PreFab UI Browserの作者であるBill Cheesemanはけっこうな高齢プログラマーであり……確実に入手しておくことは重要ではないかと考えるものです(まあ、会社の誰かに引き継がれるとは思いますが)。

2009/02/14 Keynote上でコピーされたテキストオブジェクトの内容をTextEditで解析してIllustratorで白フチ文字を作成してKeynoteにペースト v2

Keynote上で選択・コピーしておいたテキストアイテムを、白フチ文字化してKeynoteに貼り込むAppleScriptです。バージョンアップして、オリジナルのテキストアイテムのフォント種別が反映されるようになりました。

Keynoteでプレゼン資料を作っていて、どうしても白フチ文字を作りたいという場合に備えて作っておいたものです。やはり、フォント書式がそのまま反映されると仕上がりの見栄えが段違いです。スクリプトメニューに入れて使うとよいでしょう。

fuvhi1.jpg
▲Keynote上でテキストオブジェクトを選択しておいて本スクリプトを実行

fuchi2.jpg
▲Keynoteに白フチ化した文字(PDF)がペーストされる

fuchi3.jpg
▲さまざまなフォントの文字オブジェクトを白フチ化。疑似的な縦書きにも対応

スクリプト名:Keynote上でコピーされたテキストオブジェクトの内容をTextEditで解析してIllustratorで白フチ文字を作成してKeynoteにペーストv2

何もコピーされていなければリターン
set a to the clipboard
if a = “” then return

Text Editで新規ドキュメントを作成してコピーされていたデータをコピー
tell application TextEdit
  set aDoc to make new document
  
activate
end tell

tell application System Events
  tell process TextEdit
    keystroke v using {command down}
  end tell
end tell

TextEditの書類上から各種情報を取得する
tell application TextEdit
  tell text of aDoc
    set colorList to color of every attribute run
    
set fontList to font of every attribute run
    
set sizeList to size of every attribute run
    
set textList to characters of every attribute run
    
    
set itemCount to length of colorList
    
    
set contList to {}
    
repeat with i from 1 to itemCount
      set aRec to {textData:(item i of textList) as string, colorData:item i of colorList, fontData:item i of fontList, sizeData:item i of sizeList}
      
set the end of contList to aRec
    end repeat
  end tell
end tell

tell application TextEdit
  tell document 1
    close without saving
  end tell
end tell

set textList to contents of item 1 of textList

set aDirection to detectTextDirection(textList) of me
> “vertical” / “horizontal”

set aFontName to contents of item 1 of fontList
set aSize to contents of item 1 of sizeList
set aLineWidth to aSize / 8
set aLineWidth to round aLineWidth rounding up

set aCon to textList as string
set aCon to repChar(aCon, ASCII character 10, “”) of me
set aColor to item 1 of colorList
set rColor to (item 1 of aColor) / 256
set rColor to round rColor rounding down
set gColor to (item 2 of aColor) / 256
set gColor to round gColor rounding down
set bColor to (item 3 of aColor) / 256
set bColor to round bColor rounding down
set colorList to {rColor, gColor, bColor}

makeTextGraphicWithEdgeLine(aCon, aSize, aLineWidth, aDirection, aFontName, colorList) of me

tell application Keynote
  activate
end tell

tell application System Events
  tell process Keynote
    keystroke v using {command down}
  end tell
end tell

以下、サブルーチン

Attribute runsのテキストデータの並びから、Keynote上で縦書き/横書きだったかの判定を行う
on detectTextDirection(aList)
  set normCount to 0
  
set retCount to 0
  
repeat with i in aList
    set jj to contents of (item 1 of i)
    
set j to id of (contents of jj)
    
if (j = 10) or (j = 13) then
      set retCount to retCount + 1
    else
      set normCount to normCount + 1
    end if
  end repeat
  
  
set vhCalc to (retCount / normCount)
  
  
if vhCalc > 0.5 then
    return vertical
  else
    return horizontal
  end if
  
end detectTextDirection

on makeTextGraphicWithEdgeLine(aCon, aSize, aLineWidth, aDirection, aFontName, colorList)
  copy colorList to {rColor, gColor, bColor}
  
  
using terms from application Adobe Illustrator
    tell application Adobe Illustrator
      set textFont to text font aFontName
      
set aDoc to make new document with properties {color space:RGB}
      
      
tell aDoc
        setOriginToLeftCorner() of me
        
        
set aGroup to make new group item
        
        
set aFrame1 to make new text frame at the end of aGroup
        
tell aFrame1
          set position to {0, 0}
          
set contents to aCon
          
if aDirection = vertical then
            set text orientation to vertical
          else if aDirection = horizontal then
            set text orientation to horizontal
          end if
          
tell every character
            set size to aSize
            
set stroke weight to aLineWidth ふちどり線の太さ
            
set stroke color to {red:255, green:255, blue:255}
          end tell
          
set it’s text’s text font to textFont 不思議な指定方法だが、これ以外通らない
        end tell
        
        
set aFrame2 to make new text frame at the beginning of aGroup
        
tell aFrame2
          set contents to aCon
          
set position to {0, 0}
          
if aDirection = vertical then
            set text orientation to vertical
          else if aDirection = horizontal then
            set text orientation to horizontal
          end if
          
tell every character
            set size to aSize
            
set stroke weight to 0.0
            
set fill color to {red:rColor, green:gColor, blue:bColor}
          end tell
          
set it’s text’s text font to textFont 不思議な指定方法だが、これ以外通らない
        end tell
        
        
        
set selection to aGroup
        
copy ふちどり文字をクリップボードにコピー
        
        
close saving no Illustratorの書類を破棄する
      end tell
    end tell
  end using terms from
end makeTextGraphicWithEdgeLine

Illustratorの原点座標を変更する
on setOriginToLeftCorner()
  using terms from application Adobe Illustrator
    tell application Adobe Illustrator
      tell document 1
        set aHeight to height
        
set ruler origin to {0, aHeight}
      end tell
    end tell
  end using terms from
end setOriginToLeftCorner

Written By Philip Aker
文字置換ルーチン
on repChar(origText, targStr, repStr)
  set {txdl, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, targStr}
  
set temp to text items of origText
  
set AppleScript’s text item delimiters to repStr
  
set res to temp as text
  
set AppleScript’s text item delimiters to txdl
  
return res
end repChar

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/02/11 Keynote上でコピーされたテキストオブジェクトの内容をTextEditで解析してIllustratorで白フチ文字を作成してKeynoteにペースト

iWork ‘09のKeynote 5.x上で文字オブジェクトをコピーし、実行すると白フチ文字に変換してKeynote上にペーストする(趣味の)AppleScriptです。

まずは、Keynote上で文字オブジェクトをコピーして本Scriptを実行。

keynote1.jpg

クリップボードに入っているデータ(Ritch Text Format)をテキストエディットの新規書類にペースト。テキストエディット上で書式などを分析します。分析したら、用済みのテキストエディット書類は破棄。

テキストエディット上で得られた情報をもとに、今度はIllustrator CS3上で同様にオブジェクトを組み立て、白フチ文字を作成。白フチ文字のオブジェクトをコピーして、Illustrator書類を破棄します。

最後に、Keynoteを最前面に持ってきてSystem Eventsで(GUI Scriptingで)ペースト操作を実行。

keynote2.jpg

keynote3.jpg

以前に作成しておいたルーチンに一部手を加えて、縦方向の文字(1文字ごとに改行)でも、横方向の文字(通常)でも対応します。ただし、本バージョンではオリジナルのフォント情報までは白フチ文字に反映していません。

keynote4.jpg

スクリプト名:Keynote上でコピーされたテキストオブジェクトの内容をTextEditで解析してIllustratorで白フチ文字を作成してKeynoteにペースト

何もコピーされていなければリターン
set a to the clipboard
if a = “” then return

Text Editで新規ドキュメントを作成してコピーされていたデータをコピー
tell application TextEdit
  set aDoc to make new document
  
activate
end tell

tell application System Events
  tell process TextEdit
    keystroke v using {command down}
  end tell
end tell

TextEditの書類上から各種情報を取得する
tell application TextEdit
  tell text of aDoc
    set colorList to color of every attribute run
    
set fontList to font of every attribute run
    
set sizeList to size of every attribute run
    
set textList to characters of every attribute run
    
    
set itemCount to length of colorList
    
    
set contList to {}
    
repeat with i from 1 to itemCount
      set aRec to {textData:(item i of textList) as string, colorData:item i of colorList, fontData:item i of fontList, sizeData:item i of sizeList}
      
set the end of contList to aRec
    end repeat
  end tell
end tell

tell application TextEdit
  tell document 1
    close without saving
  end tell
end tell

set aDirection to detectTextDirection(textList) of me
> “vertical” / “horizontal”

set aFontName to contents of item 1 of fontList
set aSize to contents of item 1 of sizeList
set aLineWidth to aSize / 8
set aLineWidth to round aLineWidth rounding up

set aCon to textList as string
set aCon to repChar(aCon, ASCII character 10, “”) of me
set aColor to item 1 of colorList
set rColor to (item 1 of aColor) / 256
set rColor to round rColor rounding down
set gColor to (item 2 of aColor) / 256
set gColor to round gColor rounding down
set bColor to (item 3 of aColor) / 256
set bColor to round bColor rounding down
set colorList to {rColor, gColor, bColor}

makeTextGraphicWithEdgeLine(aCon, aSize, aLineWidth, aDirection, aFontName, colorList) of me

tell application Keynote
  activate
end tell

tell application System Events
  tell process Keynote
    keystroke v using {command down}
  end tell
end tell

以下、サブルーチン

Attribute runsのテキストデータの並びから、Keynote上で縦書き/横書きだったかの判定を行う
on detectTextDirection(aList)
  set normCount to 0
  
set retCount to 0
  
log aList
  
repeat with i in aList
    set jj to contents of (item 1 of i)
    
set j to id of (contents of jj)
    
display dialog (string id of j)
    
if (j = 10) or (j = 13) then
      set retCount to retCount + 1
    else
      set normCount to normCount + 1
    end if
  end repeat
  
  
set vhCalc to (retCount / normCount)
  
  
if vhCalc > 0.5 then
    return vertical
  else
    return horizontal
  end if
  
end detectTextDirection

on makeTextGraphicWithEdgeLine(aCon, aSize, aLineWidth, aDirection, aFontName, colorList)
  copy colorList to {rColor, gColor, bColor}
  
  
using terms from application Adobe Illustrator
    tell application Adobe Illustrator
      set aDoc to make new document with properties {color space:RGB}
      
      
tell aDoc
        setOriginToLeftCorner() of me
        
        
set aGroup to make new group item
        
        
set aFrame1 to make new text frame at the end of aGroup
        
tell aFrame1
          set position to {0, 0}
          
set contents to aCon
          
if aDirection = vertical then
            set text orientation to vertical
          else if aDirection = horizontal then
            set text orientation to horizontal
          end if
          
tell every character
            set size to aSize
            
set font to aFontName
            
set stroke weight to aLineWidth ふちどり線の太さ
            
set stroke color to {red:255, green:255, blue:255}
          end tell
        end tell
        
        
set aFrame2 to make new text frame at the beginning of aGroup
        
tell aFrame2
          set contents to aCon
          
set position to {0, 0}
          
if aDirection = vertical then
            set text orientation to vertical
          else if aDirection = horizontal then
            set text orientation to horizontal
          end if
          
tell every character
            set size to aSize
            
set font to aFontName
            
set stroke weight to 0.0
            
set fill color to {red:rColor, green:gColor, blue:bColor}
          end tell
        end tell
        
        
        
set selection to aGroup
        
copy ふちどり文字をクリップボードにコピー
        
        
close saving no Illustratorの書類を破棄する
      end tell
    end tell
  end using terms from
end makeTextGraphicWithEdgeLine

Illustratorの原点座標を変更する
on setOriginToLeftCorner()
  using terms from application Adobe Illustrator
    tell application Adobe Illustrator
      tell document 1
        set aHeight to height
        
set ruler origin to {0, aHeight}
      end tell
    end tell
  end using terms from
end setOriginToLeftCorner

Written By Philip Aker
文字置換ルーチン
on repChar(origText, targStr, repStr)
  set {txdl, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, targStr}
  
set temp to text items of origText
  
set AppleScript’s text item delimiters to repStr
  
set res to temp as text
  
set AppleScript’s text item delimiters to txdl
  
return res
end repChar

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/02/11 Excel 2008でX軸方向に右端から、データが存在しているセルをサーチ

マイクロソフトが配布しているOffice 2008のスクリプティングに関するドキュメントを参考に、Excelワークシート上にグラフを書かせてみたところ……たしかに、できることはできるのですが、サンプルスクリプトの「なまり」が強すぎて、いまひとつサンプルスクリプトとしては難解すぎるように感じられました。

ここに示したScriptはマイクロソフトのサンプルでは1行で記述されていたものですが、ここまで分解しないとサンプルとしては有用とは言いがたいことでしょう。内容自体は数多くのノウハウを含んでおり、それぞれについて理解すれば役立つものですが……

多数のアプリケーションを制御しつつ、機能を組み合わせ、高度な処理を実現する中で得られた「AppleScriptの定石」ともいえるものがあります。さまざまなリスクを回避するために、「1行にあまり命令を詰め込みすぎない」というのがAppleScriptの定石です。

excel1.jpg

本スクリプトでは、「データがワークシート内のどの範囲に入っているのか」をX軸方向にサーチする処理を行います。まずは、ワークシートの右端(X軸の終端)から、原点方向に(左向きに)サーチを行うというものです。

ワークシート上に入力されたデータを取得するために、処理前にデータ入力範囲を選択しておく……といった処理はお手軽なのでよく使う手ですが、それよりもデータ入力範囲をサーチするほうが有用でしょう。

スクリプト名:Excel 2008でX軸方向に右端から、データが存在しているセルをサーチ
tell application "Microsoft Excel"
  tell active sheet
    ワークシートの横幅を取得
    
set aC to (count columns)
    
一番右のセルを取得
    
set bC to (cell aC of row 1)
    
ワークシート右端から、左方向へデータが存在するセルをサーチする
    
set aD to get end bC direction toward the left
  end tell
end tell

> range "[ブック1]Sheet1!$E$1" of application "Microsoft Excel"

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/02/08 Preview.appで最低限のScript命令実行機能をイネーブルに

たまたま、Mac OS X Hintsに掲載されているのを見つけ、半信半疑で実行してみたら……open、print、quit、closeなどの基礎的な命令をPreview.appが受け付けるようになりました。

なんでも、AppleのAppleScript製品担当のSal Soghoianがコメント欄にそのような投稿をしたのだとか(汗) そもそも、なぜそのようなゲリラ的なことをやるのか? Mac OS Xの製品版のPreview.appにちゃんとしたScript対応機能を持たせればそれでよいのではないか?

疑問は尽きないのですが、とりあえずSal Soghoianが書いた内容であれば、とくに転載しても問題はないでしょう。

# 注意:本Scriptを実行する前にPreview.appのファイルを必ずバックアップしておいてください

処理内容自体は、Info.plistにエントリを追加しているだけなので、Xcode Toolsに入っている「Property List Editor」を使ったほうが安全と思われます。

スクリプト名:Preview.appに最低限のScript命令実行機能をイネーブルに
try
  tell application Finder
    set the Preview_app to (application file id com.apple.Preview“) as alias
  end tell
  
set the plist_filepath to the quoted form of ((POSIX path of the Preview_app) & Contents/Info“)
  
do shell script defaults write & the plist_filepath & space & NSAppleScriptEnabled -bool YES
end try

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/02/07 Numbersで選択範囲の情報を取得する

Numbersで、選択範囲がどの範囲なのかという情報を取得します。

まっとうな方法ではなく「name」だというのが腑に落ちないのですが、いろいろ試してみたところ、「選択範囲がどこからどこまでなのか」を取得する方法はこれしかなさそうです。

スクリプト名:Numbersで選択範囲の情報を取得する
tell application Numbers
  tell document 1
    tell sheet 1
      tell table 1
        set mySelectedRanges to name of selection range
      end tell
    end tell
  end tell
end tell
> “B2:C3″

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/02/07 Numbersで指定範囲を選択

Numbersで、指定の範囲(range)を選択します。

スクリプト名:Numbersで指定範囲を選択
tell application "Numbers"
  tell document 1
    tell sheet 1
      tell table 1
        set selection range to range "B4:C15"
      end tell
    end tell
  end tell
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/02/07 Nunbersで選択範囲の値を取得

Numbersで、選択範囲の値(value)を取得します。

numbers1.jpg

スクリプト名:Nunbersで選択範囲の値を取得
tell application Numbers
  tell document 1
    tell sheet 1
      tell table 1
        set mySelectedRanges to value of every cell of selection range
      end tell
    end tell
  end tell
end tell
> {1.0, 2.0, 3.0, 4.0}

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/02/07 Numbersで選択範囲を取得

Numbersで選択範囲を取得するサンプルです。

結果は、

<<class>> “B2:C3″ of table “表 1″ of sheet “シート 1″ of document “名称未設定” of application “Numbers”

のように返ってきます。この「<<class>>」という返り値では、その後で処理できない(エラーになる)ので、バグでしょう。

スクリプト名:Numbersで選択範囲を取得
tell application Numbers
  tell document 1
    tell sheet 1
      tell table 1
        set mySelectedRanges to selection range
      end tell
    end tell
  end tell
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/02/05 Skimでコメントつき注釈(note)の情報を取得する

Skimで、GUI側からコメント(extended text)つきの注釈(note)を作成し、その情報を取得してみました。

skim8.jpg

スクリプト名:Skimでコメントつき注釈(note)の情報を取得する
tell application Skim
  tell document 1
    tell note 1
      properties
    end tell
  end tell
end tell

> {type:anchored note, extended text:”なんてこったい!”, icon:comment icon, page:page 1 of document “InDesign CS3 スクリプティング ガイド AS.pdf” of application “Skim”, class:note, bounds:{453, 740, 469, 724}, text:”ほげほげーー”, color:{64639, 65535, 26043, 65535}}

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/02/05 Skimで注釈(note)を削除する

Skimで現在オープン中のPDF(document 1)の、指定ページ内の注釈(note)を削除します。

スクリプト名:Skimで注釈(note)を削除する
tell application Skim
  tell document 1
    tell page 1
      delete every note
    end tell
  end tell
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/02/05 Skimで注釈(note)を新規作成する

Skimで、現在オープン中のPDF(document 1)に対して、注釈(note)を作成します。意外とあっさりできてしまい、拍子抜けするほどです。

skim7.jpg

スクリプト名:Skimで注釈(note)を新規作成する
tell application Skim
  tell document 1
    tell page 1
      make new note with properties {type:text note, dash pattern:{}, font color:{0, 0, 0, 65535}, font size:36, bounds:{277, 573, 480, 532}, line style:solid line, font name:”LucidaGrande“, class:note, line width:1.0, text:”注釈だよー2“, color:{0, 65535, 26043, 65535}}
    end tell
  end tell
end tell
> note 1 of page 1 of document “InDesign CS3 スクリプティング ガイド AS.pdf” of application “Skim”

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/02/05 Skimで注釈(note)の情報を取得する

Skimで、PDF上にユーザーが作成した注釈(note)の情報を取得します。

skim6.jpg

スクリプト名:Skimで注釈(note)の情報を取得する
tell application Skim
  tell document 1
    tell note 1
      properties
    end tell
  end tell
end tell

> {type:text note, dash pattern:{}, font color:{0, 0, 0, 65535}, font size:36, bounds:{277, 573, 480, 532}, line style:solid line, page:page 11 of document “InDesign CS3 スクリプティング ガイド AS.pdf” of application “Skim”, font name:”LucidaGrande”, class:note, line width:1.0, text:”注釈だよー”, color:{64639, 65535, 26043, 65535}}

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に