合成フォントスクリプトを作成しよう
2日遅刻です、ごめんね
Q. 1日目の記事と被ってるが?
A. (今のところ)こっちのが多機能なので ヨシ!
/icons/hr.icon
合成フォントスクリプトに求められる機能
Adobe Illustlatorの合成フォント機能を参考にすると、文字種ごとに
フォント
サイズ
ベースライン
を設定できると良さそうです
このうちサイズを変更するスクリプトが実は存在します
処理の流れがなんとなく分かったのであとは書くだけ
書く
code:CompositeFont.anm.lua
--[[
@CompositeFont.anm (20221219)
(c) 2022 per_terra
文字種別に自動で制御文字を付加します
以下の制約があります
・文字毎に個別オブジェクトには対応していません
・常に左揃えで表示されます(基準の表示位置は変更可能)
・縦書には対応していません
テキストオブジェクトにMain@CompositeFontを適用して使用してください
ベースライン調整を行う場合は、Baseline@CompositeFontをMainの上に適用してください
字間・行間に設定ダイアログの範囲外の数値を入力したい場合は、同様にSpacing@CompositeFontをMainの上に適用してください
サイズは百分率で指定してください
汎用トラックバーなどで制御することも可能です
負の値を入力した場合は固定値として扱います
なお、各パラメーターはパラメーターインジェクションに対応しています
フォントはダイアログを使用するか、直接入力して指定してください
太字、斜体を使用する場合は、末尾に"Bold"、"Italic"を付加してください(フォントが収録されている場合に限る)
ユーザー指定範囲について
任意の範囲の文字をユーザー指定の文字種とすることができます
指定した範囲は他の範囲よりも優先されます
{文字コードの始点, 文字コードの終点 文字コードの始点, 文字コードの終点 ...} の形で指定してください
例: {0x8199,0x81A5} -- ☆ ★ ○ ● ◎ ◇ ◆ □ ■ △ ▲ ▽ ▼ を指定
なお、文字コードはShift_JISで指定してください
デバッグについて
入力された文字の文字種をコンソールに出力します
また、処理後のテキストをコンソールに出力します
手動で制御文字を入力した場合について
入力済みの制御文字には干渉しません
位置が競合した場合は入力済みの制御文字を優先します
]]
@Main
--dialog:ひらがな,_1=100;ひらがなフォント,_2="";カタカナ,_3=100;カタカナフォント,_4="";漢字,_5=100;漢字フォント,_6="";英字,_7=100;英字フォント,_8="";数字,_9=100;数字フォント,_10="";その他,_11=100;その他フォント,_12="";ユーザー,_13=100;ユーザーフォント,_14="";ユーザー指定範囲,_15={};デバッグ/chk,_16=0
local rikky_module = require "rikky_module"
rikky_module.font(2, 4, 6, 8, 10, 12, 14) --フォント選択ダイアログを表示
local hira = tonumber(_1) or 100 _1 = nil
local hira_font = _2 _2 = nil
local kata = tonumber(_3) or 100 _3 = nil
local kata_font = _4 _4 = nil
local kan = tonumber(_5) or 100 _5 = nil
local kan_font = _6 _6 = nil
local eng = tonumber(_7) or 100 _7 = nil
local eng_font = _8 _8 = nil
local num = tonumber(_9) or 100 _9 = nil
local num_font = _10 _10 = nil
local others = tonumber(_11) or 100 _11 = nil
local others_font = _12 _12 = nil
local user = tonumber(_13) or 100 _13 = nil
local user_font = _14 _14 = nil
local user_char = _15 _15 = nil
local text_debug = _16 ~= 0 _16 = nil
local baseline = baseline or {}
local spacing = spacing or {}
--与えられたsのShift_JISコードを返す
local function sjis_code(s)
local a, b = string.byte(s, 1, 2) --sの1バイト目,2バイト目をそれぞれa,bに代入する
return b and a * 0x100 + b or a --b が true ならば a * 0x100 + b, false ならば a
end
local model = {
-- type = {文字コードの始点, 文字コードの終点 文字コードの始点, 文字コードの終点 ...}
user = user_char,
hira = { 0x829f, 0x82f1 },
kata = { 161, 223, 0x8340, 0x8394 },
kan = { 0x8157, 0x8159, 0x889f, 0xeeec },
eng = { 65, 90, 97, 122, 0x8260, 0x829a },
num = { 48, 57, 0x824f, 0x8258 }
}
--与えられたsの文字種を判別する
local function getchartype(s)
if #s > 2 then --sのバイト数が2より大きいならば return "ctrl" --sは制御文字である
end
local code = sjis_code(s) --sのShift_JISコードを取得する
for type, range in pairs(model) do --model(配列)のキーとその値をそれぞれtypeとrangeに代入する
if rangei <= code and code <= rangei + 1 then --codeがtypeに対応するrange内ならば return type --sはtypeである
end
end
end
return "others" --sが何にも当てはまらなかった場合, sはothersである
end
local object, data = rikky_module.getinfo("object")
if object ~= "テキスト" then return end --objectがテキストでないならば処理を終了する
local text = rikky_module.getinfo("text") --テキストオブジェクトに入力された文字をtextに代入する
local font = rikky_module.getinfo("font") --setfontで設定されている値を取得しfontテーブルに代入する
local chars = rikky_module.textsplit(text) --textを1文字ずつ(制御文字はまとまる)に分割してcharsテーブルに格納する
--<s(ここを生成する)> 関数
--x:パラメータ s:基準値 f:フォント名
local function gensize(x, s, f)
if x < 0 then --xが負数ならば
return -x .. (f ~= "" and "," .. f or "") --(-x)(正数)と, (設定されている場合は)フォント名を結合した文字列を返す
elseif x == 100 then --xが100(%)ならば
return f ~= "" and "," .. f or "" --(設定されている場合は)フォント名を返す
else
return math.floor(s * x / 100 + 0.5) .. (f ~= "" and "," .. f or "") -- sのx(%)(整数)と, (設定されている場合は)フォント名を結合した文字列を返す
end
end
--gensize関数を用いて文字種ごとのサイズを格納したsizeテーブルを作成する
local size = {
hira = gensize(hira, font.size, hira_font),
kata = gensize(kata, font.size, kata_font),
kan = gensize(kan, font.size, kan_font),
eng = gensize(eng, font.size, eng_font),
num = gensize(num, font.size, num_font),
others = gensize(others, font.size, others_font),
user = gensize(user, font.size, user_font),
}
local temp = "" --最終的に返される文字列, これに結合していく
local prevtype = "" --直前の文字の文字種を格納する変数
local prevsize = "" --直前の文字のサイズを格納する変数
for i, char in ipairs(chars) do
local chartype = getchartype(char)
if text_debug then print(i, char, chartype) end
if char == "\r" then --CRはそのまま結合
temp = temp .. char
elseif char == "\n" then --LFのあとに行間を適用して結合
local py = spacing.y or data.spacing_y
local pos = py ~= 0 and (py > 0 and "<p+0,+" .. py .. ">" or "<p+0," .. py .. ">") or ""
temp = temp .. char .. pos
elseif char == "\t" then -- タブはそのまま結合
temp = temp .. char
elseif prevtype == "ctrl" and string.find(charsi - 1, "<s", 1, true) then --直前にサイズの制御文字が入力されているならば, そのまま結合 temp = temp .. char
elseif chartype == "ctrl" then --制御文字ならば, そのまま結合
temp = temp .. char
elseif chartype == prevtype then --直前の文字種と等しいならば, 字間のみを適用して結合
local px = spacing.x or data.spacing_x
local pos = px ~= 0 and (px > 0 and "<p+" .. px .. ",+0>" or "<p" .. px .. ",+0>") or ""
temp = pos and temp .. pos or temp
temp = temp .. char
else --直前の文字種と異なるならば
local px = i ~= 1 and (spacing.x or data.spacing_x) or 0 --1文字目ならば字間を適用しない
local pos = (px ~= 0 or py ~= 0) and
(px >= 0 and "<p+" .. px or "<p" .. px) .. (py >= 0 and ",+" .. py or "," .. py) .. ">" or ""
temp = i ~= 1 and temp .. pos or temp
temp = sizechartype == prevsize and temp .. char or temp .. "<s" .. sizechartype .. ">" .. char end
prevtype = chartype
end
if text_debug then print(temp) end
--[[
local yose = data.align % 3
local chushin = data.align % 9
local tate = data.align > 8 and 1 or 0
rikky_module.textload(temp, yose, chushin, tate, data.font, font.size)
]]
obj.setfont(font.name .. (font.bold and " Bold" or "") .. (font.italic and " Italic" or ""), font.size, data.type,
data.color, data.color2)
obj.load("text", temp)
if data.align < 9 then
obj.cx, obj.cy = (data.align % 3 - 1) * obj.w / 2, (math.floor(data.align / 3) - 1) * obj.h / 2
end
_G.baseline = nil
_G.spacing = nil
@Baseline
--dialog:ひらがな,_1=;カタカナ,_2=;漢字,_3=;英字,_4=;数字,_5=;その他,_6=;ユーザー,_7=
baseline = {
hira = math.floor(tonumber(_1) or 0),
kata = math.floor(tonumber(_2) or 0),
kan = math.floor(tonumber(_3) or 0),
eng = math.floor(tonumber(_4) or 0),
num = math.floor(tonumber(_5) or 0),
others = math.floor(tonumber(_6) or 0),
user = math.floor(tonumber(_7) or 0)
}
@Spacing
--dialog:字間,_1=;行間,_2=
spacing = {
x = _1 and math.floor(tonumber(_1) or 0) or nil,
y = _2 and math.floor(tonumber(_2) or 0) or nil
}
コメントをいっぱい書くことにしたので、多少は読みやすいかもしれない
使い方
使えば分かる
ToDo
「文字毎に個別オブジェクト」に対応させる
脱rikky_module
テキストバッファを直接いじる?
左揃え固定問題とか縦書きに対応できるかも
GitHubとかでちゃんと公開する
感想
「ひらがな小さ」は読むのが大変
異常なスパゲッティコード感
が、Luaの記法も色々学べたので良かった
考えることが多すぎてコードも頭もぐちゃぐちゃになりがち
何ヶ月か置いてからリファクタリングするとだいぶ良い感じになった
寝かせるのは大事
だが、コメントは残しておかないと思い出すのに時間がかかる
とりあえずそこそこ使えるものができたので満足
ところで
https://scrapbox.io/files/63a1b722abe473001db44007.png