summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/font-ocl.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/mkiv/font-ocl.lua')
-rw-r--r--tex/context/base/mkiv/font-ocl.lua308
1 files changed, 225 insertions, 83 deletions
diff --git a/tex/context/base/mkiv/font-ocl.lua b/tex/context/base/mkiv/font-ocl.lua
index 68d9ac650..2cb0c1eb7 100644
--- a/tex/context/base/mkiv/font-ocl.lua
+++ b/tex/context/base/mkiv/font-ocl.lua
@@ -10,6 +10,7 @@ if not modules then modules = { } end modules ['font-ocl'] = {
local tostring, next, format = tostring, next, string.format
local round, max = math.round, math.round
+local sortedkeys, sortedhash = table.sortedkeys, table.sortedhash
local formatters = string.formatters
local tounicode = fonts.mappings.tounicode
@@ -175,14 +176,8 @@ fonts.handlers.otf.features.register {
}
}
-local otfsvg = otf.svg or { }
-otf.svg = otfsvg
-otf.svgenabled = true
-
do
- local nofstreams = 0
-
-- local f_setstream = formatters[ [[io.savedata("svg-glyph-%05i",%q)]] ]
-- local f_getstream = formatters[ [[svg-glyph-%05i]] ]
@@ -194,47 +189,125 @@ do
-- end
-- end
- local f_name = formatters[ [[svg-glyph-%05i]] ]
- local f_used = context and formatters[ [[original:///%s]] ] or formatters[ [[%s]] ]
+ local nofstreams = 0
+ local f_name = formatters[ [[pdf-glyph-%05i]] ]
+ local f_used = context and formatters[ [[original:///%s]] ] or formatters[ [[%s]] ]
+ local hashed = { }
+ local cache = { }
+
+ function otf.storepdfdata(pdf)
+ local done = hashed[pdf]
+ if not done then
+ nofstreams = nofstreams + 1
+ local o, n = epdf.openMemStream(pdf,#pdf,f_name(nofstreams))
+ cache[n] = o -- we need to keep in mem
+ done = f_used(n)
+ hashed[pdf] = done
+ end
+ return nil, done, nil
+ end
- local cache = { }
+ -- maybe more efficient but much slower (and we hash already)
+ --
+ -- if context then
+ --
+ -- local storepdfdata = otf.storepdfdata
+ -- local initialized = false
+ --
+ -- function otf.storepdfdata(pdf)
+ -- if not initialized then
+ -- if resolvers.setmemstream then
+ -- local f_setstream = formatters[ [[resolvers.setmemstream("pdf-glyph-%05i",%q,true)]] ]
+ -- local f_getstream = formatters[ [[memstream:///pdf-glyph-%05i]] ]
+ -- local f_nilstream = formatters[ [[resolvers.resetmemstream("pdf-glyph-%05i",true)]] ]
+ -- storepdfdata = function(pdf)
+ -- local done = hashed[pdf]
+ -- local set = nil
+ -- local reset = nil
+ -- if not done then
+ -- nofstreams = nofstreams + 1
+ -- set = f_setstream(nofstreams,pdf)
+ -- done = f_getstream(nofstreams)
+ -- reset = f_nilstream(nofstreams)
+ -- hashed[pdf] = done
+ -- end
+ -- return set, done, reset
+ -- end
+ -- otf.storepdfdata = storepdfdata
+ -- end
+ -- initialized = true
+ -- end
+ -- return storepdfdata(pdf)
+ -- end
+ --
+ -- end
- function otfsvg.storepdfdata(pdf)
- nofstreams = nofstreams + 1
- local o, n = epdf.openMemStream(pdf,#pdf,f_name(nofstreams))
- cache[n] = o -- we need to keep in mem
- return nil, f_used(n), nil
- end
+end
- if context then
-
- local storepdfdata = otfsvg.storepdfdata
- local initialized = false
-
- function otfsvg.storepdfdata(pdf)
- if not initialized then
- if resolvers.setmemstream then
- local f_setstream = formatters[ [[resolvers.setmemstream("svg-glyph-%05i",%q,true)]] ]
- local f_getstream = formatters[ [[memstream:///svg-glyph-%05i]] ]
- local f_nilstream = formatters[ [[resolvers.resetmemstream("svg-glyph-%05i",true)]] ]
- storepdfdata = function(pdf)
- nofstreams = nofstreams + 1
- return
- f_setstream(nofstreams,pdf),
- f_getstream(nofstreams),
- f_nilstream(nofstreams)
- end
- otfsvg.storepdfdata = storepdfdata
+local function pdftovirtual(tfmdata,pdfshapes,kind) -- kind = sbix|svg
+ if not tfmdata or not pdfshapes or not kind then
+ return
+ end
+ --
+ local characters = tfmdata.characters
+ local properties = tfmdata.properties
+ local parameters = tfmdata.parameters
+ local hfactor = parameters.hfactor
+ --
+ properties.virtualized = true
+ --
+ tfmdata.fonts = {
+ { id = 0 }
+ }
+ --
+ local getactualtext = otf.getactualtext
+ local storepdfdata = otf.storepdfdata
+ --
+ -- local nop = { "nop" }
+ --
+ for unicode, character in sortedhash(characters) do -- sort is nicer for svg
+ local index = character.index
+ if index then
+ local pdf = pdfshapes[index]
+ local typ = type(pdf)
+ local data = nil
+ local dx = nil
+ local dy = nil
+ if typ == "table" then
+ data = pdf.data
+ dx = pdf.dx or 0
+ dy = pdf.dy or 0
+ elseif typ == "string" then
+ data = pdf
+ dx = 0
+ dy = 0
+ end
+ if data then
+ local setcode, name, nilcode = storepdfdata(data)
+ if name then
+ local bt, et = getactualtext(unicode)
+ local wd = character.width or 0
+ local ht = character.height or 0
+ local dp = character.depth or 0
+ character.commands = {
+ { "special", "pdf:direct:" .. bt },
+ { "down", dp + dy * hfactor },
+ { "right", dx * hfactor },
+ -- setcode and { "lua", setcode } or nop,
+ { "image", { filename = name, width = wd, height = ht, depth = dp } },
+ -- nilcode and { "lua", nilcode } or nop,
+ { "special", "pdf:direct:" .. et },
+ }
+ character[kind] = true
end
- initialized = true
end
- return storepdfdata(pdf)
end
-
end
-
end
+local otfsvg = otf.svg or { }
+otf.svg = otfsvg
+otf.svgenabled = true
do
@@ -323,7 +396,7 @@ do
end
statistics.stoptiming()
if statistics.elapsedseconds then
- report_svg("svg conversion time %s",statistics.elapsedseconds())
+ report_svg("svg conversion time %s",statistics.elapsedseconds() or "-")
end
end
return pdfshapes
@@ -333,17 +406,12 @@ end
local function initializesvg(tfmdata,kind,value) -- hm, always value
if value and otf.svgenabled then
- local characters = tfmdata.characters
- local descriptions = tfmdata.descriptions
- local properties = tfmdata.properties
- --
- local svg = properties.svg
+ local svg = tfmdata.properties.svg
local hash = svg and svg.hash
local timestamp = svg and svg.timestamp
if not hash then
return
end
- --
local pdffile = containers.read(otf.pdfcache,hash)
local pdfshapes = pdffile and pdffile.pdfshapes
if not pdfshapes or pdffile.timestamp ~= timestamp then
@@ -355,44 +423,7 @@ local function initializesvg(tfmdata,kind,value) -- hm, always value
timestamp = timestamp,
})
end
- if not pdfshapes or not next(pdfshapes) then
- return
- end
- --
- properties.virtualized = true
- tfmdata.fonts = {
- { id = 0 }
- }
- --
- local getactualtext = otf.getactualtext
- local storepdfdata = otfsvg.storepdfdata
- --
- local nop = { "nop" }
- --
- for unicode, character in next, characters do
- local index = character.index
- if index then
- local pdf = pdfshapes[index]
- if pdf then
- local setcode, name, nilcode = storepdfdata(pdf)
- if name then
- local bt, et = getactualtext(unicode)
- local wd = character.width or 0
- local ht = character.height or 0
- local dp = character.depth or 0
- character.commands = {
- { "special", "pdf:direct:" .. bt },
- { "down", dp },
- setcode and { "lua", setcode } or nop,
- { "image", { filename = name, width = wd, height = ht, depth = dp } },
- nilcode and { "lua", nilcode } or nop,
- { "special", "pdf:direct:" .. et },
- }
- character.svg = true
- end
- end
- end
- end
+ pdftovirtual(tfmdata,pdfshapes,"svg")
end
end
@@ -404,3 +435,114 @@ fonts.handlers.otf.features.register {
node = initializesvg,
}
}
+
+-- This can be done differently e.g. with ffi and gm and we can share code anway. Using
+-- batchmode in gm is not faster and as it accumulates we would need to flush all
+-- individual shapes.
+
+local otfsbix = otf.sbix or { }
+otf.sbix = otfsbix
+otf.sbixenabled = true
+
+do
+
+ -- for now png but also other bitmap formats
+
+ local report_sbix = logs.reporter("fonts","sbix conversion")
+
+ local loaddata = io.loaddata
+ local savedata = io.savedata
+ local remove = os.remove
+
+ local runner = sandbox and sandbox.registerrunner {
+ name = "otfsbix",
+ program = "gm",
+ template = "convert -quality 100 temp-otf-sbix-shape.sbix temp-otf-sbix-shape.pdf > temp-otf-svg-shape.log",
+ -- reporter = report_sbix,
+ }
+
+ if not runner then
+ --
+ -- poor mans variant for generic:
+ --
+ runner = function()
+ return os.execute("gm convert -quality 100 temp-otf-sbix-shape.sbix temp-otf-sbix-shape.pdf > temp-otf-svg-shape.log")
+ end
+ end
+
+ -- Alternatively we can create a single pdf file with -adjoin and then pick up pages from
+ -- that file but creating thousands of small files is no fun either.
+
+ function otfsbix.topdf(sbixshapes)
+ local pdfshapes = { }
+ local sbixfile = "temp-otf-sbix-shape.sbix"
+ local pdffile = "temp-otf-sbix-shape.pdf"
+ local nofdone = 0
+ local indices = sortedkeys(sbixshapes) -- can be sparse
+ local nofindices = #indices
+ report_sbix("processing %i sbix containers",nofindices)
+ statistics.starttiming()
+ for i=1,nofindices do
+ local index = indices[i]
+ local entry = sbixshapes[index]
+ local data = entry.data
+ local x = entry.x
+ local y = entry.y
+ savedata(sbixfile,data)
+ runner()
+ pdfshapes[index] = {
+ x = x ~= 0 and x or nil,
+ y = y ~= 0 and y or nil,
+ data = loaddata(pdffile),
+ }
+ nofdone = nofdone + 1
+ if nofdone % 100 == 0 then
+ report_sbix("%i shapes processed",nofdone)
+ end
+ end
+ report_sbix("processing %i pdf results",nofindices)
+ remove(sbixfile)
+ remove(pdffile)
+ statistics.stoptiming()
+ if statistics.elapsedseconds then
+ report_sbix("sbix conversion time %s",statistics.elapsedseconds() or "-")
+ end
+ return pdfshapes
+ -- end
+ end
+
+end
+
+local function initializesbix(tfmdata,kind,value) -- hm, always value
+ if value and otf.sbixenabled then
+ local sbix = tfmdata.properties.sbix
+ local hash = sbix and sbix.hash
+ local timestamp = sbix and sbix.timestamp
+ if not hash then
+ return
+ end
+ local pdffile = containers.read(otf.pdfcache,hash)
+ local pdfshapes = pdffile and pdffile.pdfshapes
+ if not pdfshapes or pdffile.timestamp ~= timestamp then
+ local sbixfile = containers.read(otf.sbixcache,hash)
+ local sbixshapes = sbixfile and sbixfile.sbixshapes
+ pdfshapes = sbixshapes and otfsbix.topdf(sbixshapes) or { }
+ containers.write(otf.pdfcache, hash, {
+ pdfshapes = pdfshapes,
+ timestamp = timestamp,
+ })
+ end
+ --
+ pdftovirtual(tfmdata,pdfshapes,"sbix")
+ end
+end
+
+fonts.handlers.otf.features.register {
+ name = "sbix",
+ description = "sbix glyphs",
+ manipulators = {
+ base = initializesbix,
+ node = initializesbix,
+ }
+}
+