%D \module %D [ file=m-punk, %D version=2008.04.15, %D title=\CONTEXT\ Modules, %D subtitle=Punk Support, %D author=Hans Hagen, %D date=\currentdate, %D copyright=PRAGMA] %C %C This module is part of the \CONTEXT\ macro||package and is %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. \ifx\luaversion\undefined \endinput \fi % At some point the font generation code will move into the % ConTeXt MkIV kernel. \startluacode do local concat = table.concat local chardata = characters.data local fontdata = fonts.ids fonts.mp = fonts.mp or { } fonts.mp.version = fonts.mp.version or 1.11 fonts.mp.inline = true fonts.mp.cache = containers.define("fonts", "mp", fonts.mp.version, true) metapost.characters = metapost.characters or { } -- todo: use table share as in otf local characters, descriptions = { }, { } local factor, l, n, w, h, d, total, variants = 100, { }, 0, 0, 0, 0, 0, 0, true -- A next version of mplib will provide the tfm font information which -- gives better glyph dimensions, plus additional kerning information. local flusher = { startfigure = function(chrnum,llx,lly,urx,ury) l, n = { }, chrnum w, h, d = urx - llx, ury, -lly total = total + 1 inline = fonts.mp.inline end, flushfigure = function(t) for i=1, #t do l[#l+1] = t[i] end end, stopfigure = function() local cd = chardata[n] if inline then descriptions[n] = { -- unicode = n, name = cd and cd.adobename, width = w*100, height = h*100, depth = d*100, boundingbox = { 0, -d, w, h }, } characters[n] = { commands = { -- todo: xforms, should happen in backend { "special", "pdf: " .. concat(l," ") }, } } else descriptions[n] = { -- unicode = n, name = cd and cd.adobename, width = w*100, height = h*100, depth = d*100, boundingbox = { 0, -d, w, h }, } characters[n] = { commands = { { "image", { stream = concat(l," "), bbox = { 0, -d*65536, w*65536, h*65536 } } }, } } end end } metapost.characters.instances = metapost.characters.instances or 10 function metapost.characters.process(mpxformat, name, instances, scalefactor) statistics.starttiming(metapost.characters) scalefactor = scalefactor or 1 instances = instances or metapost.characters.instances or 10 local fontname = file.removesuffix(file.basename(name)) local hash = file.robustname(string.format("%s %05i %03i", fontname, scalefactor*1000, instances)) local lists = containers.read(fonts.mp.cache(), hash) if not lists then statistics.starttiming(flusher) -- we can use a format per font local data = io.loaddata(resolvers.find_file(name)) metapost.reset(mpxformat) metapost.set_outer_color(2) -- no outer color and no reset either lists = { } for i=1,instances do list = { } characters, descriptions = { }, { } metapost.process( mpxformat, { "randomseed := " .. i*10 .. ";", "scale_factor := " .. scalefactor .. " ;", data }, false, flusher ) lists[i] = { designsize = 655360, name = string.format("%s-%03i",hash,i), parameters = { slant = 0, space = 333 * scalefactor, space_stretch = 166.5 * scalefactor, space_shrink = 111 * scalefactor, x_height = 431 * scalefactor, quad =1000 * scalefactor, extra_space = 0 }, ["type"] = "virtual", characters = characters, descriptions = descriptions, -- embedding = "subset", -- mkiv: spacer = "space", unit = 1000, shared = { }, unique = { }, } end metapost.reset(mpxformat) -- saves memory lists = containers.write(fonts.mp.cache(), hash, lists) statistics.stoptiming(flusher) end variants = variants + #lists statistics.stoptiming(metapost.characters) return lists end function fonts.vf.aux.combine.commands.metafont(g,v) local size = g.specification.size local data = metapost.characters.process(v[2],v[3],v[4],size/655360) local list, t = { }, { } for d=1,#data do t = data[d] t = fonts.tfm.scale(t, -1000) local id = font.nextid() t.fonts = { { id = id } } fontdata[id] = t fonts.vf.aux.compose_characters(t) list[d] = font.define(t) end for k=1,#t do g[k] = t[k] -- kind of replace, when not present, make nil end g.virtualized = true g.variants = list end fonts.define.methods.install( "punk", { { "metafont", "mfplain", "punkfont.mp", 10 }, } ) cases.actions[99] = function(current) local used = fontdata[current.font].variants if used then local f = math.random(1,#used) current.font = used[f] return current, true else return current, false end end metapost.characters.flusher = flusher statistics.register("metapost font generation", function() local time = statistics.elapsedtime(flusher) if total > 0 then return string.format("%i glyphs, %.3f seconds runtime, %i glyphs/second", total, time, total/time) else return string.format("%i glyphs, %.3f seconds runtime", total, time) end end) statistics.register("metapost font loading",function() local time = statistics.elapsedtime(metapost.characters) if variants > 0 then return string.format("%.3f seconds, %i instances, %0.3f instances/second", time, variants, variants/time) else return string.format("%.3f seconds, %i instances", time, variants) end end) end \stopluacode \unexpanded\def\EnableRandomPunk {\setcharactercasing[99]} \unexpanded\def\RandomPunk {\groupedcommand\EnableRandomPunk\donothing} \unexpanded\def\StartRandomPunk {\begingroup\EnableRandomPunk} \unexpanded\def\StopRandomPunk {\endgroup} \starttypescript [serif] [punk] [default] \setups[font:fallback:serif] % no style variants yet \definefontsynonym [Serif] [demo@punk] \stoptypescript \starttypescript [punk] \definetypeface [punk] [rm] [serif] [punk] [default] \stoptypescript \definefontfeature[punknova][mode=node,script=latn,rand=yes,kern=yes,liga=yes,tlig=yes] \starttypescript [serif] [punknova] \setups[font:fallback:serif] % no style variants yet, actually it's a sans \definefontsynonym [Serif] [file:punknova] [features=punknova] \stoptypescript \starttypescript [punknova] \definetypeface [punknova] [rm] [serif] [punknova] [default] \stoptypescript \endinput \usetypescript[punk] \setupbodyfont[punk,14pt] \starttext \definedfont[demo@punk at 10pt]hello world\par \definedfont[demo@punk at 12pt]hello world\par \definedfont[demo@punk at 16pt]hello world\par \definedfont[demo@punk at 20pt]hello world\par \stoptext