Archive for 7月, 2011

2011/07/31 OS X 10.7のAppleScriptリリースノート

macosxautomation.comに、OS X LionのAppleScriptのリリースノートが掲載されていました。

そもそも、macosxautomation.comはwhoisデータベースで調べてみるとSal Soghoian(AppleのAppleScript製品担当)個人でドメイン申請したサイトであり、ページ上に「このWebサイトはApple.Incによってホスティングされていません」と明記されている不思議な場所です。

Apple.com上だと(ガイドラインが厳しいとか、余裕をもったスケジュールでWebチームに渡しておかないといけないとかで)更新が不自由なため別天地を求めたのか……他のチームと折り合いが合わないのか……それともSal Soghoianの隠居に向けた何かの体制作りなのか……はたまた、Sal Soghoianとそのお友達一派の独自の動きなのかは定かではありませんが、AppleScriptのリリースノートがこのような場所に公開されているのか、いまひとつ理解できません。

それはともかく、私的な場所でありながら公的な情報が掲載されている不思議なmacosxautomation.comの、10.7, LionのAppleScript関連のリリースノートを精査してみました。

リリースノートによると、10.7におけるAppleScriptの主な変更点/機能強化点はAppleScriptObjCに関するもの、とのこと。

■Cocoa-AppleScriptアプレット

Mac OS X 10.6ではXcode上でしか記述できなかったAppleScriptObjC(Scripting Bridgeを利用できるAppleScript環境。Cocoaを直接扱える)が、OS X 10.7からはAppleScriptエディタ上からも利用できるようになりました。

ase1.jpg

10.7のAppleScriptエディタ上で、メニューから「ファイル」>「テンプレートから新規作成」>「Cocoa-AppleScript Applet」を実行すると、Cocoa-AppleScriptアプレットのひな形をオープンし、ファイル名を指定していったん保存すると編集できるようになります。

ase2.jpg

初期状態では、バンドル形式のアプレット側でload scriptして実行されるScriptを編集する状態になっており、最初に表示されるScript(main.scpt)にはほとんどコメントしか入っていません。

ただ、バンドル内に入っていて実際にmain.scptを呼び出す側のAppleScriptには、けっこうな記述量のASOCのプログラムが書かれています。ASOCでは、たかだかon idleとかドロップレットを実現するのにかなりの記述を行わなくてはならないので、ASOCテンプレートの種類をもっと増やしてほしい気がするところですが、テンプレート自体はフォルダ(~/Library/Application Support/Script Editor/Templates)内に置いておけばAppleScriptエディタから呼び出せるようになるので、各自で勝手に増やして使えということのようです。

実際に試してみたところ、10.7のAppleScriptエディタ上で作成したCocoa-AppleScriptアプレットはMac OS X 10.6上でも動作するようです。ただし、10.7の機能に依存したコードを記述した場合にはこのかぎりではありませんし、そのまま実行してクラッシュしたものもありました。また、Mac OS X 10.6上のAppleScriptエディタ上で編集することはできません。

■Scriptテンプレート

ASOC以外の、通常のAppleScriptのテンプレートも、メニューの「ファイル」>「テンプレートから新規作成」>でApertureのインポート時アクション、一般ドロップレット、iChatの呼びだし時アクションで指定するScript、Mailのルールアクションなどが用意されています。

……アドレスブックやiCal、SafariにFont Bookなど標準搭載アプリの主要な処理についてはひととおりテンプレートを用意しておくべきではないのか? などと思うところですが、これも例によってテンプレート自体はフォルダ(~/Library/Application Support/Script Editor/Templates)内に置いておけばAppleScriptエディタから呼び出せるようになるので、各自で勝手に増やして使えということのようです。

LionのScript Menuの内容を見てみると、標準搭載アプリのサンプルAppleScriptが入っていることを確認できるので、これをただテンプレート用に転用すればいいだけの話なのですが、そもそもApple社内にAppleScriptを(世間一般のプロのScripter並に)書けるエンジニアが揃っていないので、そういう「普通、こうするよね?」的な動きはとれないようです。

■Global Script Application Targets

AppleScriptエディタで操作対象のアプリケーションのtellブロックをいちいち書かなくても、ポップアップメニューからアプリケーション名を選択すれば代替してくれるというものです。

……ただ、実際にプログラムを書いていると1つのアプリケーションだけを対象に記述する例というのはあまりありませんし、微妙に頑張るところを間違えているような気もしなくはありません。

■AppleScriptObjCの機能強化

Mac OS X 10.6上のASOCは、Objective-Cのファンクションのみ呼び出せるようになっていましたが、これが10.7ではCのファンクションも呼び出せるようになったとのこと。以前に、実際にASOCでプログラミングしていて、CarbonのAPIを呼び出す必要が出てきたときに、Objective-CのAPIではなかったため呼び出しをあきらめたことがありましたが……かなりローレベルのAPIを呼び出せるようになった、ということでしょうか。

関数呼びだし時の「void *」型パラメータは、AppleScriptObjC上で「id」型の変数として記述できるようになったとのこと(10.6ではmissing valueしか使えなかった)。

2011/07/25 OS X 10.7の地道な? 新機能〜絵文字

OS X 10.7, Lionの新機能「絵文字」。絵文字といえば、メールで使うぐらいだと思っていましたが、AppleScriptのコードの中に入れられるわ、ダイアログにも表示できるわ、AppleScriptのリザルトにも表示されるわ、おまけにファイル名にも使えるわ、スクリプトメニューにも絵文字のまま出るわで……新たな頭痛の種になりそうです。

emoji1.jpg

emoji2.jpg

emoji3.jpg

emoji4.jpg

emoji5.jpg

2011/07/24 OS X 10.7の新機能でAppleScript的に美味しいもの3つ

OS X 10.7の新機能のうち、AppleScript的に美味しいものを3つをご紹介しましょう。

(1)日本語読み上げ機能

日本語テキストの読み上げを行う機能が、Mac OS 8以来久しぶりに標準搭載されました。当時は、男性の「ひろし」、女性の「まさこ」の2パターンでしたが、今回のOS X 10.7では女性の「Kyoko」のみ。

システム環境設定の「スピーチ」>「テキスト読み上げ」で、「システムの声」ポップアップメニューから「カスタマイズ…」を選ぶと……

sp1.jpg

デフォルトでインストールされていない言語の音声データファイルを選択して(あとで)ダウンロードできるようになっています。Kyokoにチェックを入れれば、日本語の音声読み上げが可能になります。

sp2.jpg

あとは、sayコマンドで日本語読み上げまくりです(ロボットっぽいですが)。英語の読み上げは気合いが入りまくって、まるでニュースを聞いているようです。中国語や韓国語もかなりいい感じに聴こえます。その一方でフランス語とかイタリア語は、「?」な出来なので、今回の音声読み上げは得意/不得意がはっきりしているのかも(日本語だけがダメなわけではない、と)。

(2)複数ユーザーのGUIログイン機能

VNC経由、画面共有.app経由で1台のOS X Lionマシンに複数のユーザーが同時にリモートログインできるようになりました。複数のユーザー環境にログインしておいて、1台のマシン上でAppleEventによるアプリケーションのリモート制御ができます。

これは、マルチコア時代になって(現時点で)最大12コアのマシンがあっても、AppleScriptでその能力をすべて出し切ることは困難です。無理やり並列処理を行ってマルチコアのパワーを絞り出すことは不可能ではありませんが……用途がかなり限定されます。

しかし、複数GUIログインができるようになったということは、FileMaker ProやInDesign、Photoshopといった一般的なアプリケーションを使って1台のマシンで並列処理を行えるようになったということです(ソフトウェア・ライセンスの話をクリアできていれば)。しかも、LAN上の複数台のマシンを使って分散処理するのと、難易度でいえばさほど変わらない(かんたん)で、1台のハイパワーなマシンの能力を出し切ることができるというのは、非常にプラスになります。

(3)AppleScriptからCocoaが呼べるAppleScriptObjCの一般化

AppleScriptの進化の歴史をひもとくと、アプリケーションをコントロールするために作られたものが、UNIXレイヤーのshellコマンドを呼び出せるようになり、GUI ScriptingによりアプリケーションをメニューやボタンといったGUI部品側から(非対応アプリケーションでも)コントロールできるようになり、XcodeでGUIつきアプリケーションが作れるようになってきました。

次に用意された機能が、Cocoaを直接呼び出せるAppleScriptObjC。しかも、Mac OS X 10.6ではXcode上でしか利用できなかったものが、通常のAppleScriptエディタ上で利用できるようになりました。「できること」が増えるという意味では、実に応用範囲の広い技術です。

ただ、AppleScriptObjCについては、まったくドキュメントが用意されていなかったり、Appleからのサンプルがほとんどなかったりでなかなか手を着けづらい状況にあります。とはいうものの去年あたりから、海外ではぼちぼちドキュメントもオンライン出版され、「こう書けば使える」といったユーザー体験が共有されつつあります。

翻ってみると、AppleScript Studioも当初はドキュメントすらほとんど用意されておらず、バグだらけで、とても使えたものではありませんでした(Mac OS X 10.3になるまで使いものにならなかった)。

海外で見ると、アプリケーションプログラマとスクリプターの間の技量差は、あるのかないのか分からない程度。むしろ、アプリケーションプログラマーとは別の技術体系を構築しつつあります。記述を楽にするツールの提供なども間もなくサードパーティからリリースされる見込みなので、そのあたりがそろって来ると高い生産性を発揮できるようになるのではないでしょうか?

2011/07/24 Google Chromeで選択範囲(のテキスト)をコピー

Google Chromeで、最前面のウィンドウの選択中のタブ内で選択中のテキストをコピーするAppleScriptです。

エラー対策にはtry〜end tryあたりでエラートラップを仕掛けておけば大丈夫でしょう。

chrome1.jpg

スクリプト名:Google Chromeで選択範囲(のテキスト)をコピー
tell application “Google Chrome”
  tell window 1
    tell active tab
      copy selection
    end tell
  end tell
end tell

set aRes to the clipboard

–>
(*
“44都道府県、正午に地デジ移行へ=アナログ放送の歴史に幕
 東日本大震災で甚大な被害を受けた岩手、宮城、福島3県を除く44都道府県で24日正午、テレビ番組のアナログ放送が終了し、地上デジタル放送に一斉に移行する。1953年に始まったアナログ放送が58年の歴史に幕を下ろすことになる。25日午前0時には電波送信も停止する。(時事通信)”
*)

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

2011/07/23 OS X 10.7, Lionへの移行について

去る2011年7月20日の夜にリリースになった(Mac)OS X 10.7, Lion。

これまでも使ってきたので、直っているバグ(少ない?)、直っていないバグ(カタカナとひらがなを同一視するとか、call xmlrpc命令でクラッシュ頻発するとか)などいろいろ感じています。

メインマシンの移行は当分先になりそうですが、サブマシンで新OSの機能については試していくつもりです。

意外とJavaを併用しているアプリがあって(Mindjet MindManagerとかAdobe系とか)Java Runtimeのダウンロード&インストールを求められてびっくり。これは一度ダウンロードすれば大丈夫ですが、OSから本当にJavaのランタイムが取り除かれてリリースされたことを実感します(深い意味ナシ)。

ただ、Twitter界隈でいちばん目につくのが、Rosetta環境がなくなったことによる「予想外の影響」です。

Mac OS X 10.6より前のMac OS Xでは、AppleScriptを「アプリケーション」(バンドル形式ではないアプリケーション)としても保存できるようになっていて、この形式だとPowerPCバイナリで保存されるので、「10.7でAppleScriptが動かなくなった!」と大騒ぎしている人を……よく見かけます。

そういう場合には、「アプリケーションバンドル」で保存し直せばUniversal Binary(10.4〜10.6)あるいはIntel Binary(10.7〜)のアプリケーションになります。落ち着いて、保存し直してください。OS X 10.7上では、AppleScriptエディタですでに「アプリケーションバンドル」しか保存できないようになっているため、あえて「バンドル」という言葉を使わずに「アプリケーション」と表記しています。10.7で書き出したAppleScriptアプリケーションはバンドル形式になっていることが、Finder上で確認できます。

10.7上で保存したAppleScriptアプリケーションは、IntelのみのBinaryで構成されているため、10.5で動作しているPowerPC機にそのまま持っていくと「動かない」ということになります。

# なんでAppleの担当がWebで説明したり、ヘルプにこういう話を入れておかないのか不思議ですが

あと、アプリケーションをGUI Scripting経由でコントロールしている場合には、OSのバージョンが上がれば、当然のようにメニューや画面などの構成に手が加わるので、GUI経由のアクセスコードは書き換えの必要が出てきます。もう、当然といえば当然のことなので、これもUI Browserあたりを併用しつつ、機械的に書き換えるほかありません。ただ、それだけです。

2011/07/23 Safari 5.1でWeb検索

Safari 5.1で追加になった検索命令を用いて、Safari経由で現在指定中のサービスプロバイダ(Google/Yahoo!/Bingのうちいずれか)でWebのキーワード検索を行うAppleScriptです。

とりあえず検索するよう最低限のコードを書いて実験。あまり期待はしていませんでしたが、Webの検索結果をAppleScriptで利用しやすいようにRecord形式にparseして返すとかいうことは一切ありません。ただSafariの画面上に表示されるだけです。表示内容のソースコードを取得して自前で解析しないとRecord形式で検索結果が返ってきたりはしません。

キーワードだけ指定してただ検索すると、新規ウィンドウがオープンしてそこに結果が表示されます。

スクリプト名:Safari 5.1でWeb検索1
set aKeyword to "ぴよまる"

tell application "Safari"
  set aVer to version as number –バージョン番号
  
if aVer < 5.1 then return
  
  
search the web for aKeyword
  
end tell

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

現在オープン中のウィンドウに対して検索結果を表示してほしい場合には、このように指定すれば大丈夫です。ウィンドウの中のTabを指定します。

スクリプト名:Safari5.1でWeb検索2
set aKeyword to "ぴよまる"

tell application "Safari"
  tell window 1
    set curTab to current tab
    
search the web for aKeyword in curTab –検索結果を表示するTabを指定
  end tell
end tell

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

2011/07/23 Safari 5.1でreading listを登録

Safari 5.1でリーディングリスト(reading list)を登録するAppleScriptです。

safa10.jpg

Safari 5.1の、「とりあえずURLをメモっておいてあとで読もう」というリーディングリスト機能。Mac上のSafariだけだとピンと来ませんが、Mac上でとりあえずURLをリーディングリストに入れておくと、iCloud経由で他のiOSデバイス(あるいはその逆)とシンクロされて、職場でメモっておいたURLを移動中にiPhoneやiPadで読む、という使い方が可能になるものです。

iOSデバイスとの自動シンクロはiOS 5の登場を待たなければなりませんが、「AppleScriptでいつも購読しているメールマガジンの本文中のURLを一括でリーディングリストに登録する」といったAppleScriptを用意しておけば、iOS5が登場する頃には便利な状態になっていることでしょう(URLリストの同期だけでなく、コンテンツのローカル保存&シンクロを行ってくれた方がよさそうな……そういうのはEvernoteなどのサービスの領分なんでしょうか)。

safa11.jpg

一番左に表示されているメガネのマークがリーディングリストのボタン。

safa12.jpg

メガネのボタンを押して、リーディングリストを展開した状態。

ここで、AppleScriptからリーディングリストを追加すると、このようになります。

safa13.jpg

文字のサムネイルが若干表示されていますが、メニュー部分なので本文の要約にはなっていません。ちょっとこのあたりがいまひとつ……

タイトルも指定どおりにはなっていませんね。自分たちでAppleScript用語辞書に書いたとおりに動作しないというのは、何事なんでしょう?(ーー;

safa14.jpg

スクリプト名:Safari 5.1でreading listを登録1
set aURL to “http://piyocast.com/as/”

tell application “Safari”
  set aVer to version as number –バージョン番号
  
if aVer < 5.1 then return
  
  
add reading list item aURL with title “AppleScriptの穴”
end tell

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

リーディングリストのプレビューテキストを指定しないといまひとつなので、明示的に登録してみました。

が……

safa14.jpg

指定しても、preview textは効きませんね。何をどう指定しても任意の文字が表示されたりはしません。これも、AppleらしいといえばAppleらしい……………(←ほめてない)。

スクリプト名:Safari 5.1でreading listを登録2
set aURL to “http://piyocast.com/as/”
set aPrevText to “AppleScriptの実践的なコードを掲載しているブログです。”

tell application “Safari”
  set aVer to version as number –バージョン番号
  
if aVer < 5.1 then return
  
  
add reading list item aURL and preview text aPrevText with title “AppleScriptの穴”
end tell

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

2011/07/23 Safari 5.1でAppleScript用語が追加に

Safari 5.1でいくつか機能が追加され、ひさしぶりにAppleScript用語辞書が更新されました。ここのところ、AppleScript用語が追加されたことはなかったので、本当に久しぶりです。

そのうちのひとつ、「リーディングリストの追加」はコマンド名「add reading list item」。追加のみで削除や書き換えのための命令はありません。

safa1.jpg

また、現在指定の検索プロバイダ(GoogleとかBingとか)を用いてWeb検索を行う「search the web」コマンドが追加されました。

safa2.jpg

返り値はとくにありません。このあたりでListやrecordにparseされた結果が返ってきたら感心したのですが、さすがにそこまでやらないのがAppleらしいといえばAppleらしい(←ほめてない)ところです。

その他、指定のタブの内容をメールで送信する(コンテンツを新規メールに入れるだけ)の命令「email contents」が若干変更に。これは、マイナーチェンジという程度の変更です。

2011/07/19 Photoshopで選択範囲を切り抜く

Photoshop CS3で、画像の選択範囲を切り抜くAppleScriptです。

あらかじめオープンしておいた画像の一部を選択しておき、本Scriptを実行すると選択部分だけを切り抜きます。

■実行前
ps1_before.jpg

■実行後
ps1_after.jpg

スクリプト名:Photoshopで選択範囲を切り抜く
–選択範囲で切り抜く
tell application "Adobe Photoshop CS3"
  tell document 1
    
    
set aSel to selection
    
try
      set {x1, y1, x2, y2} to bounds of selection
    on error
      set {x1, y1, x2, y2} to {0, 0, 0, 0}
      
return
    end try
    
    
crop bounds {x1, y1, x2, y2}
    
  end tell
end tell

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

2011/07/18 .ruドメインからのアクセスを停めます

本Blogには、投稿記事の本数の数百倍ぐらいスパムアクセスがあって、スパムフィルタで弾いている状態です。ただ、スパムフィルタもあまりに処理本数が多いと無償利用はできなくなってしまうので、割と頭の痛い問題です。

Russia経由のスパムアクセスの割合が非常に高いので、.ruドメインからのアクセスを拒否することにします。

Russia在住の日本人で、本Blogをご覧になっている方がいる場合にはご一報を。

2011/07/18 InDesign CS3で選択中のオブジェクトの外周部の座標を取得する

InDesign CS3で選択中のオブジェクトの外周部の座標を取得するAppleScriptです。

idcs_range2.jpg

複数のオブジェクトの外周部の座標のみ取得したいという場合、安直にグループ化してその座標(geometric bouds)を取得する方法も考えないではないですが、元に戻すときに何かよくないこと(前後関係が狂うとか)が起こる可能性があるため、「グループ化→座標取得→グループ化解除」の順で処理するのは避けたいところ。

そこで、力ワザでありもののソートルーチンを用いて、ソートだけで取得するように処理してみました。y1とx1は昇順ソート、y2とx2は降順ソートして、それぞれ最初の項目から値を取得しています。

基礎的な属性アクセスしか使っていないため、とくにInDesignのバージョンに依存せずに使用できるはずです(tellブロックのアプリケーション名を書き換えるぐらい)。

スクリプト名:InDesign CS3で選択中のオブジェクトの外周部の座標を取得する
tell application “Adobe InDesign CS3″
  tell active document
    set gList to geometric bounds of selection
    
    
copy gList to y1List
    
copy gList to y2List
    
copy gList to x1List
    
copy gList to x2List
    
    
set y1Res to shellSortListAscending(y1List, 1) of me
    
set x1Res to shellSortListAscending(x1List, 2) of me
    
set y2Res to shellSortListDecending(y2List, 3) of me
    
set x2Res to shellSortListDecending(x2List, 4) of me
    
    
–外周部の座標を取得する
    
–y1, x1は最小のものを取得
    
set y1min to item 1 of item 1 of y1Res
    
set x1min to item 2 of item 1 of x1Res
    
    
–y2, x2は最大のものを取得
    
set y2max to item 3 of item 1 of y2Res
    
set x2max to item 4 of item 1 of x2Res
    
    
return {y1min, x1min, y2max, x2max}
    
–> {64.666666666667, 39.0, 177.0, 202.0}
  end tell
end tell

–シェルソートで入れ子のリストを昇順ソート
on shellSortListAscending(a, keyItem)
  set n to length of a
  
set cols to {1391376, 463792, 198768, 86961, 33936, 13776, 4592, 1968, 861, 336, 112, 48, 21, 7, 3, 1}
  
repeat with h in cols
    if (h (n - 1)) then
      repeat with i from h to (n - 1)
        set v to item (i + 1) of a
        
set j to i
        
repeat while (j h) and ((contents of item keyItem of item (j - h + 1) of a) > (item keyItem of v))
          set (item (j + 1) of a) to (item (j - h + 1) of a)
          
set j to j - h
        end repeat
        
set item (j + 1) of a to v
      end repeat
    end if
  end repeat
  
return a
end shellSortListAscending

–シェルソートで入れ子のリストを降順ソート
on shellSortListDecending(a, keyItem)
  set n to length of a
  
set cols to {1391376, 463792, 198768, 86961, 33936, 13776, 4592, 1968, 861, 336, 112, 48, 21, 7, 3, 1}
  
repeat with h in cols
    if (h (n - 1)) then
      repeat with i from h to (n - 1)
        set v to item (i + 1) of a
        
set j to i
        
repeat while (j h) and ((contents of item keyItem of item (j - h + 1) of a) < (item keyItem of v))
          set (item (j + 1) of a) to (item (j - h + 1) of a)
          
set j to j - h
        end repeat
        
set item (j + 1) of a to v
      end repeat
    end if
  end repeat
  
return a
end shellSortListDecending

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

2011/07/18 InDesign CS3で指定座標内に存在しているラインオブジェクトを抽出する

InDesign CS3で、指定座標内に重なっているラインオブジェクトを抽出するAppleScriptです。

とりあえず……画像を選択して本AppleScriptを実行すると、画像に重なっているラインオブジェクトを取り出してくれます。

引き出し線とその先の解説文字も含めて、プログラムの自動判別でひとかたまりに扱ってしまおうという目論見の課程で作られた試作品です。

画像を中心とした引き出し線+解説のテキストが入っているテキストフレームまでを1つの塊として認識して、外周部の座標を計算して、別途書き出しておいた画像をトリミングするという……図鑑などのやたらと画像点数が多いデータで「画像+解説部分」をひとまとめに取り出すためのプログラムに仕立て上げる予定(1日ぐらいでできそう)。

手作業部分をイレギュラーなものだけに限定できるので、圧倒的な効率化が実現できます。

idcs3_range.jpg

InDesign CS3用といっていますが、とくにそれほどバージョン依存しているわけではありません。書き換えもおそろしく簡単でしょう。

スクリプト名:InDesign CS3で指定座標内に存在しているラインオブジェクトを抽出する
tell application “Adobe InDesign CS3″
  tell document 1
    set aSel to first item of selection
    
set imgBounds to geometric bounds of aSel
    
    
set glList to every graphic line
    
set gvList to geometric bounds of every graphic line
    
    
set aRes to corruptRange_Y1X1Y2X2_retByID(imgBounds, gvList) of me
    
    
set selList to {}
    
repeat with i in aRes
      set the end of selList to item i of glList
    end repeat
    
    
  end tell
end tell

selList
–> {graphic line id 363 of page id 238 of spread id 233 of document “testdata.indd” of application “Adobe InDesign CS3″, graphic line id 267 of page id 238 of spread id 233 of document “testdata.indd” of application “Adobe InDesign CS3″, graphic line id 266 of page id 238 of spread id 233 of document “testdata.indd” of application “Adobe InDesign CS3″}

–指定矩形内に重なるデータをアイテム番号で返す
on corruptRange_Y1X1Y2X2_retByID(rangeList, targetList)
  set includedList to {}
  
  
set aCount to 1
  
  
set y1 to item 1 of rangeList
  
set x1 to item 2 of rangeList
  
set y2 to item 3 of rangeList
  
set x2 to item 4 of rangeList
  
  
repeat with i in targetList
    set targY1 to item 1 of i
    
set targX1 to item 2 of i
    
set targY2 to item 3 of i
    
set targX2 to item 4 of i
    
    
    
if ((x1 < targX1) and (targX1 < x2) and (y1 < targY1) and (targY1 < y2)) then
      set the end of includedList to aCount
    else if ((x1 < targX2) and (targX2 < x2) and (y1 < targY2) and (targY2 < y2)) then
      set the end of includedList to aCount
    end if
    
    
set aCount to aCount + 1
    
  end repeat
  
  
return includedList
end corruptRange_Y1X1Y2X2_retByID

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

2011/07/12 Photoshopで指定座標のカラー値をRGB値で返す

Photoshop CS3で、指定座標のカラーをRGB値で返すAppleScriptです。

Photoshopで指定座標のカラー値を取得できると、処理の幅が大きく広がります。かなり独特な方法なので、これはサンプルがないと分りづらいところです。

いきなり何の断りもなくRGB値を取り出していますが、画像の色空間(カラースペース)がRGBになっていることを前提としています。

スクリプト名:指定座標のカラー値をRGB値で返す
tell application “Adobe Photoshop CS3″
  tell current document
    set {x1, y1, x2, y2} to bounds of selection
  end tell
end tell

set xCenter to x1 + (x2 - x1) / 2
set yCenter to y1 + (y2 - y1) / 2
set aList to getColValOnSpecifiedPosition(xCenter, yCenter) of me
–> {252, 156, 88}

–指定座標のカラー値をRGB値で返す
on getColValOnSpecifiedPosition(xPos, yPos)
  tell application “Adobe Photoshop CS3″
    tell current document
      –Color Samplerを作成して指定座標の色情報を取得する
      
set aSampler to make new color sampler with properties {class:color sampler, position:{xPos, yPos}}
      
      
set rgbValues to color sampler color of aSampler
      
      
set rgb_rCol to red of rgbValues
      
set rgb_gCol to green of rgbValues
      
set rgb_bCol to blue of rgbValues
      
      
–四捨五入
      
set rgb_rCol to round rgb_rCol rounding as taught in school
      
set rgb_gCol to round rgb_gCol rounding as taught in school
      
set rgb_bCol to round rgb_bCol rounding as taught in school
      
      
      
–Color Samplerを削除(Max 4個なので作ったらすぐに削除)
      
delete aSampler
      
      
return {rgb_rCol, rgb_gCol, rgb_bCol}
      
    end tell
  end tell
end getColValOnSpecifiedPosition

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

2011/07/10 文字列の先頭と末尾に指定文字が存在した場合にはトリミングして返す

与えられた文字列の先頭と末尾に指定文字が存在した場合にはトリミングして返すAppleScriptです。

指定文字列がカッコ(「(」「)」で囲まれている場合に外す、という処理を行うために用意したものです。

スクリプト名:文字列の先頭と末尾に指定文字が存在した場合にはトリミングして返す
set aStr to "(ひよこさんスペシャルサービス)"
set aRes to trimByCharPair(aStr, "(", ")") of me
–> "ひよこさんスペシャルサービス"

–文字列の先頭と末尾に指定文字が存在した場合にはトリミングして返す
on trimByCharPair(aStr, beginChar, endChar)
  
  
set aLen to length of aStr
  
set sPos to 1
  
set ePos to aLen
  
  
if aStr begins with beginChar then
    set sPos to sPos + 1
  end if
  
  
if aStr ends with endChar then
    set ePos to ePos - 1
  end if
  
  
set aResStr to text sPos thru ePos of aStr
  
return aResStr
  
end trimByCharPair

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

2011/07/10 数字の文字が入っているかどうかをテストする

与えられた文字列中に数字の文字(0〜9)が入っているかテストを行うAppleScriptです。

入っていればtrueを、入っていなければfalseを返します。

スクリプト名:数字の文字が入っているかどうかをテストする
detectContainsSomeNumChar("10名") of me

–数字の文字が入っているかどうかをテストする
–数字の文字が入っていたらtrue
on detectContainsSomeNumChar(testText)
  –ANK文字列(大文字小文字は問わない)
  
set ankChar to {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}
  
  
set _testChar to testText as Unicode text
  
  
ignoring case
    repeat with i in _testChar
      set j to contents of i
      
if j is in ankChar then
        return true
      end if
    end repeat
  end ignoring
  
  
return false
end detectContainsSomeNumChar

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

2011/07/10 指定矩形内に含まれるデータをアイテム番号で返す

指定矩形内に含まれるデータをアイテム番号で返すAppleScriptです。

以前に、指定矩形座標内に含まれる座標をピックアップというAppleScriptを掲載しましたが、その時にはデータ内容そのもの(contents)を返していました。InDesignの座標系である{Y1,X1,Y2,X2} という(珍妙な)座標の並び順を想定しています。

本ルーチンでは、アイテム番号を返すように一部変更したものです。

別途、オブジェクト参照のリストを保持しておき、本ルーチンで座標値の判定を行ったのちに、オブジェクト参照リストから対象をピックアップするような処理を想定しています。

スクリプト名:指定矩形内に含まれるデータをアイテム番号で返す
set aList to {{243.0, 17.0, 245.0, 77.0}, {169.000015228534, 12.0, 187.500015228534, 166.999999999992}, {189.000007614311, 13.0, 242.000007614312, 17.0}, {188.999990448174, 17.0, 241.999990448174, 76.999999025133}, {188.999990448174, 87.5, 241.999990448174, 123.5}}

set rangeList to {236.999990448174, 12.0, 246.999990448174, 81.999999025133} –{y1,x1,y2,x2}
set resList to withinRange_Y1X1Y2X2_retByID(rangeList, aList) of me

–指定矩形内に含まれるデータをアイテム番号で返す
on withinRange_Y1X1Y2X2_retByID(rangeList, targetList)
  set includedList to {}
  
  
set aCount to 1
  
  
set y1 to item 1 of rangeList
  
set x1 to item 2 of rangeList
  
set y2 to item 3 of rangeList
  
set x2 to item 4 of rangeList
  
  
repeat with i in targetList
    set targY1 to item 1 of i
    
set targX1 to item 2 of i
    
set targY2 to item 3 of i
    
set targX2 to item 4 of i
    
    
if (x1 < targX1) and (x2 > targX2) and (y1 < targY1) and (y2 > targY2) then
      set the end of includedList to aCount
    end if
    
    
set aCount to aCount + 1
    
  end repeat
  
  
return includedList
end withinRange_Y1X1Y2X2_retByID

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

2011/07/10 指定アイテム以降は指定アイテム目に改行で区切って連結する

与えられたリストのうち、指定アイテム以降は指定アイテム目に改行で区切って連結するAppleScriptです。

たとえば、要素数が7つあるリストのうち、4アイテム目以降をこの処理対象と指定した場合、4〜7アイテム目が(改行をはさんて)連結されます。

スクリプト名:指定アイテム以降は指定アイテム目に改行で区切って連結する
set aList to {"○○初等部", "○○中等部", "○○高等部(400)", "○○大学", "○○女子短期大学", "○○女子短期大学"}

set a to mergeLastItem(aList, 4) of me
–>
(*
{"○○初等部", "○○中等部", "○○高等部(400)", "○○大学
○○女子短期大学
○○女子短期大学"}

*)

–指定アイテム以降は指定アイテム目に改行で区切って連結する
on mergeLastItem(aList, aLimit)
  set aLen to length of aList
  
if aLen > aLimit then
    set newItem to ""
    
    
set tmpList to items aLimit thru aLen of aList
    
set newItem to retDelimedText(tmpList, return) of me
    
    
set bList to items 1 thru (aLimit - 1) of aList
    
set the end of bList to newItem
    
set aList to bList
  end if
  
  
return aList
end mergeLastItem

on retDelimedText(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 retDelimedText

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

2011/07/10 Excelの最前面のウィンドウの表示倍率を連続して変更する

Microsoft Excel 2011の最前面のウィンドウの表示倍率を連続して変更するAppleScriptです。

こういうこともできる、というデモぐらいの意味合いのものです。

Excel 2011では、ポップアップメニューから200%までの表示を指定可能
excel2011_1.jpg

100%表示
excel2011_2.jpg

200%表示
excel2011_3.jpg

300%表示
excel2011_4.jpg

400%表示
excel2011_5.jpg

400%以上の指定はできないようになっています。
excel2011_6.jpg

スクリプト名:Excelの最前面のウィンドウの表示倍率を連続して変更する 
tell application "Microsoft Excel"
  tell window 1
    repeat with i from 100 to 400 by 100
      set zoom to i
      
delay 1
    end repeat
  end tell
end tell

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

2011/07/10 文字列末尾からスペースを削る

文字列の末尾からスペース(空白文字)を削り、空白文字以外の文字に遭遇したら削除を切り上げて結果を返すAppleScriptです。

  ”PiyoPiyo ” –> “PiyoPiyo”

という処理を行います。

スクリプト名:文字列末尾からスペースを削る
set a to "GR Digital "
set b to trimSpaceFromLast(a) of me

–文字列末尾からスペースを削る
on trimSpaceFromLast(aStr)
  set revStrList to (reverse of characters of aStr)
  
set rLen to length of revStrList
  
  
set hitF to false
  
set aCount to rLen
  
  
repeat with i in revStrList
    set j to contents of i
    
    
if j is not equal to " " then
      set hitF to true
      
exit repeat
    end if
    
    
set aCount to aCount + 1
  end repeat
  
  
if hitF = false then return aStr
  
  
set bStr to text 1 thru (rLen - aCount - 1) of aStr
  
return bStr
end trimSpaceFromLast

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

2011/07/10 子番号を考慮しつつ、新しいファイル名を返す

特定のフォルダ内のファイル名リストをもとに、指定のファイルを新規作成可能か(重複がないか)判断を行い、重複がある場合にはアンダースコア(「_」)のあとに子番号を補ったファイル名を生成。子番号つきのファイルがすでに存在する場合には、そのうち一番大きな番号のものを検出して、さらに新しい子番号つきのファイル名を返すAppleScriptです。

既存フォルダへのファイルのコピーなどの際に用いる、かなり高機能なルーチンです。はっきり言って上級者向けのものであり、初心者向けのものではありません。

特定のフォルダ内に、

  ”RIMG0056.JPG”, “RIMG0056_1.JPG”

というファイルが存在しており、そこに、

  ”RIMG0056.JPG”

というファイルを新規にコピーしようとした際に、ファイル名の重複を検出し、さらに子番号のうち最大のものを検出して、

  ”RIMG0056_2.JPG”

というファイル名を返します。

スクリプト名:子番号を考慮しつつ、新しいファイル名を返す

set myName to “RIMG0056.JPG”
–set aList to {”RIMG0056.JPG”, “RIMG0056_1.JPG”, “RIMG0056_2.JPG”}
set aList to {“RIMG0056.JPG”, “RIMG0056_1.JPG”}

set my2Name to retChildFileName(myName, aList) of dupNameGenKit

script dupNameGenKit
  –子番号を考慮しつつ、新しいファイル名を返す
  
on retChildFileName(myName, aList)
    
    
set numList to {}
    
–set aList to {”RIMG0056.JPG”}
    
    
repeat with i in aList
      set j to contents of i
      
      
set tmpN to offset of “_” in j
      
if tmpN is not equal to 0 then
        set tmpA to text (tmpN + 1) thru -1 of j
        
set aOfst to offset of “.” in tmpA
        
set numStr to text (tmpN + 1) thru (tmpN + aOfst - 1) of j
        
        
set the end of numList to (numStr as number)
      end if
      
    end repeat
    
    
if numList is not equal to {} then
      –すでに「_」の子番号が存在する場合
      
set b to shellSortDecending(numList) of me
      
set largestNum to contents of first item of b
      
      
set largestNum to largestNum + 1
      
    else
      –まだ「_」の子番号が存在しない場合
      
set largestNum to 1
      
    end if
    
    
set pureName to retNameFromFilenameStr(myName) of me
    
set anExt to retExtNameFromFilenameStr(myName) of me
    
set gName to pureName & “_” & (largestNum as string) & anExt
    
    
return gName
    
  end retChildFileName
  
  
  
–ファイル名文字列から拡張子を外して返す
  
on retNameFromFilenameStr(fileNameStr)
    set fLen to length of fileNameStr
    
set revText to (reverse of (characters of fileNameStr)) as string –逆順テキストを作成
    
set anOffset to offset of “.” in revText
    
set fRes to text 1 thru (fLen - anOffset) of fileNameStr
    
return fRes
  end retNameFromFilenameStr
  
  
–ファイル名文字列から拡張子のみ取得する
  
on retExtNameFromFilenameStr(fileNameStr)
    set fLen to length of fileNameStr
    
set revText to (reverse of (characters of fileNameStr)) as string –逆順テキストを作成
    
set anOffset to offset of “.” in revText
    
set fRes to text (fLen - anOffset + 1) thru -1 of fileNameStr
    
return fRes
  end retExtNameFromFilenameStr
  
  
–シェルソートでリストを昇順ソート(入れ子ではないリスト)
  
on shellSortAscending(a)
    set n to length of a
    
set cols to {1391376, 463792, 198768, 86961, 33936, 13776, 4592, 1968, 861, 336, 112, 48, 21, 7, 3, 1}
    
repeat with h in cols
      if (h (n - 1)) then
        repeat with i from h to (n - 1)
          set v to item (i + 1) of a
          
set j to i
          
repeat while (j h) and ((contents of item (j - h + 1) of a) > v)
            set (item (j + 1) of a) to (item (j - h + 1) of a)
            
set j to j - h
          end repeat
          
set item (j + 1) of a to v
        end repeat
      end if
    end repeat
    
return a
  end shellSortAscending
  
  
–シェルソートでリストを降順ソート(入れ子ではないリスト)
  
on shellSortDecending(a)
    set n to length of a
    
set cols to {1391376, 463792, 198768, 86961, 33936, 13776, 4592, 1968, 861, 336, 112, 48, 21, 7, 3, 1}
    
repeat with h in cols
      if (h (n - 1)) then
        repeat with i from h to (n - 1)
          set v to item (i + 1) of a
          
set j to i
          
repeat while (j h) and ((contents of item (j - h + 1) of a) < v)
            set (item (j + 1) of a) to (item (j - h + 1) of a)
            
set j to j - h
          end repeat
          
set item (j + 1) of a to v
        end repeat
      end if
    end repeat
    
return a
  end shellSortDecending
end script

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

2011/07/09 SIGMA Raw画像からメーカーと機種名を取り出す v2

SIGMAのデジカメで撮影したRAW画像ファイル(拡張子「.X3F」)を分析して、内包しているEXIFデータから「メーカー名+機種名」の文字列情報を取り出すAppleScriptです。

本ScriptでSIGMAのRAW画像ファイルを処理すると「SIGMA DP1」などのメーカー名+モデル名の文字列を、取得できなかった場合にはFalseを返します。

写真家の友人から「たまった写真データを機種別にフォルダ分けして、ファイル名の重複があった場合には連番でリネームするAppleScriptを作って〜」と、頼まれて物々交換でAppleScriptを作ったときに、JPEGファイルについてはImage EventsやsipsコマンドでEXIF情報にアクセスできるのですが、肝心のSIGMAのRAWデータだけはなぜかEXIF情報が取得できないことが判明。

インターネット上でデジカメメーカー各社のRAWファイルをかき集め、CANNONの「CR2」、OLYMPUSの「ORF」、富士フィルムの「RAF」、リコーの「DNG」、ニコンの「NEF」などひととおりsipsでEXIF情報にアクセスできることを確認。

SIGMAがマイナーなマニアックなメーカーであるために、Mac OS X 10.6.xが標準でSIGMA RAWの解析機能を持っていないことが原因であることが判明しました。

そこで、仕方なくAppleScriptでSIGMAのRAWファイルを解析。どうせRAW画像ファイルといっても、EXIFの情報を内包していることは予想でき、しかもまともな技術者ならEXIF情報はファイルの先頭の方に置いておくはず。

stringsコマンドで文字列らしきところを文字ダンプ。あっさりと先頭の方にEXIF情報が見つかりました。

さらに、ファイル全体に対して実行すると数十メガバイト分も処理することになって面倒(時間がかかる)なので先頭の数十行分だけしか処理しないようにして試してみました。

他社のRAW画像はおおかたMac OS Xが標準で解析できるので、本AppleScriptはあくまでSIGMAのRAW画像解析専用です。

スクリプト名:SIGMA Raw画像からメーカーと機種名を取り出すテスト v2
set a to choose file with prompt “Please Select Raw File”
set aRes to getCameraNameFromSIGMArawfile(a) of me

–SIGMAのRawファイルを解析してメーカー名+機種名を取り出す
on getCameraNameFromSIGMArawfile(aFile)
  set aPOSIX to POSIX path of aFile
  
  
ignoring case
    if aPOSIX does not end with “.X3F” then
      return false
    end if
  end ignoring
  
  
  
–Raw画像ファイルを文字ダンプして先頭から40行取り出す
  
set sText to “/usr/bin/strings “ & quoted form of aPOSIX & ” | head -n 40″
  
set aRes to do shell script sText
  
  
set aList to paragraphs of aRes
  
set aLen to length of aList
  
  
–Exifっぽい部分をサーチ
  
set aMaker to “”
  
set aMakerModel to “”
  
  
repeat with i from 1 to aLen
    set j to contents of item i of aList
    
if j contains “Exif” then
      set aMaker to contents of item (i + 1) of aList
      
set aMakerModel to contents of item (i + 2) of aList
      
exit repeat
    end if
  end repeat
  
  
–含んでいなかった場合(T_T)
  
if aMaker = “” then
    return false
  end if
  
  
–結果表示
  
return aMakerModel
  
end getCameraNameFromSIGMArawfile

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

2011/07/06 指定のデジカメ画像のExif情報から指定のプロパティを取得する

指定のデジカメ画像のExif情報から指定のプロパティを取得するAppleScriptです。

デジカメ画像のExif情報を取得する場合には、Image Events経由でアクセスすることになりますが……実際に使ってみると、クラッシュしまくるImage Events。AppleScriptの実行をApple純正のアプリケーションが阻害するというあり得ない現象が頻発。

そこで、Image Eventsをアテにしないで、sipsコマンドをAppleScriptから呼び出すことにしてみました。Image Eventsはsipsを呼び出しているAS用インタフェース・アプリケーションですが、この調子ではAppleScriptによる並列処理などを考えるとsipsをダイレクトに呼び出した方がご利益が大きそうです。

指定できるプロパティ値については、Terminal上でsipsコマンドのhelpを見て確認してください。

Special property keys:
all binary data
allxml binary data

Image property keys:
dpiHeight float
dpiWidth float
pixelHeight integer (read-only)
pixelWidth integer (read-only)
typeIdentifier string (read-only)
format string jpeg | tiff | png | gif | jp2 | pict | bmp | qtif | psd | sgi | tga
formatOptions string default | [low|normal|high|best| ] | [lzw|packbits]
space string (read-only)
samplesPerPixel integer (read-only)
bitsPerSample integer (read-only)
creation string (read-only)
make string
model string
software string (read-only)
description string
copyright string
artist string
profile binary data
hasAlpha boolean (read-only)

Profile property keys:
description utf8 string
size integer (read-only)
cmm string
version string
class string (read-only)
space string (read-only)
pcs string (read-only)
creation string
platform string
quality string normal | draft | best
deviceManufacturer string
deviceModel integer
deviceAttributes0 integer
deviceAttributes1 integer
renderingIntent string perceptual | relative | saturation | absolute
creator string
copyright string
md5 string (read-only)

スクリプト名:retExifAttributeData v2
set aFile to choose file
set aRes to retExifAttributeData(aFile, “model”) of me
–> “GR Digital “

set bRes to retExifAttributeData(aFile, “formatOptions”) of me
–> “default”

–SIPSコマンドで指定のデジカメ画像のExif情報(プロパティ)を取得する
on retExifAttributeData(aFile, aParam)
  
  
set aPOSIX to quoted form of POSIX path of aFile
  
  
set aRes to do shell script “sips –getProperty “ & aParam & ” “ & aPOSIX
  
set aList to paragraphs of aRes
  
set anItem to contents of last item of aList
  
  
set colonPos to (offset of “:” in anItem) + 2
  
set eRes to text colonPos thru -1 of anItem
  
  
return eRes
  
end retExifAttributeData

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