【DaVinci Resolve】 Fusion Fuseで日本語テキストを表示する
🐥 はじめに
みなさん、こんにちは。Mugです 🐼
これは 📽DaVinci Resolveについての記事です
DaVinci Resolve の Fusion では Fuse
というもので新しいノードや
モディファイアを追加することができます
この記事では Fuse
を使って日本語を表示する方法についてまとめます
⚡Fuse とは?
Fuse とは Lua というプログラミング言語を使って
🖥️ プログラムとしてエフェクト,モディファイア等を作っていくものです
詳しくはこちらの document をどうぞ 🖐️
🔠 Text shape
Fuse でテキストを表示するには Text Shape
を使用します
このText Shape
使い方については
DaVinci Resolve に付属しているExample 6 Text.fuseを見てもらうのが一番早いです 🚀
Examples は DaVinci Resolve のメニュー
Help -> Documentation -> Developer
から開かれたフォルダのFusion Fuse
フォルダに入っています
Text を表示するまで
Example 6 Text.fuseの text 表示部分を簡単に説明します
Text を表示する処理はdrawstring
関数で行われていて
次のように処理されています 😤
-
TextStyleFont
を作る -
TextStyleFont
からTextStyleFontMetrics
を作る - 表示(描画)位置を計算する
-
TextStyleFontMetrics
から 1 文字分のText Shape
を作る - 全文字終わるまで 3-4 を繰り返す
- Shape をイメージに表示(描画)する
このように、 text 表示する場合 1 文字ずつshape
を作ります
この 1 文字というのをどのように判断するのかがポイント 💡 で
Example 6 Text.fuse では 👉1 文字=1byte 👈 として処理しています
✒️ 文字コード
実は前述のExample 6 Text.fuseでは日本語が表示できません
入力すると文字化けします 😵💫
Example 6 Text.fuse での文字化け
これは、Example 6 Text.fuse
で行っている1 文字=1byteという考え方に問題があるためです
Fusion ではインスペクタのコントロールに入力されたテキストは
UTF-8という形式でエンコードされます
UTF-8
ではアルファベットと一部の記号以外は1 文字=1byteにはなりません
日本語なんかは 1 文字=3byte だったりします 😥
このため、Example 6 Text.fuse では日本語が表示できません 😭
Unicode コードポイントへの変換
日本語を表示するには文字の区切りを正しくする判定する必要があり
そのためにまずは、UTF-8
を unicodeのコードポイント
に変換します
この処理はWikipedia の UTF-8 のページ等
解説ページはいろいろ存在するため詳しくはそちらを見てもらえればと思います 🙏
簡単に言えば上位ビットを見て byte 数を判断し
1byte 目の byte 数 bit 以外の部分と 2byte 目以降の下位 6bit をくっつけると
Unicodeコードポイント
になります 👍
例:"あ"
表現方法 | 1byte 目 | 2byte 目 | 3byte 目 |
---|---|---|---|
UTF-8(hex) | e3 | 81 | 82 |
UTF-8(bin) | 1110 0011 | 1000 0001 | 1000 0010 |
- 👉 1110 から始まるので 3byte で 1 文字であることがわかります
- 👉 識別子(太字)部分を除くと
0011 0000 0100 0010
- 👉 これを 16 進数で表すと
0x3042
- 👉 これを 16 進数で表すと
- 👉 識別子(太字)部分を除くと
🖊️ Unicode Code Point = U+3042
このように入力された文字列(byte 列)をすべてunicodeコードポイント
に変換します
ビット演算
UTF-8 から Unicode コードポイントへ変換するためには bit 演算が必要になってきます
しかし Fuse(Fusion) で使用されている Lua のランタイムである
Lua JITは通常のビット演算が使えません 😮
代わりにLua Bit 演算モジュールを使用する必要があります
使い方で特に難しいことはなく
"bit"モジュールを読み込んでから関数を呼ぶだけです
local bit = require("bit")
local x = 1
local y = 2
local z = 128
local _or = bit.bor(x, y, z) -- bit operation
print(_or)
print("0x" .. bit.tohex(_or, 2))
👉 131
👉 0x83
Unicode で Shape を作る
unicode のコードポイントを得られたら、あとは簡単です 😤
その値をTextStyleFontMetrics
のGetCharacterShape
に渡すだけです ❗
これでちゃんと日本語を含めて 🌏 世界中の文字がShape
として描画できるようになります ❣️
shape = tmf:GetCharacterShape(unicode)
サンプル
👇 は私が作ってる Text 表示用の Fuse です 🫡
この中の UnicodeText
のToUniCode
関数で UTF-8 から Unicode コードポイントへの変換を行っています
参考にどうぞ 🖐️
コード抜粋
ToUniCode = function(this)
local utf16bytes = {}
local utf32bytes = {}
local line = 1
local source = this.Text
if source and (0 < #source) then
utf16bytes[line] = {}
local i = 1
while i <= #source do
local c = source:byte(i)
if c == 0x0A then
line = line + 1
utf16bytes[line] = {}
i = i + 1
elseif c < 0x80 then
table.insert(utf16bytes[line], 0)
table.insert(utf16bytes[line], c)
i = i + 1
elseif c < 0xE0 then
local c2 = source:byte(i + 1)
local u = bit.bor(bit.lshift(bit.band(c, 0x1F), 6), bit.band(c2, 0x3F))
table.insert(utf16bytes[line], bit.rshift(u, 8))
table.insert(utf16bytes[line], bit.band(u, 0xFF))
i = i + 2
elseif c < 0xF0 then
local c2 = source:byte(i + 1)
local c3 = source:byte(i + 2)
local u = bit.bor(bit.lshift(bit.band(c, 0x0F), 12), bit.lshift(bit.band(c2, 0x3F), 6),
bit.band(c3, 0x3F))
table.insert(utf16bytes[line], bit.rshift(u, 8))
table.insert(utf16bytes[line], bit.band(u, 0xFF))
i = i + 3
else
local c2 = source:byte(i + 1)
local c3 = source:byte(i + 2)
local c4 = source:byte(i + 3)
local u = bit.bor(bit.lshift(bit.band(c, 0x07), 18), bit.lshift(bit.band(c2, 0x3F), 12),
bit.lshift(bit.band(c3, 0x3F), 6), bit.band(c4, 0x3F))
u = u - 0x10000
local high = bit.bor(0xD800, bit.rshift(u, 10))
local low = bit.bor(0xDC00, bit.band(u, 0x3FF))
table.insert(utf16bytes[line], bit.rshift(high, 8))
table.insert(utf16bytes[line], bit.band(high, 0xFF))
table.insert(utf16bytes[line], bit.rshift(low, 8))
table.insert(utf16bytes[line], bit.band(low, 0xFF))
i = i + 4
end
end
for line = 1, #utf16bytes do
utf32bytes[line] = {}
local i = 1
while i <= #utf16bytes[line] do
local b1 = utf16bytes[line][i]
local b2 = utf16bytes[line][i + 1]
local code_unit = bit.bor(bit.lshift(b1, 8), b2)
if code_unit >= 0xD800 and code_unit <= 0xDBFF then
-- High surrogate
local b3 = utf16bytes[line][i + 2]
local b4 = utf16bytes[line][i + 3]
local low_surrogate = bit.bor(bit.lshift(b3, 8), b4)
local code_point = bit.bor(bit.lshift(bit.band(code_unit, 0x3FF), 10),
bit.band(low_surrogate, 0x3FF)) +
0x10000
table.insert(utf32bytes[line], code_point)
i = i + 4
else
-- Non-surrogate
if code_unit ~= 0xFE0F then
table.insert(utf32bytes[line], code_unit)
end
i = i + 2
end
end
end
end
return utf32bytes
end
🐔 おわりに
📢 せんでん 📢
私が作った Text 表示をする Fuse を紹介しています
もし興味があればどうぞ 🫠
Discussion