Archive for 10月, 2010

2010/10/29 指定フォルダ以下のファイルやフォルダからラベルを外す

指定フォルダ以下のすべてのファイルやフォルダからラベルを外すAppleScriptです。

再帰で処理すると遅いし、spotlightで検索して処理するのも(できるけど)かったるいし……ということで、entire contentsですべての要素を取得してループです。

entire contetnsへの参照(a reference to)に対して一括で命令する方法もあるのですが、AppleScript側は全対象に向けて一括で指令を出してすぐに処理が終了するものの……Finder側の処理がすぐには終わらないので(実際に試しました)、こんなもんでいいんじゃないかと。

スクリプト名:指定フォルダ以下のファイルやフォルダからラベルを外す
global fList, fList_r

set aFol to choose folder

tell application "Finder"
  set fList to entire contents of aFol as alias list
end tell
set fList_r to a reference to fList

tell application "Finder"
  repeat with i in fList_r
    ignoring application responses
      set label index of i to 0
    end ignoring
  end repeat
end tell

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

2010/10/29 現在編集中のXcodeプロジェクトのビルドターゲットが生成したpreferenceファイルを削除する v4

Xcode 3.2.4で現在編集中のプロジェクトのビルドターゲットがテストラン時に作成したpreferenceファイル(plistファイル)を削除するAppleScriptです。

Shane Stanleyの「AppleScriptObjC Explored」を購入して熟読し、AppleScriptObjCの使い方がようやく掴めてきた今日このごろ。Xcodeも(ADC Online Developperに公開されている中で)最新のXcode 3.2.4をダウンロード。

Xcode上でAppleScriptObjCを使ってようやく作りたいものが作れるようになりかけてきたときに、やっぱり初期設定ファイル(ホーム/ライブラリ/Preferences フォルダ以下に作られるplistファイル)を削除したくなって、従来のバージョンを試してみたところ……なんと、削除されません。

xc1.jpg

いろいろ調べてみると、このわずかにバージョン番号が上がった間にXcodeのプロジェクト仕様に一部変更が(ーー; info.plistファイルのファイル名およびinfo.plist自体をビルド時にプリプロセッサで処理することがデフォルトになったらしく、ビルド前のXcodeプロジェクト内にあるinfo.plistファイルをそのまま読んできただけでは、うまく処理できません。

xc2.jpg

xc3.jpg

そこで、Xcode 3.2.4の仕様に合わせて書き換えてみました。

相変わらず、複数のビルドターゲットを持つXcodeプロジェクトには対応できていませんが、サンプルコードの中にそうのがあったので、そのうち対応するかもしれません。

スクリプト名:現在編集中のXcodeプロジェクトのビルドターゲットが生成したpreferenceファイルを削除する v4
(*

v4 : Xcode 3.2.4に対応

Xcodeプロジェクト内のinfo.plistファイルの記述内容が、プリプロセッサの処理が必要な形式で書かれるように変更されていたため、
${PRODUCT_NAME:identifier}の値をプロジェクトのproduct nameに置換して処理するようにした。

info.plistのファイル名を、プロジェクトのactive targetの名称から取得している。
複数のactive targetを含むようなプロジェクトでは使えないはず
ただし、複数のactive targetのプロジェクトがあれば、各active targetに対してループ処理すればいいだけなので、対応はそれほど難しくはない

*)

–現在編集中のXcodeプロジェクトのパス情報を取得
tell application “Xcode”
  try
    set aPrj to project of active project document
  on error
    activate
    
display dialog “There is no Xcode Project” with icon 1 buttons {“OK”} default button 1
    
return
  end try
  
  
tell aPrj
    set projPath to real path
    
set pName to name of active target –active targetが複数の場合を考慮していない
  end tell
end tell

–現在編集中のプロジェクトに含まれるInfo.plistファイルを検出
set projPath to POSIX file projPath

tell application “Finder”
  set parantFol to (folder of file projPath) as alias
  
tell folder parantFol
    set infoP to every file whose name contains “info.plist”
    
if infoP = {} then
      display dialog “現在編集中のプロジェクトにはInfo.plistが入っていません。” buttons {“OK”} default button 1 with icon 1
      
return
    end if
    
    
set infoP to (first item of infoP) as alias
    
  end tell
end tell

–Info.plistファイルからバンドル情報を取得する
–set pListPath to (parantFol as string) & “Info.plist”
tell application “System Events”
  set vRec to value of property list file (infoP as string) –plist fileから値を読み取る
end tell
set infoRes to |CFBundleIdentifier| of vRec

–plistファイルを消す
set aPath to (path to preferences from user domain) as string
set infoPlistPath to aPath & infoRes & “.plist”

–Xcodeプロジェクト内のinfo.plistは、まだプリプロセッサで書き換えられる前のものが入っているので、書き換えておく
set infoPlistPath to repChar(infoPlistPath, “${PRODUCT_NAME:identifier}”, pName) of me

try
  do shell script “rm -f “ & quoted form of POSIX path of infoPlistPath
  
tell application “Xcode”
    activate
    
display dialog “以下のplistファイルを消去しました。” & return & infoPlistPath buttons {“OK”} default button 1 with icon 1
  end tell
on error
  tell application “Xcode”
    activate
    
display dialog “plistファイルの消去に失敗しました” buttons {“OK”} default button 1 with icon 1
  end tell
end try

–文字置換ルーチン
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

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

2010/10/26 フォルダ差分コピー

指定した2つのフォルダ(A、B)のフォルダを比較して、フォルダAにあってフォルダBにないフォルダを、フォルダBに対してコピーします。

まとめてフォルダをコピーしている最中に、エラーなどで途中でコピーが中断されたような場合に、残りのフォルダをコピーするように作成した「作り捨て」レベルのAppleScriptです。

スクリプト名:フォルダ差分コピー
set aFol to choose folder with prompt "フォルダAを選択してください。"
set bFol to choose folder with prompt "フォルダBを選択してください。"

tell application "Finder"
  tell folder aFol
    set aList to name of every folder
  end tell
  
tell folder bFol
    set bList to name of every folder
  end tell
end tell

set aHasNotBList to {}
repeat with i in aList
  set j to contents of i
  
if j is not in bList then
    set the end of aHasNotBList to j
  end if
end repeat

set bHasNotAList to {}
repeat with i in bList
  set j to contents of i
  
if j is not in aList then
    set the end of bHasNotAList to j
  end if
end repeat

if aHasNotBList is not equal to {} then
  display dialog "フォルダAにあってBに存在しないもの:" & return & list2RETURNseparatedText(aHasNotBList) of me
end if

tell application "Finder"
  repeat with i in aHasNotBList
    set origFol to folder i of folder aFol
    
try
      duplicate origFol to folder (bFol as alias)
    end try
  end repeat
end tell

(*
if bHasNotAList is not equal to {} then
  display dialog "フォルダBにあってAに存在しないもの:" & return & list2RETURNseparatedText(bHasNotAList) of me
end if
*)

–リストをタブ区切りのテキストに変換
on list2RETURNseparatedText(aList)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to return
  
set bList to aList as string
  
set AppleScript’s text item delimiters to curDelim
  
return bList
end list2RETURNseparatedText

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

2010/10/25 指定のフォントをFont Bookから削除する v3

PostScript名称で指定したフォントをFont Bookから削除するAppleScriptです。

以前に、Font Bookからのフォント削除が行えていないと書いていましたが、その後の試行錯誤によって削除できるようになりました。ただし、Mac OS X 10.5以降で動作を確認しているものの、10.4上では削除が行えませんでした。

追記:Mac OS X 10.6上でも削除できませんでした。ほかにもバグがあって……10.6のFontBookの出来がひどすぎる……(ーー;;;

スクリプト名:指定のフォントをFont Bookから削除する v3
set delRes to deleteFontByPSName(“RyuminStd-Ultra-KS”) of me

–Font BookからPostScript nameで指定したフォントを削除
on deleteFontByPSName(aPSNameStr)
  tell application “Font Book”
    –フォントをIDで指定
    
set aFontList to (every typeface whose PostScript name = aPSNameStr)
    
if aFontList = {} then return false
    
    
set aFont to first item of aFontList
    
    
set fConL to font container of aFont
    
    
repeat with i in fConL
      set fCon to contents of i
      
try
        remove fCon
      on error
        return false
      end try
    end repeat
  end tell
  
  
return true
end deleteFontByPSName

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

2010/10/24 Google Chrome for Macがv7.xでAppleScript対応を強化

chrome.jpg

GoogleのWebブラウザ「Google Chrome for Mac」の最新バージョン、7.0.517.41でGoogle Chromium 6.xとほぼ同じレベルのAppleScript対応機能が搭載されました。オープンソース版のChromiumの方が先行してAppleScript強化が行われ、Chromeがそれに追いついた格好です。

Google Chromeは勝手に(サイレントで)オンラインアップデートされるため、このバージョン番号はあくまでも私が確認したものであり、人によって(日によって)異なる可能性があります。

ChromeのAppleScript対応度がChromiumに追いついた……といっても、詳細を調べてみるとまったく同じというわけではありません。

ChromiumとChromeのAppleScript用語辞書をHTMLに書き出して差分(diff)をとってみると、

  Chromium: paste
  Chrome: paste selection

と、paste命令が「paste selection」に変わったことと、ChromiumにはなかったJavascript実行用の「execute」コマンドが搭載されたことが分かりました。

Chromeの「execute」コマンドは、Safariで搭載されている「do JavaScript」コマンドと同じ働きをすることを目指したものと予想されます。これがまともに動作するのであれば、AppleScriptだけではページのローディング完了を厳密に取得できないApple純正のSafariよりも、ChromeのAppleScript対応度が上回ることになります。

さっそく、AppleScriptを書いて試してみましょう。SafariでJavaScript経由でオープン中のページのタイトルを取得するのは、こんな感じです。

スクリプト名:Safariでドキュメントのタイトルを取得
tell application “Safari”
  do JavaScript “document.title” in document 1
end tell
–> “Google”

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

一方、Google Chromeはdocumentオブジェクトが存在せず、windowオブジェクトでしか指定できず……さらに、tabを明確に指定しないとエラーになります。いろいろ試してみましたが……

スクリプト名:Chromeでドキュメントのタイトルを取得
tell application “Google Chrome”
  tell window 1
    tell tab 1
      execute javascript “document.title”
    end tell
  end tell
end tell

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

このようなオブジェクト階層に向けてexecute javascriptコマンドを実行するようですが、結果がつねにmissing valueです。

application “Google Chrome”とか、windowに対してexecuteコマンドを実行しても、エラーになるので、これで正しいオブジェクト階層を指定しているように見えるものの……有意な結果が返ってきません。missing valueが返ってくるだけです。

Google Chromeのexecuteコマンドは、まだ実装途中か……あるいは、まともにデバッグせずに公開してしまったもののようです。私は(現時点では)「使えない命令」だと判断しました。

2010/10/21 指定のフォントファイルをFont Bookに追加して情報を取得する

指定のフォントファイルをFont Bookに追加して各種情報を取得するAppleScriptです。

フォントファイルをFinder上でinfo forなどで突っつく程度ではファイルの種別ぐらいの情報しか得られません。名称や各種情報については、やはりFont Book経由でオープン(インストール)する必要があります。

そこで、任意のフォントのファイルをFont Book経由でインストールするAppleScriptを作成してみました。

ところが……これが苦労の連続で……Font Bookにフォントを登録しても、そのオブジェクト(フォント)への参照が返ってきません。たった今追加したフォントへの参照が得られないわけで、登録したはいいが情報が得られない、という間抜けな状況になってしまいます。

本来ならここであきらめるところですが、登録までできているところが残念です。そこで、Font Bookに対して全フォントのIDを要求、任意のフォントを追加したあとでもう一度全フォントのIDを取得。

処理前の全IDのリストと処理後の全IDのリストで差分をとって、インストールしたフォントのIDだけを抽出します。

環境によっては1,000以上もフォントがインストールされていることもあるため、処理速度の高速化のためにいくつか手を打っておきました(といいつつ、a reference toで間接参照するぐらいしか高速化の手段がないわけですが)。

Font Bookは、かなり動きの怪しいアプリケーションで……勝手にクラッシュすることもたびたびです。Font Bookを相手に時間のかかるバッチ処理を行いたいような場合には、毎回毎回、Font Bookのプロセスがクラッシュしていないか確認を行い、クラッシュしていた場合には強制起動を行うなど、さまざまな配慮が必要です。

スクリプト名:指定のフォントファイルをFont Bookに追加して情報を取得する
global beforeID, afterID, beforeID_r, afterID_r

set aFontFile to choose file

–ファイル名を取得する
tell application "Finder"
  set aName to name of aFontFile
end tell

tell application "Font Book"
  –登録したフォントを特定するために、全フォントのIDを取得
  
set beforeID to ID of every typeface
  
  
–指定のフォントファイルをFontBookに登録する(「ユーザ」コレクションに追加)
  
add aFontFile to font library "User"
  
  
–登録したフォントを特定するために、全フォントのIDを取得
  
set afterID to ID of every typeface
end tell

set beforeID_r to a reference to beforeID
set afterID_r to a reference to afterID

–IDの差分を取って、追加されたIDを算出する
set aIsNotInB to {}
repeat with i in afterID_r
  set j to contents of i
  
if j is not in beforeID_r then
    set the end of aIsNotInB to j
  end if
end repeat

–異常発生時への対応
if length of aIsNotInB is not equal to 1 then
  display dialog "なんかおかしいよ〜"
  
return
end if

set newFontID to first item of aIsNotInB

tell application "Font Book"
  
  
–追加されたフォントの情報を取得する
  
set aProp to properties of every typeface whose ID = newFontID
  
set aaProp to first item of aProp
  
set dispFontName to PostScript name of aaProp
  
  
–指定フォントを削除する?
  
–set enabled of every typeface whose ID = newFontID to false –from font library "User"
  
end tell

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

2010/10/21 Font Bookで指定文字列ではじまるfont collectionをすべて削除する

Font Book上にあるfont collectionのうち、指定文字列ではじまる名称のものをすべて削除するAppleScriptです。

スクリプト名:Font Bookで指定文字列ではじまるfont collectionをすべて削除する
tell application "Font Book"
  delete (every font collection whose displayed name starts with "font_collection_")
end tell

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

2010/10/21 Font Bookでfont collectionを作成する

Font Bookで任意のfont collectionを作成するAppleScriptです。

Font Bookでは、一種のフォルダのような「font collection」を作成してフォントを管理できるようになっています。そのfont collectionを作成するAppleScriptです。

これがなかなかくせ者で……make new font collection with propertiesなどと書いて、プロパティ値を最初から指定してみても……うまくいきませんでした。

そこで、何も指定せずにfont collectionを作成し、作成時にfont collectionへのオブジェクト参照が返ってくるかを確認。無事、返ってきたので、そのfont collectionのnameとdisplayed nameを変更して任意の名称のfont collectionの作成が行えました。

ただ……一括で大量にfont collectionを作成すると、キャッシュされたデータが残るのか、残像のように「名称未設定」font collectionが出来てしまうことがあるので、一度Font Bookを終了して再立ち上げを行うようにしてみました。

本AppleScriptを試すときにはあらかじめFont Bookを起動しておいてください。

なぜこのようなAppleScriptを作ろうとしたかといえば、ファイルサーバー上で管理されているただ置いてあるだけの大量のフォントファイルを自動でFont Bookに登録して、情報を取得してデータベースに突っ込むようなものを作っているときに、一時的にFont Bookに登録したフォントを分類すべくFont Collectionの作成を行ってみた次第です。

ただ……だんだん、Font Collectionの作成に没頭して、世界中で誰もやっていなさそうなFont BookのScriptingに傾倒。

なかなか楽しませていただけましたが、Font Bookからのフォント削除はどーーやっても成功していません。フォントファイルのパスは分かるので、単なるファイルとして削除を行ってしまってもよさそうな感じもしますが、Font Book経由で削除してみたいところです。

スクリプト名:Font Bookでfont collectionを作成する
tell application “Font Book”
  repeat with i from 1 to 10
    –font collectionを作成する前に存在確認  
    
set aNewCollectionName to “font_collection_” & (i as string)
    
set aCollectExist to exists of font collection aNewCollectionName
    
    
–font collectionが存在しない場合にのみ作成を行う
    
if aCollectExist = false then
      set aCollect to make new font collection
      
set execF to false
      
      
repeat 10 times
        try
          tell aCollect
            –片方だけ指定するとおかしなことになる。nameとdisplayed nameの両方を指定しないとダメ
            
set name to aNewCollectionName
            
set displayed name to aNewCollectionName
          end tell
          
set execF to true
          
exit repeat
        on error
          –delay 1–for debug
        end try
      end repeat
      
      
–ループを10回繰り返して、それでも結局エラーだった場合
      
if execF = false then
        display dialog (i as string) & “個目のfont collectionを作成中でしたが、エラーにより中断しました。”
        
return
      end if
      
    end if
  end repeat
end tell

tell application “Font Book” to quit
delay 1
tell application “Font Book” to launch

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

2010/10/07 GUI ScriptingでWebコンテンツを操作

GUI Scriptingでできることは、Mac OS Xのバージョンアップとともに、徐々に広がりを見せつつありますが……実際に試してみて「ついにここまで来たか」と驚かされました。

思えば、Safari自体もバージョンアップにともなって、アクセシビリティ系の機能が向上。このあたりは、読み上げなどの機能がアップしたぐらいにしか考えていなかったのですが……よくよく考えると、アクセシビリティ系の機能がSafariを通じてWebコンテンツにアクセスできるのであれば、AppleScriptもGUI Scriptingを使ってWebコンテンツにアクセスできるのではないか?

やってみたら、大成功。「HTMLコンテンツ」の中にあるフォーム部品(radio button)や画像をクリックしたり、テキストで書かれていることを取得したり……自分には、DOM経由でアクセスするよりも簡単に操作できました(このへんは個人差が……)。

web1.jpg

UI BrowserでSafariのUIを調査……

web2.jpg

▲Safariの「HTMLコンテンツ」から、さらに下位階層を掘り下げていく……

web3.jpg

▲リンクのテキストにアクセス……

このサンプルは、本BlogをSafariでオープンして、ページ上部にあるメニュー「ABOUT」のリンクをクリックします。

この仕組みを利用して、Webブラウザに表示されているフォームにテスト用のデータをAppleScriptから投入し、連続テストを行うことも可能です。

ちなみに、このリストは「ブックマックバー」が非表示の状態で実行したものであり、「ブックマークバー」を表示させた場合には、リンクのクリック部分が、

click static text 1 of UI element 2 of list 1 of UI element 1 of scroll area 1 of group 2 of window 1

となります。

こういうことを考えると、(外部からコントロールできないことが確実な)Flashのコンテンツは勘弁してほしいという気に……。

スクリプト名:GUI ScriptingでWebコンテンツを操作するテスト
–AS HoleのURLをSafariでオープンする
set aURL to “http://piyocast.com/as/”
set webRes to openPageBySafari(aURL) of me

delay 5 –念のため、ページローディング&レンダリングを待つ

activate application “Safari”
tell application “System Events”
  tell process “Safari”
    –ページ上部にあるメニューから、「ABOUT」のテキストをクリックする
    
click static text 1 of UI element 2 of list 1 of UI element 1 of scroll area 1 of group 1 of window 1
  end tell
end tell

–指定のURLをSafariでオープンする
on openPageBySafari(aURL)
  tell application “Safari”
    set d to count every window
    
if d = 0 then
      make new window
      
tell document 1
        set URL to aURL
      end tell
    else
      if aURL is not equal to “” then
        tell document 1
          set URL to aURL
        end tell
      end if
    end if
    
set aRes to page_loaded(10) of me
  end tell
end openPageBySafari

–Safariでオープン中のURLのローディング完了を待つ
on page_loaded(timeout_value)
  delay 2
  
repeat with i from 1 to the timeout_value
    tell application “Safari”
      if (do JavaScript “document.readyState” in document 1) is “complete” then
        return true
      else if i is the timeout_value then
        return false
      else
        delay 1
      end if
    end tell
  end repeat
  
return false
end page_loaded

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

2010/10/07 指定名称のムービーを指定開始-終了時間の間を取り出して指定名称で保存 v1

QuickTime Player 7をコントロールして、現在オープン中のムービーの一部をコピー&ペーストして別名のムービーとして保存するAppleScriptです。

ムービーの一部を切り出して別ファイルに保存するようなことはよくありますが、QuickTime Playerを操作するのは面倒です。何分何秒から何分何秒まで選択してコピーして新規ムービーにペースト…………というのは、かなり煩雑な操作。

そこで、あらかじめリストで{ファイル名、開始時刻、終了時刻}と指定しておけば、そのとおりに小分けしてくれるAppleScriptを作成してみました。本Scriptでだいたいの抜き出しを行っておいて、細かいところ(微修正)については手作業でもいいだろう、ぐらいのスタンスです。

プログラムの中にムービーのファイル名をダイレクトコーディングしていますが、このあたりをもう少し「賢い処理」に書き換えるといいのではないでしょうか。

こうして作業を行ったムービーを、他のコーデック&解像度に変換するのに、いろいろ便利なツールはないかと調べていたら、意外なところで「HandBrake」が一番速くて確実という結果に。なるほど。

スクリプト名:指定名称のムービーを指定開始-終了時間の間を取り出して指定名称で保存 v1
set aData to {{“m1″, “00:01:24″, “00:02:57″}, {“m2″, “00:03:04″, “00:05:43″}, {“m3″, “00:16:51″, “00:18:34″}, {“m4″, “00:18:40″, “00:19:15″}, {“m5″, “00:19:23″, “00:23:53″}, {“m6″, “00:26:43″, “00:27:06″}, {“m7″, “00:24:20″, “00:26:36″}, {“m8″, “00:26:43″, “00:27:06″}, {“m9″, “00:27:14″, “00:28:10″}}

set outFol to choose folder with prompt “ムービー書き出し先フォルダを選択してください”
set targetMovie to “DVD_VIDEO-2.m4v”

repeat with i in aData
  set {aName, sTime, eTime} to i
  
copyAndSaveMovie(outFol, targetMovie, aName, sTime, eTime) of me
end repeat

–指定名称のムービーを指定開始-終了時間の間を取り出して指定名称で保存
on copyAndSaveMovie(outFol, targetMovie, aName, sTime, eTime)
  
  
–QuickTime Player 7をコントロール
  
tell application id “com.apple.quicktimeplayer”
    tell document targetMovie
      set timeScale to time scale
      
set aDuration to duration
    end tell
    
    
set realTime to aDuration / timeScale
    
    
set fromTime to (retTimeBySecond(sTime) of me) * timeScale
    
set toTime to (retTimeBySecond(eTime) of me) * timeScale
    
    
tell document targetMovie
      select at fromTime to the toTime
      
copy
    end tell
    
    
set newMovie to make new document
    
paste document 1 –★重要★ この書き方以外はコンパイル(構文確認)が通らない
    
    
set savePath to (outFol as string) & aName
    
    
tell document 1
      set current time to 0
      
save self contained in file savePath
    end tell
    
  end tell
  
end copyAndSaveMovie

–時刻の文字列を秒に直して返す
on retTimeBySecond(aTime)
  set aList to parseByDelim(aTime, “:”) of me
  
set {hourStr, minuteStr, secondStr} to aList
  
  
set hourNum to (hourStr as number) * 60 * 60
  
set minuteNum to (minuteStr as number) * 60
  
set secondNum to secondStr as number
  
  
return (hourNum + minuteNum + secondNum)
  
end retTimeBySecond

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

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

2010/10/02 SkimでPDFをページごとに分割する

オープンソースのPDFビューワー「Skim」でPDF書類をページごとに分割するAppleScriptです。

たいていオープンソースのアプリケーションといえばAppleScriptへの対応はなかったり中途半端だったり、勘違いした実装を行っているようなもの(FireFoxあたりがその代表例)が普通ですが、このSkimは例外中の例外。バージョンアップとともにAppleScriptの対応度がアップするなど、なかなか見逃せないアプリケーションです。

複数のPDFを1つの書類にまとめる機能を持つものは多々あります。しかし、探してみると1つのPDF書類をページごとに分解する機能を持つものはそれほど見かけません。

調べてみたら、AdobeのAcrobat Reader、Smile SoftwareのPDF Pen、そしてSkimぐらい(以前はPDFtoolkitが使えたのですが、Mac OS X 10.4までしか対応していなかったので)。そのうち、AppleScriptに(まともに)対応しているのがPDFpenとSkim。フリーで入手できるものでいえばSkimしかありません。

そんなわけで、SkimをAppleScriptから制御してページごとにPDFを分解させてみました。

ちなみに、PDFpenには標準でPDFをページ単位に分解するAppleScriptが添付されており、PDFpenのScriptメニューから実行できるようになっていますが、同じデータを処理させてみたところSkimの方が高速に処理できました。

スクリプト名:SkimでPDFをページごとに分割する
set dtPath to path to desktop from user domain
set dtPathStr to dtPath as string

tell application “Skim”
  tell document 1
    set cCount to count every page
    
set cDigit to length of (cCount as string)
    
    
set docName to name
    
    
tell page 1
      set bList to bounds
    end tell
  end tell
  
  
repeat with i from 1 to cCount
    tell document 1
      tell page i
        set anImage to grab for bList –type “PDF”
      end tell
    end tell
    
    
set target_file to dtPathStr & makeFN(i, cDigit) of me & “_” & docName
    
write_to_file(anImage, target_file, false) of me
    
  end repeat
  
end tell

on makeFN(aNum, aDigit)
  set aText to “00000000000″ & (aNum as text)
  
set aLen to length of aText
  
set aRes to text (aLen - aDigit) thru -1 of aText
  
return aRes
end makeFN

–ファイルの追記ルーチン「write_to_file」
–追記データ、追記対象ファイル、boolean(trueで追記)
on write_to_file(this_data, target_file, append_data)
  try
    set the target_file to the target_file as text
    
set the open_target_file to open for access file target_file with write permission
    
if append_data is false then set eof of the open_target_file to 0
    
write this_data to the open_target_file starting at eof
    
close access the open_target_file
    
return true
  on error error_message
    try
      close access file target_file
    end try
    
return error_message
  end try
end write_to_file

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

2010/10/02 アプリのアイコンをJPEG画像化してデスクトップに書き出すv23

Finder上で選択中のアプリケーション(アプリケーションファイル)のアイコンファイルをデスクトップにJPEGで書き出すAppleScriptです。

書き出せるのは、バンドル形式のアプリケーションのアイコンに限ります。本ScriptはScript Menuに登録して呼び出すことを前提に試作したものです。

このAppleScriptを作った当時は古いアプリケーション形式の、1ファイルから構成されるCarbonベースのPowerPC用アプリケーションもたくさん存在していたためにてこずらされましたが、最近はバンドル形式のものばかりになって、解析しやすくなりました。

ただ……アイコンファイルが変な場所に置かれているアプリケーションもたまにあるので、100%の保証はないのですが…………

スクリプト名:アプリのアイコンをJPEG画像化してデスクトップに書き出すv23
on run
  tell application “Finder”
    set a to selection
    
    
if a = {} then
      set aFile to choose file
      
set a to {aFile}
    end if
    
    
repeat with i in a
      set j to contents of i
      
set aClass to class of j
      
      
if aClass = application file then
        writeOutICNS(j as alias) of me
      else
        –do nothing
      end if
    end repeat
    
display dialog “デスクトップへのアイコンの書き出しを終了しました。” buttons {“OK”} default button 1 with icon note
  end tell
end run

–Script Menuから実行するのでドロップレット用のハンドラは不要だが……
on open (filelist)
  repeat with i in filelist
    set j to contents of i
    
writeOutICNS(j) of me
  end repeat
end open

–指定ファイルのアイコンをCFBundleIdentifierの名称でtmpにPNGで書き出す
on writeOutICNS(aFile)
  
  
–set aFile to choose file
  
  
set aPOSIXpath to POSIX path of aFile
  
set appBinPOSIXpath to aPOSIXpath & “Contents/MacOS/”
  
  
–Info.plistの内容を確認して実行ファイルの名称を取得する
  
set plistpath to aPOSIXpath & “Contents/Info.plist”
  
tell application “System Events”
    try
      set infoplistFile to contents of property list file plistpath
      
set anIconFileName to value of property list item “CFBundleIconFile” of infoplistFile
      
set anAppID to value of property list item “CFBundleIdentifier” of infoplistFile
    on error
      –バンドル形式ではなかったもよう
      
display dialog “ERROR”
      
return
    end try
  end tell
  
  
if anAppID = “” or anAppID = missing value then return
  
set anAppID to correctWrongChars(anAppID) of me
  
  
–アイコン名には拡張子を省略してもよいので、ない場合には補う
  
if anIconFileName does not end with “.icns” then
    set anIconFileName to anIconFileName & “.icns”
  end if
  
  
set ifonFileFullPath to aPOSIXpath & “Contents/Resources/” & anIconFileName
  
  
–Resourcesフォルダの直下にicnsファイルが存在しないパターンに備える
  
–各種言語のlprojフォルダの中にicnsファイルが存在しないかをチェック
  
–存在する場合には取得、なければエラー
  
  
try
    set aPathAlias to POSIX file ifonFileFullPath
    
set aPathAlias to aPathAlias as alias
  on error
    set aPathAlias to “”
  end try
  
  
  
try
    tell application “Finder”
      if not (exists file aPathAlias) then
        
        
–Resourcesフォルダの直下にアイコンのファイルが存在していない場合の処理
        
set aPOSIXalias to aFile as string
        
set aPOSIXalias to aPOSIXalias as Unicode text
        
set aOrigPath to aPOSIXalias & “Contents:Resources:”
        
        
–各種言語のlprojフォルダ名称一覧リスト
        
set lprojList to {“Japanese.lproj”, “English.lproj”, “da.lproj”, “Dutch.lproj”, “fi.lproj”, “French.lproj”, “German.lproj”, “Italian.lproj”, “ko.lproj”, “no.lproj”, “pt.lproj”, “Spanish.lproj”, “sv.lproj”, “zh_CN.lproj”, “zh_TW.lproj”}
        
        
set hitF to false
        
        
repeat with i in lprojList
          set j to contents of i
          
set tmpIconFullPath to aOrigPath & j & “:” & anIconFileName
          
tell application “Finder”
            if exists (file tmpIconFullPath) then
              set hitF to true
              
exit repeat
            end if
          end tell
        end repeat
        
        
if hitF = false then
          display dialog “Error in detecting Icon file in application bundle :” & return & aPOSIXpath buttons {“OK”} default button 1
          
return
        end if
        
set this_file to (tmpIconFullPath)
        
      else
        set this_file to (ifonFileFullPath)
      end if
    end tell
    
  end try
  
  
set sText to “cp “ & quoted form of this_file & ” ~/Desktop/tmp.icns”
  
do shell script sText
  
set desktopIcon to (path to desktop as string) & “tmp.icns”
  
  
try
    tell application “Image Events”
      launch
      
set the parent_folder to the path to desktop
      
set this_image to open (alias desktopIcon)
      
set new_name to anAppID & “.jpg”
      
set the new_image to save this_image as JPEG in file new_name of the parent_folder with icon
      
close this_image
    end tell
  on error error_message
    display dialog error_message
  end try
  
end writeOutICNS

on add_extension(this_file, new_extension)
  set this_info to the info for this_file
  
set this_name to the name of this_info
  
set this_extension to the name extension of this_info
  
if this_extension is missing value then
    set the default_name to this_name
  else
    set the default_name to text 1 thru -((length of this_extension) + 2) of this_name
  end if
  
return (the default_name & “.” & the new_extension)
end add_extension

–ファイル名に使用できない文字を置換
on correctWrongChars(aText)
  set a to repChar(aText, “/”, “_”) of me
  
set a to repChar(a, “:”, “_”) of me
  
set a to repChar(a, “\”, “_”) of me
  
return a
end correctWrongChars

–文字置換
on repChar(origText, targChar, repChar)
  set origText to origText as string
  
set targChar to targChar as string
  
set repChar to repChar as string
  
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to targChar
  
set tmpList to text items of origText
  
set AppleScript’s text item delimiters to repChar
  
set retText to tmpList as string
  
set AppleScript’s text item delimiters to curDelim
  
return retText
end repChar

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