Skip to content

Instantly share code, notes, and snippets.

@pgundlach
Created April 3, 2010 19:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pgundlach/354808 to your computer and use it in GitHub Desktop.
Save pgundlach/354808 to your computer and use it in GitHub Desktop.
Fontloader für LuaTeX (http://www.luatex.de)
\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üÜ ß ⌀ ℃}
\ladefont{texgyreheros-bold.otf}{TeXgyreherosRegular}
\ladefont{texgyreheros-bold.otf}{TeXgyreherosBold}
\ladefont{lmr10.pfb}{LatinModern}
\TeXgyreherosRegular
\beispieltext
\TeXgyreherosBold
\beispieltext
\LatinModern
\beispieltext
\bye
-- 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 neuer_font
local dateiname_mit_pfad
local lookup_codepoint_by_name = {}
local lookup_codepoint_by_number = {}
dateiname_mit_pfad = kpse.find_file(name)
if not dateiname_mit_pfad then return false, string.format("Fontdatei '%s' nicht gefunden.",dateiname_mit_pfad or name) end
neuer_font = fontloader.to_table(fontloader.open(dateiname_mit_pfad))
if neuer_font == nil then return false, string.format("Problem beim Laden des Fonts '%s'",tostring(dateiname_mit_pfad)) end
neuer_font.dateiname_mit_pfad = dateiname_mit_pfad
local is_unicode = (neuer_font.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,#neuer_font.glyphs do
local g=neuer_font.glyphs[i]
lookup_codepoint_by_name[g.name] = neuer_font.map.backmap[i]
lookup_codepoint_by_number[i] = neuer_font.map.backmap[i]
end
else
-- Type1, benutze glyph.unicode
for i = 1,#neuer_font.glyphs do
local g=neuer_font.glyphs[i]
lookup_codepoint_by_name[g.name] = g.unicode
lookup_codepoint_by_number[i] = g.unicode
end
end -- is unicode
if (size < 0) then size = (- 655.36) * size end
if neuer_font.units_per_em == 0 then neuer_font.units_per_em = 1000 end -- manche type1 fonts haben u_p_em=0
local mag = size / neuer_font.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 = neuer_font
f.name = neuer_font.fontname
f.fullname = neuer_font.fontname
f.designsize = size
f.size = size
f.direction = 0
f.filename = neuer_font.dateiname_mit_pfad
f.type = 'real'
f.encodingbytes = 2
f.tounicode = 1
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 '".. neuer_font.dateiname_mit_pfad .."' nicht bestimmen." end
f.embedding = "subset"
f.cidinfo = neuer_font.cidinfo
for i=1,#neuer_font.glyphs do
local glyph = neuer_font.glyphs[i]
local codepoint = lookup_codepoint_by_number[i]
-- 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,
}
-- 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
return true,f
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment