배경 나는 몇 년 동안 세계의 문자와 언어에 관한 책을 집필하느라 바빴습니다. 그것은 커버모두나열된 스크립트는 유니코드로 되어 있으며, 아직 유니코드 표준이 없고 글꼴 대신 이미지를 사용하는 12개 정도의 스크립트도 있습니다.
Noto 글꼴, 유니코드 LuaLaTeX 및 l3 성숙도를 통해 글 작성 시 필요에 따라 모든 스크립트에 대해 합리적인 범위를 인쇄할 수 있었습니다. 동아시아 스크립트를 제외하면 스크립트당 몇 페이지만 있습니다. 저는 Brill을 기본 글꼴로 사용하고 나머지 스크립트를 덮기 위해 대체 글꼴을 추가했습니다. 지금까지 책은 약 350페이지 정도 되었으며 최종 크기는 600페이지에 달할 것으로 예상됩니다. 유니코드 포인트를 포함하려면 글꼴에서 +-150,000개의 글리프를 제공해야 합니다. 책에서 모든 코드포인트가 사용되는 것은 아닙니다. 앞서 언급했듯이 제 생각에는 그 중 절반 정도만 필요할 것 같습니다. 분명히 컴파일 속도가 문제이므로 luaotfload-fallback.lua에서 사용되는 알고리즘을 이해하여 처리 시간을 향상시킬 수 있는지 확인하려고 합니다. 나는 내 문서뿐만 아니라 전반적인 컴파일 시간을 최적화하기 위한 전략을 찾고 있습니다.
나는 주로 a) 글꼴 b) 이미지 c) 로깅(일반적으로 디스크 쓰기) 세 가지 영역에서 병목 현상을 확인했습니다. 이미지 저는 전처리기를 사용하여 모든 것을 최적화하고 PDF를 생성할 것입니다. 필요한 경우 마킹도 할 수 있는 전처리기로 Golang을 사용하겠습니다. 글꼴 및 로깅에 대한 아이디어는 아래를 참조하세요.
나는 처리 중에 노드에 필요한 문자 모양 정보를 로컬 서버를 통해 획득하여 일부 작업을 외부화하고 동시성으로 실행할 수 있다는 (미친) 아이디어를 가지고 있습니다. 나는 자주 사용되는 코드 포인트에 대한 데이터를 빠르게 제공하고 두 번째 실행에서 사용되지 않는 코드 포인트를 캐시에서 제거할 수 있도록 일종의 우선순위 쿼리를 생각하고 있습니다. 여기서도 모든 것이 로컬이므로 Golang과 sqlite3을 사용하겠습니다. 현재 구성 파일을 기반으로 유니코드 포인트를 글꼴에 매핑하는 Lua 테이블이 있습니다.
모든 로깅은 디스크에 기록되지 않고 서버로 전송됩니다. aux 파일에도 가능합니다.
PDF를 생성하는 데도 시간이 걸리지만, 최적화할 수 있을지 현재로서는 결정되지 않았습니다. 현재 컴파일 속도는 페이지당 약 1.3초 + 초기 30~40초입니다.
질문 luaotfload-fallback.lua의 알고리즘 단계를 누군가 나에게 설명해 줄 수 있습니까? 문서를 작성할 때 LuaTeX에서 언제 어떻게 사용됩니까? 어느 시점에서 글리프 정보가 필요합니까? 어떤 아이디어라도 환영합니다. 여기까지 읽어주셔서 감사합니다.
답변1
이것은 질문 제목의 질문에 전혀 대답하지 않지만 질문 본문에 제시된 문제를 해결한다고 생각합니다.
간접 답변
다음은 LuaLaTeX를 사용하여 231개의 고유 글꼴을 로드하고 7.505초(평균)에 83,020개의 고유 문자(103페이지)를 인쇄하는 솔루션입니다.
먼저 이 스크립트를 실행하여 모든 글꼴을 다운로드하세요.
#!/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는 평균 4.849초로 50% 더 빠릅니다.
\ctxloadluafile{all-characters}
\starttext
\printallchars
\stoptext
\allcharactersfont
더 유용하게도 이는 로드된 모든 글꼴의 문자를 포함하는 가상 글꼴도 정의합니다 .
\documentclass{article}
\pagestyle{empty}
\ExplSyntaxOn
\lua_load_module:n { all-characters }
\ExplSyntaxOn
\begin{document}
{\allcharactersfont
A Ξ Ж س
क ௵ ෴ ფ
ጄ ᑠ ᘟ Ⅶ
∰ ⡿ だ 㬯
䷥