Subtitle フィルタで文字または文字の縁の色を透明にする方法
AviSynth 2.5.8 RC1 のヘルプを見ていて気づいたのですが、Subtitle フィルタで文字の色(text_color)と文字の縁の色(halo_color)の透明度を設定することが可能になっています。更新履歴を見ると、AviSynth 2.5.8 から追加される機能のようです(2.5.8 RC1 で動作確認済み。それ以前については不明)。
設定方法は簡単です。これまでは 16 進数を使って「$RRGGBB」という形式で R(赤)、G(緑)、B(青)をそれぞれ指定していました。透明度を指定したい場合は、さらに「$AARRGGBB」というように A の部分に 16 進数でアルファ値を指定すればよいのです。
たとえば、
$00000000
なら、完全に不透明な黒に、
$FF000000
なら、完全に透明になります。
もう少し例を挙げます。
# クリップの生成
BlankClip(1, 320, 240, color=$eaeaea)
# halo_color=$ff0000 と同じ
Subtitle("transparent?", y=0, size=48, text_color=$336699, halo_color=$00ff0000)
# 文字の縁の色を半透明に
Subtitle("transparent?", y=40, size=48, text_color=$336699, halo_color=$80ff0000)
# 文字の縁の色を完全な透明に
Subtitle("transparent?", y=80, size=48, text_color=$336699, halo_color=$ffff0000)
# 文字の色も縁の色も半透明に
Subtitle("transparent?", y=120, size=48, text_color=$80336699, halo_color=$80ff0000)
# 文字の色を透明に、縁の色を不透明に
Subtitle("transparent?", y=160, size=48, text_color=$ff336699, halo_color=$00ff0000)

なお、従来通り「$RRGGBB」という形式で指定した場合は、完全に不透明な色(つまりこれまでと同じ)になります。
mojimoji 関数を更新
テキストの移動と拡大縮小を行うための関数 mojimoji を更新しました。変更点は、以下のとおりです:
変更点
- 複数行の文字列に対応(2.57 以降の場合のみ。Subtitle 向けの書式に変換する必要あり)
- x/y が -1 の時に中央寄せされてしまう問題に対処(回避策)
- グローバル変数名の変更(変数名の衝突をなるべく回避するため)
- パラメータの順番の変更(x2, y2 が指定されていない場合は移動なしが可能に)
- mojimojiOvr 関数(テスト版)を追加。
ダウンロード
mojimoji関数: テキストの移動と拡大縮小からダウンロードできます。
変更点に関する補足説明
複数行の文字列への対応
lsp パラメータが指定可能になっています(デフォルトでは lsp = 0)ので、文字列内に \n が含まれていれば、そこで改行されます。以下の記事も参照。
- Project N: 025 - Subtitle フィルタの複数行サポート(AviSynth v2.57 以降)
- 複数行の文字列を Subtitle フィルタ形式に変換する JavaScript
- 複数行の文字列を Subtitle フィルタ形式に変換する AvsP 用マクロ
x/y が -1 の時に中央寄せされてしまう問題
Subtitle では x と/または y を -1 に設定すると中央揃えされるので、x と/または y が -1 の時は強制的に 0 になるようにした。
mojimojiOvr 関数(テスト版)
ConditionalReader を使ってテキストを移動させるバージョン。移動、ズームのほかにフェードにも対応。
実験目的で作っただけのものです。ConditionalReader の使用例として参考になるかもしれません。
注意
- パラメータの順番を変更したため、以前の書式で記述されたものはそのままでは使用できません。ご注意ください。
- mojimojiOvr はテスト版であり、ちゃんと動作するかどうかもわかりません。また、今後更新する予定もありません。
Subtitle フィルタにとって -1 は魔法の値
Subtitle フィルタで x と/または y の値を -1 に設定すると自動的に中央揃えされるという話。少し古いネタですが、整理していたら出てきたのでメモ。
IanB 氏曰く、この -1 は「魔法の値」だそうです。
What is causing a glitch at frame 294 in my script? - Doom9's Forum
Originally Posted by documentation
... The parameters x and y can be set to -1 to automatically calculate and use the horizontal or vertical center coordinate.
Ahhhgggg magic values
このことは Subtitle フィルタのマニュアルにも書かれていますし、Subtitle 単独で使用する場合にはすぐに気づくと思います。ただし、Subtitle を Animate などと組み合わせて使用する際には、意図せず x と/または y に -1 が入ってしまうケースもあるかと思います(逆に偶然 -1 が入らないケースもあるでしょう)。
例
BlankClip(5, 320, 240)
Animate(0, 4, "Subtitle", "'-1' is a magic value.",2,-1, "'-1' is a magic value.",-2,-1)
このスクリプトを VirtualDub や AvsP を使ってコマ送りしてみてください(5 フレームしかないので、再生すると一瞬で終わってしまいます)。ちょうど x の値が -1 になるフレーム 3 で、テキストが急に中央に移動します。y の値は -1 で固定させていますので、そちらでも -1 がどういう働きをするかを確認できると思います。
対処法
いくつか対処法が考えられます。
- メッセージの頭にスペースを付け足して、-1 よりも大きい値をスキップし、直接 -2 から開始する(What is causing a glitch at frame 294 in my script? - Doom9's Forum より IanB 氏のアイデア)
- ラッパー関数を用意して、x または y が -1 の場合は、0 または -2 にする(完全な解決にはなりませんが、簡単な次善の策として)。
- Animate ではなく、Overlay と ConditionalReader の組み合わせにする(ConditionalReader で ol_x_offset/ol_y_offset を定義して移動させる)。
- 絶対に -1 にならないようにする(例えば、大きめのクリップを用意して最小値が -1 より大きくなるようにし、あとでいらない部分を Crop する、など)。
対処例
2 番目のラッパー関数を使う方法を示します。
まず次のような関数を用意します。
# 簡単な Wrapper 関数の例
function SubtitleWrapperTest(clip input, string moji, int x, int y) {
# x が -1 なら 0 に設定、それ以外ならそのまま
x = (x == -1) ? 0 : x # 0 でなく -2 にしてもよい
# y が -1 なら 0 に設定、それ以外ならそのまま
y = (y == -1) ? 0 : y # 0 でなく -2 にしてもよい
# 新しい x と y を Subtitle の引数に指定
output = input.Subtitle(moji, x, y)
# output 返す
return output
}
ここでは簡略化のために size や font などの設定は省略しています。よって、このままでは実用的ではありません。Animate との併用時にはフォントなどは固定でしょうから、関数の中でデフォルト値を設定してしまってもいいでしょう。
BlankClip(5, 320, 240)
Animate(0, 4, "SubtitleWrapperTest", "'-1' is a magic value.",2,-1, "'-1' is a magic value.",-2,-1)
Subtitle の代わりに用意した関数を指定します。コマ送りしてみると、フレーム 3 で少し停止したような印象を受けるかもしれません。しかし、中央揃えされるよりはいいでしょう。
これはあくまでも回避策ですので、他の方法も試してみてください。ちなみに mojimoji 関数: テキストの移動と拡大縮小の mojimoji ではこのラッパー関数を利用する方法を、mojimojiOvr では 3 番目の Overlay と ConditionalReader を併用する方法を使っています。
関連記事
ラッパー関数について
FilterRange で最終フレームまでを範囲に指定すると 1 フレーム水増しされる件
Leben ist vorbei \(^o^)/: FilterRange を読んで、自分が改造したもののことを思い出したので、もう一回、確認の意味で調べてみました。にーやんのブログ :: プチ更新情報に、この件についての記述があるので、約 4 年前のネタになります……。
検証
以下のようなスクリプトを作成します。
# ソース
ColorBars(320,240).Trim(0,9) # 10 フレームのみ
# フレーム番号の追加
ScriptClip("Subtitle(String(current_frame), size=120, align=5)")
# FilterRange
FilterRange(7, 9, "Invert()") # 最終フレームまで
FilterRange 適用前は

このようなクリップだったのが、FilterRange 適用後は

こうなります。やはり最後の 1 フレームが水増しされています。そして、水増しされたフレームは、フィルタ適用前のものです。
原因と対策
c3 = clip.trim(end + 1, 0)
オリジナルの FilterRange では、ここで end + 1 から 0(0 は最後までを意味する)を選択しているのですが、end が最終フレームの場合、c3 には最終フレームが入ります。
c = end == 0 ? c : c + c3
そして、end が最終フレームの番号と一致しても end == 0 の条件にはあてはまらないので、c に c3 (つまり最終フレーム)を結合したクリップを返します。これが 1 フレーム水増しされる原因です。
これを防ぐには、最低限、end が最終フレームの場合にも c のみを返すように条件を追加すればいいことになります。最終フレームかどうかの判定には、FrameCount() 関数を使用するとよいでしょう。
改造版
AviSynth Wiki - FilterRange に改造版をアップしました。以前、改造したものより、さらに手を加えてあります。もう少しうまく書けそうですな気もしますが、今日のところはこれで。
関連ページ
ShowTimeCode 関数を更新。AviSynth Wiki へ移動。
ShowTimeCode - タイムコードを表示する関数を更新しました。
AviSynth Wiki 内に ShowTimeCode のページ(AviSynth Wiki - ShowTimeCode)を設けましたので、今後はそちらを参照してください。ブログのページもそのまま残しておきますが、スクリプトは AviSynth Wiki からのみ入手可能です。
なお今回の更新では、2ちゃんねる「お前らのショボイAvisynthスクリプト貼ってくださいpart2」の 253 さんにミリ秒と整数秒の計算がいい加減だった部分を修正していただいています。253 さんには改めて感謝申し上げます。




