Skip to content

Instantly share code, notes, and snippets.

@dohyunkim
Last active May 6, 2024 00:18
Show Gist options
  • Save dohyunkim/007eb8d8b25804b5322c14bbefbc30d2 to your computer and use it in GitHub Desktop.
Save dohyunkim/007eb8d8b25804b5322c14bbefbc30d2 to your computer and use it in GitHub Desktop.
\documentclass{article}
\usepackage{fontspec}
\setmainfont{TeX Gyre Pagella}
%\setmainfont{Noto Sans CJK KR}
\usepackage{luamplib}
\mplibsetformat{metafun}
\directlua{ mplibglyph = require'mplibglyph' }
\begin{document}
\mpfig*
def mplibglyph expr c of f =
runscript (
"return mplibglyph.glyph('"
& if numeric f: decimal fi f
& "','"
& if numeric c: decimal fi c
& "')"
)
enddef;
def mplibdrawglyph expr g =
draw image(
save i; numeric i; i:=0;
for item within g:
i := i+1;
fill pathpart item
if i < length g: withpostscript "collect" fi;
endfor
)
enddef;
\endmpfig
\mpfig
picture g;
% g := mplibglyph "Dcaron" of \fontid\font scaled .2; % current font
% g := mplibglyph "g" of "TU/TeXGyrePagella(0)/m/n/10" scaled .2;
% g := mplibglyph "똠" of "NotoSansCJKkr-Regular.otf" scaled .15;
% g := mplibglyph 50 of "Times.ttc(1)" scaled .2;
g := mplibglyph "Q" of "Times.ttc(2)" scaled .2;
fill bbox g xscaled 2 withcolor .7[red,white];
draw g shifted (xpart lrcorner g, 0);
mplibdrawglyph g withcolor .7white;
path p;
i:=0;
for item within g:
i:=i+1;
p := pathpart item;
drawarrow p withcolor if turningnumber p > 0: red else: blue fi;
label(decimal i, 5 unitvector direction 0 of p) shifted point 0 of p;
endfor
\endmpfig
\mpfig
picture Q, u, e;
Q = g;
u := mplibglyph "u" of "Times.ttc(2)" scaled .2 shifted lrcorner Q;
e := mplibglyph "e" of "Times.ttc(2)" scaled .2 shifted lrcorner u;
i:=0;
totallen := length Q + length u + length e;
for pic=Q, u, e:
for item within pic:
i:=i+1;
fill pathpart item
if i < totallen: withpostscript "collect"; fi
endfor
endfor
withshademethod "linear"
withshadedirection (0.5,2.5)
withshadecolors (.7red,.7yellow)
;
\endmpfig
\end{document}
local format = string.format
local insert = table.insert
local unpack = table.unpack
local concat = table.concat
local function getangle (a,b,c)
local r = math.deg(math.atan(c.y-b.y, c.x-b.x) - math.atan(b.y-a.y, b.x-a.x))
if r > 180 then
r = r - 360
elseif r < -180 then
r = r + 360
end
return r
end
local function turning (t)
local r, n = 0, #t
for i=1,2 do
insert(t, t[i])
end
for i=1,n do
r = r + getangle(t[i], t[i+1], t[i+2])
end
return r/360
end
local function err (str)
return format('hide(errmessage "%s")', str)
end
local function glpaths(t, fmt)
local q,p,r = {{},{}}
for i,v in ipairs(t) do
local cmd = v[#v]
if cmd == "m" then
p = {format('(%s,%s)',unpack(v))}
r = {{x=v[1],y=v[2]}}
else
local nt = t[i+1]
local last = not nt or nt[#nt] == "m"
if cmd == "l" then
local pt = t[i-1]
local seco = pt[#pt] == "m"
if (last or seco) and r[1].x == v[1] and r[1].y == v[2] then
else
insert(p, format('--(%s,%s)',unpack(v)))
insert(r, {x=v[1],y=v[2]})
end
if last then
insert(p, '--cycle')
end
elseif cmd == "c" then
insert(p, format('..controls(%s,%s)and(%s,%s)',unpack(v)))
if last and r[1].x == v[5] and r[1].y == v[6] then
insert(p, '..cycle')
else
insert(p, format('..(%s,%s)',v[5],v[6]))
if last then
insert(p, '--cycle')
end
insert(r, {x=v[5],y=v[6]})
end
else
return err"unknown operator"
end
if last then
insert(q[ turning(r) > 0 and 1 or 2 ], concat(p))
end
end
end
r = { }
if fmt == "opentype" then
for _,v in ipairs(q[1]) do
insert(r, format('addto currentpicture contour %s;',v))
end
for _,v in ipairs(q[2]) do
insert(r, format('addto currentpicture contour %s withcolor background;',v))
end
else
for _,v in ipairs(q[2]) do
insert(r, format('addto currentpicture contour %s;',v))
end
for _,v in ipairs(q[1]) do
insert(r, format('addto currentpicture contour %s withcolor background;',v))
end
end
return format('image(%s)', concat(r))
end
if not file then require"lualibs" end
local function mplibglyph(f, c)
local filename, subfont, instance, kind, shapedata, cachedir
local fid = tonumber(f) or font.id(f) -- string: fontname
if fid > 0 then
local fontdata = font.getfont(fid)
filename, subfont, kind = fontdata.filename, fontdata.subfont, fontdata.format
instance = fontdata.specification and fontdata.specification.instance
else
local name
f = f:match"^%s*(.+)%s*$"
name, subfont, instance = f:match"(.+)%((%d+)%)%[(.-)%]$"
if not name then
name, instance = f:match"(.+)%[(.-)%]$" -- SourceHanSansK-VF.otf[Heavy]
end
if not name then
name, subfont = f:match"(.+)%((%d+)%)$" -- Times.ttc(2)
end
name = name or f
subfont = (subfont or 0)+1
instance = instance and instance:lower()
for _,ftype in ipairs{"opentype", "truetype"} do
filename = kpse.find_file(name, ftype.." fonts")
if filename then
kind = ftype; break
end
end
end
if kind ~= "opentype" and kind ~= "truetype" then
f = fid and fid > 0 and tex.fontname(fid) or f
if kpse.find_file(f, "tfm") then
c = tonumber(c) or format("%q",c)
return 'glyph '..c..' of "'..f..'"'
else
return err"font not found"
end
end
for _,dir in ipairs{ kpse.var_value"TEXMFVAR", "." } do
if dir and dir ~= "" then
dir = format("%s/luamplib_cache", dir)
if not lfs.isdir(dir) then
lfs.mkdirp(dir)
end
if file.is_writable(dir) then
cachedir = dir
break
end
end
end
local time = lfs.attributes(filename).modification
local newname = format("%s/shapes_%s%s%s.lua",
cachedir,
filename:gsub("%W","_"),
subfont and subfont > 1 and format("(%i)",subfont) or "",
instance and instance ~= "" and format("[%s]",instance) or "")
local newattr = lfs.attributes(newname)
local newtime = newattr and newattr.modification or 0
if time == newtime then
shapedata = require(newname)
end
if not shapedata then
shapedata = fonts.handlers.otf.readers.loadshapes(filename,subfont,instance)
table.tofile(newname, shapedata, "return")
lfs.touch(newname, time, time)
end
local gid = tonumber(c)
if not gid then
local codepoint = utf8.codepoint(c)
for i,v in ipairs(shapedata.glyphs) do
if c == v.name or codepoint == v.unicode then
gid = i
break
end
end
end
if not gid then return err"cannot get glyph id" end
local fac = 1000 / (shapedata.units or 1000)
local t = shapedata.glyphs[gid].segments
if not t then return err"glyph has no contour. Maybe blank space" end
for i,v in ipairs(t) do
if type(v) == "table" then
for ii,vv in ipairs(v) do
if type(vv) == "number" then
t[i][ii] = format("%.0f", vv * fac)
end
end
end
end
return glpaths(t, kind)
end
return {
glyph = mplibglyph,
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment