tikz add tag
user 3.14159
I am wondering if one can get the outlines of glyphs somehow into Ti*k*Z without too much hassle. 

In asymptote and to some extent in PSTricks this is possible, see e.g. https://tex.stackexchange.com/a/21593. (IMHO in PSTricks this is sort of a cheat, but I do not want to discuss this here.)

In Ti*k*Z it seems to be possible only with tremendous effort, see e.g. https://tex.stackexchange.com/a/21594. However, this information is almost a decade old. So I am hoping that there are now more user-friendly methods available, ideally as easy to use as in asymptote. 

Why am I interested in this? One reason is that there is the perspective library, another reason is that there are generic nonlinear transformations. It would be really gorgeous if one could apply them to glyphs in Ti*k*Z.

To be clear, what I am not interested in is something that can also be achieved with path fading. I really want to have an explicit path that can be transformed in an any way a path can be transformed, without limitations. And, of course, the more user-friendly, the better.

What have I tried? Not much that I can present here. So no MWE, sorry. I could copy one from the links above, but do not see what this will add. (This is not because I am too lazy to forge an MWE, but I really do not see its purpose here.)
Top Answer
Anonymous 2084
The present answer builds upon two good answers from Stack Exchange:

- https://tex.stackexchange.com/a/451951
- https://tex.stackexchange.com/a/605893

Maybe Tikz can add a library for this.
```
\documentclass{article}
\usepackage{fontspec}
\usepackage{tikz}
\usepackage{luacode}
\begin{luacode*}
local concat = table.concat

local function f_moveto(...)
    return string.format("\\pgfsyssoftpath@movetotoken{%fpt}{%fpt}", ...)
end
local function f_lineto(...)
    return string.format("\\pgfsyssoftpath@linetotoken{%fpt}{%fpt}", ...)
end
local function f_curveto(...)
    return string.format(
        "\\pgfsyssoftpath@curvetosupportatoken{%fpt}{%fpt}" ..
        "\\pgfsyssoftpath@curvetosupportbtoken{%fpt}{%fpt}" ..
        "\\pgfsyssoftpath@curvetotoken{%fpt}{%fpt}", ...)
end
local s_cycle = "\\pgfsyssoftpath@closepath"
  
-- from font-mps.lua
local function glyph_to_paths(d,xfactor,yfactor)
    local sequence = d.sequence
    local segments = d.segments
    local list     = { }
    local path     = { } -- recycled
    local size     = 0
    local xfactor  = xfactor or 1
    local yfactor  = yfactor or xfactor
    if sequence then
        local i = 1
        local n = #sequence
        while i < n do
            local operator = sequence[i]
            if operator == "m" then -- "moveto"
                if size > 0 then
                    size = size + 1
                    path[size] = s_cycle
                    list[#list+1] = concat(path,"",1,size)
                    size = 1
                else
                    size = size + 1
                end
                path[size] = f_moveto(xfactor*sequence[i+1],yfactor*sequence[i+2])
                i = i + 3
            elseif operator == "l" then -- "lineto"
                size = size + 1
                path[size] = f_lineto(xfactor*sequence[i+1],yfactor*sequence[i+2])
                i = i + 3
            elseif operator == "c" then -- "curveto"
                size = size + 1
                path[size] = f_curveto(xfactor*sequence[i+1],yfactor*sequence[i+2],xfactor*sequence[i+3],yfactor*sequence[i+4],xfactor*sequence[i+5],yfactor*sequence[i+6])
                i = i + 7
            elseif operator =="q" then -- "quadraticto"
                size = size + 1
                -- first is always a moveto
                local l_x = xfactor*sequence[i-2]
                local l_y = yfactor*sequence[i-1]
                local m_x = xfactor*sequence[i+1]
                local m_y = yfactor*sequence[i+2]
                local r_x = xfactor*sequence[i+3]
                local r_y = yfactor*sequence[i+4]
                path[size] = f_curveto (
                    l_x + 2/3 * (m_x-l_x),
                    l_y + 2/3 * (m_y-l_y),
                    r_x + 2/3 * (m_x-r_x),
                    r_y + 2/3 * (m_y-r_y),
                    r_x, r_y
                )
                i = i + 5
            else
                -- weird
                i = i + 1
            end
        end
    elseif segments then
        for i=1,#segments do
            local segment  = segments[i]
            local operator = segment[#segment]
            if operator == "m" then -- "moveto"
                if size > 0 then
                    size = size + 1
                    path[size] = s_cycle
                    list[#list+1] = concat(path,"",1,size)
                    size = 1
                else
                    size = size + 1
                end
                path[size] = f_moveto(xfactor*segment[1],yfactor*segment[2])
            elseif operator == "l" then -- "lineto"
                size = size + 1
                path[size] = f_lineto(xfactor*segment[1],yfactor*segment[2])
            elseif operator == "c" then -- "curveto"
                size = size + 1
                path[size] = f_curveto(xfactor*segment[1],yfactor*segment[2],xfactor*segment[3],yfactor*segment[4],xfactor*segment[5],yfactor*segment[6])
            elseif operator =="q" then -- "quadraticto"
                size = size + 1
                -- first is always a moveto
                local prev = segments[i-1]
                local l_x = xfactor*prev[#prev-2]
                local l_y = yfactor*prev[#prev-1]
                local m_x = xfactor*segment[1]
                local m_y = yfactor*segment[2]
                local r_x = xfactor*segment[3]
                local r_y = yfactor*segment[4]
                path[size] = f_curveto (
                    l_x + 2/3 * (m_x-l_x),
                    l_y + 2/3 * (m_y-l_y),
                    r_x + 2/3 * (m_x-r_x),
                    r_y + 2/3 * (m_y-r_y),
                    r_x, r_y
                )
            else
                -- weird
            end
        end
    else
        return
    end
    if size > 0 then
        size = size + 1
        path[size] = s_cycle
        list[#list+1] = concat(path,"",1,size)
    end
    return list
end

-- from meta-imp-outlines.mkiv
-- That's a simple reimplemetation of ConTeXt's \showshape macro
function outlinepaths(character)
    local fontid      = font.current()
    local shapedata   = fonts.hashes.shapes[fontid] -- by index
    local chardata    = fonts.hashes.characters[fontid] -- by unicode
    local shapeglyphs = shapedata.glyphs or { }

    character = utf.byte(character)
    local c = chardata[character]
    if c then
        if not c.index then
            return {}
        end
        local glyph = shapeglyphs[c.index]
        if glyph and (glyph.segments or glyph.sequence) then
            local units  = shapedata.units or 1000
            local factor = 100/units
            local paths  = glyph_to_paths(glyph,factor)
            return paths
        end
    end
end
\end{luacode*}
\begin{document}

\makeatletter
\directlua{
    for i, path in ipairs(outlinepaths("A")) do
        token.set_macro("path" .. string.char(string.byte("A") + i - 1), path)
    end
}
\makeatother

\begin{tikzpicture}
  \draw[use path=\pathA];
  \draw[use path=\pathB];
\end{tikzpicture}

\end{document}
```

Boring output is

![Screenshot](/image?hash=18f71734ca4d3b05f7a56bac9adca005b0c63e125c71a4dc642d8d1da5c077a3)

Enter question or answer id or url (and optionally further answer ids/urls from the same question) from

Separate each id/url with a space. No need to list your own answers; they will be imported automatically.