Created
April 3, 2010 19:56
-
-
Save pgundlach/354808 to your computer and use it in GitHub Desktop.
Fontloader für LuaTeX (http://www.luatex.de)
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
\pdfadjustspacing=2 | |
\directlua{ | |
dofile("fontloader.lua") | |
} | |
\def\ladefont#1#2{\directlua{ | |
local ok,f = define_font("#1",65536 * 12) | |
if ok then | |
local num = font.define(f) | |
tex.definefont("#2",num) | |
else | |
texio.write_nl(f) | |
end | |
}} | |
\def\beispieltext{Hallo Welt aäÄ oöÖ uüÜ ß ⌀ ℃ -- Va --- fl fi ffi fk ffl} | |
\ladefont{texgyreheros-regular.otf}{TeXgyreherosRegular} | |
\ladefont{texgyreheros-bold.otf}{TeXgyreherosBold} | |
\ladefont{lmr10.pfb}{LatinModern} | |
\TeXgyreherosRegular | |
\beispieltext | |
\TeXgyreherosBold | |
\beispieltext | |
\LatinModern | |
\beispieltext | |
\bye |
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
-- Gibt "truetype", "opentype" oder "type1" zurück, je nach Endung von "dateiname". | |
-- Wenn der Typ nicht ermittelt werden kann, wird nil zurückgegeben. | |
function guess_fonttype( dateiname ) | |
local f=dateiname:lower() | |
if f:match(".*%.ttf") then return "truetype" | |
elseif f:match(".*%.otf") then return "opentype" | |
elseif f:match(".*%.pfb") then return "type1" | |
else return nil | |
end | |
end | |
function to_utf16(codepoint) | |
assert(codepoint) | |
if codepoint < 65536 then | |
return string.format("%04X",codepoint) | |
else | |
return string.format("%04X%04X",codepoint / 1024 + 0xD800 ,codepoint % 1024 + 0xDC00) | |
end | |
end | |
-- "name" ist der Dateiname, "size" ist eine Zahl in scaled points (sp) | |
-- Rückkabe sind zwei Werte. Wenn der erste Wert "false" ist, dann ist im zweiten Wert | |
-- eine Fehlermeldung, wenn der erste Wert "true" ist, dann ist im zweiten Wert eine | |
-- TeX-Tabelle mit dem Font. | |
function define_font(name, size) | |
local lookup_codepoint_by_name = {} | |
local lookup_codepoint_by_number = {} | |
local dateiname_mit_pfad = kpse.lookup(name) | |
if not dateiname_mit_pfad then return false, string.format("Fontdatei '%s' nicht gefunden.",dateiname_mit_pfad or name) end | |
local fontinfo = fontloader.to_table(fontloader.open(dateiname_mit_pfad)) | |
if fontinfo == nil then return false, string.format("Problem beim Laden des Fonts '%s'",tostring(dateiname_mit_pfad)) end | |
fontinfo.dateiname_mit_pfad = dateiname_mit_pfad | |
local is_unicode = (fontinfo.pfminfo.unicoderanges ~= nil) | |
-- Es wird ein Mapping Zeichennummer -> codepoint benötigt, damit wir beim Durchgehen der | |
-- Zeichen die direkt an die richtige Stelle (codepoint) geben können. | |
-- Das Problem ist, dass TTF/OTF und Type1 unterschiedlich behandelt werden müssen. | |
-- TTF/OTF haben ein Unicode Mapping, das mit map.backmap (key: glyph, value: Codepoint) | |
-- durchgegangen werden kann. Type1 benötigt die Information aus glyph.unicode. | |
-- Ebenso wird fürs Kerning ein Mapping Zeichenname -> codepoint benötigt. | |
if is_unicode then | |
-- TTF/OTF, benutze map.backmap | |
for i = 1,#fontinfo.glyphs do | |
local g=fontinfo.glyphs[i] | |
local cp = fontinfo.map.backmap[i] | |
lookup_codepoint_by_name[g.name] = cp | |
lookup_codepoint_by_number[i] = cp | |
end | |
else | |
-- Type1, benutze glyph.unicode | |
for i = 1,#fontinfo.glyphs do | |
local g=fontinfo.glyphs[i] | |
local cp = g.unicode | |
lookup_codepoint_by_name[g.name] = cp | |
lookup_codepoint_by_number[i] = cp | |
end | |
end -- is unicode | |
if (size < 0) then size = (- 655.36) * size end | |
if fontinfo.units_per_em == 0 then fontinfo.units_per_em = 1000 end -- manche type1 fonts haben u_p_em=0 | |
local mag = size / fontinfo.units_per_em -- magnification | |
local f = { } -- Fontstruktur für TeX (Kap. 7 LuaTeX) | |
f.characters = { } -- alle Zeichen für TeX, Index ist der Unicode Codepoint | |
f.fontloader = fontinfo | |
f.name = fontinfo.fontname | |
f.fullname = fontinfo.fontname | |
f.designsize = size | |
f.size = size | |
f.direction = 0 | |
f.filename = fontinfo.dateiname_mit_pfad | |
f.type = 'real' | |
f.encodingbytes = 2 | |
f.tounicode = 1 | |
f.stretch = 30 | |
f.shrink = 20 | |
f.step = 10 | |
f.auto_expand = true | |
f.parameters = { } | |
f.parameters.slant = 0 | |
f.parameters.space = 0.25 * size | |
f.parameters.space_stretch = 0.3 * size | |
f.parameters.space_shrink = 0.1 * size | |
f.parameters.x_height = 0.4 * size | |
f.parameters.quad = 1.0 * size | |
f.parameters.extra_space = 0 | |
f.format = guess_fonttype(name) | |
if f.format==nil then return false,"Konnte Fontformat der Datei '".. fontinfo.dateiname_mit_pfad .."' nicht bestimmen." end | |
f.embedding = "subset" | |
f.cidinfo = fontinfo.cidinfo | |
-- Hier stehen die Schreibsysteme (scripts) und Sprachen, für die die Ligaturen gesucht werden sollen. | |
local scripts_OK = { DFLT = true, latn = true } | |
local langs_OK = { dflt = true } | |
local lookups = {} | |
if fontinfo.gsub then | |
for i=1,#fontinfo.gsub do | |
local gsub = fontinfo.gsub[i] | |
for j=1,#gsub.features do | |
local features = gsub.features[j] | |
if features.tag =="liga" then | |
for k=1,#features.scripts do | |
local script_tbl = features.scripts[k] | |
if scripts_OK[script_tbl.script] then | |
-- die richtigen "scripts" haben wir gefunden, jetzt kommt es noch | |
-- auf die richtige Sprache an. | |
for l=1,#script_tbl.langs do | |
local lang = script_tbl.langs[l] | |
if langs_OK[lang] then | |
lookups[gsub.subtables[1].name] = true | |
end | |
end | |
end | |
end | |
end | |
end | |
end | |
end | |
ligatures = {} | |
for i=1,#fontinfo.glyphs do | |
local glyph = fontinfo.glyphs[i] | |
local codepoint = lookup_codepoint_by_number[i] | |
if glyph.lookups then | |
for k,v in pairs(glyph.lookups) do | |
if lookups[k] then | |
for i,w in ipairs(v) do | |
ligatures[#ligatures + 1] = w | |
end | |
end | |
end | |
end | |
-- TeX benutzt U+002D HYPHEN-MINUS als Trennstrich, korrekt wäre U+2010 HYPHEN. Da | |
-- aber die Fonts unberechenbar sind, mappen wir alle HYPHEN auf 0x2D (dez. 45) | |
if glyph.name:lower():match("^hyphen$") then codepoint=45 end | |
f.characters[codepoint] = { | |
index = i, | |
width = glyph.width * mag, | |
name = glyph.name, | |
expansion_factor = 1000, | |
} | |
-- Höhe und Tiefe des Zeichens | |
if glyph.boundingbox[4] then f.characters[codepoint].height = glyph.boundingbox[4] * mag end | |
if glyph.boundingbox[2] then f.characters[codepoint].depth = -glyph.boundingbox[2] * mag end | |
-- tounicode setzen. Damit bei Kapitälchen etc. auch copy und paste funktioniert. Strenggenommen | |
-- benötigen wir die Funktionalität bei diesem einfachen Fontloader nicht (keine OTF-Features) | |
if glyph.name:match("%.") then | |
-- Bsp: Kapitälchen a hat a.sc oder a.c2sc als Name. Wir interessieren uns nur für den Teil vor dem Punkt. | |
-- ziemlich einfache Variante, aber es scheint ganz gut zu funktionieren | |
local destname = glyph.name:gsub("^([^%.]*)%..*$","%1") | |
local cp = lookup_codepoint_by_name[destname] | |
if cp then | |
f.characters[codepoint].tounicode=to_utf16(cp) | |
end | |
end | |
-- Optischer Randausgleich, dazu muss \pdfprotrudechars=2 eingeschaltet sein. Hier nur als Beispiel. | |
local faktor = 0.5 | |
if (glyph.name=="hyphen" or glyph.name=="period" or glyph.name=="comma") then | |
f.characters[codepoint]["right_protruding"] = glyph.width * faktor | |
end | |
-- Kerning | |
local kerns={} | |
if glyph.kerns then | |
for _,kern in pairs(glyph.kerns) do | |
local ziel = lookup_codepoint_by_name[kern.char] | |
if ziel and ziel > 0 then | |
kerns[ziel] = kern.off * mag | |
else | |
end | |
end | |
end | |
f.characters[codepoint].kerns = kerns | |
end | |
-- Zu diesem Zeitpunkt sind alle Zeichen bekannt, nun können die gewünschten Ligaturen | |
-- in diese Zeichen eingefügt werden. | |
for _,v in ipairs(ligatures) do | |
local spec = v.specification | |
local result_cp = lookup_codepoint_by_name[spec.char] | |
if result_cp > 0 then -- -1 == unencoded | |
local components = string.explode(spec.components) -- z.B. "ff i" | |
if #components == 2 then -- wir behandeln nur Ligaturen mit 2 Komponenten | |
local char = f.characters[lookup_codepoint_by_name[components[1]]] | |
char.ligatures = char.ligatures or {} | |
char.ligatures[lookup_codepoint_by_name[components[2]]] = { char = result_cp } | |
end | |
end | |
end | |
-- Ligaturen sind ergänzt worden | |
return true,f | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment