Last active
December 18, 2015 16:38
-
-
Save phi-gamma/5812290 to your computer and use it in GitHub Desktop.
example code for http://tex.stackexchange.com/q/119883 (tracking missing glyphs with luaotfload)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
----------------------------------------------------------------------- | |
-- FILE: track-missing-glyphs.lua | |
-- USAGE: dofile "track-missing-glyphs.lua" | |
-- DESCRIPTION: output a message if a font lacks a glyph for a | |
-- codepoint | |
-- REQUIREMENTS: luatex, luaotfload | |
-- COPYRIGHT: Hans Hagen, Pragma ADE, Hasselt NL | |
-- AUTHOR: Philipp Gesang (Phg), <[email protected]> | |
-- MODIFIED: 2013-06-22 12:39:26+0200 | |
----------------------------------------------------------------------- | |
-- | |
local stringformat = string.format | |
local traverse_id = node.traverse_id | |
local utf8char = unicode.utf8.char | |
local fonthashes = fonts.hashes | |
local fontdata = fonthashes.identifiers | |
local chardata = characters.data | |
local names_report = logs.names_report | |
local glyph_t = nodes.nodecodes.glyph | |
local nullfont = 0 | |
--- namespace | |
documentdata = documentdata or { } | |
documentdata.missing_glyphs = documentdata.missing_glyphs or { } | |
local missing_glyphs = documentdata.missing_glyphs | |
local complain = function (font_id, char) | |
local tfmdata = fontdata[font_id] | |
if tfmdata then | |
local fontname = tfmdata.fontname or "" | |
names_report("both", 0, "missing glyph", | |
"%d [%s] of %s", char, utf8char(char), fontname) | |
else | |
names_report("both", 0, "missing glyph", | |
"%d [%s] of %d", char, utf8char(char), font_id) | |
end | |
end | |
local fontcharacters = { } | |
table.setmetatableindex(fontcharacters, function (t, k) | |
if k == true then | |
return fontcharacters[currentfont()] | |
else | |
local tfmdata = fontdata[k] | |
if not tfmdata then --- unsafe | |
tfmdata = font.fonts[k] | |
if not (tfmdata and type (tfmdata) == "table") then | |
return false | |
end | |
end | |
local characters = tfmdata.characters | |
t[k] = characters | |
return characters | |
end | |
end) | |
local initialize = function ( ) | |
local chardef = assert(kpse.find_file ("char-def.lua", "lua"), | |
"\nError: cannot find char-def.lua; \z | |
please install Context.") | |
dofile(chardef) --- will overwrite the partial character table | |
chardata = characters.data | |
return chardata | |
end | |
local is_character = table.tohash({ --- from char-ini.lua | |
"lu", "ll", "lt", "lm", "lo", | |
"nd", "nl", "no", | |
"mn", | |
"nl", "no", | |
"pc", "pd", "ps", "pe", "pi", "pf", "po", | |
"sm", "sc", "sk", "so" | |
}) | |
local once = false --- complain only once per glyph | |
local missing = { } --- (font_id, glyph_id set) hash_t | |
local initialized = false --- track loading of char-def for older versions | |
local nodeprocessor = function (head) | |
local lastfont, characters = nil, nil | |
local missing = missing | |
for n in traverse_id(glyph_t, head) do | |
local font = n.font | |
local char = n.char | |
if missing[font] and missing[font][char] == true then | |
--- already registered | |
if once == false then | |
complain(font, char) | |
end | |
else | |
if font ~= lastfont and font ~= nullfont then | |
characters = fontcharacters[font] | |
end | |
if characters ~= false then | |
lastfont = font | |
if not characters[char] then | |
local category = chardata[char].category | |
if not category then --- old luaotfload | |
initialize() | |
category = chardata[char].category | |
end | |
if category and is_character[category] then | |
missing[font] = missing[font] or { } | |
--- could have a counter and do some stats here | |
missing[font][char] = true | |
complain(font, char) | |
end | |
end | |
end | |
end | |
end | |
return head, false | |
end | |
local active = false | |
local enable = function (parm) | |
if active == false then | |
if parm == "once" then | |
once = true | |
end | |
luatexbase.add_to_callback( | |
"pre_linebreak_filter", nodeprocessor, "user.missing_glyphs") | |
luatexbase.add_to_callback( | |
"hpack_filter", nodeprocessor, "user.missing_glyphs") | |
active = true | |
end | |
end | |
local disable = function ( ) | |
if active == true then | |
luatexbase.remove_from_callback( | |
"pre_linebreak_filter", "user.missing_glyphs") | |
luatexbase.remove_from_callback( | |
"hpack_filter", "user.missing_glyphs") | |
once = false | |
active = false | |
end | |
end | |
documentdata.missing_glyphs.enable = enable | |
documentdata.missing_glyphs.disable = disable |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
\documentclass{article} | |
\usepackage{luacode,fontspec} | |
%% 1) initialize the tracker code (could go to separate file) | |
\makeatletter | |
\directlua{dofile "track_missing_glyphs.lua"} | |
%% 2) Environment start: the optional argument “once”, in square | |
%% brackets, requests that the missing glyph message be printed | |
%% only once per character and font. | |
\def\startreportmissingglyphs{% | |
\@ifnextchar[\missingglyphs@start@indeed% | |
{\missingglyphs@start@indeed[]}% | |
} | |
\def\missingglyphs@start@indeed[#1]{% | |
\directlua{documentdata.missing_glyphs.enable"\luaescapestring{#1}"}% | |
} | |
%% 3) Environment stop: we need to force a \par here to | |
%% have the callback apply to the current paragraph. | |
\def\stopreportmissingglyphs{% | |
\endgraf %% paragraph-based callback! | |
\directlua{documentdata.missing_glyphs.disable()}% | |
} | |
\makeatother | |
%% Usage examples. | |
\begin{document} | |
%% Latin modern lacks glyphs for the Greek script so we use that for | |
%% testing. | |
\startreportmissingglyphs | |
Program the μC, please. | |
%% Works in math mode (different font model) as well. | |
$f = ma$ | |
\stopreportmissingglyphs | |
lorem schmipsum | |
\startreportmissingglyphs[once] | |
%% With the “once” flag, no message is emitted for repetitions of | |
%% missing chars. | |
Θάλαττα, θάλαττα. | |
\stopreportmissingglyphs | |
\end{document} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment