Какой алгоритм использует LuaLaTeX для резервных шрифтов?

Какой алгоритм использует LuaLaTeX для резервных шрифтов?

Фон Я был занят книгой о мировых письменностях и языках в течение нескольких лет. Она охватываетвсеперечисленные скрипты в юникоде, а также около десятка, для которых пока нет стандарта юникода и я использую изображения вместо шрифтов.

С шрифтами Noto, unicode LuaLaTeX и l3 maturing я смог напечатать разумный диапазон для всех сценариев, как это было необходимо в написании. За исключением восточноазиатских сценариев, для которых у меня есть только несколько страниц на сценарий. Я использую в качестве основного шрифта Brill и добавил резервные шрифты, чтобы охватить остальные сценарии. Книга на данный момент составляет около 350 страниц, и я ожидаю, что она достигнет окончательного размера в 600 страниц. Чтобы охватить точки unicode, шрифты должны предоставить +-150 000 глифов. Не все кодовые точки используются в книге, как я упоминал ранее, по моим оценкам, мне нужно только около половины этого. Очевидно и понятно, что скорость компиляции является проблемой, поэтому я пытаюсь понять алгоритм, используемый luaotfload-fallback.lua, чтобы попытаться увидеть, смогу ли я улучшить время обработки. Я ищу стратегии для оптимизации времени компиляции не только для моего документа, но и в целом.

Я выявил узкие места в основном в трех областях: a) шрифты b) изображения c) ведение журнала (запись на диск в целом). Изображения Я буду использовать препроцессор и оптимизировать их все, а также создавать pdf-файлы. Я буду использовать Golang для препроцессора, который также может делать разметку, если это необходимо. Идеи для шрифтов и ведения журнала см. ниже.

  1. У меня есть эта (сумасшедшая) идея, что информация о глифе, необходимая узлам во время обработки, должна быть получена через локальный сервер, чтобы некоторые задачи можно было вынести на внешний сервер и запускать с параллелизмом. Я думаю о некоей форме приоритетной очереди, чтобы данные для часто используемых кодовых точек могли обслуживаться быстро, а любые неиспользуемые кодовые точки при втором запуске извлекались из кэша. Опять же, здесь я буду использовать Golang и sqlite3, поскольку все локально. На данный момент у меня есть таблица Lua, которая сопоставляет точки Unicode со шрифтами на основе файла конфигурации.

  2. Все журналы также должны быть отправлены на сервер, а не записаны на диск. Также может быть сделано для aux-файлов.

  3. Генерация pdf также занимает время, но я не решил на данный момент, можно ли ее оптимизировать. Текущая скорость компиляции составляет около 1,3 секунды на страницу + начальная 30-40 секунд.

Вопрос Может ли кто-нибудь объяснить мне алгоритмические шаги в luaotfload-fallback.lua? Когда и как это используется LuaTeX при построении документа? В какой момент нужна информация о глифе? Приветствуются любые идеи. Спасибо, что дочитали до этого места.

решение1

Это вообще не отвечает на вопрос, поставленный в заголовке, но я думаю, что это решает проблемы, изложенные в тексте вопроса (надеюсь).

Косвенный ответ

Вот решение, которое загружает 231 уникальный шрифт и печатает 83 020 уникальных символов (103 страницы) за 7,505 секунд (в среднем) с использованием LuaLaTeX.

Сначала запустите этот скрипт, чтобы загрузить все шрифты:

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

Затем поместите следующее 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)

Затем вы можете распечатать все символы, используя следующий документ:

\documentclass{article}

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

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

ConTeXt на 50% быстрее — в среднем 4,849 секунды:

\ctxloadluafile{all-characters}

\starttext
    \printallchars
\stoptext

Что еще более полезно, это также определяет виртуальный шрифт \allcharactersfont , содержащий символы из всех загруженных шрифтов:

\documentclass{article}
\pagestyle{empty}

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

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

Связанный контент