本文发布于 1246 天前。
很早就想接触的坑,因为忙(lan)一直没下手,这两天有朋友来问了关于文字连筋的问题,虽然没能解决,但是还是逼自己学一下拆字。实际上核心代码并没有看懂,先抄作业,用着再说。
拆字的本质是拆分绘图的连通域。把每个字单独的部分独立拆出来,形成了新的绘图。[1]
用到了DOMO的算法。[2]
Comment: 0,0:00:00.00,0:00:05.00,Default,text to shape,0,0,0,code syl noblank,style=syl.style text = _G.decode.create_font(style.fontname, style.bold, style.italic, style.underline, style.strikeout, style.fontsize).text_to_shape(syl.text_stripped) text=string.gsub(text," c","") text1=_G.Yutils.shape.filter(text, function(x,y) return math.round(x),math.round(y) end)
Comment: 0,0:00:00.00,0:00:05.00,Default,,0,0,0,code once,function pointmeshshape(shape,x,y) local pixels=_G.Yutils.shape.to_pixels(shape) local n=1 local x=math.round(x) local y=math.round(y) local x1,y1,x2,y2=_G.Yutils.shape.bounding(shape) if x<x1 or x>x2 or y<y1 or y>y2 then return false end for i=1,#pixels do if x==pixels[i].x and y==pixels[i].y then n=0 end end if n==0 then return true else return false end end
Comment: 0,0:00:00.00,0:00:05.00,Default,,0,0,0,code once,function text_split(text_shape) local function delete_empty(tbl,mode) if mode == 1 then for i=#tbl,1,-1 do if tbl[i] == "" then _G.table.remove(tbl, i) end end elseif mode==2 then for i=#tbl,1,-1 do if (tbl[i].shape_i == "" or tbl[i].shape == nil) then _G.table.remove(tbl, i) end end end return tbl end local function is_include(value, tbl) for k,v in _G.ipairs(tbl) do if v == value then return true end end return false end local function string_split(str, split_char) local sub_str_tab = {} while true do local pos = string.find(str, split_char) if not pos then _G.table.insert(sub_str_tab,str) break end local sub_str = string.sub(str, 1, pos - 1) _G.table.insert(sub_str_tab,sub_str) str = string.sub(str, pos + 1, string.len(str)) end return sub_str_tab end local function split_by_m(text) text = string_split(text,"m") _G.table.remove(text,1) point = {} for i=1,#text do point[i] = {} text[i] = "m"..text[i] for x,y in string.gmatch(text[i],"[m|l|b] (-?%d+) (-?%d+)") do _G.table.insert(point[i],{x = x,y = y}) end end return text end local function rec(text) new_shape_tbl = {} record = {} for i=1,#text do for j=1,#text do x,y = _G.tonumber(point[j][1].x),_G.tonumber(point[j][1].y) if (pointmeshshape(text[i],x,y) and i~=j) then _G.table.insert(record,{inner = j,outer = i}) else _G.table.insert(record,"") end end end return record end local function record_handler(record_tbl,text) info_tbl = {} outer = {} inner = {} for i=1,#record_tbl do outer[i]={} inner[i]={} for j=1,#record_tbl do if record_tbl[j].inner == i then _G.table.insert(outer[i],record_tbl[j].outer) end if record_tbl[j].outer == i then _G.table.insert(inner[i],record_tbl[j].inner) end end _G.table.insert(info_tbl,{shape_i = i, o_count = #outer[i],outer = outer[i],in_count = #inner[i],inner=inner[i], shape = text[i]}) end return delete_empty(info_tbl) end local function shape_assembler(info_tbl) new_t = {} delete_empty(info_tbl,2) _G.table.sort(info_tbl,function (a,b) return a.o_count > b.o_count end) info_tbl["n"]= #info_tbl for i=1,info_tbl.n do if ((info_tbl[i].o_count==0 or info_tbl[i].o_count%2==0) and info_tbl[i].in_count==0) then new_t[i] = info_tbl[i] elseif (info_tbl[i].in_count>=1 and info_tbl[i].o_count~=0 and info_tbl[i].o_count%2==0) then for j=i,1,-1 do if is_include(info_tbl[i].shape_i,info_tbl[j].outer) then info_tbl[i].shape = info_tbl[i].shape.." "..info_tbl[j].shape end end new_t[i] = info_tbl[i] elseif (info_tbl[i].o_count==0 and info_tbl[i].in_count~=0) then for j=i,1,-1 do if is_include(info_tbl[i].shape_i,info_tbl[j].outer) and #info_tbl[j].outer==1 then info_tbl[i].shape = info_tbl[i].shape.." "..info_tbl[j].shape end end new_t[i] = info_tbl[i] else new_t[i] ="" end end new_t = delete_empty(new_t,1) for i=1,#new_t do new_t[i] = new_t[i].shape end return new_t end local text_tbl=split_by_m(text_shape) local record_tbl=rec(text_tbl) local new_table=record_handler(record_tbl,text_tbl) local shapes=shape_assembler(new_table) return shapes end
Comment: 0,0:00:00.00,0:00:05.00,Default,,0,0,0,code syl noblank,aaa = text_split(text1)
Comment: 0,0:00:00.00,0:00:00.00,Default,,0,0,0,template syl noblank notext,!maxloop(#aaa)!{\an7\bord3\pos($left,$top)\p1\blur2}!aaa[j]!
Comment: 0,0:00:00.00,0:00:05.00,Default,,0,0,0,karaoke,{\k100}你{\k100}好{\k100} {\k100}世{\k100}界
Dialogue: 0,0:00:00.00,0:00:05.00,Default,,0,0,0,fx,{\an7\bord3\pos(858,1000)\p1\blur2}m 12 15 b 9 22 5 29 1 33 2 35 3 38 4 39 5 38 6 37 7 35 l 7 60 12 60 12 27 b 14 24 16 20 17 17
Dialogue: 0,0:00:00.00,0:00:05.00,Default,,0,0,0,fx,{\an7\bord3\pos(858,1000)\p1\blur2}m 41 29 b 40 31 40 33 40 35 l 45 36 b 45 33 46 28 47 24 l 43 24 42 24 25 24 b 26 21 27 19 27 17 l 22 15 b 20 22 17 29 14 33 15 34 17 35 18 37 20 34 21 32 23 29 l 28 29 28 54 b 28 54 28 55 28 55 27 55 25 55 23 55 24 56 25 59 25 60 28 60 30 60 32 59 34 58 34 57 34 54 l 34 29
Dialogue: 0,0:00:00.00,0:00:05.00,Default,,0,0,0,fx,{\an7\bord3\pos(858,1000)\p1\blur2}m 21 37 b 19 42 17 47 15 51 16 52 18 53 20 54 22 50 25 44 26 38
Dialogue: 0,0:00:00.00,0:00:05.00,Default,,0,0,0,fx,{\an7\bord3\pos(858,1000)\p1\blur2}m 36 38 b 38 43 40 50 41 54 l 46 52 b 46 48 44 41 41 36
Dialogue: 0,0:00:00.00,0:00:05.00,Default,,0,0,0,fx,{\an7\bord3\pos(906,1000)\p1\blur2}m 18 25 l 17 25 12 25 b 12 22 13 19 13 16 l 7 15 b 7 18 7 21 6 25 l 2 25 2 30 5 30 b 4 34 3 38 2 41 5 43 7 45 10 48 7 51 4 54 1 56 2 57 4 59 4 60 8 58 11 55 14 51 16 53 17 55 18 57 l 22 52 b 21 50 19 48 17 46 19 41 21 34 22 25 m 16 30 b 15 35 14 39 12 42 11 41 10 40 8 39 9 37 10 33 11 30
Dialogue: 0,0:00:00.00,0:00:05.00,Default,,0,0,0,fx,{\an7\bord3\pos(906,1000)\p1\blur2}m 47 35 l 37 35 37 31 b 41 28 44 24 46 21 l 42 18 41 18 23 18 23 23 37 23 b 35 26 33 29 31 30 l 31 35 21 35 21 40 31 40 31 54 b 31 55 31 55 30 55 29 55 26 55 24 55 25 56 26 59 26 60 30 60 32 60 34 59 36 58 37 57 37 54 l 37 40 47 40
Dialogue: 0,0:00:00.00,0:00:05.00,Default,,0,0,0,fx,{\an7\bord3\pos(965,1000)\p1\blur2}m 40 47 l 40 32 46 32 46 27 40 27 40 16 34 16 34 27 27 27 27 16 21 16 21 27 15 27 15 17 9 17 9 27 2 27 2 32 9 32 9 58 45 58 45 52 15 52 15 32 21 32 21 47 m 34 32 l 34 41 27 41 27 32
Dialogue: 0,0:00:00.00,0:00:05.00,Default,,0,0,0,fx,{\an7\bord3\pos(1014,1000)\p1\blur2}m 42 37 l 42 17 7 17 7 37 15 37 b 11 40 7 43 2 44 3 45 5 48 5 49 9 48 12 46 14 44 l 14 46 b 14 49 13 53 5 56 6 57 8 59 9 61 19 57 20 51 20 46 l 20 43 16 43 b 18 41 20 39 22 37 l 27 37 b 28 40 30 41 33 43 l 29 43 29 60 35 60 35 45 b 37 47 40 48 43 49 44 47 46 45 47 44 42 43 37 40 34 37 m 13 21 l 21 21 21 25 13 25 m 36 25 l 27 25 27 21 36 21 m 36 33 l 27 33 27 29 36 29 m 13 29 l 21 29 21 33 13 33
文字转绘图
关于文字转绘图,请参考Yutils库 绘图相关
函数:判断点是否在绘图上
遍历算法,用图形转像素来判断。[3]
function pointmeshshape(shape,x,y)
local pixels=_G.Yutils.shape.to_pixels(shape)
local n=1
local x=math.round(x)
local y=math.round(y)
local x1,y1,x2,y2=_G.Yutils.shape.bounding(shape)
if x<x1 or x>x2 or y<y1 or y>y2 then
return false
end
for i=1,#pixels do
if x==pixels[i].x and y==pixels[i].y then
n=0
end
end
if n==0 then
return true
else
return false
end
end
使拆分出来的绘图控制点在图形中心
xy={}
for i=1, #aaa do
if aaa[i]~=nil then
a,b,c,d=_G.Yutils.shape.bounding(aaa[i]) xy[i]={x=(a+c)/2,y=(b+d)/2}
aaa[i]=_G.Yutils.shape.move(aaa[i],-xy[i].x,-xy[i].y)
end
end
应用到字幕文件中,
Comment: 0,0:00:00.00,0:00:05.00,Default,text to shape,0,0,0,code syl noblank,style=syl.style text = _G.decode.create_font(style.fontname, style.bold, style.italic, style.underline, style.strikeout, style.fontsize).text_to_shape(syl.text_stripped) text=string.gsub(text," c","") text1=_G.Yutils.shape.filter(text, function(x,y) return math.round(x),math.round(y) end)
Comment: 0,0:00:00.00,0:00:05.00,Default,判断点是否在图形上,0,0,0,code once,function pointmeshshape(shape,x,y) local pixels=_G.Yutils.shape.to_pixels(shape) local n=1 local x=math.round(x) local y=math.round(y) local x1,y1,x2,y2=_G.Yutils.shape.bounding(shape) if x<x1 or x>x2 or y<y1 or y>y2 then return false end for i=1,#pixels do if x==pixels[i].x and y==pixels[i].y then n=0 end end if n==0 then return true else return false end end
Comment: 0,0:00:00.00,0:00:05.00,Default,DOMO拆字 函数,0,0,0,code once,function text_split(text_shape) local function delete_empty(tbl,mode) if mode == 1 then for i=#tbl,1,-1 do if tbl[i] == "" then _G.table.remove(tbl, i) end end elseif mode==2 then for i=#tbl,1,-1 do if (tbl[i].shape_i == "" or tbl[i].shape == nil) then _G.table.remove(tbl, i) end end end return tbl end local function is_include(value, tbl) for k,v in _G.ipairs(tbl) do if v == value then return true end end return false end local function string_split(str, split_char) local sub_str_tab = {} while true do local pos = string.find(str, split_char) if not pos then _G.table.insert(sub_str_tab,str) break end local sub_str = string.sub(str, 1, pos - 1) _G.table.insert(sub_str_tab,sub_str) str = string.sub(str, pos + 1, string.len(str)) end return sub_str_tab end local function split_by_m(text) text = string_split(text,"m") _G.table.remove(text,1) point = {} for i=1,#text do point[i] = {} text[i] = "m"..text[i] for x,y in string.gmatch(text[i],"[m|l|b] (-?%d+) (-?%d+)") do _G.table.insert(point[i],{x = x,y = y}) end end return text end local function rec(text) new_shape_tbl = {} record = {} for i=1,#text do for j=1,#text do x,y = _G.tonumber(point[j][1].x),_G.tonumber(point[j][1].y) if (pointmeshshape(text[i],x,y) and i~=j) then _G.table.insert(record,{inner = j,outer = i}) else _G.table.insert(record,"") end end end return record end local function record_handler(record_tbl,text) info_tbl = {} outer = {} inner = {} for i=1,#record_tbl do outer[i]={} inner[i]={} for j=1,#record_tbl do if record_tbl[j].inner == i then _G.table.insert(outer[i],record_tbl[j].outer) end if record_tbl[j].outer == i then _G.table.insert(inner[i],record_tbl[j].inner) end end _G.table.insert(info_tbl,{shape_i = i, o_count = #outer[i],outer = outer[i],in_count = #inner[i],inner=inner[i], shape = text[i]}) end return delete_empty(info_tbl) end local function shape_assembler(info_tbl) new_t = {} delete_empty(info_tbl,2) _G.table.sort(info_tbl,function (a,b) return a.o_count > b.o_count end) info_tbl["n"]= #info_tbl for i=1,info_tbl.n do if ((info_tbl[i].o_count==0 or info_tbl[i].o_count%2==0) and info_tbl[i].in_count==0) then new_t[i] = info_tbl[i] elseif (info_tbl[i].in_count>=1 and info_tbl[i].o_count~=0 and info_tbl[i].o_count%2==0) then for j=i,1,-1 do if is_include(info_tbl[i].shape_i,info_tbl[j].outer) then info_tbl[i].shape = info_tbl[i].shape.." "..info_tbl[j].shape end end new_t[i] = info_tbl[i] elseif (info_tbl[i].o_count==0 and info_tbl[i].in_count~=0) then for j=i,1,-1 do if is_include(info_tbl[i].shape_i,info_tbl[j].outer) and #info_tbl[j].outer==1 then info_tbl[i].shape = info_tbl[i].shape.." "..info_tbl[j].shape end end new_t[i] = info_tbl[i] else new_t[i] ="" end end new_t = delete_empty(new_t,1) for i=1,#new_t do new_t[i] = new_t[i].shape end return new_t end local text_tbl=split_by_m(text_shape) local record_tbl=rec(text_tbl) local new_table=record_handler(record_tbl,text_tbl) local shapes=shape_assembler(new_table) return shapes end
Comment: 0,0:00:00.00,0:00:05.00,Default,拆出来的存到表aaa,0,0,0,code syl noblank,aaa = text_split(text1)
Comment: 0,0:00:00.00,0:00:05.00,Default,移动到中心,0,0,0,code syl noblank,xy={} for i=1, #aaa do if aaa[i]~=nil then a,b,c,d=_G.Yutils.shape.bounding(aaa[i]) xy[i]={x=(a+c)/2,y=(b+d)/2} aaa[i]=_G.Yutils.shape.move(aaa[i],-xy[i].x,-xy[i].y) end end
Comment: 0,0:00:00.00,0:00:00.00,Default,,0,0,0,template syl noblank notext,!maxloop(#aaa)!{\an7\pos(!$left+xy[j].x!,!$top+xy[j].y!)\p1\blur2\1c!_G.ass_color(_G.HSV_to_RGB(math.random(0,300),1,1))!}!aaa[j]!
Comment: 0,0:00:00.00,0:00:05.00,Default,,0,0,0,karaoke,{\k125}测{\k125}试{\k125}字{\k125}幕