●寸法の計算
「小道具その2」が少々ヘヴィだったので、今回はものすご〜く軽い小道具を作りましょう。今回の小道具は「ミリをピクセルに変換する」小道具です。実写の映像制作にはほとんど縁のない、しかしアニメーション制作では必ずついてまわる「原稿の寸法」=「動画」「背景」原稿の寸法のピクセル換算値を計算する小道具を作る事にしましょう。
実写映像の世界で「解像度」の話をすると、大抵「ビデオ解像度」の事を指しますが、今回のターゲットは「スキャン解像度」「印刷解像度」です。アニメーション制作では映像の要素の他にDTPの要素も入り交じりますから、「解像度」とひとくちにいっても、「何の解像度?」「どの行程での解像度?」と言う話になります。例えば、「24cm x 13.5cm」と言う原稿サイズがあった場合、その原稿をどのようにピクセル寸法に変換するのか?‥‥現在の日本のアニメーション制作では「実寸からピクセル寸法」への変換は必要不可欠な要素です。
1cmを何ピクセルとするか?‥‥これをまず最初に決めれば「実寸からピクセル寸法」への変換は簡単に計算できます。しかしこの「1cmを何ピクセルとするか?」は、多くの場合dpi→ドット・パー・インチ、つまり「1インチを何ピクセルとするか?」という変換法で計算されます。「インチって、全然馴染み無いなあ‥‥」と思う事でしょう。私も然り。まず何といっても、文房具屋さんに売っている定規がインチで表記されていないですし、学校でもメートル法で教えられてきました。日本人にインチやフィートで物を考えろと言う方が無理です。
‥‥無理ならば、その無理な部分=「厄介な計算」をコンピュータに代行させれば良いのです。その昔、電算機と呼ばれていたコンピュータは、「電子計算機」の文字通り計算は大得意です。1インチは2.54cmですから、人が暗算で計算するにはちょっと荷が重く時間もかかりますが、コンピュータなら小数点以下何桁までも「瞬時に」計算してくれます。
では早速、「ミリをピクセルに変換する」小道具の製作に入りましょう。
●単位を換える
まずdpi=「ドット・パー・インチ」のインチをミリに換えるところから始めます。「1インチは何ミリだったっけ?」と一生懸命調べなくても、AppleScriptにはちゃんとインチという単位が用意されています。
「1というインチ」、すなわち1インチです。これをミリに換えましょう。しかし、AppleScriptが扱うメートル法の最小単位はセンチメートルなのでまずセンチに変換します。「1 as inches」というひとまとまりを明示するために括弧でくくってから、センチメートルに変換しましょう。
| (1 as inches) as centimeters |
ここで「インチ換算終了! バンザイ!」‥‥と喜ぶのはいくらなんでも早すぎです。人は無意識に「2.54cm」という値を「2.54」に読み換える事ができますが、コンピュータはそうもいきません。明示的にセンチを数字におきかえましょう。先ほどと同じ要領で括弧でくくってから、変換です。
| ((1 as inches) as centimeters) as number |
1センチは10ミリですから、センチをミリに置き換えるには10を掛算します。
| (((1 as inches) as centimeters) as number) * 10 |
これでインチ→ミリの変換倍率が計算できました。掛けるという意味を込めて「x」と言う名の変数にセットしておきましょう。
| set x to (((1 as inches) as centimeters) as number) * 10 |
ここまでくれば、後は単純な計算だけです。240ミリを150dpiで計算した場合のピクセル数は以下のようになります。
あきれるほど簡単です。しかしいつも240ミリで150dpiとは限りませんよね?‥‥使用者がミリとdpiを適宜入力できるようにひと工夫しましょう。
set mm to text returned of (display dialog "ミリを入力" default answer "240")
set dpi to text returned of (display dialog "dpiを入力" default answer "150")
set x to (((1 as inches) as centimeters) as number) * 10
display dialog (mm * dpi / x) as text
|



これで終了!‥‥??‥‥う〜ん、ちょっとアマいですね。小数点以下が満タンの「1417.322834645669」なんていう数値は実際にはほとんど使いません。計算結果が使い勝手に対し、必ずしも適しているとは言えないのが、小道具作りの難しいところです。使い勝手に合わせて、計算結果を使いやすいものに「ネブって」みましょう。
●数字を「丸めて」使いやすく
日常生活の中で、小数点が不要ならばどう処理するでしょうか?‥‥だいたい、四捨五入して処理しますよね。では、以下のように「数値を整数に変換」してみては如何でしょうか。また、合わせて、結果の数値をユーザがコピペできるように、ダイアログ入力欄に結果を表示する仕様に変えてみましょう。
set mm to text returned of (display dialog "ミリを入力" default answer "240")
set dpi to text returned of (display dialog "dpiを入力" default answer "150")
set x to (((1 as inches) as centimeters) as number) * 10
set ans to mm * dpi / x
display dialog mm & "ミリ/" & dpi & "dpiのピクセル数" & (ans as text) default answer (ans as integer) as text
|
「ans as integer」のくだりが、数値(小数点付きの数値)から整数(小数点なしの数値)に「丸めて」いる部分です。「せっかくだから、小数点の数値も知っておきたい!」‥‥と言うニーズもあるでしょうから、ダイアログには計算結果そのものを表示し、テキスト入力ボックスに四捨五入した数値を入れてみました。「俺は逆の方がイイ!」という人は、そのように改造してくださいネ。

ちなみにAppleScriptでは他の言語同様「round」という四捨五入の命令も用意されています。「round」命令の利点は、「繰り上げ」「繰り下げ」などのオプション計算が可能な点ですが、今回は単純な四捨五入しか使いませんので「as integer」を使っています。好きなほうを使ってもらって構いませんよ。
●偶数に丸める
ではさらに調子にのって、「偶数に丸める」計算もしてみましょう。映像制作では扱うピクセル数は偶数のほうが都合が良い事がたくさんあります。インターレースフィールドはその理由の最たるモノですが、少なくとも「1回は2で割り切れる数字」にしておくと色々融通がきいて便利です。1417なんていう数値は仮に「ハーフサイズにする場合、繰り上げる?繰り下げる??」と不要な配慮を生み出します。
偶数にするのは、それなりにトンチを働かせないと命令文にできません。‥‥ちょっとやってみましょう。
まず、偶数奇数の判別は「2で割って余りがでるか?」を判別すればすぐに解ります。例えば、以下の命令文です。
| (1417.322834645669 as integer) mod 2 |
「mod」は割り算の余りを求める命令語です。上記の結果は1です。
さて、ここからが問題。1417を偶数にする場合1416と1418の2つの選択肢があります。まあ、普通に考えて1417.3ならば1418にしますよね?‥‥何故って、1417.3ならば1418の偶数の方が「近い」からです。つまり、この「普通に考えた」内容を単純に命令文で表現すれば「自分の考えと同じ」プログラムが出来上がります。ちょっとやってみましょう。
◆上位偶数から余りを引いた数値と、下位偶数から余りを引いた数値を比べて、近い方(差分の小さい方)の偶数を見つける
if (ans as integer) mod 2 = 1 then
if ((ans as integer) + 1 - (ans mod 2)) < ((ans as integer) - 1 - (ans mod 2)) then
set e to (ans as integer) + 1
else
set e to (ans as integer) + 1
end if
else
set e to ans as integer
end if |
近い偶数を見つける方法はこれだけでしょうか?‥‥まだまだありそうですよ。例えば、こんな方法もありです。
◆余りを比較して、もし1より小さい場合は下位偶数に近いと判断し、1より大きい場合は上位偶数に近いと判断する
if (ans as integer) mod 2 = 1 then
if ans mod 2 < 1 then
set e to (ans as integer) - 1
else
set e to (ans as integer) + 1
end if
else
set e to ans as integer
end if |
他にももっとあると思います。自分ならこうする!‥‥と言う人はそのように命令文で表現すれば良いのです。他人が作ったルーチンを丸写しするよりは、少々命令文が長くなっても自身で考案したルーチンで「近い偶数」を見つければ、それで「結果オーライ」です。それに、後々自分でプログラムコードの内容を改良する際、理解の及ばぬ(またはどうしても馴染めない)借り物のルーチンが重要な箇所を占めていると手を下せなくなります。「自分の作った小道具の整備と改良は自分でする」と言う基本原則を実現できるよう、多少遠回りになっても自分なりのルーチンで作ることをお勧めします。
では、「整数に丸める」「偶数に丸める」ルーチンを組み込みましょう。表示する結果が増えたので、ダイアログ文を数行に分けます。「"」の囲みの中で改行した文章はちゃんとダイアログ上でも改行されます。
set mm to text returned of (display dialog "ミリを入力" default answer "240")
set dpi to text returned of (display dialog "dpiを入力" default answer "150")
set x to (((1 as inches) as centimeters) as number) * 10
set ans to mm * dpi / x
if (ans as integer) mod 2 = 1 then
if ans mod 2 < 1 then
set e to (ans as integer) - 1
else
set e to (ans as integer) + 1
end if
else
set e to ans as integer
end if
display dialog mm & "ミリ/" & dpi & "dpiのピクセル数:
計算結果:" & (ans as text) & "
推奨偶数値: " & (e as text) default answer (ans as integer as text)
|

●最後の仕上げ
あともうひと工夫しましょう。「まだ、イジるの〜?」と言わないでください。ここでもう一工夫しておけば、この道具を使う際の快適度は、使うたびに実感できるのですから!
毎度同じ「240」「150」が表示されるのは果たして使い勝手が良いと言えるでしょうか?‥‥前回の入力を憶えておく機能があると便利かも知れませんよ。前回の入力を憶えておく‥‥すなわち、mmやdpiなどの変数が「蒸発」して消失しないようにどこかに留めておく必要があります。そんな用途には、「property」が使えます。使い方はこんな感じです。
property mm : 240
property dpi : 150 |
property mm : 240‥‥の「240」は変数mmの初期値です。このように命令文に書く事で、変数の内容をアプリケーション内部に保持する事が可能です。「property 変数名 : 初期値」を文頭に宣言しておくだけで、変数「mm」「dpi」に格納したユーザ入力は次回入力時まで保持されます。以下のように、組み込んでみましょう。
property mm : 240
property dpi : 150
set mm to text returned of (display dialog "ミリを入力" default answer mm)
set dpi to text returned of (display dialog "dpiを入力" default answer dpi)
set x to (((1 as inches) as centimeters) as number) * 10
set ans to mm * dpi / x
if (ans as integer) mod 2 = 1 then
if ans mod 2 < 1 then
set e to (ans as integer) - 1
else
set e to (ans as integer) + 1
end if
else
set e to ans as integer
end if
display dialog mm & "ミリ/" & dpi & "dpiのピクセル数:
計算結果:" & (ans as text) & "
推奨偶数値: " & (e as text) default answer (ans as integer as text)
|

↓↓↓↓ 240を260に書き換える ↓↓↓↓


↓↓↓↓ 150を125に書き換える ↓↓↓↓

結果は以下の通り

次回立ち上げた際の表示


ちゃんと、前回入力した数値が表示されている
ちなみにこの「property」は命令文全文で使用可能な「グローバル変数」です。プログラムが複雑化、高度化してくると、多種多様なルーチンを本文とは別に組み込むようになりますが、その際「全ルーチンで共有できる変数」が「グローバル変数」です。‥‥しかし、今まで解説してきたAppleScriptはすべて単文(単ブロック内で完結)で書いていますので、「グローバルか否か」という区分けを実感することはありません。プログラムの基本にも慣れ、より複雑な内容の小道具を作る際に、「グローバル変数」の扱いにチャレンジしてみてください。
そして、最後の最後、「キャンセルするまで問い合わせる」仕組みを組み込んでみましょう。つまり、ユーザがダイアログのキャンセルボタンまたはescキーを押すまで、新たな計算を繰り返すという仕組みです。これは好みの部分が大きいですから、もし必要なかったら組み込む必要はありません。
property mm : 240
property dpi : 150
repeat
set mm to text returned of (display dialog "ミリを入力" default answer mm)
set dpi to text returned of (display dialog "dpiを入力" default answer dpi)
set x to (((1 as inches) as centimeters) as number) * 10
set ans to mm * dpi / x
if (ans as integer) mod 2 = 1 then
if ans mod 2 < 1 then
set e to (ans as integer) - 1
else
set e to (ans as integer) + 1
end if
else
set e to ans as integer
end if
display dialog mm & "ミリ/" & dpi & "dpiのピクセル数:
計算結果:" & (ans as text) & "
推奨偶数値: " & (e as text) default answer (ans as integer as text)
end repeat
|
「キャンセルするまで続ける」にはどうしたら良いでしょうか?‥‥そのような「動き続ける」ニーズには、「無限ループ」を使います。この場合の無限ループは以下のような段取りとなります。
- ユーザが実寸ミリ数値を入力する
- ユーザがdpi数値を入力する
- 結果を表示する
- ユーザがキャンセル/OKボタンもしくはesc/returnキーを押すまで、待機状態
- もしユーザがキャンセルしなかった場合は、1に戻ってリピート
無限ループと聞くと「出口なし」のようなイメージがありますが、ちゃんと出口は用意してあります。また、コンピュータの計算余地をすべて占有する性質(タチ)の悪い無限ループではありませんから、他のプロセス(アプリケーション)に悪影響もありません。

結果表示ダイアログのOKボタンをクリック(またはreturnキーをタイプ)すると即座にまた最初の入力画面が表示される

ハイ、これで小道具3はすべて終了! 全部で20行の簡単な命令文でしたが、いざと言う時には役に立つ小道具です。今回は20行でしたが、10行にも満たない数行のプログラムでも、作業場面によっては多いに役立つ小道具になる事もあるのです。
| AppleScript メモ:よくある数値計算、あれこれ |
|
■小数点1つくらいは欲しい
たとえば、1417.322834645669から1417.3を得るにはこんな感じで計算します。
set val to 1417.322834645669
set newVal to ((val * 10) as integer) / 10 |
10をかけて、四捨五入し、10で割る‥‥何のヒネりも無い、簡素なルーチンですネ。
■0から255までの数値を16進数表記に変換したい
0から255までの10進数の数値を、0からFの16進数2桁の数値に変更するルーチンです。エラーハンドリング(エラー発生時の対応処理)も組み込んでいるので、ご参考にどうぞ。ちなみに、ボタン名を"Cancel"または"キャンセル"にしてクリックすると、故意にエラーを発生させて処理終了する事が可能です。
property char : {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70}
set val to text returned of (display dialog "0から255の数値を入力" default answer "")
try
set val to val as integer
if not (val > -1 and val < 256) then error
on error msg
display dialog msg buttons "Cancel" default button 1 with icon 0
end try
display dialog (val as string) & "の16進数値" default answer ((ASCII character (item (val div 16 + 1) of char)) & (ASCII character (item (val mod 16 + 1) of char))) as string
|
■連番に使う4桁の数列が欲しい
実際にプログラムを実行してみるとわかりますが、0001は1になってしまいます。これは困った。
|
set val to "0001" as number
結果:1
|
私たちが読みやすい「任意桁の数列」の先頭のゼロは数値計算した際にすべて消えてしまいます。まさかプログラムの都合で、1.tga〜9.tga, 10.tga〜99.tga, 100.tga〜999.tga,.....とする訳にもいきません。どうすれば良いか、いろいろ作って見ましょう。
|
地道にゼロを追加するルーチン
set |番号| to (text returned of (display dialog "番号は?" default answer "1")) as integer
set |桁数| to (text returned of (display dialog "桁数は?" default answer "4")) as integer
set |番号の文字列| to |番号| as string
repeat |桁数| - (length of (|番号| as string)) times
set |番号の文字列| to "0" & |番号の文字列|
end repeat
display dialog "結果" default answer |番号の文字列|
|
足りないゼロを現在の数文字列に追加する「強行手段!」と言った感じのルーチンですね。このルーチンなら10桁だろうが1000桁だろうが全部追随できる強みを有していますが、ルーチン的にはなんとも野性味あふるるものとなっていますネ。

20桁でもOK!!‥‥でも‥‥。
他には、以下のようなルーチンも考えられます。
|
べき算と文字列抜粋を使ったルーチン
set |番号| to (text returned of (display dialog "番号は?" default answer "1")) as integer
set |桁数| to (text returned of (display dialog "桁数は?" default answer "4")) as integer
set |底数| to (10 ^ |桁数|) as integer
set |番号の文字列| to (characters 2 thru -1 of ((|底数| + |番号|) as string)) as string
display dialog "結果" default answer |番号の文字列|
|
今度のルーチンは、暫定の数値を設定し最後に先頭の1を取るなど、少々ひねっていますが、構造そのものはとても簡素です。repeat文が無いので速度向上も期待できます。しかし「9桁以上は表示が崩れる」と言う欠点もあり、一長一短です。

正常な8桁の結果

散々な9桁の結果
映像制作に使うフレーム数は9時間でも6桁内で収まっていますから、8桁の制限付きでも撮影エフェクト業務で困ることはほとんどありません。一定桁数で繰り上げてゼロに戻すなど、状況に合わせてルーチンを工夫すれば良いわけです。
さて、試しに上記ルーチンを用いて、連番生成の小道具を作ってみました。キーボードをタイプしてA_0001.tga〜A_0100.tgaの数列を書くのは、そりゃもう大変ですが、コンピュータに命令すれば百個の数列生成など屁でもありません。
|
連番ファイル名を作り出すルーチン
set |ヘッダ| to text returned of (display dialog "文字列ヘッダは?" default answer "A_")
set |フッタ| to text returned of (display dialog "文字列フッタは?" default answer ".tga")
set |開始番号| to (text returned of (display dialog "開始番号は?" default answer "1")) as integer
set |終了番号| to (text returned of (display dialog "終了番号は?" default answer "100")) as integer
set |桁数| to (text returned of (display dialog "桁数は?" default answer "4")) as integer
set |底数| to (10 ^ |桁数|) as integer
set |出力文字列| to ""
repeat with i from |開始番号| to |終了番号|
set |出力文字列| to |出力文字列| & |ヘッダ| & ((characters 2 thru -1 of ((|底数| + i) as string)) as string) & |フッタ| & return
end repeat
display dialog "結果" default answer |出力文字列|
|
結果はこんな感じです。
A_0001.tga
A_0002.tga
A_0003.tga
A_0004.tga
A_0005.tga
A_0006.tga
A_0007.tga
A_0008.tga
A_0009.tga
A_0010.tga
A_0011.tga
A_0012.tga
A_0013.tga
A_0014.tga
A_0015.tga
A_0016.tga
A_0017.tga
A_0018.tga
A_0019.tga
A_0020.tga
A_0021.tga
A_0022.tga
A_0023.tga
A_0024.tga
A_0025.tga
A_0026.tga
A_0027.tga
A_0028.tga
A_0029.tga
A_0030.tga
A_0031.tga
A_0032.tga
A_0033.tga
A_0034.tga
A_0035.tga
A_0036.tga
A_0037.tga
A_0038.tga
A_0039.tga
A_0040.tga
A_0041.tga
A_0042.tga
A_0043.tga
A_0044.tga
A_0045.tga
A_0046.tga
A_0047.tga
A_0048.tga
A_0049.tga
A_0050.tga
A_0051.tga
A_0052.tga
A_0053.tga
A_0054.tga
A_0055.tga
A_0056.tga
A_0057.tga
A_0058.tga
A_0059.tga
A_0060.tga
A_0061.tga
A_0062.tga
A_0063.tga
A_0064.tga
A_0065.tga
A_0066.tga
A_0067.tga
A_0068.tga
A_0069.tga
A_0070.tga
A_0071.tga
A_0072.tga
A_0073.tga
A_0074.tga
A_0075.tga
A_0076.tga
A_0077.tga
A_0078.tga
A_0079.tga
A_0080.tga
A_0081.tga
A_0082.tga
A_0083.tga
A_0084.tga
A_0085.tga
A_0086.tga
A_0087.tga
A_0088.tga
A_0089.tga
A_0090.tga
A_0091.tga
A_0092.tga
A_0093.tga
A_0094.tga
A_0095.tga
A_0096.tga
A_0097.tga
A_0098.tga
A_0099.tga
A_0100.tga
いや、ほんとに長い。しかし「この程度」の雑事でしたら、コンピュータならあっという間に完了です。
■カンマ秒数をタイムシートのコマ数に変換したい
60進数でカウントする分と秒、100進数でカウントするゼロカンマの秒数。コイツをアニメ制作(と、ハリウッド)で使用している24FPS(1秒間24コマ)=24進数の数値にパパっと変換したい場面は、よくあるのではないでしょうか。すなわち、「5.68秒って、結局何コマ?」と言う問いに答えるルーチンです。
|
ストップウォッチ秒数をコマ数に変換するルーチン
property fps : 24
set res to (text returned of (display dialog "秒数は?
(1.50などのストップウォッチの数値を入力)" default answer "1.5")) as Unicode text
set AppleScript's text item delimiters to ":" as Unicode text
set tim to text items of res
set AppleScript's text item delimiters to ""
repeat
if length of tim > 2 then exit repeat
set tim to {"0"} & tim
end repeat
set kVal to (((item 3 of tim) as real) * fps) as integer
set kMod to kVal mod fps
set kDiv to kVal div fps
set sVal to (((item 1 of tim) as integer) * 60 * 60) + (((item 2 of tim) as integer) * 60) + kDiv
display dialog "[" & (res as string) & "]のfpsfps換算コマ数:" default answer "尺:(" & (sVal as string) & "+" & (kMod as string) & ")
コマ数:" & (((sVal * fps) + kMod) as string)
|


24コマに変換&24コマ上での四捨五入を処理し、結果を表示
「秒 to コマ」換算のルーチン自体はとても簡単です。何よりもこのルーチンのキモ=難しさは、「数値に24や60をかけて‥‥」という変換計算よりも、ユーザインターフェイスの方、つまり「ユーザの異なる入力スタイルに追随」する部分です。
ストップウォッチはご存知のように秒数だけでなく、時間や分も表示されます。
単に「1.53秒」「6.84秒」と言う秒の数値入力しか受け付けないルーチンは、「ストップウォッチの表示数値を変換する」ルーチンとしては少々ショボいと思いませんか?‥‥だからといって、プログラマの都合で「必ず時間は『時:分:秒.ゼロカンマ』で入力しなければならない」と決めるのも、使う側にとっては、「0.5を入力するのにいちいち0:0:0.5と入力させるか?」と大きな不満の原因となります。
ではどうすべきか?‥‥ユーザが例えば61.5秒を「61.5」「1:1.5」「0:1:1.5」「0:61.5」‥‥など色々な書式で表現した入力値に対し、正常に処理する能力をちゃんと用意しておけば良いのです。
まず必要なのは、ユーザが「:」で区切ったかどうかの判別。その次は「時、分、秒の3要素が揃っているか」の判別と補完、そしてようやく秒からコマへの換算です。


秒数のみのユーザ入力で正常な結果


分と秒数のユーザ入力においても正常な結果


時と分と秒数のユーザ入力においても正常な結果
こうした工夫は、何よりも自作の小道具を使う「自分の為」です。少々手間でも実装したほうが良いでしょう。
ちなみに、AppleScriptでは""=何も入力無しの値は、整数に変換するよう命令した場合、0に変換されます。しかし、""を実数(real)に変換しようとしてもエラーが発生します。そしてもちろん、「あいうえお」を数値に変換することはできません。


この辺のエラーハンドリング(エラー発生時の取り扱い)は、自分しか使わない場合は徹底しなくてもよいでしょうね。「数値を入力せよ」とダイアログしているのに、そのダイアログを作った張本人が「あいうえお」なんて入力する事はないでしょうし、もし勘違いしてエラーが発生しても自分の書いたコードですからすぐに原因が解るでしょう。誰が使うか、どんなスキルの人間が使うかが特定できる自作の小道具ソフトウェアは、何よりもエラーハンドリングの手間が格段に減るのが長所と言えます。‥‥もちろん、見ず知らずの他者に、しかも有料(たとえ¥50でも!)で配布する場合は、エラーハンドリングの省略・手抜きは「ご法度」です。
|
|