%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 ADE \& \CONTEXT\ Development Team}] %C %C This module is part of the \CONTEXT\ macro||package and is %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. %D You can actually turn a punk font into music (wintergatan): %D %D \starttyping %D https://www.youtube.com/watch?v=g5c2Htj8Vtw %D \stoptyping \ifcase\contextlmtxmode\else \writestatus{punk}{use metapost library punk instead} \expandafter\endinput \fi \startluacode local concat = table.concat local round = math.round local chardata = characters.data local fontdata = fonts.hashes.identifiers fonts.mp = fonts.mp or { } fonts.mp.version = fonts.mp.version or 1.15 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: type 3 in lmtx { "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, round(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.findfile(name)) metapost.reset(mpxformat) metapost.setoutercolor(2) -- no outer color and no reset either lists = { } for i=1,instances do characters = { } descriptions = { } metapost.process { mpx = mpxformat, -- trialrun = false, flusher = flusher, -- multipass = false, -- isextrapass = false, askedfig = "all", -- incontext = false, data = { "randomseed := " .. i*10 .. ";", "scale_factor := " .. scalefactor .. " ;", data }, } lists[i] = { characters = characters, descriptions = descriptions, parameters = { designsize = 655360, slant = 0, space = 333 * scalefactor, space_stretch = 166.5 * scalefactor, space_shrink = 111 * scalefactor, x_height = 431 * scalefactor, quad = 1000 * scalefactor, extra_space = 0, }, properties = { name = string.format("%s-%03i",hash,i), virtualized = true, spacer = "space", } } 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.handlers.vf.combiner.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.constructors.scale(t, -1000) local id = font.nextid() t.fonts = { { id = id } } fontdata[id] = t fonts.handlers.vf.helpers.composecharacters(t) list[d] = font.define(t) end for k, v in next, t do g[k] = v -- kind of replace, when not present, make nil end g.properties.virtualized = true g.variants = list end fonts.definers.methods.install( "punk", { { "metafont", "mfplain", "punkfont.mp", 10 }, } ) fonts.definers.methods.install( "punkbold", { { "metafont", "mfplain", "punkfont-bold.mp", 10 }, } ) fonts.definers.methods.install( "punkslanted", { { "metafont", "mfplain", "punkfont-slanted.mp", 10 }, } ) fonts.definers.methods.install( "punkboldslanted", { { "metafont", "mfplain", "punkfont-boldslanted.mp", 10 }, } ) -- typesetters.cases.register("RandomPunk", function(current) -- local used = fontdata[current].variants -- if used then -- local f = math.random(1,#used) -- current.font = used[f] -- return current, true -- else -- return current, false -- end -- end) local getfont = nodes.nuts.getfont local setfield = nodes.nuts.setfield local random = math.random typesetters.cases.register("RandomPunk", function(start) local used = fontdata[getfont(start)].variants if used then local f = random(1,#used) setfield(start,"font",used[f]) return start, true else return start, 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, %s seconds runtime, %0.3f glyphs/second", total, time, total/tonumber(time)) else return string.format("%i glyphs, %s 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("%s seconds, %i instances, %0.3f instances/second", time, variants, variants/tonumber(time)) else return string.format("%s seconds, %i instances", time, variants) end end) \stopluacode \unexpanded\def\EnableRandomPunk {\setcharactercasing[RandomPunk]} \unexpanded\def\RandomPunk {\groupedcommand\EnableRandomPunk\donothing} \unexpanded\def\StartRandomPunk {\begingroup\EnableRandomPunk} \unexpanded\def\StopRandomPunk {\endgroup} \starttypescript [serif] [punk] \definefontsynonym [Serif] [demo@punk] \definefontsynonym [SerifBold] [demobold@punkbold] \definefontsynonym [SerifSlanted] [demoslanted@punkslanted] \definefontsynonym [SerifBoldSlanted] [demoboldslanted@punkboldslanted] \definefontsynonym [SerifItalic] [SerifSlanted] \definefontsynonym [SerifBoldItalic] [SerifBoldSlanted] \stoptypescript \starttypescript [punk] \definetypeface [punk] [rm] [serif] [punk] [default] \stoptypescript \continueifinputfile{m-punk.mkiv} \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