Implement counterhinting in Type1 to Type2 code

Gives better hinted output for asian fonts
This commit is contained in:
Marcel Krüger 2020-07-30 19:57:03 +02:00
parent 3ec7bc1c1e
commit 4d356676b1
2 changed files with 66 additions and 19 deletions

View File

@ -40,7 +40,7 @@ local function parse_charstring(cs, subrs, result)
elseif cmd == 1 then -- Flex initialization elseif cmd == 1 then -- Flex initialization
elseif cmd == 2 then -- Flex parameter elseif cmd == 2 then -- Flex parameter
if result[#result-1].flex then if result[#result-1].flex then
result[#result] = nil -- TODO: Warn if there were values. result[#result] = nil -- TODO: Warn if there were additional values in lastresult.
lastresult = result[#result] -- We keep collecting arguments lastresult = result[#result] -- We keep collecting arguments
end end
lastresult.flex = true lastresult.flex = true
@ -64,14 +64,51 @@ local function parse_charstring(cs, subrs, result)
pending[i] = lastresult[results-numargs+i] pending[i] = lastresult[results-numargs+i]
lastresult[results-numargs+i] = nil lastresult[results-numargs+i] = nil
end end
if lastresult.pendingargs then
for i = 1,#lastresult.pendingargs do for i = 1,#lastresult.pendingargs do
pending[numargs+i] = lastresult.pendingargs[i] pending[numargs+i] = lastresult.pendingargs[i]
end end
end
if cmd == 12 then if cmd == 12 then
lastresult.pendingargs = pending lastresult.pendingargs = pending
else else
lastresult.pendingargs = nil lastresult.pendingargs = nil
-- TODO Translate pending to counter mask local n = pending[1]
local i = 2
local groups = {}
for group = 1, n do
local current = {20}
local last = 0
while pending[i+1] > 0 do
last = last + pending[i]
current[#current+1] = {1, last, pending[i+1]}
last = last + pending[i+1]
i = i+2
end
last = last + pending[i]
current[#current+1] = {1, last + pending[i+1], -pending[i+1]}
groups[group] = current
i = i+2
end
n = pending[i]
i = i+1
for group = 1, n do
local current = groups[group] or {20}
local last = 0
while pending[i+1] > 0 do
last = last + pending[i]
current[#current+1] = {3, last, pending[i+1]}
last = last + pending[i+1]
i = i+2
end
last = last + pending[i]
current[#current+1] = {3, last + pending[i+1], -pending[i+1]}
groups[group] = current
i = i+2
end
assert(i == #pending+1)
table.move(groups, 1, #groups, #result, result) -- This overwrites lastresult
result[#result+1] = lastresult -- And restore lastresult
end end
else else
error[[UNSUPPORTED Othersubr]] error[[UNSUPPORTED Othersubr]]
@ -132,12 +169,12 @@ local function adjust_charstring(cs) -- Here we get a not yet optimized but pars
cs[1][1] = nil cs[1][1] = nil
-- That's it for the width, now we need some hinting stuff. This would be easy, if hint replacement -- That's it for the width, now we need some hinting stuff. This would be easy, if hint replacement
-- wouldn't require hint masks in Type2. And because we really enjoy this BS, we get counter -- wouldn't require hint masks in Type2. And because we really enjoy this BS, we get counter
-- hinting as an additional treat... Oh, if you actually you counter hinting: Please test this -- hinting as an additional treat... Oh, if you actually use counter hinting: Please test this
-- and report back if it works, because this is pretty much untested. -- and report back if it works, because this is pretty much untested.
-- TODO: Even more than that, counters are not implemented at all right now, except for [hv]stem3
local stems = {} local stems = {}
local stem3 = {} local stem3 = {20}
-- First iterate over the charstring, recording all hints and collecting them in stems/stem3 local cntrs = {}
-- First iterate over the charstring, recording all hints and collecting them in stems/stem3/cntrs
for i, cmd in ipairs(cs) do for i, cmd in ipairs(cs) do
if cmd[1] == 1 or cmd[1] == 3 then if cmd[1] == 1 or cmd[1] == 3 then
stems[#stems + 1] = cmd stems[#stems + 1] = cmd
@ -148,6 +185,9 @@ local function adjust_charstring(cs) -- Here we get a not yet optimized but pars
stems[#stems + 1] = {c, cmd[6], cmd[7]} stems[#stems + 1] = {c, cmd[6], cmd[7]}
table.move(stems, #stems-2, #stems, #stem3+1, stem3) table.move(stems, #stems-2, #stems, #stem3+1, stem3)
cs[i] = false cs[i] = false
elseif cmd[1] == 20 then
cntrs[#cntrs+1] = cmd
table.move(cmd, 2, #cmd, #stems+1, stems)
end end
end end
table.sort(stems, function(first, second) table.sort(stems, function(first, second)
@ -168,18 +208,25 @@ local function adjust_charstring(cs) -- Here we get a not yet optimized but pars
stems[i].idx = j stems[i].idx = j
end end
end end
-- Now the indices are known, so the cntrmask can be written, if stem3 occured. -- Now the indices are known, so the cntrmask can be written, if counters or stem3 occured.
-- This is done before writing the stem list to make the thable.insert parameters easier. -- This is done before writing the stem list to make the thable.insert parameters easier.
-- First translate stem3 into a counter group
if stem3[2] then
cntrs[#cntrs+1] = stem3
table.insert(cs, 2, stem3)
end
local bytes = {} local bytes = {}
if stem3[1] then for i=1, #cntrs do
local cntr = cntrs[i]
for l = 1, math.floor((j + 7)/8) do for l = 1, math.floor((j + 7)/8) do
bytes[l] = 0 bytes[l] = 0
end end
for l = 1, #stem3 do for l = 2, #cntr do
local idx = stem3[l].idx-1 local idx = cntr[l].idx-1
bytes[math.floor(idx/8) + 1] = bytes[math.floor(idx/8) + 1] | (1<<(7-idx%8)) bytes[math.floor(idx/8) + 1] = bytes[math.floor(idx/8) + 1] | (1<<(7-idx%8))
cntr[l] = nil
end end
table.insert(cs, 2, {20, string.char(table.unpack(bytes))}) cntr[2] = string.char(table.unpack(bytes))
end end
local current = 1 local current = 1
-- Then list the collected stems at the beginning of the charstring -- Then list the collected stems at the beginning of the charstring
@ -220,7 +267,7 @@ local function adjust_charstring(cs) -- Here we get a not yet optimized but pars
cs[i] = false cs[i] = false
i = i+1 i = i+1
end end
for l = 1, #stem3 do for l = 2, #stem3 do
local idx = stem3[l].idx-1 local idx = stem3[l].idx-1
bytes[math.floor(idx/8) + 1] = bytes[math.floor(idx/8) + 1] | (1<<(7-idx%8)) bytes[math.floor(idx/8) + 1] = bytes[math.floor(idx/8) + 1] | (1<<(7-idx%8))
end end

View File

@ -10,7 +10,7 @@ local our_callbacks = {
vf = {'vf', false, 'rb', 'find_vf_file', 'read_vf_file'}, vf = {'vf', false, 'rb', 'find_vf_file', 'read_vf_file'},
tfm = {'tfm', false, 'rb', 'find_font_file', 'read_font_file'}, tfm = {'tfm', false, 'rb', 'find_font_file', 'read_font_file'},
map = {'map', 2, 'r', 'find_map_file', 'read_map_file'}, map = {'map', 2, 'r', 'find_map_file', 'read_map_file'},
enc = {'enc', false, 'r', 'find_enc_file', 'read_enc_file'}, enc = {'enc files', false, 'r', 'find_enc_file', 'read_enc_file'},
type1 = {'type1 fonts', 4, 'rb', 'find_type1_file', 'read_type1_file'}, type1 = {'type1 fonts', 4, 'rb', 'find_type1_file', 'read_type1_file'},
truetype = {'truetype fonts', 4, 'rb', 'find_truetype_file', 'read_truetype_file'}, truetype = {'truetype fonts', 4, 'rb', 'find_truetype_file', 'read_truetype_file'},
opentype = {'opentype fonts', 4, 'rb', 'find_opentype_file', 'read_opentype_file'}, opentype = {'opentype fonts', 4, 'rb', 'find_opentype_file', 'read_opentype_file'},