Welchen Algorithmus verwendet LuaLaTeX für Fallback-Schriftarten?

Welchen Algorithmus verwendet LuaLaTeX für Fallback-Schriftarten?

Hintergrund Ich habe seit einigen Jahren immer wieder an einem Buch über die Schriften und Sprachen der Welt gearbeitet. Es behandeltalledie aufgeführten Schriften in Unicode, sowie etwa ein Dutzend, bei denen es noch keinen Unicode-Standard gibt und ich Bilder statt Schriftarten verwende.

Mit der Weiterentwicklung der Noto-Schriftarten, des Unicode-Formats LuaLaTeX und der L3-Version konnte ich einen angemessenen Bereich für alle Schriften drucken, wie für die Niederschrift erforderlich. Mit Ausnahme der ostasiatischen Schriften, von denen ich nur wenige Seiten pro Schrift habe. Ich verwende Brill als Hauptschriftart und habe Ersatzschriften hinzugefügt, um die restlichen Schriften abzudecken. Das Buch hat bisher etwa 350 Seiten und ich gehe davon aus, dass es eine endgültige Größe von 600 Seiten erreichen wird. Um die Unicode-Punkte abzudecken, müssen die Schriften +-150.000 Glyphen bereitstellen. Wie ich bereits erwähnt habe, werden nicht alle Codepunkte im Buch verwendet. Meiner Schätzung nach brauche ich nur etwa die Hälfte davon. Offensichtlich und verständlicherweise ist die Kompilierungsgeschwindigkeit ein Problem, daher versuche ich, den von luaotfload-fallback.lua verwendeten Algorithmus zu verstehen, um zu versuchen, die Verarbeitungszeit zu verbessern. Ich suche nach Strategien zur Optimierung der Kompilierungszeiten, nicht nur für mein Dokument, sondern allgemein.

Ich habe Engpässe hauptsächlich in drei Bereichen identifiziert: a) Schriftarten, b) Bilder, c) Protokollierung (Festplattenschreibvorgänge im Allgemeinen). Für Bilder werde ich einen Präprozessor verwenden und sie alle optimieren sowie PDFs erstellen. Ich werde Golang für den Präprozessor verwenden, der bei Bedarf auch Markierungen vornehmen kann. Ideen für Schriftarten und Protokollierung siehe unten.

  1. Ich habe diese (verrückte) Idee, dass die während der Verarbeitung an den Knoten benötigten Glypheninformationen über einen lokalen Server abgerufen werden, sodass einige Aufgaben ausgelagert und parallel ausgeführt werden können. Ich denke an eine Art Prioritätswarteschlange, sodass Daten für häufig verwendete Codepunkte schnell bereitgestellt werden können und alle nicht verwendeten Codepunkte bei einem zweiten Durchlauf aus dem Cache entfernt werden. Auch hier werde ich Golang und SQLite3 verwenden, da alles lokal ist. Im Moment habe ich eine Lua-Tabelle, die Unicode-Punkte basierend auf einer Konfigurationsdatei Schriftarten zuordnet.

  2. Alle Protokolle werden auch an einen Server gesendet und nicht auf die Festplatte geschrieben. Dies kann auch für die AUX-Dateien erfolgen.

  3. Die Generierung des PDFs dauert ebenfalls, aber ich bin mir derzeit nicht sicher, ob sie optimiert werden kann. Die aktuelle Kompilierungsgeschwindigkeit beträgt etwa 1,3 Sekunden pro Seite + anfänglich 30-40 Sekunden.

Frage Kann mir jemand die algorithmischen Schritte in luaotfload-fallback.lua erklären? Wann und wie wird dies von LuaTeX beim Erstellen eines Dokuments verwendet? An welcher Stelle werden die Glypheninformationen benötigt? Alle Ideen sind willkommen. Vielen Dank, dass Sie bis hierhin gelesen haben.

Antwort1

Dies beantwortet die Frage im Fragentitel überhaupt nicht, aber ich denke, dass hierdurch (hoffentlich) die im Fragentext dargestellten Probleme angesprochen werden.

Indirekte Antwort

Hier ist eine Lösung, die mit LuaLaTeX 231 einzigartige Schriftarten lädt und 83.020 einzigartige Zeichen (103 Seiten) in 7,505 Sekunden (im Durchschnitt) druckt.

Führen Sie zunächst dieses Skript aus, um alle Schriftarten herunterzuladen:

#!/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 ..

Platzieren Sie dann Folgendes in 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)

Anschließend können Sie alle Zeichen mithilfe des folgenden Dokuments ausdrucken:

\documentclass{article}

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

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

ConTeXt ist mit durchschnittlich 4,849 Sekunden 50 % schneller:

\ctxloadluafile{all-characters}

\starttext
    \printallchars
\stoptext

Nützlicher ist, dass dadurch auch eine virtuelle Schriftart definiert wird \allcharactersfont , die Zeichen aus allen geladenen Schriftarten enthält:

\documentclass{article}
\pagestyle{empty}

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

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

verwandte Informationen