🌏

【DaVinci Resolve】 Fusion Fuseで日本語テキストを表示する

2025/02/18に公開

🐥 はじめに

みなさん、こんにちは。Mugです 🐼

これは 📽DaVinci Resolveについての記事です
DaVinci Resolve の Fusion では Fuseというもので新しいノードや
モディファイアを追加することができます
この記事では Fuse を使って日本語を表示する方法についてまとめます

⚡Fuse とは?

Fuse とは Lua というプログラミング言語を使って
🖥️ プログラムとしてエフェクト,モディファイア等を作っていくものです
詳しくはこちらの document をどうぞ 🖐️
https://documents.blackmagicdesign.com/UserManuals/Fusion_Fuse_SDK.pdf

🔠 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関数で行われていて
次のように処理されています 😤

  1. TextStyleFontを作る
  2. TextStyleFontからTextStyleFontMetricsを作る
  3. 表示(描画)位置を計算する
  4. TextStyleFontMetricsから 1 文字分のText Shapeを作る
  5. 全文字終わるまで 3-4 を繰り返す
  6. Shape をイメージに表示(描画)する

このように、 text 表示する場合 1 文字ずつshapeを作ります
この 1 文字というのをどのように判断するのかがポイント 💡 で
Example 6 Text.fuse では 👉1 文字=1byte 👈 として処理しています

✒️ 文字コード

実は前述のExample 6 Text.fuseでは日本語が表示できません
入力すると文字化けします 😵‍💫

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-8unicodeのコードポイントに変換します

この処理は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

🖊️ 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 のコードポイントを得られたら、あとは簡単です 😤
その値をTextStyleFontMetricsGetCharacterShapeに渡すだけです ❗
これでちゃんと日本語を含めて 🌏 世界中の文字がShapeとして描画できるようになります ❣️

shape = tmf:GetCharacterShape(unicode)

サンプル

👇 は私が作ってる Text 表示用の Fuse です 🫡
この中の UnicodeTextToUniCode関数で UTF-8 から Unicode コードポイントへの変換を行っています
参考にどうぞ 🖐️

https://github.com/mug-lab-3/DaVinciResolveEffects/blob/a2c51f972fa195e7d5d7e82d7951769629976c14/fuses/MugLazyText.fuse#L872

コード抜粋
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 を紹介しています
もし興味があればどうぞ 🫠

https://youtu.be/U4UI3_Jklro

GitHubで編集を提案

Discussion