Archive for 9月, 2011

2011/09/25 TextWranglerで連続置換を指定フォルダ内のhtmlファイルに対してすべて実行

TextWranglerで連続置換を指定フォルダ内のhtmlファイルに対してすべて実行するAppleScriptです。

冒頭の「指定フォルダ内のHTMLを取得する」とか、HTMLの置換内容自体はドーでもよくて、「TextWrangler上での文字置換の方法のサンプル」としてのみ価値があります。

TextWranglerはGUI画面側からもAppleScript上からもよく使っており、これなしでは各種作業が滞ります。単なるテキストファイルを操作するだけなら直接テキストファイルを読み込んで処理すればよいのですが、文字コードを厳密に指定しなければならないような場合には、テキストエディタをAppleScriptでコントロールする必要が出てきます。勝手に書き換えたりするのはまずいので。

そんな時に国産のテキストエディタは……Jedit Xは何か全力で間違った方向に突っ走っているし、miだとAppleScript側から使える機能がいまひとつ。本来はBBeditを活用すべきところですが、そこまで重武装のエディタは必要ないし……結果としてTextWranglerが大活躍することに。

たぶん、(フリーなのに使えまくる)TextWranglerがなくなったらものすごく困ると思います。

スクリプト名:TextWranglerで連続置換を指定フォルダ内のhtmlファイルに対してすべて実行
set aFol to choose folder

tell application "Finder"
  tell folder aFol
    set aList to (every file whose name ends with ".html") as alias list
  end tell
end tell

tell application "TextWrangler"
  repeat with i in aList
    close every text document
    
open i
    
    
set anID to 65 –Ascii number of "A"
    
    
repeat
      set fRes to find "<input type=’radio’ name=’Choice’" searching in text of text document 1 options {starting at top:true}
      
set fFlag to found of fRes
      
      
if fFlag = false then exit repeat
      
      
set fObj to found object of fRes
      
      
select fObj
      
      
set contents of selection to "<input type=’radio’ name=’Choice" & (ASCII character anID) & "’"
      
set anID to anID + 1
    end repeat
    
    
close text document 1 saving yes
    
  end repeat
end tell

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

2011/09/25 PDFのページ数をカウントする v3

Mac OS X 10.5以降で、PDFのページ数をカウントするAppleScriptです。

よそで拾ってきたScript(どこで拾ってきたか忘れてしまいました)がサブルーチンになっていなかったので、サブルーチン化したぐらいで書き換えはほとんどやっていないのですが……とりあえずGUI Scripting経由でページ数を取得するとかいう「悪い冗談」みたいな処理ではないので安心感があり、よく使っています。

Mac OS X 10.7以降であればrubyの部分をAppleScriptObjCに書き換えてみてもよさそうですが……わざわざ10.5/10.6で動かないように作ってもしょうがないですし、専用のバンドル形式のランタイムでないと動作しない(AppleScriptエディタ上で記述する)AppleScriptObjCはイマイチではないかと。AppleScriptObjCの記述はさすがにXcode上で行うことがほとんどです。

スクリプト名:PDFのページ数をカウントする v3
set aPDF to choose file of type "com.adobe.pdf"
set pNum to pdfCount(aPDF) of me

–指定PDFのページ数をかぞえる
on pdfCount(aPDF)
  return ((do shell script ("ruby -e \"require ‘osx/cocoa’;include OSX;require_framework ‘Quartz’;print PDFDocument.alloc.initWithURL(NSURL.fileURLWithPath(" & (quoted form of POSIX path of aPDF) & ")).pageCount\"")) as number)
end pdfCount

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

2011/09/25 指定フォルダ内のPDFの1ページ目のみ取り出して別フォルダに保存 v2

指定フォルダ内のPDFの1ページ目のみ取り出して、別フォルダに1ページ目だけのPDFを保存するAppleScriptです。

オープンソースなのにAppleScript対応度のきわめて高いPDFビューワー「Skim」をコントロールして、PDFの指定ページ上にコンテンツが存在しないかのチェック、およびページ切り出しを行っています。

ここでいうPDFは、ドキュメントスキャナーで読み込んだPDFではなく、何らかのアプリケーションから書き出したPDF(文字情報が選択できる)を意図しています。

大量のHTMLを印刷する際に、1枚ずつプリンタに送ると時間がかかるため、CLIのHTMLレンダラー(wkpdf)にかけて大量のPDFを生成。この大量のPDFを1つのドキュメントにまとめてプリンタに送れば、印刷時間の圧倒的な短縮が可能になるのではないか、という話を実現する過程で作成したものです。

だいたいは思い通りに行ったのですが、誤算がひとつ。HTMLレンダラーが1ページ分のコンテンツも2ページにまたがってPDF出力(しかも2ページ目は空白)することが多く……単純に1ページ目のみ抽出しようとしても、今度は本当にHTMLの分量が多くて複数ページにまたがってレンダリングされている場合もあったために、単純作業で2ページ以降を捨てるのでは困るということになりました。

そこで、ほとんど文字情報から構成されるコンテンツであったため、2ページ目に何か文字の情報がないかSkimをコントロールしてAppleScriptでチェックし、存在しなければ1ページ目のみ抽出。存在している場合には抽出処理を行わないようにしました。

人間が目で見て確認しなくてよいので、作業の飛躍的な高速化を実現できました。もちろん、印刷もあっという間。

もし、文字情報が入っていない画像系のPDFが対象だったら……解像度を指定してPhotoshopで読み込み、ヒストグラムを取得するなどして情報の有無を判定すると楽ができてよいでしょう。

スクリプト名:指定フォルダ内のPDFの1ページ目のみ取り出して別フォルダに保存 v2
set inFol to choose folder with prompt “処理対象のPDFが入っているフォルダを指定”

set dtPath to choose folder with prompt “出力先フォルダを選択”
set dtPathStr to dtPath as string

tell application “Finder”
  tell folder inFol
    set aFileList to (every file whose name ends with “.pdf”) as alias list
  end tell
end tell

–それぞれのPDFの1ページ目のみ抽出
repeat with i in aFileList
  trimPDF(i, dtPathStr) of me
end repeat

–PDFの最初のページのみトリミング
on trimPDF(aFile, outFol)
  tell application “Skim”
    close every document
    
    
open aFile
    
    
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
      
      
if cCount > 1 then
        tell page 2
          set aProp to properties
          
set aText to first item of text of aProp
        end tell
        
        
if aText is not equal to “” then
          
          
display dialog “書類「” & docName & “」は、2ページ目に実際に内容が存在するため、2ページ目を削除せずそのままコピーします。”
          
          
tell application “Finder”
            set target_file to outFol & docName
            
            
duplicate aFile to file target_file
            
          end tell
          
          
return –ここが重要
          
        end if
      end if
    end tell
    
    
tell document 1
      tell page 1
        set anImage to grab for bList –type “PDF”
      end tell
    end tell
    
    
set target_file to outFol & docName
    
write_to_file(anImage, target_file, false) of me
    
    
close every document
    
  end tell
end trimPDF

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

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

2011/09/25 1〜指定数までの乱数を返す、ただし別途指定の数(aException)を除く

1〜指定数(aMaxNum)までの乱数、ただし別途指定の数(aException)を除くものを返すAppleScriptです。

クイズ系のWebコンテンツのデータのデバッグを行う際に、SafariをAppleScriptからコントロール。Formに正解を突っ込んで1000問以上のすべての問いが正常に動作しているかどうかを検証するという仕事がありました。

本来は正解だけ突っ込んでチェックすれば、それでよかったのですが……それでは不足ではないかということで、「不正解の答えを入れて、必ず不正解になるかどうか」もチェックしようということになりました。

そこで、本ルーチンを作って「正解以外の選択肢」を選ばせるようにした次第です。

# 初回掲載時、内容に間違いがあったため、差し替えを行っています(2011/9/25)

スクリプト名:1〜指定数までの乱数を返す、ただし別途指定の数(aException)を除く
calcRandomNumWithExpection(5, 3) of me

–1〜指定数までの乱数を返す、ただし別途指定の数(aException)を除く
on calcRandomNumWithExpection(aMaxNum, aException)
  repeat
    set aRND to random number from 1 to aMaxNum
    
if aRND is not equal to aException then
      return aRND
    end if
  end repeat
end calcRandomNumWithExpection

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

2011/09/17 Mac Blu-ray Playerをコントロール

br5.jpg

友人のBlogで紹介されていて気になっていた「Mac Blu-ray Player」(バージョン1.8.3.0623)。本当に使えるのか? これって本気なのか? シェアウェア登録しちゃって大丈夫なのか? ホームページに開発元の住所が書かれてないけど、訴えられたら逃げる気マンマンなんじゃないのか? などなど……疑問の尽きないソフトウェアですが、ぴよまるソフトウェアの相棒がBlu-rayドライブ(SK-BRP-6U)を買ってつないでみたら「ちゃんと再生できた」とのことだったので、ドライブ+BDソフトを借りて検証してみました。

試してびっくり、なんと驚きのScriptable。AppleScriptエディタにアプリケーションをドラッグ&ドロップしてAppleScript用語辞書が表示され、喫茶店でどよめいてしまいました。

br1.jpg

MacBook Air 2011 midモデルにつないで検証。実行にはインターネット接続環境が必須

br3.jpg

バスパワー駆動可能なポータブルBlu-rayドライブ「SK-BRP6U」。Panasonicのドライブユニットを採用だとか

br2.jpg

起動してみると、ちゃんと日本語でメニューやらボタンやらが表示されています。BDのソフト市場は日本以外ではまともに立ち上がっていないと思われるので、日本語ローカライズは必須の機能と考えられます

br4.jpg

MacBook Airでは部分的に描画系のパワー不足を感じたので、MacBook Pro 17インチ 2010にチェンジ。こちらでは不満はまったくありませんでした

Mac Blu-ray Playerが持っているAppleScript用語は、playURL、eject、play、stop、prev、next、forward、backward、volumeUp、volumeDown、mute、fullscreen、snapshotの各コマンド。一応、Standard Suiteのopenとかquitなどの一般的なコマンドも使えるようです。

とりあえず、BDソフトの再生を行いたいところですが……ここで「play」コマンドを実行しても、再生は行われません。

アプリケーションにBDソフトをオープンさせなくてはならないので(このあたり、まだものすごくこなれていない感じが)、いろいろ試行錯誤してみたら……

スクリプト名:Mac Blu-ray PlayerでBD再生
set aBD to choose folder

tell application “Blu-ray Player”
  open aBD
end tell

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

こんな感じで、choose folderでBDのルートフォルダを指定してあげると再生できました。

bd7.jpg

playコマンドは、一時停止している状態で実行すると受け付けるようですが……じゃあ、その一時停止状態にするためのコマンドは? と、「stop」コマンドを実行してみると……起動直後のBDディスクを認識していない状態に戻ってしまうので、playコマンドはいまのところ使えません(なんだそれ?!)。後述しますが、現状ではplayコマンドは早送り/巻き戻し状態から通常再生モードに戻るためだけに使えるようです。

一般的かつ常識的な意味でのBDソフトの「再生」を行いたい場合には、openコマンドでソフトを指定してください。

pauseコマンドがついてないと、使えないよ〜>誰となく

forwardとかbackwardコマンドは使えるのかと試してみたら、30秒ごとに早送り/逆戻りを行うようです。チャプター間の移動はできません。

で、一回forwardとかbackwardコマンドを発行すると、30秒単位でスキップしながら前または後ろに向けて再生を行うので、通常再生状態に戻したいときにはここで「play」コマンドを実行します(なんだそれ?!!)。

チャプター間の前後移動は「prev」「next」コマンドで行えますが、チャプターのリストを取得するとか、具体的にどのチャプターに移動するとかいうことはできません。GUI Scriptingを使ってメニュー内容からチャプターを取得することは不可能ではないようですが、操作のたびにメニューが表示されるというのはナンセンスです。

volumeUp/VolumeDownコマンドはありますが、具体的に数値を指定して任意の音量レベルに設定することができません(このあたりで遠い目に……)。

BDソフトの再生中に「fullscreen」コマンドを実行するとフルスクリーン再生モードに移行しますが、フルスクリーン再生状態から通常再生に戻る手段がありません。

唯一期待どおりの動作を行ってくれたのがsnapshotコマンド。現在表示中の画面内容をデスクトップに「スナップショット-2011-09-17 at 10_53_55 PM-1120860989.png」といったファイル名でPNG画像で保存します。ファイル名とかファイル形式とか書き出し先のフォルダなどは一切指定できません。

ejectコマンドについても言及しておく必要があるでしょう。ejectコマンドは、とりあえずBDのディスクをマウントした状態であれば実行して大丈夫です。BDソフトの再生中にejectコマンドを実行すると、問答無用でBDディスクがイジェクトされます。せめて再生中はejectできないように管理すべきだと思うのですが……

存在自体がツッコミどころ満載の本ソフト、AppleScriptで操作しようと試みると、さらにツッコミどころ満載ですが……それでも動作していること自体を評価すべきなのかもしれません。