Qual algoritmo o LuaLaTeX usa para fontes substitutas?

Qual algoritmo o LuaLaTeX usa para fontes substitutas?

Fundo Tenho estado ocupado com um livro sobre as escritas e idiomas do mundo há alguns anos. Cobretodosos scripts listados em unicode, bem como uma dúzia ou mais, onde ainda não existe um padrão unicode e eu uso imagens em vez de fontes.

Com as fontes Noto, unicode LuaLaTeX e l3 em maturação, consegui imprimir um intervalo razoável para todos os scripts, conforme necessário na redação. Com exceção dos scripts do Leste Asiático, tenho apenas algumas páginas por script. Eu uso como fonte principal Brill e adicionei fontes substitutas para cobrir o restante dos scripts. O livro até agora gira em torno de 350 páginas e prevejo que terá um tamanho final de 600 páginas. Para cobrir os pontos Unicode, as fontes precisam fornecer +-150.000 glifos. Nem todos os pontos de código são usados ​​no livro, como mencionei anteriormente; na minha opinião, só preciso de cerca de metade disso. Obviamente e compreensivelmente, a velocidade de compilação é um problema, então estou procurando entender o algoritmo usado por luaotfload-fallback.lua para tentar ver se consigo melhorar o tempo de processamento. Estou buscando estratégias para otimizar os tempos de compilação, não só para o meu documento, mas em geral.

Identifiquei gargalos principalmente em três áreas: a) fontes b) imagens c) registro (gravações em disco em geral). Imagens Usarei um pré-processador e otimizarei todas elas além de produzir PDFs. Usarei Golang como pré-processador, que também pode fazer marcação, se necessário. Idéias para fontes e registros, veja abaixo.

  1. Tenho essa ideia (maluca) de que as informações do glifo exigidas nos nós durante o processamento sejam obtidas por meio de um servidor local, para que algumas tarefas possam ser externalizadas e executadas com simultaneidade. Estou pensando em alguma forma de prioridade, para que os dados dos pontos de código usados ​​​​com frequência possam ser servidos rapidamente e quaisquer pontos de código não utilizados em uma segunda execução sejam retirados do cache. Novamente aqui usarei Golang e sqlite3 já que tudo é local. Eu tenho uma tabela Lua no momento, que mapeia pontos Unicode para fontes, com base em um arquivo de configuração.

  2. Todos os registros também serão enviados para um servidor, em vez de gravados no disco. Também pode ser feito para os arquivos aux.

  3. A geração do pdf também leva tempo, mas neste momento estou indeciso se ele pode ser otimizado. A velocidade de compilação atual é de cerca de 1,3 segundos por página + uma inicial de 30 a 40 segundos.

Pergunta Alguém pode me explicar as etapas algorítmicas em luaotfload-fallback.lua? Quando e como isso é usado pelo LuaTeX na construção de um documento? Em que ponto as informações do glifo são necessárias? Qualquer ideia é bem-vinda. Obrigado por ler até aqui.

Responder1

Isso não responde à pergunta no título da pergunta, mas acho que aborda os problemas apresentados no corpo da pergunta (espero).

Resposta indireta

Aqui está uma solução que carrega 231 fontes exclusivas e imprime 83.020 caracteres únicos (103 páginas) em 7.505 segundos (em média) usando LuaLaTeX.

Primeiro, execute este script para baixar todas as fontes:

#!/bin/sh
set -eu

mkdir fonts
cd fonts

git clone --depth 1 --no-checkout --filter=blob:none \
    https://github.com/notofonts/notofonts.github.io.git
cd notofonts.github.io
git sparse-checkout set --no-cone '!/*' '/fonts/**/hinted/ttf/*-Regular.ttf'
git checkout main
cd ..

git clone --depth 1 --no-checkout --filter=blob:none \
    https://github.com/notofonts/noto-cjk.git
cd noto-cjk
git sparse-checkout set --no-cone '!/*' '/Serif/SubsetOTF/**/*-Regular.otf'
git checkout main
cd ..

wget -O unifont-Regular.otf \
    https://unifoundry.com/pub/unifont/unifont-15.1.04/font-builds/unifont-15.1.04.otf
wget -O unifont_upper-Regular.otf \
    https://unifoundry.com/pub/unifont/unifont-15.1.04/font-builds/unifont_upper-15.1.04.otf

wget -O NotoEmoji-Regular.ttf \
    "$(curl 'https://fonts.googleapis.com/css2?family=Noto+Emoji' | grep -o 'https.*ttf')"

cd ..

Em seguida, coloque o seguinte em all-characters.lua:

-- Save some globals for speed
local ipairs = ipairs
local max = math.max
local new_node = node.new
local node_write = node.write
local pairs = pairs

-- Define some constants
local GLUE_ID = node.id("glue")
local GLYPH_ID = node.id("glyph")
local SIZE = tex.sp("10pt")

-- Get all the fonts
local fontpaths = dir.glob("**-Regular.*", "./fonts")

-- Sort the fonts such that the "preferred" fonts are last
table.sort(fontpaths, function(a, b)
    local a = file.nameonly(a):match("(.+)-Regular")
    local b = file.nameonly(b):match("(.+)-Regular")

    if a:match("Serif") and not b:match("Serif") then
        return false
    end
    if b:match("Serif") and not a:match("Serif") then
        return true
    end
    if a:match("unifont") and not b:match("unifont") then
        return true
    end
    if b:match("unifont") and not a:match("unifont") then
        return false
    end
    if #a == #b then
        return a > b
    end
    return #a > #b
end)


-- Create a mapping from codepoint to font id
local by_character = {}
local virtual_fonts = {}

for _, filename in ipairs(fontpaths) do
    local fontdata = fonts.definers.read {
        lookup = "file",
        name = filename,
        size = SIZE,
        features = {},
    }
    local id = font.define(fontdata)
    fonts.definers.register(fontdata, id)

    virtual_fonts[#virtual_fonts + 1] = { id = id }

    for codepoint, char in pairs(fontdata.characters) do
        if char.unicode == codepoint then
            by_character[codepoint] = {
                width = char.width,
                height = char.height,
                depth = char.depth,
                font = id,
                commands = {
                    { "slot", #virtual_fonts, codepoint }
                },
            }
        end
    end
end

local function print_all_chars()
    local count = 0

    tex.forcehmode()
    for codepoint, data in table.sortedpairs(by_character) do
        local glyph = new_node(GLYPH_ID)
        glyph.font = data.font
        glyph.char = codepoint

        local space = new_node(GLUE_ID)
        space.width = max(2 * SIZE - glyph.width, 0)
        glyph.next = space

        node_write(glyph)
        count = count + 1
    end
    tex.sprint("\\par Characters: " .. count)
    tex.sprint("\\par Fonts: " .. #virtual_fonts)
end


-- Make the virtual font
local id = font.define {
    name = "all-characters",
    parameters = {},
    characters = by_character,
    properties = {},
    type = "virtual",
    fonts = virtual_fonts,
}

local new_command
if ltx then
    new_command = function(name, func)
        local index = luatexbase.new_luafunction(name)
        lua.get_functions_table()[index] = func
        token.set_lua(name, index, "protected")
    end
elseif context then
    new_command = function(name, func)
        interfaces.implement {
            name = name,
            actions = func,
            public = true,
        }
    end
end

new_command("printallchars", print_all_chars)
new_command("allcharactersfont", function() font.current(id) end)

Então, você pode imprimir todos os caracteres usando o seguinte documento:

\documentclass{article}

\ExplSyntaxOn
\lua_load_module:n { all-characters }
\ExplSyntaxOn

\begin{document}
    \printallchars
\end{document}

ConTeXt é 50% mais rápido com 4,849 segundos em média:

\ctxloadluafile{all-characters}

\starttext
    \printallchars
\stoptext

Mais útil, isso também define uma fonte virtual \allcharactersfont que contém caracteres de todas as fontes carregadas:

\documentclass{article}
\pagestyle{empty}

\ExplSyntaxOn
\lua_load_module:n { all-characters }
\ExplSyntaxOn

\begin{document}
    {\allcharactersfont
        A Ξ Ж س
        क ௵ ෴ ფ
        ጄ ᑠ ᘟ Ⅶ
        ∰ ⡿ だ 㬯

informação relacionada