if not modules then modules = { } end modules ['mtx-fonts'] = { version = 1.001, comment = "companion to mtxrun.lua", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files" } local helpinfo = [[ --save save open type font in raw table --reload generate new font database --reload --simple generate 'luatex-fonts-names.lua' (not for context!) --list --name list installed fonts, filter by name [--pattern] --list --spec list installed fonts, filter by spec [--filter] --list --file list installed fonts, filter by file [--pattern] --pattern=str filter files using pattern --filter=list key-value pairs --all show all found instances --info give more details --track=list enable trackers --statistics some info about the database examples of searches: mtxrun --script font --list somename (== --pattern=*somename*) mtxrun --script font --list --name somename mtxrun --script font --list --name --pattern=*somename* mtxrun --script font --list --spec somename mtxrun --script font --list --spec somename-bold-italic mtxrun --script font --list --spec --pattern=*somename* mtxrun --script font --list --spec --filter="fontname=somename" mtxrun --script font --list --spec --filter="familyname=somename,weight=bold,style=italic,width=condensed" mtxrun --script font --list --spec --filter="familyname=crap*,weight=bold,style=italic" mtxrun --script font --list --file somename mtxrun --script font --list --file --pattern=*somename* ]] local application = logs.application { name = "mtx-fonts", banner = "ConTeXt Font Database Management 0.21", helpinfo = helpinfo, } local report = application.report -- todo: fc-cache -v en check dirs, or better is: fc-cat -v | grep Directory if not fontloader then fontloader = fontforge end dofile(resolvers.findfile("font-otp.lua","tex")) -- we need to unpack the font for analysis dofile(resolvers.findfile("font-syn.lua","tex")) dofile(resolvers.findfile("font-mis.lua","tex")) scripts = scripts or { } scripts.fonts = scripts.fonts or { } function fonts.names.statistics() fonts.names.load() local data = fonts.names.data local statistics = data.statistics local function counted(t) local n = { } for k, v in next, t do n[k] = table.count(v) end return table.sequenced(n) end report("cache uuid : %s", data.cache_uuid) report("cache version : %s", data.cache_version) report("number of trees : %s", #data.datastate) report() report("number of fonts : %s", statistics.fonts or 0) report("used files : %s", statistics.readfiles or 0) report("skipped files : %s", statistics.skippedfiles or 0) report("duplicate files : %s", statistics.duplicatefiles or 0) report("specifications : %s", #data.specifications) report("families : %s", table.count(data.families)) report() report("mappings : %s", counted(data.mappings)) report("fallbacks : %s", counted(data.fallbacks)) report() report("used styles : %s", table.sequenced(statistics.used_styles)) report("used variants : %s", table.sequenced(statistics.used_variants)) report("used weights : %s", table.sequenced(statistics.used_weights)) report("used widths : %s", table.sequenced(statistics.used_widths)) report() report("found styles : %s", table.sequenced(statistics.styles)) report("found variants : %s", table.sequenced(statistics.variants)) report("found weights : %s", table.sequenced(statistics.weights)) report("found widths : %s", table.sequenced(statistics.widths)) end function fonts.names.simple() local simpleversion = 1.001 local simplelist = { "ttf", "otf", "ttc", "dfont" } local name = "luatex-fonts-names.lua" fonts.names.filters.list = simplelist fonts.names.version = simpleversion -- this number is the same as in font-dum.lua report("generating font database for 'luatex-fonts' version %s",fonts.names.version) fonts.names.identify(true) local data = fonts.names.data if data then local simplemappings = { } local simplified = { mappings = simplemappings, version = simpleversion, } local specifications = data.specifications for i=1,#simplelist do local format = simplelist[i] for tag, index in next, data.mappings[format] do local s = specifications[index] simplemappings[tag] = { s.rawname, s.filename, s.subfont } end end report("saving names in '%s'",name) io.savedata(name,table.serialize(simplified,true)) local data = io.loaddata(resolvers.findfile("font-dum.lua","tex")) local dummy = string.match(data,"fonts%.names%.version%s*=%s*([%d%.]+)") if tonumber(dummy) ~= simpleversion then report("warning: version number %s in 'font-dum' does not match database version number %s",dummy or "?",simpleversion) end elseif lfs.isfile(name) then os.remove(name) end end function scripts.fonts.reload() if environment.argument("simple") then fonts.names.simple() else fonts.names.load(true) end end local function subfont(sf) if sf then return string.format("index: % 2s", sf) else return "" end end local function fontweight(fw) if fw then return string.format("conflict: %s", fw) else return "" end end local function showfeatures(tag,specification) report() report("mapping : %s",tag) report("fontname: %s",specification.fontname) report("fullname: %s",specification.fullname) report("filename: %s",specification.filename) report("family : %s",specification.familyname or "") report("weight : %s",specification.weight or "") report("style : %s",specification.style or "") report("width : %s",specification.width or "") report("variant : %s",specification.variant or "") report("subfont : %s",subfont(specification.subfont)) report("fweight : %s",fontweight(specification.fontweight)) -- maybe more local features = fonts.get_features(specification.filename,specification.format) if features then for what, v in table.sortedhash(features) do local data = features[what] if data and next(data) then report() report("%s features:",what) report() report("feature script languages") report() for f,ff in table.sortedhash(data) do local done = false for s, ss in table.sortedhash(ff) do if s == "*" then s = "all" end if ss ["*"] then ss["*"] = nil ss.all = true end if done then f = "" else done = true end report("% -8s % -8s % -8s",f,s,table.concat(table.sortedkeys(ss), " ")) -- todo: padd 4 end end end end else report("no features") end report() end local function reloadbase(reload) if reload then report("fontnames, reloading font database") names.load(true) report("fontnames, done\n\n") end end local function list_specifications(t,info) if t then local s = table.sortedkeys(t) if info then for k=1,#s do local v = s[k] showfeatures(v,t[v]) end else for k=1,#s do local v = s[k] local entry = t[v] s[k] = { entry.familyname or "", entry.weight or "", entry.style or "", entry.width or "", entry.variant or "", entry.fontname, entry.filename, subfont(entry.subfont), fontweight(entry.fontweight), } end utilities.formatters.formatcolumns(s) for k=1,#s do texio.write_nl(s[k]) end end end end local function list_matches(t,info) if t then local s, w = table.sortedkeys(t), { 0, 0, 0 } if info then for k=1,#s do local v = s[k] showfeatures(v,t[v]) end else for k=1,#s do local v = s[k] local entry = t[v] s[k] = { v, entry.fontname, entry.filename, subfont(entry.subfont) } end utilities.formatters.formatcolumns(s) for k=1,#s do texio.write_nl(s[k]) end end end end function scripts.fonts.list() local all = environment.argument("all") local info = environment.argument("info") local reload = environment.argument("reload") local pattern = environment.argument("pattern") local filter = environment.argument("filter") local given = environment.files[1] reloadbase(reload) if environment.argument("name") then if pattern then --~ mtxrun --script font --list --name --pattern=*somename* list_matches(fonts.names.list(string.topattern(pattern,true),reload,all),info) elseif filter then report("not supported: --list --name --filter",name) elseif given then --~ mtxrun --script font --list --name somename list_matches(fonts.names.list(given,reload,all),info) else report("not supported: --list --name ",name) end elseif environment.argument("spec") then if pattern then --~ mtxrun --script font --list --spec --pattern=*somename* report("not supported: --list --spec --pattern",name) elseif filter then --~ mtxrun --script font --list --spec --filter="fontname=somename" list_specifications(fonts.names.getlookups(filter),info) elseif given then --~ mtxrun --script font --list --spec somename list_specifications(fonts.names.collectspec(given,reload,all),info) else report("not supported: --list --spec ",name) end elseif environment.argument("file") then if pattern then --~ mtxrun --script font --list --file --pattern=*somename* list_specifications(fonts.names.collectfiles(string.topattern(pattern,true),reload,all),info) elseif filter then report("not supported: --list --spec",name) elseif given then --~ mtxrun --script font --list --file somename list_specifications(fonts.names.collectfiles(given,reload,all),info) else report("not supported: --list --file ",name) end elseif pattern then --~ mtxrun --script font --list --pattern=*somename* list_matches(fonts.names.list(string.topattern(pattern,true),reload,all),info) elseif given then --~ mtxrun --script font --list somename list_matches(fonts.names.list(given,reload,all),info) elseif all then pattern = "*" list_matches(fonts.names.list(string.topattern(pattern,true),reload,all),info) else report("not supported: --list ",name) end end function scripts.fonts.save() local name = environment.files[1] or "" local sub = environment.files[2] or "" local function save(savename,fontblob) if fontblob then savename = savename:lower() .. ".lua" report("fontsave, saving data in %s",savename) table.tofile(savename,fontloader.to_table(fontblob),"return") fontloader.close(fontblob) end end if name and name ~= "" then local filename = resolvers.findfile(name) -- maybe also search for opentype if filename and filename ~= "" then local suffix = string.lower(file.extname(filename)) if suffix == 'ttf' or suffix == 'otf' or suffix == 'ttc' or suffix == "dfont" then local fontinfo = fontloader.info(filename) if fontinfo then report("font: %s located as %s",name,filename) if fontinfo[1] then for k=1,#fontinfo do local v = fontinfo[k] save(v.fontname,fontloader.open(filename,v.fullname)) end else save(fontinfo.fullname,fontloader.open(filename)) end else report("font: %s cannot be read",filename) end else report("font: %s not saved",filename) end else report("font: %s not found",name) end else report("font: no name given") end end local track = environment.argument("track") if track then trackers.enable(track) end if environment.argument("names") then environment.setargument("reload",true) environment.setargument("simple",true) end if environment.argument("list") then scripts.fonts.list() elseif environment.argument("reload") then scripts.fonts.reload() elseif environment.argument("save") then scripts.fonts.save() elseif environment.argument("statistics") then fonts.names.statistics() else application.help() end