diff options
Diffstat (limited to 'tex/context/base/mkiv/font-web.lua')
-rw-r--r-- | tex/context/base/mkiv/font-web.lua | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/tex/context/base/mkiv/font-web.lua b/tex/context/base/mkiv/font-web.lua new file mode 100644 index 000000000..452a8f59b --- /dev/null +++ b/tex/context/base/mkiv/font-web.lua @@ -0,0 +1,202 @@ +if not modules then modules = { } end modules ['font-otr'] = { + version = 1.001, + comment = "companion to font-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- Okay, compressing fonts this way is rather simple but one might wonder what the gain +-- is in this time of 4K youtube movies and most of the web pages wasting space and +-- bandwidth on advertisements. For version 2 we can use "woff2_decompress" from google +-- and in a tex environment one can as well store the ttf/otf files in the tex tree. So, +-- eventually we might even remove this code when version 1 is obsolete. + +local ioopen = io.open +local replacesuffix = file.replacesuffix + +local readers = fonts and fonts.handlers.otf.readers + +local streamreader = readers and readers.streamreader or utilities.files +local streamwriter = readers and readers.streamwriter or utilities.files + +local readstring = streamreader.readstring +local readcardinal2 = streamreader.readcardinal2 +local readcardinal4 = streamreader.readcardinal4 + +local writestring = streamwriter.writestring +local writecardinal4 = streamwriter.writecardinal4 +local writecardinal2 = streamwriter.writecardinal2 +local writebyte = streamwriter.writebyte + +local getsize = streamreader.getsize +local setposition = streamreader.setposition +local getposition = streamreader.getposition + +local decompress = zlib.decompress + +local infotags = { + ["os/2"] = true, + ["head"] = true, + ["maxp"] = true, + ["hhea"] = true, + ["hmtx"] = true, + ["post"] = true, + ["cmap"] = true, +} + +local report = logs.reporter("fonts","woff") + +local runner = sandbox.registerrunner { + name = "woff2otf", + method = "execute", + program = "woff2_decompress", + template = "%inputfile% %outputfile%", + reporter = report, + checkers = { + inputfile = "readable", + outputfile = "writable", + } +} + +local function woff2otf(inpname,outname,infoonly) + + local outname = outname or replacesuffix(inpname,"otf") + local inp = ioopen(inpname,"rb") + + if not inp then + report("invalid input file %a",inpname) + return + end + + local signature = readstring(inp,4) + + if not (signature == "wOFF" or signature == "wOF2") then + inp:close() + report("invalid signature in %a",inpname) + return + end + + local flavor = readstring(inp,4) + + if not (flavor == "OTTO" or flavor == "true" or flavor == "\0\1\0\0") then + inp:close() + report("unsupported flavor %a in %a",flavor,inpname) + return + end + + if signature == "wOF2" then + inp:close() + if false then + if runner then + runner { + inputfile = inpname, + outputfile = outname, + } + end + return outname, flavor + else + report("skipping version 2 file %a",inpname) + return + end + end + + local out = ioopen(outname,"wb") + + if not out then + inp:close() + report("invalid output file %a",outname) + return + end + + local header = { + signature = signature, + flavor = flavor, + length = readcardinal4(inp), + numtables = readcardinal2(inp), + reserved = readcardinal2(inp), + totalsfntsize = readcardinal4(inp), + majorversion = readcardinal2(inp), + minorversion = readcardinal2(inp), + metaoffset = readcardinal4(inp), + metalength = readcardinal4(inp), + metaoriglength = readcardinal4(inp), + privoffset = readcardinal4(inp), + privlength = readcardinal4(inp), + } + + local entries = { } + + for i=1,header.numtables do + local entry = { + tag = readstring (inp,4), + offset = readcardinal4(inp), + compressed = readcardinal4(inp), + size = readcardinal4(inp), + checksum = readcardinal4(inp), + } + if not infoonly or infotags[lower(entry.tag)] then + entries[#entries+1] = entry + end + end + + local nofentries = #entries + local entryselector = 0 -- we don't need these + local searchrange = 0 -- we don't need these + local rangeshift = 0 -- we don't need these + + writestring (out,flavor) + writecardinal2(out,nofentries) + writecardinal2(out,entryselector) + writecardinal2(out,searchrange) + writecardinal2(out,rangeshift) + + local offset = 12 + nofentries * 16 + local offsets = { } + + for i=1,nofentries do + local entry = entries[i] + local size = entry.size + writestring(out,entry.tag) + writecardinal4(out,entry.checksum) + writecardinal4(out,offset) -- the new offset + writecardinal4(out,size) + offsets[i] = offset + offset = offset + size + local p = 4 - offset % 4 + if p > 0 then + offset = offset + p + end + end + + for i=1,nofentries do + local entry = entries[i] + local offset = offsets[i] + local size = entry.size + setposition(inp,entry.offset+1) + local data = readstring(inp,entry.compressed) + if #data ~= size then + data = decompress(data) + end + setposition(out,offset+1) + writestring(out,data) + local p = 4 - offset + size % 4 + if p > 0 then + for i=1,p do + writebyte(out,0) + end + end + end + + inp:close() + out:close() + + return outname, flavor + +end + +if readers then + readers.woff2otf = woff2otf +else + return woff2otf +end |