スポンサード リンク

Project N: 025 - Subtitle フィルタの複数行サポート(AviSynth v2.57 以降)

AviSynth 2.5.7 から、Subtitle フィルタにおいて複数行の文字列の表示が可能になっています。これまで tategaki というユーザー定義関数を作って、半ば無理矢理、縦書きを実現していましたが、もうその必要もなくなりました。

Subtitle フィルタで複数行の文字列を表示するためには、具体的に次の 2 つの条件を満たす必要があります:

  1. lsp パラメータを明示する。
  2. 文字列中の改行したい箇所に \n (バックスラッシュ+n。日本語環境では、円記号+n(ともに半角))を挿入する。

これで \n の部分で改行されるようになります。実際に試してみましょう:

BlankClip(width=320, height=240)
Subtitle("Line 1\nLine 2\n\nLine 4", lsp=0)

Subtilteフィルタの複数行のテスト

3 行目は空なので、空行(改行のみ)になっています。

これまで tategaki という自作の関数で実現していたものを、2.5.7 以降の Subtitle フィルタに置き換えるとこのようになります。

# 固定値の指定
font = "Courier NEW" # フォント
font_size = 18 # フォントのサイズ
font_color = $6FE47A # フォントの色
halo_color = $11B301 # 文字の縁の色
lsp = 0 # lsp パラメータ
# 背景
BlankClip(width=320, height=240)
# AviSynth 2.57 以降
Subtitle("A\nB\nC\nD\nE\n", 4,0, 0,0, font, font_size, font_color, halo_color, lsp=lsp)

Subtilteフィルタの複数行のテスト2

このままでは、少し文字と文字との縦の間隔が空いているように見えます。このようなときは、lsp パラメータの値を変更することで行間のスペースを調整することが可能です(lsp は line spacing に由来)。たとえば lsp = -24 にすると、このようになります:

Subtilteフィルタの複数行のテスト3

逆に lsp の値を大きくすると、行間が広くなります。

なお、Subtitle フィルタや lsp パラメータの詳細は、マニュアルを参考にしてください。AviSynth WikiSubtitle フィルタのページは古いままなので、複数行に関する説明はありません(2008-03-06 現在。後日、新しい訳に差し替える予定)。

関連記事

Project N: 024 - 文字雨(Animateフィルタを使う)

関数化することによって、1 行で文字の縦書き(みたいなの)が可能になりました。

しかし、これだけでは不十分です。なぜなら、縦書き文字列を動かす(動いているように見せる)ためには、以下のように一部のパラメータの値を変化させたコマンドを、いちいち書かなければならないからです。

# Import("tategaki.avs") # インポートする場合
bg = BlankClip(width=320, height=240)
bg.tategaki(4, 0, 0, 0, "A", "B", "C", "D", "E")
tategaki(4, 10, 1, 1, "A", "B", "C", "D", "E")
tategaki(4, 20, 2, 2, "A", "B", "C", "D", "E")
return last

上のスクリプトをよく見ると、使っている関数は自作の tategaki 関数だけで、y, start, end の 3 つの値だけが一定の割合で変化していることがわかります。

AviSynth には、このようにパラメータが連続的に変化する同一のフィルタ(関数)を評価するメタフィルタがあります。それは、Animate フィルタです。

Animate フィルタの書式と引数

Animate(clip clip, int start_frame, int end_frame, string filtername, start_args, end_args)
  • start_frame: 開始フレーム。
  • end_frame: 終了フレーム。
  • filtername: 評価するフィルタ(または関数)。
  • start_args: start_frame 時の filtername の引数。
  • end_args: end_frame 時の filtername の引数。

start_frame と end_frame の中間のフレームでは、引数は補間されます。

Animate フィルタを使ってみる

イメージ

start_frame と end_frame のときに、それぞれ上の図の位置に文字が来るようにしてみます。このとき、start_frame では y = 0、end_frame では y = 170 です。

# Import("tategaki.avs") # インポートする場合
bg = BlankClip(width=320, height=240)
Animate(bg, 0, 29, "tategaki", 4,0,0,0,"A","B","C","D","E", 4,170,29,29,"A","B","C","D","E")
return last

start_frame = 0, end_frame = 29 とすると、スクリプトは上記のようになります。

Animate(0, 29, "tategaki", bg,4,0,0,0,"A","B","C","D","E", bg,4,170,29,29,"A","B","C","D","E")

Animate フィルタは、このように記述することもできます。

サンプル動画

サンプル動画(MPEG-1, 84KB)

上記のスクリプトを、MPEG-1 形式の動画に変換してみました(30 フレーム以降をカットし、音声なしにしてあります)。

文字が上から下へと移動していると思います。ようやく形が見えてきました。

Project N: 023 - 文字雨(関数化してみる)

前回のスクリプトは、あまりにも長すぎて、とても実用的なものではありませんでした。とりあえず今回は、文字を縦書きにする部分を関数にして、少し簡略化してみたいと思います。

last = BlankClip(width=320, height=240)
last = last.Subtitle("A", 4,0, 0,0, "Courier NEW", 18, $6FE47A, $11B301)
last = last.Subtitle("B", 4,13, 0,0, "Courier NEW", 18, $6FE47A, $11B301)
last = last.Subtitle("C", 4,26, 0,0, "Courier NEW", 18, $6FE47A, $11B301)
last = last.Subtitle("D", 4,39, 0,0, "Courier NEW", 18, $6FE47A, $11B301)
last = last.Subtitle("E", 4,52, 0,0, "Courier NEW", 18, $6FE47A, $11B301)
return last

これは前回の 2 つ目のスクリプトから、0 フレーム目の部分だけを抜き出して、クリップの変数を明示したものです。AviSynth では、変数が省略された場合、直前に処理されたクリップという意味の特別な変数 last が割り当てられます。これは、ただそれを省略せずに書いただけです。ちなみに、この場合、「return last」は省略することができません。

# 背景
bg = BlankClip(width=320, height=240)
# 固定値の指定
font = "Courier NEW" # フォント
font_size = 18 # フォントのサイズ
font_color = $6FE47A # フォントの色
halo_color = $11B301 # 文字の縁の色
# 縦書き
c1 = bg.Subtitle("A", 4,0, 0,0, font, font_size, font_color, halo_color)
c2 = c1.Subtitle("B", 4,13, 0,0, font, font_size, font_color, halo_color)
c3 = c2.Subtitle("C", 4,26, 0,0, font, font_size, font_color, halo_color)
c4 = c3.Subtitle("D", 4,39, 0,0, font, font_size, font_color, halo_color)
c5 = c4.Subtitle("E", 4,52, 0,0, font, font_size, font_color, halo_color)
# return 文
return c5

次に、フォントやフォントサイズなどの固定された値を、あらかじめ変数指定してみました(4 ~ 7 行目)。クリップの変数もわかりやすいように(?)、それぞれ違う名前を割り当ててみました。

Subtitle フィルタの x, y, first_frame, last_frame と 5つの文字(文字列)は、毎回、別の値を指定する可能性があります。そのため、これらの値(+clip)は、関数の引数として指定できるようにします。

つまり、引数リストの中身は、以下のようになります。

  • c: 入力クリップを受け付ける部分。clip 型。
  • x, y: 文字の位置を指定。Subtitle フィルタの x と y 。int 型。
  • start, end: Subtitle フィルタの first_frame と last_frame。int 型。
  • t1 ~ t5: 文字を指定。string 型。

では、関数化してみましょう。関数名は「tategaki」にして、引数リストと関数のコマンドを指定します。

function tategaki(clip c, int x, int y, int start, int end,
\ string t1, string t2, string t3, string t4, string t5)
{
# 固定値の指定
font = "Courier NEW" # フォント
font_size = 18 # フォントのサイズ
font_color = $6FE47A # フォントの色
halo_color = $11B301 # 文字の縁の色
# 縦書き
c1 = c.Subtitle(t1, x,y, start,end, font, font_size, font_color, halo_color)
c2 = c1.Subtitle(t2, x,y+13, start,end, font, font_size, font_color, halo_color)
c3 = c2.Subtitle(t3, x,y+26, start,end, font, font_size, font_color, halo_color)
c4 = c3.Subtitle(t4, x,y+39, start,end, font, font_size, font_color, halo_color)
c5 = c4.Subtitle(t5, x,y+52, start,end, font, font_size, font_color, halo_color)
# return 文
return c5
}

関数のコマンドは、さきほどのスクリプトの背景(1-2 行目)以外の部分と、大きく異なる部分はありません。入力クリップを受け入れる引数は「c」ですので、10 行目を「c1 = bg.Subtitle(...」から「c1 = c.Subtitle(...」に変更しています。

# Import("tategaki.avs") # インポートする場合
bg = BlankClip(width=320, height=240)
bg.tategaki(4, 0, 0, 0, "A", "B", "C", "D", "E") # 「tategaki(bg, 4, ...」でも可
return last

あとは、このように書けば、前回と同じように縦書き表示が可能になります。

tategaki関数の使用例

tategaki 関数は、同じスクリプトの任意の場所に書いておくか、別の avs ファイルに保存して import フィルタでインポートしてください。

しかし、まだこれで終わりではありません。


ユーザー定義関数作成の参考になるかもしれないページ

Project N: 022 - 文字雨(文字の落下)

文字を上から下に移動させるには、どうすればいいのでしょうか。Subtitle フィルタの書式を思い出してみましょう。

Subtitle(clip clip, string text, int x, int y, int first_frame, int last_frame, string font, int size, int text_color, int halo_color, int align, int spc)

この中で、文字の位置に関係する引数は、x と y の 2 つです。このうち、縦方向の座標を指定する y を変化させれば、何とかなりそうです(本当か?)。文字の表示開始フレームと表示終了フレームを表す first_frame と last_frame も指定する必要があるでしょう。

BlankClip(width=320, height=240)
Subtitle("A", 4,0, 0,0, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("A", 4,10, 1,1, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("A", 4,20, 2,2, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("A", 4,30, 3,3, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("A", 4,40, 4,4, "Courier NEW", 18, $6FE47A, $11B301)
return last

とりあえず、このような感じで書いてみました。A という文字を、0 フレームから 4 フレームまでの 各 1 フレームずつ、位置を変えて表示します。y の値が 10 ずつ増えていることに注目してください。

文字の落下 その 1

このように、文字が上から下へ落下しているように見える・・・はずです。パラパラマンガの要領ですね。

ただし、まだこの段階では、フレーム数が少なく、文字の表示時間も短いため、動画再生プレイヤーで再生しても、ほとんど真っ黒けの動画でしかないでしょうけれど。

では次に、もう少し文字数を増やしてみます。A, B, C, D, E の 5 文字を縦にならべて、同じように移動させます。

BlankClip(width=320, height=240)
# 0 フレーム
Subtitle("A", 4,0, 0,0, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("B", 4,13, 0,0, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("C", 4,26, 0,0, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("D", 4,39, 0,0, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("E", 4,52, 0,0, "Courier NEW", 18, $6FE47A, $11B301)
# 1 フレーム
Subtitle("A", 4,0+10, 1,1, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("B", 4,13+10, 1,1, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("C", 4,26+10, 1,1, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("D", 4,39+10, 1,1, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("E", 4,52+10, 1,1, "Courier NEW", 18, $6FE47A, $11B301)
# 2 フレーム
Subtitle("A", 4,0+20, 2,2, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("B", 4,13+20, 2,2, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("C", 4,26+20, 2,2, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("D", 4,39+20, 2,2, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("E", 4,52+20, 2,2, "Courier NEW", 18, $6FE47A, $11B301)
# 3 フレーム
Subtitle("A", 4,0+30, 3,3, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("B", 4,13+30, 3,3, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("C", 4,26+30, 3,3, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("D", 4,39+30, 3,3, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("E", 4,52+30, 3,3, "Courier NEW", 18, $6FE47A, $11B301)
# 4 フレーム
Subtitle("A", 4,0+40, 4,4, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("B", 4,13+40, 4,4, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("C", 4,26+40, 4,4, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("D", 4,39+40, 4,4, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("E", 4,52+40, 4,4, "Courier NEW", 18, $6FE47A, $11B301)
return last

あらかじめ、A から E の各文字の間隔が一定になるように、y の値を調整しておきます。こうすることで、縦書きのようになります。そして、最初のスクリプトと同じように、y の値を一定の割合で増加させます。+n の部分がそれです。

文字の落下 その 2

このように、5 文字が連結した状態で落下する(しているように見える)と思います。

ただし、見てわかるように、このスクリプトは実用的ではありません。4 フレーム目でこの状態です。29.97fps の動画なら、1 秒でこの約 6 倍、1 分で約 360 倍の長さになってしまいます。

次回は、もう少しスクリプトを簡略化させる方法を考えてみたいと思います。


連載を再開するにあたって、前回から、いくつかの変更を行っています。変更点は、下記の通りです。

Project N: 021 - 文字雨5(どうやって文字を降らせるか)

ようやく文字を表示させ、位置を指定することもできるようになりました。さて、これからが本題です。この文字を、雨(季節的には雪でもいい)が降るかのように移動させます。

まず、どのようにして文字を降らせるか(または、降っているように見せるか)を考えることにします。

とりあえず、次の2案を思いつきました。本当の思いつきです。

案
  • (1)案: 複数の文字を縦に並べておいて、下に移動させる。
  • (2)案: 文字の色を黒から緑に変化させることで、文字が移動しているように見せかける。
図がわかりにくいのは仕様です・・・私の。

(1)案は、比較的簡単に出来そうな気がします。でも、ちょっと、しょぼ・・・面白みに欠ける気がしなくもありません。(2)案も、Subtitleのtext_colorhalo_colorを変更することで何とかなりそうです。ただ、本当に降っているように見えるかどうか、やってみないとわかりません。

とりあえず、両方やってみることにしましょう(ますますペースが遅くなりますが)。

# 他に、文字をランダムに入れ替えるなどの効果を付け加えれば、よりマトリックスっぽく見えるかもしれません。でも、そこまでやっちゃうと、かなり処理が重くなりそう・・・。

Page 1 of 5: 1 2 3 4 5 »