From e5f189d9965a70c8f3043c07c7b07d41ef268e93 Mon Sep 17 00:00:00 2001
From: Hans Hagen <pragma@wxs.nl>
Date: Wed, 17 Oct 2018 15:43:08 +0200
Subject: 2018-10-17 15:14:00

---
 tex/context/base/mkii/cont-new.mkii                |    2 +-
 tex/context/base/mkii/context.mkii                 |    2 +-
 tex/context/base/mkii/mult-fr.mkii                 |    1 +
 tex/context/base/mkiv/back-pdf.mkiv                |    1 +
 tex/context/base/mkiv/bibl-tra.mkiv                |    2 +-
 tex/context/base/mkiv/cldf-ini.mkiv                |    4 +-
 tex/context/base/mkiv/cont-new.mkiv                |    2 +-
 tex/context/base/mkiv/context.mkiv                 |    2 +-
 tex/context/base/mkiv/font-con.lua                 |    2 +
 tex/context/base/mkiv/font-imp-quality.lua         |    6 +-
 tex/context/base/mkiv/font-otc.lua                 |   18 +-
 tex/context/base/mkiv/font-oto.lua                 |   52 +-
 tex/context/base/mkiv/font-set.mkvi                |    2 +-
 tex/context/base/mkiv/grph-img.lua                 |  747 ++++++++++++++
 tex/context/base/mkiv/grph-inc.lua                 |  212 ++++
 tex/context/base/mkiv/grph-inc.mkiv                |    1 +
 tex/context/base/mkiv/l-macro-imp-optimize.lua     |    1 +
 tex/context/base/mkiv/l-number.lua                 |    4 +
 tex/context/base/mkiv/lpdf-img.lua                 | 1061 ++++++++++++++++++++
 tex/context/base/mkiv/pack-com.mkiv                |    4 +-
 tex/context/base/mkiv/pack-lyr.mkiv                |    4 +-
 tex/context/base/mkiv/page-lin.mkvi                |    4 +-
 tex/context/base/mkiv/page-set.mkiv                |   10 +-
 tex/context/base/mkiv/scrn-fld.mkvi                |    2 +-
 tex/context/base/mkiv/spac-pag.mkiv                |    4 +-
 tex/context/base/mkiv/status-files.pdf             |  Bin 26105 -> 26098 bytes
 tex/context/base/mkiv/status-lua.pdf               |  Bin 269460 -> 270199 bytes
 tex/context/base/mkiv/strc-con.mkvi                |    4 +-
 tex/context/base/mkiv/strc-flt.mkvi                |   18 +-
 tex/context/base/mkiv/strc-mat.mkiv                |    6 +-
 tex/context/base/mkiv/strc-not.mkvi                |    8 +-
 tex/context/base/mkiv/strc-num.mkiv                |    8 +-
 tex/context/base/mkiv/strc-pag.mkiv                |    2 +-
 tex/context/base/mkiv/strc-ref.mkvi                |    4 +-
 tex/context/base/mkiv/strc-reg.mkiv                |   20 +-
 tex/context/base/mkiv/strc-sec.mkiv                |   14 +-
 tex/context/base/mkiv/strc-syn.mkiv                |    4 +-
 tex/context/base/mkiv/symb-imp-mvs.mkiv            |   18 +-
 tex/context/base/mkiv/syst-aux.mkiv                |    4 -
 tex/context/base/mkiv/syst-ini.mkiv                |   12 +-
 tex/context/base/mkiv/tabl-tab.mkiv                |   16 +-
 tex/context/base/mkiv/tabl-tbl.mkiv                |    2 +-
 tex/context/base/mkiv/typo-drp.mkiv                |    2 +-
 tex/context/base/mkiv/typo-fln.mkiv                |    2 +-
 tex/context/base/mkiv/util-sac.lua                 |   64 +-
 tex/context/interface/mkii/keys-fr.xml             |    1 +
 tex/context/interface/mkiv/i-context.pdf           |  Bin 857333 -> 857333 bytes
 tex/context/interface/mkiv/i-readme.pdf            |  Bin 60774 -> 60773 bytes
 tex/context/modules/mkiv/m-format.mkiv             |    4 +-
 tex/context/modules/mkiv/s-fonts-charts.mkiv       |   65 +-
 tex/context/modules/mkiv/s-fonts-complete.mkiv     |  119 ++-
 tex/context/modules/mkiv/s-fonts-system.lua        |   87 ++
 tex/context/modules/mkiv/s-fonts-system.mkiv       |   12 +-
 tex/context/modules/mkiv/s-maps.mkiv               |    8 +-
 tex/generic/context/luatex/luatex-fonts-merged.lua |   65 +-
 55 files changed, 2488 insertions(+), 231 deletions(-)
 create mode 100644 tex/context/base/mkiv/grph-img.lua
 create mode 100644 tex/context/base/mkiv/lpdf-img.lua

(limited to 'tex')

diff --git a/tex/context/base/mkii/cont-new.mkii b/tex/context/base/mkii/cont-new.mkii
index 439cdf147..72d476f01 100644
--- a/tex/context/base/mkii/cont-new.mkii
+++ b/tex/context/base/mkii/cont-new.mkii
@@ -11,7 +11,7 @@
 %C therefore copyrighted by \PRAGMA. See mreadme.pdf for
 %C details.
 
-\newcontextversion{2018.10.08 17:44}
+\newcontextversion{2018.10.17 15:06}
 
 %D This file is loaded at runtime, thereby providing an
 %D excellent place for hacks, patches, extensions and new
diff --git a/tex/context/base/mkii/context.mkii b/tex/context/base/mkii/context.mkii
index 88a4cac8c..922f96320 100644
--- a/tex/context/base/mkii/context.mkii
+++ b/tex/context/base/mkii/context.mkii
@@ -20,7 +20,7 @@
 %D your styles an modules.
 
 \edef\contextformat {\jobname}
-\edef\contextversion{2018.10.08 17:44}
+\edef\contextversion{2018.10.17 15:06}
 
 %D For those who want to use this:
 
diff --git a/tex/context/base/mkii/mult-fr.mkii b/tex/context/base/mkii/mult-fr.mkii
index 5c94eaf24..69804afcb 100644
--- a/tex/context/base/mkii/mult-fr.mkii
+++ b/tex/context/base/mkii/mult-fr.mkii
@@ -1241,6 +1241,7 @@
 \setinterfaceconstant{textstyle}{styletexte}
 \setinterfaceconstant{textwidth}{largeurtexte}
 \setinterfaceconstant{threshold}{threshold}
+\setinterfaceconstant{time}{time}
 \setinterfaceconstant{title}{titre}
 \setinterfaceconstant{titlecolor}{couleurtitre}
 \setinterfaceconstant{titlecommand}{titlecommand}
diff --git a/tex/context/base/mkiv/back-pdf.mkiv b/tex/context/base/mkiv/back-pdf.mkiv
index 365493fff..799df2538 100644
--- a/tex/context/base/mkiv/back-pdf.mkiv
+++ b/tex/context/base/mkiv/back-pdf.mkiv
@@ -37,6 +37,7 @@
     \registerctxluafile{lpdf-epd}{}
 \else
     \registerctxluafile{lpdf-pde}{}
+    \registerctxluafile{lpdf-img}{optimize}
 \fi
 
 \registerctxluafile{lpdf-epa}{}
diff --git a/tex/context/base/mkiv/bibl-tra.mkiv b/tex/context/base/mkiv/bibl-tra.mkiv
index 3ff07ead5..5389400f3 100644
--- a/tex/context/base/mkiv/bibl-tra.mkiv
+++ b/tex/context/base/mkiv/bibl-tra.mkiv
@@ -1500,7 +1500,7 @@
    \c!numbercommand=\bibleftnumber]
 
 \unexpanded\def\preloadbiblist
-  {\globallet\preloadbiblist\relax
+  {\glet\preloadbiblist\relax
    \dousepublications\jobname}
 
 % \appendtoks \preloadbiblist \to \everysetuppublications
diff --git a/tex/context/base/mkiv/cldf-ini.mkiv b/tex/context/base/mkiv/cldf-ini.mkiv
index 67eea6892..29fb15d68 100644
--- a/tex/context/base/mkiv/cldf-ini.mkiv
+++ b/tex/context/base/mkiv/cldf-ini.mkiv
@@ -47,8 +47,8 @@
 
 % \catcode`=\activecatcode \let\luafunction % saves 10% on the call
 
-% \catcodetable\ctxcatcodes \catcode`^=\superscriptcatcode\catcode1=\activecatcode \global\let^^A=\cldf
-% \catcodetable\ctxcatcodes \catcode`^=\superscriptcatcode\catcode2=\activecatcode \global\let^^B=\cldn
+% \catcodetable\ctxcatcodes \catcode`^=\superscriptcatcode\catcode1=\activecatcode \glet^^A=\cldf
+% \catcodetable\ctxcatcodes \catcode`^=\superscriptcatcode\catcode2=\activecatcode \glet^^B=\cldn
 
 \normalprotected\def\cldprocessfile#1{\directlua{context.runfile("#1")}}
                 \def\cldloadfile   #1{\directlua{context.loadfile("#1")}}
diff --git a/tex/context/base/mkiv/cont-new.mkiv b/tex/context/base/mkiv/cont-new.mkiv
index c3c035160..5ce172570 100644
--- a/tex/context/base/mkiv/cont-new.mkiv
+++ b/tex/context/base/mkiv/cont-new.mkiv
@@ -11,7 +11,7 @@
 %C therefore copyrighted by \PRAGMA. See mreadme.pdf for
 %C details.
 
-\newcontextversion{2018.10.08 17:44}
+\newcontextversion{2018.10.17 15:06}
 
 %D This file is loaded at runtime, thereby providing an excellent place for
 %D hacks, patches, extensions and new features.
diff --git a/tex/context/base/mkiv/context.mkiv b/tex/context/base/mkiv/context.mkiv
index 9b166fb03..8b144d609 100644
--- a/tex/context/base/mkiv/context.mkiv
+++ b/tex/context/base/mkiv/context.mkiv
@@ -42,7 +42,7 @@
 %D has to match \type {YYYY.MM.DD HH:MM} format.
 
 \edef\contextformat {\jobname}
-\edef\contextversion{2018.10.08 17:44}
+\edef\contextversion{2018.10.17 15:06}
 \edef\contextkind   {beta}
 
 %D For those who want to use this:
diff --git a/tex/context/base/mkiv/font-con.lua b/tex/context/base/mkiv/font-con.lua
index 54cf2c199..d238084d0 100644
--- a/tex/context/base/mkiv/font-con.lua
+++ b/tex/context/base/mkiv/font-con.lua
@@ -739,6 +739,8 @@ function constructors.scale(tfmdata,specification)
             chr.tounicode = tounicode(isunicode)
             -- in luatex > 0.85 we can do this:
             -- chr.tounicode = isunicode
+        else
+--             chr.tounicode = "FFFD"
         end
         if hasquality then
             -- we could move these calculations elsewhere (saves calculations)
diff --git a/tex/context/base/mkiv/font-imp-quality.lua b/tex/context/base/mkiv/font-imp-quality.lua
index 52eed080c..bb78d9435 100644
--- a/tex/context/base/mkiv/font-imp-quality.lua
+++ b/tex/context/base/mkiv/font-imp-quality.lua
@@ -343,8 +343,7 @@ local function map_opbd_onto_protrusion(tfmdata,value,opbd)
                                 if v == true then
                                     -- zero
                                 else
-                                --  local p = - v[3] / descriptions[k].width-- or 1 ~= 0 too but the same
-                                    local p = - (v[1] / 1000) * factor * left
+                                    local p = - (v[3] / 1000) * factor * left
                                     characters[k].left_protruding = p
                                     if trace_protrusion then
                                         report_protrusions("lfbd -> %C -> %p",k,p)
@@ -376,8 +375,7 @@ local function map_opbd_onto_protrusion(tfmdata,value,opbd)
                                 if v == true then
                                     -- zero
                                 else
-                                --  local p = v[3] / descriptions[k].width -- or 3
-                                    local p = (v[1] / 1000) * factor * right
+                                    local p = (v[1] / 1000) * factor * right -- or [3] ?
                                     characters[k].right_protruding = p
                                     if trace_protrusion then
                                         report_protrusions("rtbd -> %C -> %p",k,p)
diff --git a/tex/context/base/mkiv/font-otc.lua b/tex/context/base/mkiv/font-otc.lua
index c2e89599a..595778e34 100644
--- a/tex/context/base/mkiv/font-otc.lua
+++ b/tex/context/base/mkiv/font-otc.lua
@@ -7,7 +7,7 @@ if not modules then modules = { } end modules ['font-otc'] = {
 }
 
 local insert, sortedkeys, sortedhash, tohash = table.insert, table.sortedkeys, table.sortedhash, table.tohash
-local type, next = type, next
+local type, next, tonumber = type, next, tonumber
 local lpegmatch = lpeg.match
 local utfbyte, utflen = utf.byte, utf.len
 local sortedhash = table.sortedhash
@@ -174,6 +174,10 @@ local function addfeature(data,feature,specifications)
         return
     end
 
+    local p = lpeg.P("P")
+            * (lpeg.patterns.hexdigit^1/function(s) return tonumber(s,16) end)
+            * lpeg.P(-1)
+
     local function tounicode(code)
         if not code then
             return
@@ -183,6 +187,7 @@ local function addfeature(data,feature,specifications)
         end
         local u = unicodes[code]
         if u then
+         -- unicodes[code] = u
             return u
         end
         if utflen(code) == 1 then
@@ -191,10 +196,19 @@ local function addfeature(data,feature,specifications)
                 return u
             end
         end
+        local u = lpegmatch(p,code)
+        if u then
+         -- unicodes[code] = u
+            return u
+        end
         if not aglunicodes then
             aglunicodes = fonts.encodings.agl.unicodes -- delayed
         end
-        return aglunicodes[code]
+        local u = aglunicodes[code]
+        if u then
+         -- unicodes[code] = u
+            return u
+        end
     end
 
     local coverup      = otf.coverup
diff --git a/tex/context/base/mkiv/font-oto.lua b/tex/context/base/mkiv/font-oto.lua
index 4b986bd3b..c32a7af25 100644
--- a/tex/context/base/mkiv/font-oto.lua
+++ b/tex/context/base/mkiv/font-oto.lua
@@ -415,36 +415,42 @@ local function checkmathreplacements(tfmdata,fullname,fixitalics)
             for unicode, replacement in next, changed do
                 local u = characters[unicode]
                 local r = characters[replacement]
-                local n = u.next
-                local v = u.vert_variants
-                local h = u.horiz_variants
-                if fixitalics then
-                    -- quite some warnings on stix ...
-                    local ui = u.italic
-                    if ui and not r.italic then
+                if u and r then
+                    local n = u.next
+                    local v = u.vert_variants
+                    local h = u.horiz_variants
+                    if fixitalics then
+                        -- quite some warnings on stix ...
+                        local ui = u.italic
+                        if ui and not r.italic then
+                            if trace_preparing then
+                                report_prepare("using %i units of italic correction from %C for %U",ui,unicode,replacement)
+                            end
+                            r.italic = ui -- print(ui,ri)
+                        end
+                    end
+                    if n and not r.next then
                         if trace_preparing then
-                            report_prepare("using %i units of italic correction from %C for %U",ui,unicode,replacement)
+                            report_prepare("forcing %s for %C substituted by %U","incremental step",unicode,replacement)
                         end
-                        r.italic = ui -- print(ui,ri)
+                        r.next = n
                     end
-                end
-                if n and not r.next then
-                    if trace_preparing then
-                        report_prepare("forcing %s for %C substituted by %U","incremental step",unicode,replacement)
+                    if v and not r.vert_variants then
+                        if trace_preparing then
+                            report_prepare("forcing %s for %C substituted by %U","vertical variants",unicode,replacement)
+                        end
+                        r.vert_variants = v
                     end
-                    r.next = n
-                end
-                if v and not r.vert_variants then
-                    if trace_preparing then
-                        report_prepare("forcing %s for %C substituted by %U","vertical variants",unicode,replacement)
+                    if h and not r.horiz_variants then
+                        if trace_preparing then
+                            report_prepare("forcing %s for %C substituted by %U","horizontal variants",unicode,replacement)
+                        end
+                        r.horiz_variants = h
                     end
-                    r.vert_variants = v
-                end
-                if h and not r.horiz_variants then
+                else
                     if trace_preparing then
-                        report_prepare("forcing %s for %C substituted by %U","horizontal variants",unicode,replacement)
+                        report_prepare("error replacing %C by %U",unicode,replacement)
                     end
-                    r.horiz_variants = h
                 end
             end
         end
diff --git a/tex/context/base/mkiv/font-set.mkvi b/tex/context/base/mkiv/font-set.mkvi
index fe0fb6cad..aac83e1aa 100644
--- a/tex/context/base/mkiv/font-set.mkvi
+++ b/tex/context/base/mkiv/font-set.mkvi
@@ -46,7 +46,7 @@
 % \def\font_preloads_reset_nullfont % this is needed because some macro packages (tikz) misuse \nullfont
 %   {\dorecurse\plusseven{\fontdimen\recurselevel\nullfont\zeropoint}% keep en eye on this as:
 %    \clf_resetnullfont % in luatex 0.70 this will also do the previous
-%    \globallet\font_preloads_reset_nullfont\relax}
+%    \glet\font_preloads_reset_nullfont\relax}
 
 \def\font_preload_check_mode
   {\doifelsemode{lmmath}
diff --git a/tex/context/base/mkiv/grph-img.lua b/tex/context/base/mkiv/grph-img.lua
new file mode 100644
index 000000000..3714b649e
--- /dev/null
+++ b/tex/context/base/mkiv/grph-img.lua
@@ -0,0 +1,747 @@
+if not modules then modules = { } end modules ['grph-img'] = {
+    version   = 1.001,
+    comment   = "companion to grph-inc.mkiv",
+    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+    copyright = "PRAGMA ADE / ConTeXt Development Team",
+    license   = "see context related readme files"
+}
+
+-- The jpg identification and inclusion code is based on the code in \LUATEX\ but as we
+-- use \LUA\ we can do it a bit cleaner. We can also use some helpers for reading from
+-- file. We could make it even more lean and mean. When all works out ok I will clean
+-- up this code a bit as we can divert more from luatex.
+
+local lower, strip = string.lower, string.strip
+local round = math.round
+local concat = table.concat
+local suffixonly = file.suffix
+
+local files              = utilities.files
+local getsize            = files.getsize
+local readbyte           = files.readbyte
+local readstring         = files.readstring
+local readcardinal       = files.readcardinal
+local readcardinal2      = files.readcardinal2
+local readcardinal4      = files.readcardinal4
+local readcardinal2le    = files.readcardinal2le
+local readcardinal4le    = files.readcardinal4le
+local skipbytes          = files.skip
+local setposition        = files.setposition
+local getposition        = files.getposition
+
+local setmetatableindex  = table.setmetatableindex
+local setmetatablecall   = table.setmetatablecall
+
+local lpdf               = lpdf or { }
+local pdfmajorversion    = lpdf.majorversion
+local pdfminorversion    = lpdf.minorversion
+
+local graphics       = graphics or { }
+local identifiers    = { }
+graphics.identifiers = identifiers
+
+do
+
+    local colorspaces = {
+        [1] = 1, -- gray
+        [3] = 2, -- rgb
+        [4] = 3, -- cmyk
+    }
+
+    local tags = {
+        [0xC0] = { name = "SOF0",                    }, -- baseline DCT
+        [0xC1] = { name = "SOF1",                    }, -- extended sequential DCT
+        [0xC2] = { name = "SOF2",                    }, -- progressive DCT
+        [0xC3] = { name = "SOF3",  supported = false }, -- lossless (sequential)
+
+        [0xC5] = { name = "SOF5",  supported = false }, -- differential sequential DCT
+        [0xC6] = { name = "SOF6",  supported = false }, -- differential progressive DCT
+        [0xC7] = { name = "SOF7",  supported = false }, -- differential lossless (sequential)
+
+        [0xC8] = { name = "JPG",                     }, -- reserved for JPEG extensions
+        [0xC9] = { name = "SOF9",                    }, -- extended sequential DCT
+        [0xCA] = { name = "SOF10", supported = false }, -- progressive DCT
+        [0xCB] = { name = "SOF11", supported = false }, -- lossless (sequential)
+
+        [0xCD] = { name = "SOF13", supported = false }, -- differential sequential DCT
+        [0xCE] = { name = "SOF14", supported = false }, -- differential progressive DCT
+        [0xCF] = { name = "SOF15", supported = false }, -- differential lossless (sequential)
+
+        [0xC4] = { name = "DHT"                      }, -- define Huffman table(s)
+
+        [0xCC] = { name = "DAC"                      }, -- define arithmetic conditioning table
+
+        [0xD0] = { name = "RST0", zerolength = true }, -- restart
+        [0xD1] = { name = "RST1", zerolength = true }, -- restart
+        [0xD2] = { name = "RST2", zerolength = true }, -- restart
+        [0xD3] = { name = "RST3", zerolength = true }, -- restart
+        [0xD4] = { name = "RST4", zerolength = true }, -- restart
+        [0xD5] = { name = "RST5", zerolength = true }, -- restart
+        [0xD6] = { name = "RST6", zerolength = true }, -- restart
+        [0xD7] = { name = "RST7", zerolength = true }, -- restart
+
+        [0xD8] = { name = "SOI",  zerolength = true }, -- start of image
+        [0xD9] = { name = "EOI",  zerolength = true }, -- end of image
+        [0xDA] = { name = "SOS"                     }, -- start of scan
+        [0xDB] = { name = "DQT"                     }, -- define quantization tables
+        [0xDC] = { name = "DNL"                     }, -- define number of lines
+        [0xDD] = { name = "DRI"                     }, -- define restart interval
+        [0xDE] = { name = "DHP"                     }, -- define hierarchical progression
+        [0xDF] = { name = "EXP"                     }, -- expand reference image(s)
+
+        [0xE0] = { name = "APP0"                    }, -- application marker, used for JFIF
+        [0xE1] = { name = "APP1"                    }, -- application marker
+        [0xE2] = { name = "APP2"                    }, -- application marker
+        [0xE3] = { name = "APP3"                    }, -- application marker
+        [0xE4] = { name = "APP4"                    }, -- application marker
+        [0xE5] = { name = "APP5"                    }, -- application marker
+        [0xE6] = { name = "APP6"                    }, -- application marker
+        [0xE7] = { name = "APP7"                    }, -- application marker
+        [0xE8] = { name = "APP8"                    }, -- application marker
+        [0xE9] = { name = "APP9"                    }, -- application marker
+        [0xEA] = { name = "APP10"                   }, -- application marker
+        [0xEB] = { name = "APP11"                   }, -- application marker
+        [0xEC] = { name = "APP12"                   }, -- application marker
+        [0xED] = { name = "APP13"                   }, -- application marker
+        [0xEE] = { name = "APP14"                   }, -- application marker, used by Adobe
+        [0xEF] = { name = "APP15"                   }, -- application marker
+
+        [0xF0] = { name = "JPG0"                    }, -- reserved for JPEG extensions
+        [0xFD] = { name = "JPG13"                   }, -- reserved for JPEG extensions
+        [0xFE] = { name = "COM"                     }, -- comment
+
+        [0x01] = { name = "TEM",  zerolength = true }, -- temporary use
+    }
+
+    -- More can be found in http://www.exif.org/Exif2-2.PDF but basically we have
+    -- good old tiff tags here.
+
+    local function read_APP1_Exif(f, xres, yres, orientation) -- untested
+        local position      = false
+        local readcardinal2 = readcardinal2
+        local readcardinal4 = readcardinal4
+        -- endian II|MM
+        while true do
+            position = getposition(f)
+            local b  = readbyte(f)
+            if b == 0 then
+                -- next one
+            elseif b == 0x4D and readbyte(f) == 0x4D then -- M
+                -- big endian
+                break
+            elseif b == 0x49 and readbyte(f) == 0x49 then -- I
+                -- little endian
+                readcardinal2 = readcardinal2le
+                readcardinal4 = readcardinal4le
+                break
+            else
+                -- warning "bad exif data"
+                return xres, yres, orientation
+            end
+        end
+        -- version
+        local version = readcardinal2(f)
+        if version ~= 42 then
+            return xres, yres, orientation
+        end
+        -- offset to records
+        local offset = readcardinal4(f)
+        if not offset then
+            return xres, yres, orientation
+        end
+        setposition(f,position + offset)
+        local entries = readcardinal2(f)
+        if not entries or entries == 0 then
+            return xres, yres, orientation
+        end
+        local x_res, y_res, x_res_ms, y_res_ms, x_temp, y_temp
+        local res_unit, res_unit_ms
+        for i=1,entries do
+            local tag    = readcardinal2(f)
+            local kind   = readcardinal2(f)
+            local size   = readcardinal4(f)
+            local value  = 0
+            local num    = 0
+            local den    = 0
+            if kind == 1 or kind == 7 then -- byte | undefined
+                value = readbyte(f)
+                skipbytes(f,3)
+            elseif kind == 3 or kind == 8 then -- (un)signed short
+                value = readcardinal2(f)
+                skipbytes(f,2)
+            elseif kind == 4 or kind == 9 then -- (un)signed long
+                value = readcardinal4(f)
+            elseif kind == 5 or kind == 10 then -- (s)rational
+                local offset = readcardinal4(f)
+                local saved  = getposition(f)
+                setposition(f,position+offset)
+                num = readcardinal4(f)
+                den = readcardinal4(f)
+                setposition(f,saved)
+            else -- 2 -- ascii
+                skipbytes(f,4)
+            end
+            if tag == 274 then         -- orientation
+                orientation = value
+            elseif tag == 282 then     -- x resolution
+                if den ~= 0 then
+                    x_res = num/den
+                end
+            elseif tag == 283 then     -- y resolution
+                if den ~= 0 then
+                    y_res = num/den
+                end
+            elseif tag == 296 then     -- resolution unit
+                if value == 2 then
+                    res_unit = 1
+                elseif value == 3 then
+                    res_unit = 2.54
+                end
+            elseif tag == 0x5110 then  -- pixel unit
+                res_unit_ms = value == 1
+            elseif tag == 0x5111 then  -- x pixels per unit
+                x_res_ms = value
+            elseif tag == 0x5112 then  -- y pixels per unit
+                y_res_ms = value
+            end
+        end
+        if x_res and y_res and res_unit and res_unit > 0 then
+            x_temp = round(x_res * res_unit)
+            y_temp = round(y_res * res_unit)
+        elseif x_res_ms and y_res_ms and res_unit_ms then
+            x_temp = round(x_res_ms * 0.0254) -- in meters
+            y_temp = round(y_res_ms * 0.0254) -- in meters
+        end
+        if x_temp and a_temp and x_temp > 0 and y_temp > 0 then
+            if (x_temp ~= x_res or y_temp ~=  y_res) and x_res ~= 0 and y_res ~= 0 then
+                -- exif resolution differs from already found resolution
+            elseif x_temp == 1 or y_temp == 1 then
+                -- exif resolution is kind of weird
+            else
+                return x_temp, y_temp, orientation
+            end
+        end
+        return round(xres), round(yres), orientation
+    end
+
+    function identifiers.jpg(filename)
+        local specification = {
+            filename = filename,
+            filetype = "jpg",
+        }
+        if not filename or filename == "" then
+            specification.error = "invalid filename"
+            return specification -- error
+        end
+        local f = io.open(filename,"rb")
+        if not f then
+            specification.error = "unable to open file"
+            return specification -- error
+        end
+        specification.xres        = 0
+        specification.yres        = 0
+        specification.orientation = 1
+        specification.totalpages  = 1
+        specification.pagenum     = 1
+        specification.length      = 0
+        local banner = readcardinal2(f)
+        if banner ~= 0xFFD8 then
+            specification.error = "no jpeg file"
+            return specification -- error
+        end
+        local xres         = 0
+        local yres         = 0
+        local orientation  = 1
+        local okay         = false
+        local filesize     = getsize(f) -- seek end
+        local majorversion = pdfmajorversion and pdfmajorversion() or 2
+        local minorversion = pdfminorversion and pdfminorversion() or 2
+        while getposition(f) < filesize do
+            local b = readbyte(f)
+            if not b then
+                break
+            elseif b ~= 0xFF then
+                if not okay then
+                    -- or check for size
+                    specification.error = "incomplete file"
+                end
+                break
+            end
+            local category  = readbyte(f)
+            local position  = getposition(f)
+            local length    = 0
+            local tagdata   = tags[category]
+            if not tagdata then
+                specification.error = "invalid tag"
+                break
+            elseif tagdata.supported == false then
+                specification.error = "unsupported " .. tagdata.comment
+                break
+            end
+            local name = tagdata.name
+            if name == "SOF2" then
+                if majorversion < 2 or minorversion <= 2 then
+                    specification.error = "no progressive DCT in PDF <= 1.2"
+                    break
+                end
+            elseif name == "SOF0" or name == "SOF1" then
+                length = readcardinal2(f)
+                specification.colordepth = readcardinal(f)
+                specification.ysize      = readcardinal2(f)
+                specification.xsize      = readcardinal2(f)
+                specification.colorspace = colorspaces[readcardinal(f)]
+                if not specification.colorspace then
+                    specification.error = "unsupported color space"
+                    break
+                end
+                okay = true
+            elseif name == "APP0" then
+                length = readcardinal2(f)
+                if length > 6 then
+                    local format = readstring(f,5)
+                    if format  == "JFIF\000" then
+                        skipbytes(f,2)
+                        units = readcardinal(f)
+                        xres  = readcardinal2(f)
+                        yres  = readcardinal2(f)
+                        if units == 1 then
+                            -- pixels per inch
+                            if xres == 1 or yres == 1 then
+                                -- warning
+                            end
+                        elseif units == 2 then
+                            -- pixels per cm */
+                            xres = xres * 2.54
+                            yres = yres * 2.54
+                        else
+                            xres = 0
+                            yres = 0
+                        end
+                    end
+                end
+            elseif name == "APP1" then
+                length = readcardinal2(f)
+                if length > 7 then
+                    local format = readstring(f,5)
+                    if format == "Exif\000" then
+                        xres, yres, orientation = read_APP1_Exif(f,xres,yres,orientation)
+                    end
+                end
+            elseif not tagdata.zerolength then
+                length = readcardinal2(f)
+            end
+            if length > 0 then
+                setposition(f,position+length)
+            end
+        end
+        f:close()
+        if not okay then
+            specification.error = "invalid file"
+        elseif not specification.error then
+            if xres == 0 and yres ~= 0 then
+                xres = yres
+            end
+            if yres == 0 and xres ~= 0 then
+                yres = xres
+            end
+        end
+        specification.xres        = xres
+        specification.yres        = yres
+        specification.orientation = orientation
+        specification.length      = filesize
+        return specification
+    end
+
+end
+
+do
+
+    local function read_boxhdr(specification,f)
+        local size = readcardinal4(f)
+        local kind = readstring(f,4)
+        if kind then
+            kind = strip(lower(kind))
+        else
+            kind = ""
+        end
+        if size == 1 then
+            size = readcardinal4(f) * 0xFFFF0000 + readcardinal4(f)
+        end
+        if size == 0 and kind ~= "jp2c" then  -- move this
+            specification.error = "invalid size"
+        end
+        return kind, size
+    end
+
+    local function scan_ihdr(specification,f)
+        specification.ysize = readcardinal4(f)
+        specification.xsize = readcardinal4(f)
+        skipbytes(f,2) -- nc
+        specification.colordepth = readcardinal(f) + 1
+        skipbytes(f,3) -- c unkc ipr
+    end
+
+    local function scan_resc_resd(specification,f)
+        local vr_n = readcardinal2(f)
+        local vr_d = readcardinal2(f)
+        local hr_n = readcardinal2(f)
+        local hr_d = readcardinal2(f)
+        local vr_e = readcardinal(f)
+        local hr_e = readcardinal(f)
+        specification.xres = math.round((hr_n / hr_d) * math.exp(hr_e * math.log(10.0)) * 0.0254)
+        specification.yres = math.round((vr_n / vr_d) * math.exp(vr_e * math.log(10.0)) * 0.0254)
+    end
+
+    local function scan_res(specification,f,last)
+        local pos = getposition(f)
+        while true do
+            local kind, size = read_boxhdr(specification,f)
+            pos = pos + size
+            if kind == "resc" then
+                if specification.xres == 0 and specification.yres == 0 then
+                    scan_resc_resd(specification,f)
+                    if getposition(f) ~= pos then
+                        specification.error = "invalid resc"
+                        return
+                    end
+                end
+            elseif tpos == "resd" then
+                scan_resc_resd(specification,f)
+                if getposition(f) ~= pos then
+                    specification.error = "invalid resd"
+                    return
+                end
+            elseif pos > last then
+                specification.error = "invalid res"
+                return
+            elseif pos == last then
+                break
+            end
+            if specification.error then
+                break
+            end
+            setposition(f,pos)
+        end
+    end
+
+    local function scan_jp2h(specification,f,last)
+        local okay = false
+        local pos = getposition(f)
+        while true do
+            local kind, size = read_boxhdr(specification,f)
+            pos = pos + size
+            if kind == "ihdr" then
+                scan_ihdr(specification,f)
+                if getposition(f) ~= pos then
+                    specification.error = "invalid ihdr"
+                    return false
+                end
+                okay = true
+            elseif kind == "res" then
+                scan_res(specification,f,pos)
+            elseif pos > last then
+                specification.error = "invalid jp2h"
+                return false
+            elseif pos == last then
+                break
+            end
+            if specification.error then
+                break
+            end
+            setposition(f,pos)
+        end
+        return okay
+    end
+
+    function identifiers.jp2(filename)
+        local specification = {
+            filename = filename,
+            filetype = "jp2",
+        }
+        if not filename or filename == "" then
+            specification.error = "invalid filename"
+            return specification -- error
+        end
+        local f = io.open(filename,"rb")
+        if not f then
+            specification.error = "unable to open file"
+            return specification -- error
+        end
+        specification.xres        = 0
+        specification.yres        = 0
+        specification.orientation = 1
+        specification.totalpages  = 1
+        specification.pagenum     = 1
+        specification.length      = 0
+        local xres         = 0
+        local yres         = 0
+        local orientation  = 1
+        local okay         = false
+        local filesize     = getsize(f) -- seek end
+        local majorversion = pdfmajorversion and pdfmajorversion() or 2
+        local minorversion = pdfminorversion and pdfminorversion() or 2
+        --
+        local pos = 0
+        --  signature
+        local kind, size = read_boxhdr(specification,f)
+        pos = pos + size
+        setposition(f,pos)
+        -- filetype
+        local kind, size = read_boxhdr(specification,f)
+        if kind ~= "ftyp" then
+            specification.error = "missing ftyp box"
+            return specification
+        end
+        pos = pos + size
+        setposition(f,pos)
+        while not okay do
+            local kind, size = read_boxhdr(specification,f)
+            pos = pos + size
+            if kind == "jp2h" then
+               okay = scan_jp2h(specification,f,pos)
+            elseif kind == "jp2c" and not okay then
+                specification.error = "no ihdr box found"
+                return specification
+            end
+            setposition(f,pos)
+        end
+        --
+        f:close()
+        if not okay then
+            specification.error = "invalid file"
+        elseif not specification.error then
+            if xres == 0 and yres ~= 0 then
+                xres = yres
+            end
+            if yres == 0 and xres ~= 0 then
+                yres = xres
+            end
+        end
+        specification.xres        = xres
+        specification.yres        = yres
+        specification.orientation = orientation
+        specification.length      = filesize
+        return specification
+    end
+
+end
+
+do
+
+    -- 0 = gray               "image b"
+    -- 2 = rgb                "image c"
+    -- 3 = palette            "image c" + "image i"
+    -- 4 = gray + alpha       "image b"
+    -- 6 = rgb + alpha        "image c"
+
+    -- for i=1,length/3 do
+    --     palette[i] = readstring(f,3)
+    -- end
+
+    local function grab(t,f,once)
+        if once then
+            for i=1,#t do
+                local l = t[i]
+                setposition(f,l.offset)
+                t[i] = readstring(f,l.length)
+            end
+            local data = concat(t)
+            return data
+        else
+            local data = { }
+            for i=1,#t do
+                local l = t[i]
+                setposition(f,l.offset)
+                data[i] = readstring(f,l.length)
+            end
+            return concat(data)
+        end
+    end
+
+    function identifiers.png(filename)
+        local specification = {
+            filename = filename,
+            filetype = "png",
+        }
+        if not filename or filename == "" then
+            specification.error = "invalid filename"
+            return specification -- error
+        end
+        local f = io.open(filename,"rb")
+        if not f then
+            specification.error = "unable to open file"
+            return specification -- error
+        end
+        specification.xres        = 0
+        specification.yres        = 0
+        specification.orientation = 1
+        specification.totalpages  = 1
+        specification.pagenum     = 1
+        specification.offset      = 0
+        specification.length      = 0
+        local filesize = getsize(f) -- seek end
+        local tables   = { }
+        local banner   = readstring(f,8)
+        if banner ~= "\137PNG\013\010\026\010" then
+            specification.error = "no png file"
+            return specification -- error
+        end
+        while true do
+            local position = getposition(f)
+            if position >= filesize then
+                break
+            end
+            local length = readcardinal4(f)
+            if not length then
+                break
+            end
+            local kind = readstring(f,4)
+            if kind then
+                kind = lower(kind)
+            else
+                break
+            end
+            if kind == "ihdr" then -- metadata
+                specification.xsize       = readcardinal4(f)
+                specification.ysize       = readcardinal4(f)
+                specification.colordepth  = readcardinal(f)
+                specification.colorspace  = readcardinal(f)
+                specification.compression = readcardinal(f)
+                specification.filter      = readcardinal(f)
+                specification.interlace   = readcardinal(f)
+                tables[kind] = true
+            elseif kind == "iend" then
+                tables[kind] = true
+                break
+            elseif kind == "phys" then
+                local x = readcardinal4(f)
+                local y = readcardinal4(f)
+                local u = readcardinal(f)
+                if u == 1 then -- meters
+                 -- x = round(0.0254 * x)
+                 -- y = round(0.0254 * y)
+                end
+                specification.xres = x
+                specification.yres = y
+                tables[kind] = true
+            elseif kind == "idat" or kind == "plte" or kind == "gama" or kind == "trns" then
+                local t = tables[kind]
+                if not t then
+                    t = setmetatablecall(grab)
+                    tables[kind] = t
+                end
+                t[#t+1] = {
+                    offset = getposition(f),
+                    length = length,
+                }
+            else
+                tables[kind] = true
+            end
+            setposition(f,position+length+12) -- #size #kind #crc
+        end
+        specification.tables = tables
+        return specification
+    end
+
+end
+
+do
+
+    local function gray(t,k)
+        local v = 0
+        t[k] = v
+        return v
+    end
+
+    local function rgb(t,k)
+        local v = { 0, 0, 0 }
+        t[k] = v
+        return v
+    end
+
+    local function cmyk(t,k)
+        local v = { 0, 0, 0, 0 }
+        t[k] = v
+        return v
+    end
+
+    function identifiers.bitmap(specification)
+        local xsize      = specification.xsize or 0
+        local ysize      = specification.ysize or 0
+        local width      = specification.width or xsize * 65536
+        local height     = specification.height or ysize * 65536
+        local colordepth = specification.colordepth or 1 -- 1 .. 2
+        local colorspace = specification.colorspace or 1 -- 1 .. 3
+        local pixel      = false
+        local data       = specification.data
+        local mask       = specification.mask
+        if colorspace == 1 or colorspace == "gray" then
+            pixel      = gray
+            colorspace = 1
+        elseif colorspace == 2 or colorspace == "rgb"  then
+            pixel      = rgb
+            colorspace = 2
+        elseif colorspace == 3 or colorspace == "cmyk"  then
+            pixel      = cmyk
+            colorspace = 3
+        else
+            return
+        end
+        -- maybe alpha some day
+        if colordepth == 8 then
+            colordepth = 1
+        elseif colordepth == 16 then
+            colordepth = 2
+        end
+        if colordepth > 1 then
+            -- not yet
+            return
+        end
+        if data then
+            -- assume correct data
+        else
+            data = { }
+            for i=1,ysize do
+                data[i] = setmetatableindex(pixel)
+            end
+        end
+        if mask == true then
+            mask = { }
+            for i=1,ysize do
+                mask[i] = setmetatableindex(gray)
+            end
+        end
+        local specification = {
+            xsize      = xsize,
+            ysize      = ysize,
+            width      = width,
+            height     = height,
+            colordepth = colordepth,
+            colorspace = colorspace,
+            data       = data,
+            mask       = mask,
+        }
+        return specification
+    end
+
+end
+
+function graphics.identify(filename,filetype)
+    local identify = filetype and identifiers[filetype]
+    if identify then
+        return identify(filename)
+    end
+    local identify = identifiers[suffixonly(filename)]
+    if identify then
+        return identify(filename)
+    end
+    -- auto
+    return {
+        filename = filename,
+        filetype = filetype,
+        error    = "identification failed",
+    }
+end
+
+-- inspect(identifiers.jpg("t:/sources/hacker.jpg"))
+-- inspect(identifiers.png("t:/sources/mill.png"))
diff --git a/tex/context/base/mkiv/grph-inc.lua b/tex/context/base/mkiv/grph-inc.lua
index 09084606d..553c60463 100644
--- a/tex/context/base/mkiv/grph-inc.lua
+++ b/tex/context/base/mkiv/grph-inc.lua
@@ -60,6 +60,8 @@ local allocate          = utilities.storage.allocate
 local setmetatableindex = table.setmetatableindex
 local replacetemplate   = utilities.templates.replace
 
+-- local bpfactor          = number.dimenfactors.bp
+
 local images            = img
 
 local hasscheme         = url.hasscheme
@@ -2139,6 +2141,126 @@ local function pdf_checker(data)
     return checkers.generic(data)
 end
 
+local function wrappedidentify(identify,filename)
+    local wrapup    = function() report_inclusion("fatal error reading %a",filename) end
+    local _, result = xpcall(identify,wrapup,filename)
+    return result or { error = "fatal error" }
+end
+
+local function jpg_checker(data)
+    local request = data.request
+    local used    = data.used
+    if request and used and not request.scanimage then
+        local identify = graphics.identify
+        local inject   = lpdf.injectors.jpg
+        local found    = false
+        request.scanimage = function(t)
+            local filename = t.filename
+            local result   = wrappedidentify(identify,filename)
+            local xsize    = result.xsize or 0
+            local ysize    = result.ysize or 0
+            found = not result.error
+            return {
+                filename    = filename,
+                width       = xsize * 65536,
+                height      = ysize * 65536,
+                depth       = 0,
+                colordepth  = result.colordepth or 0,
+                xres        = result.xres,
+                yres        = result.yres,
+                xsize       = xsize,
+                ysize       = ysize,
+                rotation    = result.rotation or 0,
+                colorspace  = result.colorspace or 0,
+            }
+        end
+        request.copyimage = function(t)
+            if found then
+                found = false
+                return inject(t)
+            end
+        end
+    end
+    return checkers.generic(data)
+end
+
+local function jp2_checker(data) -- idem as jpg
+    local request = data.request
+    local used    = data.used
+    if request and used and not request.scanimage then
+        local identify = graphics.identify
+        local inject   = lpdf.injectors.jp2
+        local found    = false
+        request.scanimage = function(t)
+            local filename = t.filename
+            local result   = wrappedidentify(identify,filename)
+            local xsize    = result.xsize or 0
+            local ysize    = result.ysize or 0
+            found = not result.error
+            return {
+                filename    = filename,
+                width       = xsize * 65536,
+                height      = ysize * 65536,
+                depth       = 0,
+                colordepth  = result.colordepth or 0,
+                xres        = result.xres,
+                yres        = result.yres,
+                xsize       = xsize,
+                ysize       = ysize,
+                rotation    = result.rotation or 0,
+                colorspace  = result.colorspace or 0,
+            }
+        end
+        request.copyimage = function(t)
+            if found then
+                found = false
+                return inject(t)
+            end
+        end
+    end
+    return checkers.generic(data)
+end
+
+local function png_checker(data) -- same as jpg (for now)
+    local request = data.request
+    local used    = data.used
+    if request and used and not request.scanimage then
+        local identify = graphics.identify
+        local inject   = lpdf.injectors.png
+        local found    = false
+        request.scanimage = function(t)
+            local filename = t.filename
+            local result   = wrappedidentify(identify,filename)
+            local xsize    = result.xsize or 0
+            local ysize    = result.ysize or 0
+            found = not result.error
+            return {
+                filename    = filename,
+                width       = xsize * 65536,
+                height      = ysize * 65536,
+                depth       = 0,
+                colordepth  = result.colordepth or 0,
+                xres        = result.xres,
+                yres        = result.yres,
+                xsize       = xsize,
+                ysize       = ysize,
+                rotation    = result.rotation or 0,
+                colorspace  = result.colorspace or 0,
+                tables      = result.tables,
+                interlace   = result.interlace,
+                filter      = result.filter,
+            }
+        end
+        request.copyimage = function(t)
+            if found then
+                found = false
+                return inject(t)
+            end
+        end
+    end
+    return checkers.generic(data)
+end
+
 directives.register("graphics.pdf.uselua",function(v)
     if v then
         report("%s Lua based PDF inclusion","enabling")
@@ -2149,6 +2271,37 @@ directives.register("graphics.pdf.uselua",function(v)
     end
 end)
 
+directives.register("graphics.jpg.uselua",function(v)
+    if v then
+        report("%s Lua based JPG inclusion","enabling")
+        checkers.jpg = jpg_checker
+    else
+        report("%s Lua based JPG inclusion","disabling")
+        checkers.jpg = nil
+    end
+end)
+
+directives.register("graphics.jp2.uselua",function(v)
+    if v then
+        report("%s Lua based JP2 inclusion","enabling")
+        checkers.jp2 = jp2_checker
+    else
+        report("%s Lua based JP2 inclusion","disabling")
+        checkers.jp2 = nil
+    end
+end)
+
+directives.register("graphics.png.uselua",function(v)
+    if v then
+        report("%s Lua based PNG inclusion","enabling")
+        checkers.png = png_checker
+    else
+        report("%s Lua based PNG inclusion","disabling")
+        checkers.png = nil
+    end
+end)
+
+
 -- directives.enable("graphics.pdf.uselua")
 --
 -- local filename = "luatex.pdf"
@@ -2160,3 +2313,62 @@ end)
 --         context.stopTEXpage()
 --     end)
 -- end
+
+-- This is experimental, for the moment here:
+
+local bitmaps       = { }
+graphics.bitmaps    = bitmaps
+
+local report_bitmap = logs.reporter("graphics","bitmap")
+
+function bitmaps.new(xsize,ysize,colorspace,colordepth,mask)
+    if not xsize or not ysize or xsize == 0 or ysize == 0 then
+        report_bitmap("provide 'xsize' and 'ysize' larger than zero")
+        return
+    end
+    if not colorspace then
+        report_bitmap("provide 'colorspace' (1, 2, 3, 'gray', 'rgb', 'cmyk'")
+        return
+    end
+    if not colordepth then
+        report_bitmap("provide 'colordepth' (1, 2)")
+        return
+    end
+    return graphics.identifiers.bitmap {
+        colorspace = colorspace,
+        colordepth = colordepth,
+        xsize      = xsize,
+        ysize      = ysize,
+        mask       = mask and true or nil,
+    }
+end
+
+local function flush(bitmap)
+    img.write(lpdf.injectors.bitmap(bitmap))
+end
+
+bitmaps.flush = flush
+
+function bitmaps.tocontext(bitmap,width,height)
+    if type(width) == "number" then
+        width = width .. "sp"
+    end
+    if type(height) == "number" then
+        height = height .. "sp"
+    end
+    if not height and not height then
+        width  = bitmap.xsize .. "bp"
+        height = bitmap.ysize .. "bp"
+    end
+    context.scale (
+        {
+            width  = width,
+            height = height,
+        },
+        function()
+            flush(bitmap)
+        end
+    )
+end
+
+
diff --git a/tex/context/base/mkiv/grph-inc.mkiv b/tex/context/base/mkiv/grph-inc.mkiv
index 371725271..cefb114e9 100644
--- a/tex/context/base/mkiv/grph-inc.mkiv
+++ b/tex/context/base/mkiv/grph-inc.mkiv
@@ -20,6 +20,7 @@
 
 \writestatus{loading}{ConTeXt Graphic Macros / Figure Inclusion}
 
+\registerctxluafile{grph-img}{}
 \registerctxluafile{grph-inc}{}
 \registerctxluafile{grph-con}{}
 \registerctxluafile{grph-fil}{}
diff --git a/tex/context/base/mkiv/l-macro-imp-optimize.lua b/tex/context/base/mkiv/l-macro-imp-optimize.lua
index 856cab038..982548785 100644
--- a/tex/context/base/mkiv/l-macro-imp-optimize.lua
+++ b/tex/context/base/mkiv/l-macro-imp-optimize.lua
@@ -57,6 +57,7 @@ lua.macros.resolvestring [[
 #define extract(a,b)   ((a>>b)&0x1)
 #define lshift(a,b)    ((a<<b)&0xFFFFFFFF)
 #define rshift(a,b)    ((a>>b)&0xFFFFFFFF)
+#define intdiv(a,b)    (a//b)
 ]]
 
 end
diff --git a/tex/context/base/mkiv/l-number.lua b/tex/context/base/mkiv/l-number.lua
index a83e8f8f9..dc4a93b0e 100644
--- a/tex/context/base/mkiv/l-number.lua
+++ b/tex/context/base/mkiv/l-number.lua
@@ -232,3 +232,7 @@ function number.decimaltobyte(d)
         return b
     end
 end
+
+function number.idiv(i,d)
+    return floor(i/d) -- i//d in 5.3
+end
diff --git a/tex/context/base/mkiv/lpdf-img.lua b/tex/context/base/mkiv/lpdf-img.lua
new file mode 100644
index 000000000..28890887a
--- /dev/null
+++ b/tex/context/base/mkiv/lpdf-img.lua
@@ -0,0 +1,1061 @@
+if not modules then modules = { } end modules ['lpdf-img'] = {
+    version   = 1.001,
+    comment   = "companion to lpdf-ini.mkiv",
+    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+    copyright = "PRAGMA ADE / ConTeXt Development Team",
+    license   = "see context related readme files"
+}
+
+local concat, remove, insert = table.concat, table.remove, table.insert
+local ceil = math.ceil
+local char, find = string.char, string.find
+local idiv = number.idiv
+local band, rshift = bit32.band, bit32.rshift
+
+local loaddata             = io.loaddata
+local setmetatableindex    = table.setmetatableindex
+
+local streams              = utilities.streams
+local openstring           = streams.openstring
+local readstring           = streams.readstring
+local readbytetable        = streams.readbytetable
+
+local lpdf                 = lpdf or { }
+local pdfdictionary        = lpdf.dictionary
+local pdfarray             = lpdf.array
+local pdfconstant          = lpdf.constant
+local pdfstring            = lpdf.string
+local pdfflushstreamobject = lpdf.flushstreamobject
+local pdfreference         = lpdf.reference
+
+local pdfmajorversion      = lpdf.majorversion
+local pdfminorversion      = lpdf.minorversion
+
+local newimage             = img.new
+
+local trace                = false
+
+local report_jpg           = logs.reporter("graphics","jpg")
+local report_jp2           = logs.reporter("graphics","jp2")
+local report_png           = logs.reporter("graphics","png")
+
+local injectors = { }
+lpdf.injectors  = injectors
+
+local chars = setmetatableindex(function(t,k) -- share this one
+    local v = (k <= 0 and "\000") or (k >= 255 and "\255") or char(k)
+    t[k] = v
+    return v
+end)
+
+do
+
+    function injectors.jpg(specification)
+        if specification.error then
+            return
+        end
+        local filename = specification.filename
+        if not filename then
+            return
+        end
+        local colorspace  = specification.colorspace or jpg_gray
+        local attributes  = specification.attr
+        local decodearray = nil
+        ----- procset     = colorspace == 0 and "image b" or "image c"
+        if colorspace == 1 then
+            colorspace = "DeviceGray"
+        elseif colorspace == 2 then
+            colorspace = "DeviceRGB"
+        elseif colorspace == 3 then
+            colorspace  = "DeviceCMYK"
+            decodearray = pdfarray { 1, 0, 1, 0, 1, 0, 1, 0 }
+        end
+        -- todo: set filename
+        local xsize      = specification.xsize
+        local ysize      = specification.ysize
+        local colordepth = specification.colordepth
+        local content    = loaddata(filename)
+        local xobject    = pdfdictionary {
+            Type             = pdfconstant("XObject"),
+            Subtype          = pdfconstant("Image"),
+            BBox             = pdfarray { 0, 0, xsize, ysize },
+            Width            = xsize,
+            Height           = ysize,
+            BitsPerComponent = colordepth,
+            Filter           = pdfconstant("DCTDecode"),
+            ColorSpace       = pdfconstant(colorspace),
+            Decode           = decodearray,
+            Length           = #content, -- specification.length
+        }
+        if attributes then
+            -- todo: add attributes to d
+        end
+        if trace then
+            report_jpg("%s: width %i, height %i, colordepth %i, size %i",filename,xsize,ysize,colordepth,#content)
+        end
+        return newimage {
+            bbox     = { 0, 0, specification.width/xsize, specification.height/ysize }, -- mandate
+            nolength = true,
+            nobbox   = true,
+            notype   = true,
+            stream   = content,
+            attr     = xobject(),
+        }
+    end
+
+end
+
+do
+
+    function injectors.jp2(specification)
+        if specification.error then
+            return
+        end
+        local filename = specification.filename
+        if not filename then
+            return
+        end
+        local attributes  = specification.attr
+        -- todo: set filename
+        local xsize   = specification.xsize
+        local ysize   = specification.ysize
+        local content = loaddata(filename)
+        local xobject = pdfdictionary {
+            Type    = pdfconstant("XObject"),
+            Subtype = pdfconstant("Image"),
+            BBox    = pdfarray { 0, 0, xsize, ysize },
+            Width   = xsize,
+            Height  = ysize,
+            Filter  = pdfconstant("JPXDecode"),
+            Length  = #content, -- specification.length
+        }
+        if attributes then
+            -- todo: add attributes to d
+        end
+        if trace then
+            report_jp2("%s: width %i, height %i, size %i",filename,xsize,ysize,#content)
+        end
+        return newimage {
+            bbox     = { 0, 0, specification.width/xsize, specification.height/ysize }, -- mandate
+            nolength = true,
+            nobbox   = true,
+            notype   = true,
+            stream   = content,
+            attr     = xobject(),
+        }
+    end
+
+end
+
+do
+
+    -- We don't like interlaced files. You can deinterlace them beforehand because otherwise
+    -- each run you add runtime. Actually, even masked images can best be converted to PDF
+    -- beforehand.
+
+    -- The amount of code is larger that I like and looks somewhat redundant but we sort of
+    -- optimize a few combinations that happen often.
+
+    local function convert(t,len)
+        if len then
+local n = 0
+            for i=1,#t,len do
+                t[i] = ""
+n = n + 1
+            end
+        end
+        for i=1,#t do
+            local ti = t[i]
+            if ti ~= "" then
+                t[i] = chars[ti]
+            end
+        end
+        return concat(t)
+    end
+
+    local function zero(t,k)
+        return 0
+    end
+
+    local function bump(txt,t,xsize,ysize,bpp)
+        local l = xsize * bpp + 1
+        print(txt,">",xsize,ysize,bpp,l)
+        for i=1,ysize do
+            local f = (i-1) * l + 1
+            print(txt,i,":",concat(t," ",f,f+l-1))
+        end
+    end
+
+    local function decodeall(t,xsize,ysize,bpp)
+        local len  = xsize * bpp + 1
+        local n    = 1
+        local m    = len - 1
+        for i=1,ysize do
+            local filter = t[n]
+t[n] = 0 -- not needed
+            if filter == 0 then
+            elseif filter == 1 then
+                for j=n+bpp+1,n+m do
+                    t[j] = (t[j] + t[j-bpp]) % 256
+                end
+            elseif filter == 2 then
+                for j=n+1,n+m do
+                    t[j] = (t[j] + t[j-len]) % 256
+                end
+            elseif filter == 3 then
+                for j=n+1,n+bpp do
+                    t[j] = (t[j] + idiv(t[j-len],2)) % 256
+                end
+                for j=n+bpp+1,n+m do
+                    t[j] = (t[j] + idiv(t[j-bpp] + t[j-len],2)) % 256
+                end
+            elseif filter == 4 then
+                for j=n+1,n+bpp do
+                    local p = j - len
+                    local b = t[p]
+                    if b < 0 then
+                        b = - b
+                    end
+                    if b > 0 then
+                        t[j] = (t[j] + b) % 256
+                    end
+                end
+                for j=n+bpp+1,n+m do
+                    local p = j - len
+                    local a = t[j-bpp]
+                    local b = t[p]
+                    local c = t[p-bpp]
+                    local pa = b - c
+                    local pb = a - c
+                    local pc = pa + pb
+                    if pa < 0 then pa = - pa end
+                    if pb < 0 then pb = - pb end
+                    if pc < 0 then pc = - pc end
+                    t[j] = (t[j] + ((pa <= pb and pa <= pc and a) or (pb <= pc and b) or c)) % 256
+                end
+            end
+            n = n + len
+        end
+    end
+
+    local xstart = { 0, 4, 0, 2, 0, 1, 0 }
+    local xstep  = { 8, 8, 4, 4, 2, 2, 1 }
+    local ystart = { 0, 0, 4, 0, 2, 0, 1 }
+    local ystep  = { 8, 8, 8, 4, 4, 2, 2 }
+    ----- xmax   = { 8, 4, 4, 2, 2, 1, 1 } -- for block fill
+    ----- ymax   = { 8, 8, 4, 4, 2, 2, 1 } -- for block fill
+
+    local function newoutput(width,height)
+        local t = { }
+        for i=1,height*width do
+            t[i] = 0
+        end
+        return t
+    end
+
+    local function expand(t,xsize,ysize,parts,factor) -- we don't compact
+        local o = { }
+        local k = 0
+        local l = ceil(xsize*parts/8) + 1
+        local n = 1
+        if factor then
+            if parts == 4 then
+                for i=1,ysize do
+                    k = k + 1 ; o[k] = t[n]
+                    for j=n+1,n+l do
+                        local v = t[j]
+                        k = k + 1 ; o[k] = band(rshift(v,4),0x0F) * 0x11 ; k = k + 1 ; o[k] = band(rshift(v,0),0x0F) * 0x11
+                    end
+                    k = i * (xsize + 1)
+                    n = n + l
+                end
+            elseif parts == 2 then
+                for i=1,ysize do
+                    k = k + 1 ; o[k] = t[n]
+                    for j=n+1,n+l do
+                        local v = t[j]
+                        k = k + 1 ; o[k] = band(rshift(v,6),0x03) * 0x55 ; k = k + 1 ; o[k] = band(rshift(v,4),0x03) * 0x55
+                        k = k + 1 ; o[k] = band(rshift(v,2),0x03) * 0x55 ; k = k + 1 ; o[k] = band(rshift(v,0),0x03) * 0x55
+                    end
+                    k = i * (xsize + 1)
+                    n = n + l
+                end
+            else
+                for i=1,ysize do
+                    k = k + 1 ; o[k] = t[n]
+                    for j=n+1,n+l do
+                        local v = t[j]
+                        k = k + 1 ; o[k] = band(rshift(v,7),0x01) * 0xFF ; k = k + 1 ; o[k] = band(rshift(v,6),0x01) * 0xFF
+                        k = k + 1 ; o[k] = band(rshift(v,5),0x01) * 0xFF ; k = k + 1 ; o[k] = band(rshift(v,4),0x01) * 0xFF
+                        k = k + 1 ; o[k] = band(rshift(v,3),0x01) * 0xFF ; k = k + 1 ; o[k] = band(rshift(v,2),0x01) * 0xFF
+                        k = k + 1 ; o[k] = band(rshift(v,1),0x01) * 0xFF ; k = k + 1 ; o[k] = band(rshift(v,0),0x01) * 0xFF
+                    end
+                    k = i * (xsize + 1)
+                    n = n + l
+                end
+            end
+        else
+            if parts == 4 then
+                for i=1,ysize do
+                    k = k + 1 ; o[k] = t[n]
+                    for j=n+1,n+l do
+                        local v = t[j]
+                        k = k + 1 ; o[k] = band(rshift(v,4),0x0F) ; k = k + 1 ; o[k] = band(rshift(v,0),0x0F)
+                    end
+                    k = i * (xsize + 1)
+                    n = n + l
+                end
+            elseif parts == 2 then
+                for i=1,ysize do
+                    k = k + 1 ; o[k] = t[n]
+                    for j=n+1,n+l do
+                        local v = t[j]
+                        k = k + 1 ; o[k] = band(rshift(v,6),0x03) ; k = k + 1 ; o[k] = band(rshift(v,4),0x03)
+                        k = k + 1 ; o[k] = band(rshift(v,2),0x03) ; k = k + 1 ; o[k] = band(rshift(v,0),0x03)
+                    end
+                    k = i * (xsize + 1)
+                    n = n + l
+                end
+            else
+                for i=1,ysize do
+                    k = k + 1 ; o[k] = t[n]
+                    for j=n+1,n+l do
+                        local v = t[j]
+                        k = k + 1 ; o[k] = band(rshift(v,7),0x01) ; k = k + 1 ; o[k] = band(rshift(v,6),0x01)
+                        k = k + 1 ; o[k] = band(rshift(v,5),0x01) ; k = k + 1 ; o[k] = band(rshift(v,4),0x01)
+                        k = k + 1 ; o[k] = band(rshift(v,3),0x01) ; k = k + 1 ; o[k] = band(rshift(v,2),0x01)
+                        k = k + 1 ; o[k] = band(rshift(v,1),0x01) ; k = k + 1 ; o[k] = band(rshift(v,0),0x01)
+                    end
+                    k = i * (xsize + 1)
+                    n = n + l
+                end
+            end
+        end
+        for i=#o,k+1,-1 do
+            o[i] = nil
+        end
+        return o
+    end
+
+    local function deinterlaceXX(s,xsize,ysize,bytes,parts,factor)
+        local output = newoutput(xsize*bytes,ysize)
+        for pass=1,7 do
+            local ystart = ystart[pass]
+            local ystep  = ystep[pass]
+            local xstart = xstart[pass]
+            local xstep  = xstep[pass]
+            local nx     = idiv(xsize + xstep - xstart - 1,xstep)
+            local ny     = idiv(ysize + ystep - ystart - 1,ystep)
+            if nx > 0 and ny > 0 then
+                local input
+                if parts then
+                    local nxx = ceil(nx*parts/8)
+                    input = readbytetable(s,ny*(nxx+1))
+                    setmetatableindex(input,zero)
+                    decodeall(input,nxx,ny,bytes)
+                    input = expand(input,nx,ny,parts,factor)
+                else
+                    input = readbytetable(s,ny*(nx*bytes+1))
+                    setmetatableindex(input,zero)
+                    decodeall(input,nx,ny,bytes)
+                end
+                local l = nx*bytes + 1
+                for i=ny,1,-1 do
+                    remove(input,(i-1)*l+1)
+                end
+                local xstep  = xstep * bytes
+                local xstart = xstart * bytes
+                local xsize  = xsize * bytes
+                local target = ystart * xsize + xstart + 1
+                local ystep  = ystep * xsize
+                local start  = 1
+                local blobs  = bytes - 1
+                for j=0,ny-1 do
+                    local target = target + j * ystep
+                    for i=1,nx do
+                        for i=0,blobs do
+                            output[target+i] = input[start]
+                            start= start + 1
+                        end
+                        target = target + xstep
+                    end
+                end
+            end
+        end
+        return output
+    end
+
+    local function deinterlaceYY(s,xsize,ysize,bytes,parts,factor)
+        local input
+        if parts then
+            local nxx = ceil(xsize*parts/8)
+            input = readbytetable(s,ysize*(nxx+1))
+            setmetatableindex(input,zero)
+            decodeall(input,nxx,ysize,bytes)
+            input = expand(input,xsize,ysize,parts,factor)
+        else
+            input = readbytetable(s,ysize*(xsize*bytes+1))
+            setmetatableindex(input,zero)
+            decodeall(input,xsize,ysize,bytes)
+        end
+        local l = xsize*bytes + 1
+        local n = 1
+        for i=1,ysize do
+            input[n] = ""
+            n = n + l
+        end
+        return input
+    end
+
+    local function analyze(colordepth,colorspace,palette,mask)
+        local bytes, parts, factor
+        if palette then
+            if colordepth == 16 then
+                return 2, false, false
+            elseif colordepth == 8 then
+                return 1, false, false
+            elseif colordepth == 4 then
+                return 1, 4, false
+            elseif colordepth == 2 then
+                return 1, 2, false
+            elseif colordepth == 1 then
+                return 1, 1, false
+            end
+        elseif colorspace == "DeviceGray" then
+            if colordepth == 16 then
+                return mask and 4 or 2, false, false
+            elseif colordepth == 8 then
+                return mask and 2 or 1, false, false
+            elseif colordepth == 4 then
+                return 1, 4, true
+            elseif colordepth == 2 then
+                return 1, 2, true
+            elseif colordepth == 1 then
+                return 1, 1, true
+            end
+        else
+            if colordepth == 16 then
+                return mask and 8 or 6, false, false
+            elseif colordepth == 8 then
+                return mask and 4 or 3, false, false
+            elseif colordepth == 4 then
+                return 3, 4, true
+            elseif colordepth == 2 then
+                return 3, 2, true
+            elseif colordepth == 1 then
+                return 3, 1, true
+            end
+        end
+        return false, false, false
+    end
+
+    local function deinterlace(content,xsize,ysize,colordepth,colorspace,palette,mask)
+        local bytes, parts, factor = analyze(colordepth,colorspace,palette,mask)
+        if bytes then
+            content = zlib.decompress(content)
+            local s = openstring(content)
+            local r = deinterlaceXX(s,xsize,ysize,bytes,parts,factor)
+            return r, parts and 8 or false
+        end
+    end
+
+    local function decompose(content,xsize,ysize,colordepth,colorspace,palette,mask)
+        local bytes, parts, factor = analyze(colordepth,colorspace,palette,mask)
+        if bytes then
+            content = zlib.decompress(content)
+            local s = openstring(content)
+            local r = deinterlaceYY(s,xsize,ysize,bytes,parts,factor)
+            return r, parts and 8 or false
+        end
+    end
+
+    -- 1 (palette used), 2 (color used), and 4 (alpha channel used)
+
+    -- paeth:
+    --
+    -- p  = a + b - c
+    -- pa = abs(p - a) => a + b - c - a => b - c
+    -- pb = abs(p - b) => a + b - c - b => a - c
+    -- pc = abs(p - c) => a + b - c - c => a + b - c - c => a - c + b - c => pa + pb
+
+    local function prepareimage(content,xsize,ysize,depth,colorspace,mask)
+        local bpp = (depth == 16 and 2 or 1) * ((colorspace == "DeviceRGB" and 3 or 1) + mask)        local len = bpp * xsize + 1
+        local s   = openstring(content)
+        local t   = readbytetable(s,#content)
+        setmetatableindex(t,zero)
+        return t, bpp, len
+    end
+
+    local function filtermask08(xsize,ysize,t,bpp,len,n)
+        local mask = { }
+        local l = 0
+        local m = len - n
+        for i=1,ysize do
+            for j=n+bpp,n+m,bpp do
+                l = l + 1 ; mask[l] = chars[t[j]] ; t[j] = ""
+            end
+            n = n + len
+        end
+        return concat(mask)
+    end
+
+    local function filtermask16(xsize,ysize,t,bpp,len,n)
+        local mask = { }
+        local l = 0
+        local m = len - n
+        for i=1,ysize do
+            for j=n+bpp-1,n+m-1,bpp do
+                l = l + 1 ; mask[l] = chars[t[j]] ; t[j] = ""
+                j = j + 1
+                l = l + 1 ; mask[l] = chars[t[j]] ; t[j] = ""
+            end
+            n = n + len
+        end
+        return concat(mask)
+    end
+
+    local function decodemask08(content,xsize,ysize,depth,colorspace)
+        local t, bpp, len = prepareimage(content,xsize,ysize,depth,colorspace,1)
+        local bpp2 = mask and (bpp + bpp) or bpp
+        local n = 1
+        local m = len - 1
+        for i=1,ysize do
+            local filter = t[n]
+            if filter == 0 then
+            elseif filter == 1 then
+                for j=n+bpp2,n+m,bpp do
+                    t[j] = (t[j] + t[j-bpp]) % 256
+                end
+            elseif filter == 2 then
+                for j=n+bpp,n+m,bpp do
+                    t[j] = (t[j] + t[j-len]) % 256
+                end
+            elseif filter == 3 then
+                local j = n + bpp
+                t[j] = (t[j] + idiv(t[j-len],2)) % 256
+                for j=n+bpp2,n+m,bpp do
+                    t[j] = (t[j] + idiv(t[j-bpp] + t[j-len],2)) % 256
+                end
+            elseif filter == 4 then
+                local j = n + bpp
+                local p = j - len
+                local b = t[p]
+                if b < 0 then
+                    b = - b
+                end
+                if b > 0 then
+                    t[j] = (t[j] + b) % 256
+                end
+                for j=n+bpp2,n+m,bpp do
+                    local p = j - len
+                    local a = t[j-bpp]
+                    local b = t[p]
+                    local c = t[p-bpp]
+                    local pa = b - c
+                    local pb = a - c
+                    local pc = pa + pb
+                    if pa < 0 then pa = - pa end
+                    if pb < 0 then pb = - pb end
+                    if pc < 0 then pc = - pc end
+                    t[j] = (t[j] + ((pa <= pb and pa <= pc and a) or (pb <= pc and b) or c)) % 256
+                end
+            end
+            n = n + len
+        end
+        local mask = filtermask08(xsize,ysize,t,bpp,len,1)
+        return convert(t), mask
+    end
+
+    local function decodemask16(content,xsize,ysize,depth,colorspace)
+        local t, bpp, len = prepareimage(content,xsize,ysize,depth,colorspace,1)
+        local bpp2 = bpp + bpp
+        local n = 1
+        local m = len - 1
+        for i=1,ysize do
+            local filter = t[n]
+            if filter == 0 then
+            elseif filter == 1 then
+                for j=n+bpp2,n+m,bpp do
+                    local k = j - 1
+                    t[j] = (t[j] + t[j-bpp]) % 256
+                    t[k] = (t[k] + t[k-bpp]) % 256
+                end
+            elseif filter == 2 then
+                for j=n+bpp,n+m,bpp do
+                    local k = j - 1
+                    t[j] = (t[j] + t[j-len]) % 256
+                    t[k] = (t[k] + t[k-len]) % 256
+                end
+            elseif filter == 3 then
+                local j = n + bpp
+                local k = j - 1
+                t[j] = (t[j] + idiv(t[j-len],2)) % 256
+                t[k] = (t[k] + idiv(t[k-len],2)) % 256
+                for j=n+bpp2,n+m,bpp do
+                    local k = j - 1
+                    t[j] = (t[j] + idiv(t[j-bpp] + t[j-len],2)) % 256
+                    t[k] = (t[k] + idiv(t[k-bpp] + t[k-len],2)) % 256
+                end
+            elseif filter == 4 then
+                for i=-1,0 do
+                    local j = n + bpp + i
+                    local p = j - len
+                    local b = t[p]
+                    if b < 0 then
+                        b = - b
+                    end
+                    if b > 0 then
+                        t[j] = (t[j] + b) % 256
+                    end
+                    for j=n+i+bpp2,n+i+m,bpp do
+                        local p = j - len
+                        local a = t[j-bpp]
+                        local b = t[p]
+                        local c = t[p-bpp]
+                        local pa = b - c
+                        local pb = a - c
+                        local pc = pa + pb
+                        if pa < 0 then pa = - pa end
+                        if pb < 0 then pb = - pb end
+                        if pc < 0 then pc = - pc end
+                        t[j] = (t[j] + ((pa <= pb and pa <= pc and a) or (pb <= pc and b) or c)) % 256
+                    end
+                end
+            end
+            n = n + len
+        end
+        local mask = filtermask16(xsize,ysize,t,bpp,len,1)
+        return convert(t), mask
+    end
+
+    local function full(t,k) local v = "\xFF" t[k] = v return v end
+
+    local function create(content,palette,transparent,xsize,ysize,colordepth,colorspace)
+        if palette then
+            --
+            local s = openstring(transparent)
+            local n = #transparent
+            local r = { }
+            for i=0,n-1 do
+                r[i] = readstring(s,1)
+            end
+            setmetatableindex(r,full)
+            --
+            local c = zlib.decompress(content)
+            local s = openstring(c)
+            --
+            local o = { }
+            local len = ceil(xsize*colordepth/8) + 1
+            local m = len - 1
+            local u = setmetatableindex(zero)
+            --
+            for i=1,ysize do
+                local t = readbytetable(s,len)
+                local k = (i-1) * xsize
+                local filter = t[1]
+                if filter == 0 then
+                elseif filter == 1 then
+                    for j=3,len do
+                        t[j] = (t[j] + t[j-1]) % 256
+                    end
+                elseif filter == 2 then
+                    for j=2,len do
+                        t[j] = (t[j] + u[j]) % 256
+                    end
+                elseif filter == 3 then
+                    local j = 2
+                    t[j] = (t[j] + idiv(u[j],2)) % 256
+                    for j=3,len do
+                        t[j] = (t[j] + idiv(t[j-1] + u[j],2)) % 256
+                    end
+                elseif filter == 4 then
+                    local j = 2
+                    local p = j - len
+                    local b = t[p]
+                    if b < 0 then
+                        b = - b
+                    end
+                    if b > 0 then
+                        t[j] = (t[j] + b) % 256
+                    end
+                    for j=3,len do
+                        local p = j - len
+                        local a = t[j-1]
+                        local b = t[p]
+                        local c = t[p-1]
+                        local pa = b - c
+                        local pb = a - c
+                        local pc = pa + pb
+                        if pa < 0 then pa = - pa end
+                        if pb < 0 then pb = - pb end
+                        if pc < 0 then pc = - pc end
+                        t[j] = (t[j] + ((pa <= pb and pa <= pc and a) or (pb <= pc and b) or c)) % 256
+                    end
+                end
+                if colordepth == 8 then
+                    for j=2,len do
+                        local v = t[j]
+                        k = k + 1 ; o[k] = r[v] or "\xFF"
+                    end
+                elseif colordepth == 4 then
+                    for j=2,len do
+                        local v = t[j]
+                        k = k + 1 ; o[k] = r[band(rshift(v,4),0x0F)]
+                        k = k + 1 ; o[k] = r[band(rshift(v,0),0x0F)]
+                    end
+                elseif colordepth == 2 then
+                    for j=2,len do
+                        local v = t[j]
+                        k = k + 1 ; o[k] = r[band(rshift(v,6),0x03)]
+                        k = k + 1 ; o[k] = r[band(rshift(v,4),0x03)]
+                        k = k + 1 ; o[k] = r[band(rshift(v,2),0x03)]
+                        k = k + 1 ; o[k] = r[band(rshift(v,0),0x03)]
+                    end
+                else
+                    for j=2,len do
+                        local v = t[j]
+                        k = k + 1 ; o[k] = r[band(rshift(v,7),0x01)]
+                        k = k + 1 ; o[k] = r[band(rshift(v,6),0x01)]
+                        k = k + 1 ; o[k] = r[band(rshift(v,5),0x01)]
+                        k = k + 1 ; o[k] = r[band(rshift(v,4),0x01)]
+                        k = k + 1 ; o[k] = r[band(rshift(v,3),0x01)]
+                        k = k + 1 ; o[k] = r[band(rshift(v,2),0x01)]
+                        k = k + 1 ; o[k] = r[band(rshift(v,2),0x01)]
+                        k = k + 1 ; o[k] = r[band(rshift(v,1),0x01)]
+                    end
+                end
+                u = t
+            end
+            return concat(o,"",1,ysize * xsize)
+        end
+    end
+
+    local alwaysdecode = false
+
+    directives.register("graphics.png.decode", function(v)
+        alwaysdecode = v
+    end)
+
+    function injectors.png(specification)
+        if specification.error then
+            return
+        end
+        local filename = specification.filename
+        if not filename then
+            return
+        end
+        local colorspace = specification.colorspace
+        if not colorspace then
+            return
+        end
+        local interlace = specification.interlace or 0
+        if interlace == 1 then
+            interlace = true
+        elseif interlace == 0 then
+            interlace = false
+        else
+            report_png("unknown interlacing %i",interlace)
+            return
+        end
+        local tables = specification.tables
+        if not tables then
+            return
+        end
+        local idat = tables.idat
+        if not idat then
+            return
+        end
+        local pngfile = io.open(filename,"rb")
+        if not pngfile then
+            return
+        end
+        local content = idat(pngfile,true)
+        tables.idat = false
+        --
+     -- if tables.gama then
+     --     report_png("ignoring gamma correction")
+     -- end
+        --
+        local xsize       = specification.xsize
+        local ysize       = specification.ysize
+        local colordepth  = specification.colordepth or 8
+        local mask        = false
+        local transparent = false
+        local palette     = false
+        local colors      = 1
+        if     colorspace == 0 then    -- gray | image b
+            colorspace  = "DeviceGray"
+            transparent = true
+        elseif colorspace == 2 then    -- rgb | image c
+            colorspace  = "DeviceRGB"
+            colors      = 3
+            transparent = true
+        elseif colorspace == 3 then    -- palette | image c+i
+            colorspace  = "DeviceRGB"
+            palette     = true
+            transparent = true
+        elseif colorspace == 4 then    -- gray | alpha | image b
+            colorspace = "DeviceGray"
+            mask       = true
+        elseif colorspace == 6 then    -- rgb | alpha | image c
+            colorspace = "DeviceRGB"
+            colors     = 3
+            mask       = true
+        else
+            report_png("unknown colorspace %i",colorspace)
+            return
+        end
+        --
+        if transparent then
+            local trns = tables.trns
+            if trns then
+                transparent = trns(pngfile,true)
+                if transparent == "" then
+                    transparent = false
+                end
+                tables.trns = false
+            else
+                transparent = false
+            end
+        end
+        --
+        local decode = alwaysdecode
+        local major  = pdfmajorversion()
+        local minor  = pdfminorversion()
+        if major > 1 then
+            -- we're okay
+        elseif minor < 5 and colordepth == 16 then
+            report_png("16 bit colordepth not supported in pdf < 1.5")
+            return
+        elseif minor < 4 and (mask or transparent) then
+            report_png("alpha channels not supported in pdf < 1.4")
+            return
+        elseif minor < 2 then
+            decode = true
+        end
+        --
+        -- todo: compresslevel (or delegate)
+        --
+        if palette then
+            local plte = tables.plte
+            if plte then
+                palette = plte(pngfile,true)
+                if palette == "" then
+                    palette = false
+                end
+                tables.plte = false
+            else
+                palette = false
+            end
+        end
+        --
+        if interlace then
+            local r, p = deinterlace(content,xsize,ysize,colordepth,colorspace,palette,mask)
+            if not r then
+                return
+            end
+            if p then
+                colordepth = p
+            end
+            if mask then
+                local bpp = (colordepth == 16 and 2 or 1) * ((colorspace == "DeviceRGB" and 3 or 1) + 1)
+                local len = bpp * xsize -- + 1
+                if colordepth == 8 then -- bpp == 1
+                    mask = filtermask08(xsize,ysize,r,bpp,len,0)
+                elseif colordepth == 16 then -- bpp == 2
+                    mask = filtermask16(xsize,ysize,r,bpp,len,0)
+                else
+                    report_png("mask can't be split from the image")
+                    return
+                end
+            end
+            decode  = true
+            content = convert(r)
+            content = zlib.compress(content)
+        elseif mask then
+            local decoder
+            if colordepth == 8 then
+                decoder = decodemask08
+            elseif colordepth == 16 then
+                decoder = decodemask16
+            end
+            if not decoder then
+                report_png("mask can't be split from the image")
+                return
+            end
+            content = zlib.decompress(content)
+            content, mask = decoder(content,xsize,ysize,colordepth,colorspace)
+            content = zlib.compress(content)
+            decode  = false
+        elseif transparent then
+            if palette then
+                mask = create(content,palette,transparent,xsize,ysize,colordepth,colorspace)
+            else
+                pallette = false
+            end
+        elseif decode then
+            local r, p = decompose(content,xsize,ysize,colordepth,colorspace,palette)
+            if not r then
+                return
+            end
+            if p then
+                colordepth = p
+            end
+            content = convert(r)
+            content = zlib.compress(content)
+        end
+        if palette then
+            palette = pdfarray {
+                pdfconstant("Indexed"),
+                pdfconstant("DeviceRGB"),
+                idiv(#palette,3),
+                pdfreference(pdfflushstreamobject(palette)),
+            }
+        end
+        pngfile:close()
+        local xobject = pdfdictionary {
+            Type             = pdfconstant("XObject"),
+            Subtype          = pdfconstant("Image"),
+            BBox             = pdfarray { 0, 0, xsize, ysize },
+            Width            = xsize,
+            Height           = ysize,
+            BitsPerComponent = colordepth,
+            Filter           = pdfconstant("FlateDecode"),
+            ColorSpace       = palette or pdfconstant(colorspace),
+            Length           = #content,
+        }
+        if mask then
+            local d = pdfdictionary {
+                Type             = pdfconstant("XObject"),
+                Subtype          = pdfconstant("Image"),
+                Width            = xsize,
+                Height           = ysize,
+                BitsPerComponent = palette and 8 or colordepth,
+                ColorSpace       = pdfconstant("DeviceGray"),
+            }
+            xobject.SMask = pdfreference(pdfflushstreamobject(mask,d()))
+        end
+        if not decode then
+            xobject.DecodeParms  = pdfdictionary {
+                Colors           = colors,
+                Columns          = xsize,
+                BitsPerComponent = colordepth,
+                Predictor        = 15,
+            }
+        end
+        if attributes then
+            -- todo: add attributes to d
+        end
+        if trace then
+            report_png("%s: width %i, height %i, colordepth: %i, size: %i, palette %l, mask: %l, transparent %l, decode %l",filename,xsize,ysize,colordepth,#content,palette,mask,transparent,decode)
+        end
+        return newimage {
+            bbox     = { 0, 0, specification.width/xsize, specification.height/ysize }, -- mandate
+            nolength = true,
+            nobbox   = true,
+            notype   = true,
+            stream   = content,
+            attr     = xobject(),
+        }
+    end
+
+end
+
+do
+
+    local function pack(specification,what)
+        local t = { }
+        local n = 0
+        local s = specification.colorspace
+        local d = specification.data
+        local x = specification.xsize
+        local y = specification.ysize
+        if what == "mask" then
+            d = specification.mask
+            s = 1
+        end
+        if s == 1 then
+            for i=1,y do
+                local r = d[i]
+                for j=1,x do
+                    n = n + 1 ; t[n] = chars[r[j]]
+                end
+            end
+        elseif s == 2 then
+            for i=1,y do
+                local r = d[i]
+                for j=1,x do
+                    local c = r[j]
+                    n = n + 1 ; t[n] = chars[c[1]]
+                    n = n + 1 ; t[n] = chars[c[2]]
+                    n = n + 1 ; t[n] = chars[c[3]]
+                end
+            end
+        elseif s == 3 then
+            for i=1,y do
+                local r = d[i]
+                for j=1,x do
+                    local c = r[j]
+                    n = n + 1 ; t[n] = chars[c[1]]
+                    n = n + 1 ; t[n] = chars[c[2]]
+                    n = n + 1 ; t[n] = chars[c[3]]
+                    n = n + 1 ; t[n] = chars[c[4]]
+                end
+            end
+        end
+        return concat(t)
+    end
+
+    function injectors.bitmap(specification)
+        local data = specification.data
+        if not data then
+            return
+        end
+        local xsize = specification.xsize or 0
+        local ysize = specification.ysize or 0
+        if xsize == 0 or ysize == 0 then
+            return
+        end
+        local colorspace = specification.colorspace or 1
+        if colorspace == 1 then
+            colorspace = "DeviceGray"
+        elseif colorspace == 2 then
+            colorspace = "DeviceRGB"
+        elseif colorspace == 3 then
+            colorspace  = "DeviceCMYK"
+        end
+        local colordepth = (specification.colordepth or 2) == 16 or 8
+        local content    = pack(specification,"data")
+        local mask       = specification.mask
+        local xobject    = pdfdictionary {
+            Type             = pdfconstant("XObject"),
+            Subtype          = pdfconstant("Image"),
+            BBox             = pdfarray { 0, 0, xsize, ysize },
+            Width            = xsize,
+            Height           = ysize,
+            BitsPerComponent = colordepth,
+            ColorSpace       = pdfconstant(colorspace),
+            Length           = #content, -- specification.length
+        }
+        if mask then
+            local d = pdfdictionary {
+                Type             = pdfconstant("XObject"),
+                Subtype          = pdfconstant("Image"),
+                Width            = xsize,
+                Height           = ysize,
+                BitsPerComponent = colordepth,
+                ColorSpace       = pdfconstant("DeviceGray"),
+            }
+            xobject.SMask = pdfreference(pdfflushstreamobject(pack(specification,"mask"),d()))
+        end
+        return newimage {
+            bbox     = { 0, 0, specification.width/xsize, specification.height/ysize }, -- mandate
+         -- nolength = true,
+            nobbox   = true,
+            notype   = true,
+            stream   = content,
+            attr     = xobject(),
+        }
+    end
+
+end
diff --git a/tex/context/base/mkiv/pack-com.mkiv b/tex/context/base/mkiv/pack-com.mkiv
index b69f812e5..badda0127 100644
--- a/tex/context/base/mkiv/pack-com.mkiv
+++ b/tex/context/base/mkiv/pack-com.mkiv
@@ -437,10 +437,10 @@
         \nointerlineskip % indeed
         \combinationparameter\c!inbetween
         \global\c_pack_combinations_x\c_pack_combinations_max
-        \globallet\pack_combinations_flush_captions_indeed\pack_combinations_flush_captions_yes
+        \glet\pack_combinations_flush_captions_indeed\pack_combinations_flush_captions_yes
       \else
         \global\setbox\b_pack_combinations_captions\emptybox
-        \globallet\pack_combinations_flush_captions_indeed\pack_combinations_flush_captions_nop
+        \glet\pack_combinations_flush_captions_indeed\pack_combinations_flush_captions_nop
       \fi}%
    \pack_combinations_flush_captions_indeed
    \crcr}
diff --git a/tex/context/base/mkiv/pack-lyr.mkiv b/tex/context/base/mkiv/pack-lyr.mkiv
index 99a0dfb2a..e7070cfde 100644
--- a/tex/context/base/mkiv/pack-lyr.mkiv
+++ b/tex/context/base/mkiv/pack-lyr.mkiv
@@ -293,8 +293,8 @@
   {\setbox\b_layers\emptybox
    \d_pack_layers_x_position\p_pack_layers_sx\dimexpr\p_pack_layers_x\relax
    \d_pack_layers_y_position\p_pack_layers_sy\dimexpr\p_pack_layers_y\relax
-   \globallet\lastlayerxpos\!!zeropoint
-   \globallet\lastlayerypos\!!zeropoint
+   \glet\lastlayerxpos\!!zeropoint
+   \glet\lastlayerypos\!!zeropoint
    \doifinset\v!bottom\p_pack_layers_corner\pack_layers_set_bottom_positions
    \doifinset\v!right \p_pack_layers_corner\pack_layers_set_right_positions
    \doifinset\v!middle\p_pack_layers_corner\pack_layers_set_middle_positions
diff --git a/tex/context/base/mkiv/page-lin.mkvi b/tex/context/base/mkiv/page-lin.mkvi
index 4348d6770..6470a8094 100644
--- a/tex/context/base/mkiv/page-lin.mkvi
+++ b/tex/context/base/mkiv/page-lin.mkvi
@@ -275,8 +275,8 @@
      \fi\fi\fi
    \fi
    \the\beforeeverylinenumbering
-   \globallet\page_postprocessors_page  \page_postprocessors_linenumbers_page
-   \globallet\page_postprocessors_column\page_postprocessors_linenumbers_column
+   \glet\page_postprocessors_page  \page_postprocessors_linenumbers_page
+   \glet\page_postprocessors_column\page_postprocessors_linenumbers_column
    \global\settrue\page_postprocessors_needed_box % see core-rul.mkiv
    \ifcase\c_page_lines_mode\relax
      \page_lines_start_update % continue
diff --git a/tex/context/base/mkiv/page-set.mkiv b/tex/context/base/mkiv/page-set.mkiv
index f2755195a..dd145b322 100644
--- a/tex/context/base/mkiv/page-set.mkiv
+++ b/tex/context/base/mkiv/page-set.mkiv
@@ -487,7 +487,7 @@
 \let\OTRSETbalht\zeropoint
 
 \def\OTRSETreducegridbox % for the moment no difference between methods
-  {\globallet\OTRSETbalht\zeropoint
+  {\glet\OTRSETbalht\zeropoint
    \ifcase\OTRSETbalancemethod
      % no balancing
    \else
@@ -578,7 +578,7 @@
      \else
        \page_otr_construct_and_shipout\box\OTRfinalpagebox\zerocount % three arguments
      \fi \fi
-     \globallet\OTRSETbalht\zeropoint
+     \glet\OTRSETbalht\zeropoint
      \egroup
    \fi}
 
@@ -1624,12 +1624,12 @@
    \ifnum\columnsetlevel=\plusone
      \bgroup
      \saveinterlinespace
-     \globallet\columnsetpage\!!plusone
+     \glet\columnsetpage\!!plusone
      \def\currentcolumnset{#2}%
      \insidecolumnstrue % will be different flag in addition
      \setupoutputroutine[\s!columnset]%
      \doifelsenothing{#1}
-       {\globallet\OTRSETlist\s!default}
+       {\glet\OTRSETlist\s!default}
        {\xdef\OTRSETlist{#1}}%
      \OTRSETstartnextpage
      \OTRSETassignwidths
@@ -1659,7 +1659,7 @@
       \global\setbox\OTRfinalpagebox\OTRSETmakegridbox
       \ht\OTRfinalpagebox\textheight % signals output that there is content
       \OTRSETdofinaloutput
-      \globallet\OTRSETbalht\zeropoint
+      \glet\OTRSETbalht\zeropoint
       \egroup}
      {}}
 
diff --git a/tex/context/base/mkiv/scrn-fld.mkvi b/tex/context/base/mkiv/scrn-fld.mkvi
index 41d117480..7710a32dc 100644
--- a/tex/context/base/mkiv/scrn-fld.mkvi
+++ b/tex/context/base/mkiv/scrn-fld.mkvi
@@ -480,7 +480,7 @@
 
 \let\resetfields\relax
 
-\def\scrn_field_load_scripts{\useJSscripts[fld]\globallet\scrn_field_load_scripts\relax}
+\def\scrn_field_load_scripts{\useJSscripts[fld]\glet\scrn_field_load_scripts\relax}
 
 \newconditional\fieldlabelshown
 \newconditional\fieldframeshown
diff --git a/tex/context/base/mkiv/spac-pag.mkiv b/tex/context/base/mkiv/spac-pag.mkiv
index 89a5ce36d..9adc591ed 100644
--- a/tex/context/base/mkiv/spac-pag.mkiv
+++ b/tex/context/base/mkiv/spac-pag.mkiv
@@ -170,9 +170,9 @@
    \fi
    \ifpagechanged
      \letgvalue{\??pagechanges#2:#1}\m_spac_pagestates_realpage
-     \globallet\lastchangedpage\m_spac_pagestates_realpage
+     \glet\lastchangedpage\m_spac_pagestates_realpage
    \else
-     \globallet\lastchangedpage\realfolio
+     \glet\lastchangedpage\realfolio
    \fi}
 
 \def\changedpagestate#1#2%
diff --git a/tex/context/base/mkiv/status-files.pdf b/tex/context/base/mkiv/status-files.pdf
index 31155292e..20a7f18e1 100644
Binary files a/tex/context/base/mkiv/status-files.pdf and b/tex/context/base/mkiv/status-files.pdf differ
diff --git a/tex/context/base/mkiv/status-lua.pdf b/tex/context/base/mkiv/status-lua.pdf
index b1227d969..b48b2651a 100644
Binary files a/tex/context/base/mkiv/status-lua.pdf and b/tex/context/base/mkiv/status-lua.pdf differ
diff --git a/tex/context/base/mkiv/strc-con.mkvi b/tex/context/base/mkiv/strc-con.mkvi
index 0e5f3d8a5..d67307ba7 100644
--- a/tex/context/base/mkiv/strc-con.mkvi
+++ b/tex/context/base/mkiv/strc-con.mkvi
@@ -1016,9 +1016,9 @@
        \fi \fi
      \fi
      \ifx\currentconstructionlist\empty
-       \globallet\currentconstructionlist\currentconstructiontitle
+       \glet\currentconstructionlist\currentconstructiontitle
      \fi
-     \globallet\currentconstructioncoding\s!tex
+     \glet\currentconstructioncoding\s!tex
    \fi
    %
    \ifx\currentconstructiontitle\v!none % will become obsolete
diff --git a/tex/context/base/mkiv/strc-flt.mkvi b/tex/context/base/mkiv/strc-flt.mkvi
index 805a6edc7..28fa950c7 100644
--- a/tex/context/base/mkiv/strc-flt.mkvi
+++ b/tex/context/base/mkiv/strc-flt.mkvi
@@ -425,7 +425,7 @@
 %D   {\global\advance\c_strc_floats_n\plusone
 %D    \xdef\strc_float_realpage{\datasetvariable\s!float{\number\c_strc_floats_n}\s!page}%
 %D    \ifx\strc_float_realpage\empty
-%D      \globallet\strc_float_realpage\realpageno % \realfolio
+%D      \glet\strc_float_realpage\realpageno % \realfolio
 %D    \fi}
 %D \stoptyping
 %D
@@ -444,7 +444,7 @@
   {\global\advance\c_strc_floats_n\plusone
    \xdef\strc_float_realpage{\pagestaterealpage\s!float{\number\c_strc_floats_n}}%
    \ifx\strc_float_realpage\empty
-     \globallet\strc_float_realpage\realpageno % \realfolio
+    \glet\strc_float_realpage\realpageno % \realfolio
    \fi}
 
 %D test case:
@@ -955,9 +955,9 @@
 \def\strc_floats_place_packaged_boxes_indeed#userdata%
   {\bgroup
    \ifconditional\usesamefloatnumber
-     \globallet\currentfloatnumber     \previousfloatnumber
-     \globallet\currentfloatattribute  \empty
-     \globallet\currentfloatsynchronize\relax
+     \glet\currentfloatnumber     \previousfloatnumber
+     \glet\currentfloatattribute  \empty
+     \glet\currentfloatsynchronize\relax
    \else
      \edef\currentfloatcounter{\namedcounterparameter\currentfloat\s!name}%
      \edef\currentfloatgroup  {\floatcaptionparameter\c!group}%
@@ -989,10 +989,10 @@
         \s!hasnumber=\ifnofloatnumber   \v!no\else\v!yes\fi,%
         \s!hastitle=\ifemptyfloatcaption\v!no\else\v!yes\fi]%
        [#userdata]%
-     \globallet\previousfloatnumber    \m_strc_counters_last_registered_index
-     \globallet\currentfloatnumber     \m_strc_counters_last_registered_index
-     \globallet\currentfloatattribute  \m_strc_counters_last_registered_attribute
-     \globallet\currentfloatsynchronize\m_strc_counters_last_registered_synchronize
+     \glet\previousfloatnumber    \m_strc_counters_last_registered_index
+     \glet\currentfloatnumber     \m_strc_counters_last_registered_index
+     \glet\currentfloatattribute  \m_strc_counters_last_registered_attribute
+     \glet\currentfloatsynchronize\m_strc_counters_last_registered_synchronize
    \fi
    %
    \global\setfalse\usesamefloatnumber % one shot
diff --git a/tex/context/base/mkiv/strc-mat.mkiv b/tex/context/base/mkiv/strc-mat.mkiv
index 89912d904..0b80a26cd 100644
--- a/tex/context/base/mkiv/strc-mat.mkiv
+++ b/tex/context/base/mkiv/strc-mat.mkiv
@@ -208,9 +208,9 @@
       \c!reference=#1,\c!title=\namedformulaentry,\c!bookmark=]%
      [#2]%
    \glet\namedformulaentry\empty % \relax
-   \globallet#3\m_strc_counters_last_registered_index
-   \globallet#4\m_strc_counters_last_registered_synchronize
-   \globallet#5\m_strc_counters_last_registered_attribute}
+   \glet#3\m_strc_counters_last_registered_index
+   \glet#4\m_strc_counters_last_registered_synchronize
+   \glet#5\m_strc_counters_last_registered_attribute}
 
 % modes: 0=unset, 1=forced, 2=none, 3=reference
 
diff --git a/tex/context/base/mkiv/strc-not.mkvi b/tex/context/base/mkiv/strc-not.mkvi
index 403247b9c..3ce01ef34 100644
--- a/tex/context/base/mkiv/strc-not.mkvi
+++ b/tex/context/base/mkiv/strc-not.mkvi
@@ -456,7 +456,7 @@
        \edef\currentnotenumber{\clf_storenote{\currentnote}\currentconstructionlistentry}%
        \settrue\processingnote
        \ifconditional\c_strc_notes_skip
-         \globallet\lastnotesymbol\strc_notes_inject_symbol_nop
+         \glet\lastnotesymbol\strc_notes_inject_symbol_nop
        \else
          \iftypesettinglines % otherwise problems with \type <crlf> {xxx}
            \ignorelines % makes footnotes work in \startlines ... \stoplines
@@ -465,7 +465,7 @@
            \strc_notes_inject_symbol_yes
          \else
            \unskip\unskip
-           \globallet\lastnotesymbol\strc_notes_inject_symbol_yes
+           \glet\lastnotesymbol\strc_notes_inject_symbol_yes
          \fi
        \fi
        \ifconditional\postponingnotes % todo: per note class
@@ -734,7 +734,7 @@
      \dostoptagged
    \egroup
    \endgroup
-   \globallet\lastnotesymbol\relax}
+   \glet\lastnotesymbol\relax}
 
 \unexpanded\def\strc_notes_inject_dummy % temp hack
   {\removeunwantedspaces
@@ -745,7 +745,7 @@
    \fi
    \nobreak
    \hpack to .5\emwidth{}%
-   \globallet\lastnotesymbol\relax}
+   \glet\lastnotesymbol\relax}
 
 \unexpanded\def\strc_notes_inject_separator % patch by WS due to request on list
   {\edef\p_textseparator{\noteparameter\c!textseparator}%
diff --git a/tex/context/base/mkiv/strc-num.mkiv b/tex/context/base/mkiv/strc-num.mkiv
index cca66a6f5..747df29a5 100644
--- a/tex/context/base/mkiv/strc-num.mkiv
+++ b/tex/context/base/mkiv/strc-num.mkiv
@@ -578,9 +578,9 @@
        \xdef\currentstructurecomponentlist    {#2\c!list}%
      \xmlstopraw
      \ifx\currentstructurecomponentlist\empty
-       \globallet\currentstructurecomponentlist\currentstructurecomponenttitle
+       \glet\currentstructurecomponentlist\currentstructurecomponenttitle
      \fi
-     \globallet\currentstructurecomponentcoding\s!xml
+     \glet\currentstructurecomponentcoding\s!xml
    \else
      \ifx\currentstructurecomponentexpansion\v!yes
        \xdef\currentstructurecomponenttitle   {#2\c!title}%
@@ -600,9 +600,9 @@
        \fi \fi
      \fi
      \ifx\currentstructurecomponentlist\empty
-       \globallet\currentstructurecomponentlist\currentstructurecomponenttitle
+       \glet\currentstructurecomponentlist\currentstructurecomponenttitle
      \fi
-     \globallet\currentstructurecomponentcoding\s!tex
+     \glet\currentstructurecomponentcoding\s!tex
    \fi
    %
    \setnextinternalreference
diff --git a/tex/context/base/mkiv/strc-pag.mkiv b/tex/context/base/mkiv/strc-pag.mkiv
index 949806c82..01361e2c5 100644
--- a/tex/context/base/mkiv/strc-pag.mkiv
+++ b/tex/context/base/mkiv/strc-pag.mkiv
@@ -263,7 +263,7 @@
 \def\currentpage{\the\realpageno}% rather useless
 
 \appendtoks
-    \ifnum\realpageno>\lastpage \globallet\lastpage\lastrealpage \fi
+    \ifnum\realpageno>\lastpage \glet\lastpage\lastrealpage \fi
 \to \everyinitializepagecounters
 
 % States:
diff --git a/tex/context/base/mkiv/strc-ref.mkvi b/tex/context/base/mkiv/strc-ref.mkvi
index 0ae2cfccc..47719ffe2 100644
--- a/tex/context/base/mkiv/strc-ref.mkvi
+++ b/tex/context/base/mkiv/strc-ref.mkvi
@@ -212,14 +212,14 @@
          \xmlstartraw
            \xdef\currentreferencedata{#text}% data, no text else conflict
          \xmlstopraw
-         \globallet\currentreferencecoding\s!xml
+         \glet\currentreferencecoding\s!xml
        \else
          \ifx\currentreferenceexpansion\v!yes
            \xdef\currentreferencedata{#text}%
          \else
            \xdef\currentreferencedata{\detokenize{#text}}%
          \fi
-         \globallet\currentreferencecoding\s!tex
+         \glet\currentreferencecoding\s!tex
        \fi
        % beware, the structures.references.set writes a
        \setnextinternalreference
diff --git a/tex/context/base/mkiv/strc-reg.mkiv b/tex/context/base/mkiv/strc-reg.mkiv
index 21779f479..559e1bd42 100644
--- a/tex/context/base/mkiv/strc-reg.mkiv
+++ b/tex/context/base/mkiv/strc-reg.mkiv
@@ -176,33 +176,33 @@
      \xdef\currentregisterentriesb{\registerparameter{\c!entries:2}}%
      \xdef\currentregisterentriesc{\registerparameter{\c!entries:3}}%
    \xmlstopraw
-   \globallet\currentregistercoding\s!xml}
+   \glet\currentregistercoding\s!xml}
 
 \def\strc_registers_register_page_expand_yes_entries
   {\xdef\currentregisterentriesa{\registerparameter{\c!entries:1}}%
    \xdef\currentregisterentriesb{\registerparameter{\c!entries:2}}%
    \xdef\currentregisterentriesc{\registerparameter{\c!entries:3}}%
-   \globallet\currentregistercoding\s!tex}
+   \glet\currentregistercoding\s!tex}
 
 \def\strc_registers_register_page_expand_nop_entries
   {\xdef\currentregisterentriesa{\detokenizedregisterparameter{\c!entries:1}}%
    \xdef\currentregisterentriesb{\detokenizedregisterparameter{\c!entries:2}}%
    \xdef\currentregisterentriesc{\detokenizedregisterparameter{\c!entries:3}}%
-   \globallet\currentregistercoding\s!tex}
+   \glet\currentregistercoding\s!tex}
 
 \def\strc_registers_register_page_expand_xml
   {\xmlstartraw
      \xdef\currentregisterentries{\registerparameter\c!entries}%
    \xmlstopraw
-   \globallet\currentregistercoding\s!xml}
+   \glet\currentregistercoding\s!xml}
 
 \def\strc_registers_register_page_expand_yes
   {\xdef\currentregisterentries{\registerparameter\c!entries}%
-   \globallet\currentregistercoding\s!tex}
+   \glet\currentregistercoding\s!tex}
 
 \def\strc_registers_register_page_expand_nop
   {\xdef\currentregisterentries{\detokenizedregisterparameter\c!entries}%
-   \globallet\currentregistercoding\s!tex}
+   \glet\currentregistercoding\s!tex}
 
 \def\strc_registers_register_page_expand_xml_keys
   {\xmlstartraw
@@ -434,14 +434,14 @@
      \xmlstartraw
        \xdef\currentregisterentries{\registerparameter\c!entries}%
      \xmlstopraw
-     \globallet\currentregistercoding\s!xml
+     \glet\currentregistercoding\s!xml
    \else
      \ifx\currentregisterexpansion\v!yes
        \xdef\currentregisterentries{\registerparameter\c!entries}%
      \else
        \xdef\currentregisterentries{\detokenizedregisterparameter\c!entries}%
      \fi
-     \globallet\currentregistercoding\s!tex
+     \glet\currentregistercoding\s!tex
    \fi
    % I hate this kind of mess ... but it's a user request.
    \ifx\currentregisterentries\empty
@@ -524,7 +524,7 @@
        \xdef\currentregisterentries{\detokenize{#3}}% not ok yet
        \xdef\currentregisterseeword{\detokenize{#4}}% not ok yet
      \xmlstopraw
-     \globallet\currentregistercoding\s!xml
+     \glet\currentregistercoding\s!xml
    \else
      \ifx\currentregisterexpansion\v!yes
        \xdef\currentregisterentries{#3}% not ok yet
@@ -533,7 +533,7 @@
        \xdef\currentregisterentries{\detokenize{#3}}% not ok yet
        \xdef\currentregisterseeword{\detokenize{#4}}% not ok yet
      \fi
-     \globallet\currentregistercoding\s!tex
+     \glet\currentregistercoding\s!tex
    \fi
    \setnextinternalreference
    % we could consider storing register entries in list
diff --git a/tex/context/base/mkiv/strc-sec.mkiv b/tex/context/base/mkiv/strc-sec.mkiv
index 8f6038da7..cff73718a 100644
--- a/tex/context/base/mkiv/strc-sec.mkiv
+++ b/tex/context/base/mkiv/strc-sec.mkiv
@@ -116,7 +116,7 @@
  % \settrialtypesetting
    \the\everypreroll
    \nodestostring\tempstring{#1}%
-   \globallet\currentstructurebookmark\tempstring
+   \glet\currentstructurebookmark\tempstring
    \endgroup}
 
 % zeros:
@@ -156,9 +156,9 @@
        \strc_sectioning_autobookmark\currentstructuretitle
      \fi \fi \fi
      \ifx\currentstructurelist\empty
-       \globallet\currentstructurelist\currentstructuretitle
+       \glet\currentstructurelist\currentstructuretitle
      \fi
-     \globallet\currentstructurecoding\s!xml
+     \glet\currentstructurecoding\s!xml
    \else
      \ifx\currentstructureexpansion\v!yes
        \xdef\currentstructuretitle   {\structureparameter\c!title}%
@@ -185,9 +185,9 @@
        \fi \fi
      \fi
      \ifx\currentstructurelist\empty
-       \globallet\currentstructurelist\currentstructuretitle
+       \glet\currentstructurelist\currentstructuretitle
      \fi
-     \globallet\currentstructurecoding\s!tex
+     \glet\currentstructurecoding\s!tex
    \fi
    \setnextinternalreference
    \storeinternalreference\currentstructurename{\the\locationcount}%
@@ -1206,7 +1206,7 @@
    \else
      \strc_sectioning_check_layout
    \fi
-   \globallet\previoushead\currenthead}
+   \glet\previoushead\currenthead}
 
 \def\strc_sectioning_handle_page_yes
   {\ifconditional\c_strc_sectioning_ignore_page
@@ -1230,7 +1230,7 @@
      \fi
      \global\c_strc_sectioning_preceding_level\currentheadlevel
    \fi
-   \globallet\previoushead\currenthead}
+   \glet\previoushead\currenthead}
 
 \unexpanded\def\strc_sectioning_prevent_page_break#1% see strc-con
   {\ifconditional\c_strc_sectioning_auto_break
diff --git a/tex/context/base/mkiv/strc-syn.mkiv b/tex/context/base/mkiv/strc-syn.mkiv
index 1fb079f04..7f71e88f5 100644
--- a/tex/context/base/mkiv/strc-syn.mkiv
+++ b/tex/context/base/mkiv/strc-syn.mkiv
@@ -114,14 +114,14 @@
      \xmlstartraw
        \xdef#2{#4}%
      \xmlstopraw
-     \globallet#3\s!xml
+     \glet#3\s!xml
    \else
      \ifx#1\v!yes
        \xdef#2{#4}%
      \else
        \xdef#2{\detokenize{#4}}%
      \fi
-     \globallet#3\s!tex
+     \glet#3\s!tex
    \fi}
 
 %D We now use a simple list variant:
diff --git a/tex/context/base/mkiv/symb-imp-mvs.mkiv b/tex/context/base/mkiv/symb-imp-mvs.mkiv
index 9902fc9e8..f6a38214f 100644
--- a/tex/context/base/mkiv/symb-imp-mvs.mkiv
+++ b/tex/context/base/mkiv/symb-imp-mvs.mkiv
@@ -254,10 +254,16 @@
 
 \stopsymbolset
 
-%D \showsymbolset[astronomic]
-%D \showsymbolset[zodiac]
-%D \showsymbolset[europe]
-%D \showsymbolset[martinvogel 1]
-%D \showsymbolset[martinvogel 2]
+\continueifinputfile{symb-imp-mvs.mkiv}
 
-\endinput
+\usemodule[article-basic]
+
+\starttext
+
+\startsubject[title={Astronomic}]    \showsymbolset[astronomic]    \stopsubject
+\startsubject[title={Zodiac}]        \showsymbolset[zodiac]        \stopsubject
+\startsubject[title={Europe}]        \showsymbolset[europe]        \stopsubject
+\startsubject[title={Martinvogel 1}] \showsymbolset[martinvogel 1] \stopsubject
+\startsubject[title={Martinvogel 2}] \showsymbolset[martinvogel 2] \stopsubject
+
+\stoptext
diff --git a/tex/context/base/mkiv/syst-aux.mkiv b/tex/context/base/mkiv/syst-aux.mkiv
index a23563f3c..9c959a105 100644
--- a/tex/context/base/mkiv/syst-aux.mkiv
+++ b/tex/context/base/mkiv/syst-aux.mkiv
@@ -594,10 +594,6 @@
 %D tokens will save us some $300\times4=1200$ bytes of format file on a 32~bit
 %D system. Not that it matters much today. This shortcut is already defined:
 
-\ifdefined\glet\else
-    \unexpanded\def\glet{\global\let}
-\fi
-
 \let\globallet\glet
 
 %D \macros
diff --git a/tex/context/base/mkiv/syst-ini.mkiv b/tex/context/base/mkiv/syst-ini.mkiv
index 10c1fa113..f7b73a30e 100644
--- a/tex/context/base/mkiv/syst-ini.mkiv
+++ b/tex/context/base/mkiv/syst-ini.mkiv
@@ -610,10 +610,6 @@
 
 %D A few shortcuts:
 
-\ifdefined\glet \else
-    \normalprotected\def\glet{\global\let}
-\fi
-
 \normalprotected\def\udef {\normalprotected\def }
 \normalprotected\def\ugdef{\normalprotected\gdef}
 \normalprotected\def\uedef{\normalprotected\edef}
@@ -940,12 +936,12 @@
 % \bgroup
 %     \catcode`\^^M=\activecatcode%
 %     \gdef\obeylines{\catcode`\^^M\activecatcode \let^^M\par}%
-%     \global\let^^M\par%
+%     \glet^^M\par%
 % \egroup
 %
 % \bgroup
 %     \gdef\obeyspaces{\catcode`\ \activecatcode}%
-%     \obeyspaces\global\let =\space%
+%     \obeyspaces\glet =\space%
 % \egroup
 
 \def\obeylines {\catcode\endoflineasciicode\activecatcode\letcharcode\endoflineasciicode\par}
@@ -1252,10 +1248,6 @@
 \let\normalstartdmath   \Ustartdisplaymath
 \let\normalstopdmath    \Ustopdisplaymath
 
-%D For now:
-
-\ifdefined\glet                   \else \normalprotected\def\glet{\global\let} \fi
-
 \ifdefined\protrusionboundary     \else \let\protrusionboundary\boundary   \fi
 \ifdefined\wordboundary           \else \let\wordboundary      \noboundary \fi
 
diff --git a/tex/context/base/mkiv/tabl-tab.mkiv b/tex/context/base/mkiv/tabl-tab.mkiv
index 244ead530..631f29bc0 100644
--- a/tex/context/base/mkiv/tabl-tab.mkiv
+++ b/tex/context/base/mkiv/tabl-tab.mkiv
@@ -688,7 +688,7 @@
 % extensions
 
 \newtableformatkey q%
-  {\letempty\!tqStyle
+  {\let\!tqStyle\empty
    \futurelet\!tnext\!tqTestForBracket}
 
 \newtableformatkey Q%
@@ -1691,8 +1691,8 @@
    \starttablenoalign
      \nobreak
      \tabl_table_set_action\tableunknownstate
-     \globalletempty\tabl_tables_check_auto_row
-     \globalletempty\tabl_tables_chuck_auto_row
+     \glet\tabl_tables_check_auto_row\empty
+     \glet\tabl_tables_chuck_auto_row\empty
      \global\currenttablecolumn\zerocount
    \stoptablenoalign}
 
@@ -1816,21 +1816,21 @@
 %D the last row.
 
 \unexpanded\def\tabl_table_AR
-  {\globallet\tabl_tables_check_auto_row\tabl_tables_check_auto_row_indeed
-   \globallet\tabl_tables_chuck_auto_row\tabl_tables_chuck_auto_row_indeed}
+  {\glet\tabl_tables_check_auto_row\tabl_tables_check_auto_row_indeed
+   \glet\tabl_tables_chuck_auto_row\tabl_tables_chuck_auto_row_indeed}
 
 \let\tabl_tables_check_auto_row\empty
 \let\tabl_tables_chuck_auto_row\empty
 
 \def\tabl_tables_check_auto_row_indeed
-  {\globallet\tabl_tables_check_auto_row\empty
+  {\glet\tabl_tables_check_auto_row\empty
    \ifnum\tableactionstate=\tablerulestate   \FR\else
    \ifnum\tableactionstate=\tableunknownstate\FR\else
                                              \MR\fi\fi}
 
 \def\tabl_tables_chuck_auto_row_indeed
-  {\globalletempty\tabl_tables_check_auto_row
-   \globalletempty\tabl_tables_chuck_auto_row
+  {\glet\tabl_tables_check_auto_row\empty
+   \glet\tabl_tables_chuck_auto_row\empty
    \ifnum\tableactionstate=\tablerulestate   \SR\else
    \ifnum\tableactionstate=\tableunknownstate\SR\else
                                              \LR\fi\fi}
diff --git a/tex/context/base/mkiv/tabl-tbl.mkiv b/tex/context/base/mkiv/tabl-tbl.mkiv
index 97a4f63c0..75839caed 100644
--- a/tex/context/base/mkiv/tabl-tbl.mkiv
+++ b/tex/context/base/mkiv/tabl-tbl.mkiv
@@ -2235,7 +2235,7 @@
 
 % \def\tabulatedoHRfive % horizontal rule line (break untested)
 %   {\starttabulatenoalign
-%      \globallet\dotabulateautoline\dotabulatelinerule
+%      \glet\dotabulateautoline\dotabulatelinerule
 %     %\ifcase#1\or % todo: check what this does
 %        \ifnum\noftabulatelines=\zerocount
 %          \glet\dotabulateautoline\donothing
diff --git a/tex/context/base/mkiv/typo-drp.mkiv b/tex/context/base/mkiv/typo-drp.mkiv
index 371ea38d6..183925108 100644
--- a/tex/context/base/mkiv/typo-drp.mkiv
+++ b/tex/context/base/mkiv/typo-drp.mkiv
@@ -118,7 +118,7 @@
    \kern\zeropoint % we need a node
    \p_text
    \endgroup
-   \globallet\typo_initial_handle\relax}
+   \glet\typo_initial_handle\relax}
 
 \let\typo_initial_handle\relax
 
diff --git a/tex/context/base/mkiv/typo-fln.mkiv b/tex/context/base/mkiv/typo-fln.mkiv
index 37348be29..533c197cd 100644
--- a/tex/context/base/mkiv/typo-fln.mkiv
+++ b/tex/context/base/mkiv/typo-fln.mkiv
@@ -91,7 +91,7 @@
    \kern\zeropoint % we need a node
 %    \hskip\zeropoint\s!plus\emwidth\relax % can be an option
    \endgroup
-   \globallet\typo_firstline_handle\relax}
+   \glet\typo_firstline_handle\relax}
 
 \let\typo_firstline_handle\relax
 
diff --git a/tex/context/base/mkiv/util-sac.lua b/tex/context/base/mkiv/util-sac.lua
index 09c3819c5..62ce6bc1c 100644
--- a/tex/context/base/mkiv/util-sac.lua
+++ b/tex/context/base/mkiv/util-sac.lua
@@ -21,6 +21,10 @@ function streams.open(filename,zerobased)
     return { f, 1, #f, zerobased or false }
 end
 
+function streams.openstring(f,zerobased)
+    return { f, 1, #f, zerobased or false }
+end
+
 function streams.close()
     -- dummy
 end
@@ -389,8 +393,32 @@ end
 
 if sio and sio.readcardinaltable then
 
-    streams.readcardinaltable = sio.readcardinaltable
-    streams.readintegertable  = sio.readintegertable
+    local readcardinaltable = sio.readcardinaltable
+    local readintegertable  = sio.readintegertable
+
+    function utilities.streams.readcardinaltable(f,n,b)
+        local i = f[2]
+        local s = f[3]
+        local p = i + n * b
+        if p > s then
+            f[2] = s + 1
+        else
+            f[2] = p
+        end
+        return readcardinaltable(f[1],i,n,b)
+    end
+
+    function utilities.streams.readintegertable(f,n,b)
+        local i = f[2]
+        local s = f[3]
+        local p = i +  n * b
+        if p > s then
+            f[2] = s + 1
+        else
+            f[2] = p
+        end
+        return readintegertable(f[1],i,n,b)
+    end
 
 else
 
@@ -400,11 +428,19 @@ else
     local readcardinal4 = streams.readcardinal4
 
     function streams.readcardinaltable(f,n,b)
+        local i = f[2]
+        local s = f[3]
+        local p = i + n * b
+        if p > s then
+            f[2] = s + 1
+        else
+            f[2] = p
+        end
         local t = { }
-            if b == 1 then for i=1,n do t[i] = readcardinal1(f) end
-        elseif b == 2 then for i=1,n do t[i] = readcardinal2(f) end
-        elseif b == 3 then for i=1,n do t[i] = readcardinal3(f) end
-        elseif b == 4 then for i=1,n do t[i] = readcardinal4(f) end end
+            if b == 1 then for i=1,n do t[i] = readcardinal1(f[1],i) end
+        elseif b == 2 then for i=1,n do t[i] = readcardinal2(f[1],i) end
+        elseif b == 3 then for i=1,n do t[i] = readcardinal3(f[1],i) end
+        elseif b == 4 then for i=1,n do t[i] = readcardinal4(f[1],i) end end
         return t
     end
 
@@ -414,11 +450,19 @@ else
     local readinteger4 = streams.readinteger4
 
     function streams.readintegertable(f,n,b)
+        local i = f[2]
+        local s = f[3]
+        local p = i + n * b
+        if p > s then
+            f[2] = s + 1
+        else
+            f[2] = p
+        end
         local t = { }
-            if b == 1 then for i=1,n do t[i] = readinteger1(f) end
-        elseif b == 2 then for i=1,n do t[i] = readinteger2(f) end
-        elseif b == 3 then for i=1,n do t[i] = readinteger3(f) end
-        elseif b == 4 then for i=1,n do t[i] = readinteger4(f) end end
+            if b == 1 then for i=1,n do t[i] = readinteger1(f[1],i) end
+        elseif b == 2 then for i=1,n do t[i] = readinteger2(f[1],i) end
+        elseif b == 3 then for i=1,n do t[i] = readinteger3(f[1],i) end
+        elseif b == 4 then for i=1,n do t[i] = readinteger4(f[1],i) end end
         return t
     end
 
diff --git a/tex/context/interface/mkii/keys-fr.xml b/tex/context/interface/mkii/keys-fr.xml
index 5ab324b97..c5da3adca 100644
--- a/tex/context/interface/mkii/keys-fr.xml
+++ b/tex/context/interface/mkii/keys-fr.xml
@@ -1247,6 +1247,7 @@
 		<cd:constant name='textstyle' value='styletexte'/>
 		<cd:constant name='textwidth' value='largeurtexte'/>
 		<cd:constant name='threshold' value='threshold'/>
+		<cd:constant name='time' value='time'/>
 		<cd:constant name='title' value='titre'/>
 		<cd:constant name='titlecolor' value='couleurtitre'/>
 		<cd:constant name='titlecommand' value='titlecommand'/>
diff --git a/tex/context/interface/mkiv/i-context.pdf b/tex/context/interface/mkiv/i-context.pdf
index d8dc51e14..e1e1bc1cd 100644
Binary files a/tex/context/interface/mkiv/i-context.pdf and b/tex/context/interface/mkiv/i-context.pdf differ
diff --git a/tex/context/interface/mkiv/i-readme.pdf b/tex/context/interface/mkiv/i-readme.pdf
index fac1c6288..b8ae1bd64 100644
Binary files a/tex/context/interface/mkiv/i-readme.pdf and b/tex/context/interface/mkiv/i-readme.pdf differ
diff --git a/tex/context/modules/mkiv/m-format.mkiv b/tex/context/modules/mkiv/m-format.mkiv
index f9dd348a4..3a0a5bebd 100644
--- a/tex/context/modules/mkiv/m-format.mkiv
+++ b/tex/context/modules/mkiv/m-format.mkiv
@@ -217,7 +217,7 @@
      \doglobal\newcounter\formatlinesubcounter
      \reshapebox
        {\doglobal\increment\formatlinesubcounter}
-     \global\let\formatlinemaxcounter\formatlinesubcounter
+     \glet\formatlinemaxcounter\formatlinesubcounter
      \reshapebox
        {\doglobal\decrement\formatlinesubcounter
         \ifnum\formatlinesubcounter=\zerocount
@@ -303,7 +303,7 @@
    \doglobal\newcounter\formatlinesubcounter
    \reshapebox
      {\doglobal\increment\formatlinesubcounter}%
-   \global\let\formatlinemaxcounter\formatlinesubcounter
+   \glet\formatlinemaxcounter\formatlinesubcounter
    \reshapebox
      {\doglobal\decrement\formatlinesubcounter
       \ifnum\formatlinesubcounter=\zerocount
diff --git a/tex/context/modules/mkiv/s-fonts-charts.mkiv b/tex/context/modules/mkiv/s-fonts-charts.mkiv
index 50cd589e4..d8d0975de 100644
--- a/tex/context/modules/mkiv/s-fonts-charts.mkiv
+++ b/tex/context/modules/mkiv/s-fonts-charts.mkiv
@@ -169,36 +169,39 @@
 
 \starttext
 
-    \showfontchart[filename=LucidaBrightOT.otf,page=yes]
-    \showfontchart[filename=LucidaBrightOT-Demi.otf,page=yes]
-    \showfontchart[filename=LucidaBrightOT-DemiItalic.otf,page=yes]
-    \showfontchart[filename=LucidaBrightOT-Italic.otf,page=yes]
-
-    \showfontchart[filename=LucidaSansOT.otf,page=yes]
-    \showfontchart[filename=LucidaSansOT-Demi.otf,page=yes]
-    \showfontchart[filename=LucidaSansOT-DemiItalic.otf,page=yes]
-    \showfontchart[filename=LucidaSansOT-Italic.otf,page=yes]
-
-    \showfontchart[filename=LucidaSansTypewriterOT.otf,page=yes]
-    \showfontchart[filename=LucidaSansTypewriterOT-Bold.otf,page=yes]
-    \showfontchart[filename=LucidaSansTypewriterOT-BoldOblique.otf,page=yes]
-    \showfontchart[filename=LucidaSansTypewriterOT-Oblique.otf,page=yes]
-
-    \showfontchart[filename=LucidaConsoleDK.otf,page=yes]
-    \showfontchart[filename=LucidaConsoleDK-Bold.otf,page=yes]
-    \showfontchart[filename=LucidaConsoleDK-BoldItalic.otf,page=yes]
-    \showfontchart[filename=LucidaConsoleDK-Italic.otf,page=yes]
-
-    \showfontchart[filename=LucidaGrandeMonoDK.otf,page=yes]
-    \showfontchart[filename=LucidaGrandeMonoDK-Bold.otf,page=yes]
-    \showfontchart[filename=LucidaGrandeMonoDK-BoldItalic.otf,page=yes]
-    \showfontchart[filename=LucidaGrandeMonoDK-Italic.otf,page=yes]
-
-    \showfontchart[filename=LucidaBrightMathOT.otf,page=yes]
-    \showfontchart[filename=LucidaBrightMathOT-Demi.otf,page=yes]
-
-    \showfontchart[filename=LucidaBlackletterOT.otf,page=yes]
-    \showfontchart[filename=LucidaCalligraphyOT.otf,page=yes]
-    \showfontchart[filename=LucidaHandwritingOT.otf,page=yes]
+%     \showfontchart[filename=veramono.ttf,page=yes]
+    \showfontchart[filename=CoelacanthSubhdHeavy.otf,page=yes]
+
+%     \showfontchart[filename=LucidaBrightOT.otf,page=yes]
+%     \showfontchart[filename=LucidaBrightOT-Demi.otf,page=yes]
+%     \showfontchart[filename=LucidaBrightOT-DemiItalic.otf,page=yes]
+%     \showfontchart[filename=LucidaBrightOT-Italic.otf,page=yes]
+
+%     \showfontchart[filename=LucidaSansOT.otf,page=yes]
+%     \showfontchart[filename=LucidaSansOT-Demi.otf,page=yes]
+%     \showfontchart[filename=LucidaSansOT-DemiItalic.otf,page=yes]
+%     \showfontchart[filename=LucidaSansOT-Italic.otf,page=yes]
+
+%     \showfontchart[filename=LucidaSansTypewriterOT.otf,page=yes]
+%     \showfontchart[filename=LucidaSansTypewriterOT-Bold.otf,page=yes]
+%     \showfontchart[filename=LucidaSansTypewriterOT-BoldOblique.otf,page=yes]
+%     \showfontchart[filename=LucidaSansTypewriterOT-Oblique.otf,page=yes]
+
+%     \showfontchart[filename=LucidaConsoleDK.otf,page=yes]
+%     \showfontchart[filename=LucidaConsoleDK-Bold.otf,page=yes]
+%     \showfontchart[filename=LucidaConsoleDK-BoldItalic.otf,page=yes]
+%     \showfontchart[filename=LucidaConsoleDK-Italic.otf,page=yes]
+
+%     \showfontchart[filename=LucidaGrandeMonoDK.otf,page=yes]
+%     \showfontchart[filename=LucidaGrandeMonoDK-Bold.otf,page=yes]
+%     \showfontchart[filename=LucidaGrandeMonoDK-BoldItalic.otf,page=yes]
+%     \showfontchart[filename=LucidaGrandeMonoDK-Italic.otf,page=yes]
+
+%     \showfontchart[filename=LucidaBrightMathOT.otf,page=yes]
+%     \showfontchart[filename=LucidaBrightMathOT-Demi.otf,page=yes]
+
+%     \showfontchart[filename=LucidaBlackletterOT.otf,page=yes]
+%     \showfontchart[filename=LucidaCalligraphyOT.otf,page=yes]
+%     \showfontchart[filename=LucidaHandwritingOT.otf,page=yes]
 
 \stoptext
diff --git a/tex/context/modules/mkiv/s-fonts-complete.mkiv b/tex/context/modules/mkiv/s-fonts-complete.mkiv
index afdd79b4c..83aa708df 100644
--- a/tex/context/modules/mkiv/s-fonts-complete.mkiv
+++ b/tex/context/modules/mkiv/s-fonts-complete.mkiv
@@ -29,23 +29,36 @@
             local descriptions = tfmdata.descriptions or { }
             local data = characters.data
          -- context.setuptabulate { header = "repeat" }
-            context.starttabulatehead()
-                NC() bold("unicode")
-                NC() bold("visual")
-                NC() bold("index")
-                NC() bold("glyph")
-                NC() bold("adobe")
-                NC() bold("context")
-                NC() NR()
-            context.stoptabulatehead()
-            context.starttabulate { "|l|c|l|p|p|p|" }
+         -- context.starttabulatehead()
+         --     NC() bold("unicode")
+         --     NC() bold("visual")
+         --     NC() bold("index")
+         --     NC() bold("tounicode")
+         --     NC() bold("unicodes")
+         --     NC() bold("glyph")
+         --     NC() bold("adobe")
+         --     NC() bold("context")
+         --     NC() NR()
+         -- context.stoptabulatehead()
+            context.starttabulate { "|l|c|p(8em)|l|l|p|p|p|" }
+            NC() bold("unicode")
+            NC() bold("visual")
+            NC() bold("unicodes")
+            NC() bold("tounicode")
+            NC() bold("index")
+            NC() bold("glyph")
+            NC() bold("adobe")
+            NC() bold("context")
+            NC() NR()
             for unicode, chr in fonts.iterators.characters(tfmdata) do
                 local des, dat = descriptions[unicode], data[unicode]
-                local index = chr.index or 0
-                local cname = (dat and dat.contextname) or ""
-                local aname = (dat and dat.adobename) or ""
-                local gname = (des and des.name) or ""
-                local mname = dat and dat.mathname
+                local index     = chr.index or 0
+                local tounicode = chr.tounicode
+                local isunicode = chr.unicode
+                local cname     = (dat and dat.contextname) or ""
+                local aname     = (dat and dat.adobename) or ""
+                local gname     = (des and des.name) or ""
+                local mname     = dat and dat.mathname
                 if type(mname) ~= "string" then
                     mname = ""
                 end
@@ -70,12 +83,52 @@
                         cname = mname
                     end
                 end
-                NC() tttf() context("U+%05X",unicode)
-                NC()        char(unicode)
-                NC() tttf() context("%05X",index)
-                NC() if gname ~= "" then tttf() escaped(gname) end
-                NC() if aname ~= "" then tttf() context(aname) end
-                NC() if cname ~= "" then tttf() context(cname) end
+                NC()
+                    tttf()
+                    context("%05X",unicode)
+                NC()
+                    char(unicode)
+                NC()
+                    if isunicode then
+                        tttf()
+                        if type(isunicode) == "table" then
+                            for i=1,#isunicode do
+                                if i > 1 then
+                                    if i % 2 ~= 0 then
+                                        context.crlf()
+                                    else
+                                        context.space()
+                                    end
+                                end
+                                context("%05X",isunicode[i])
+                            end
+                        else
+                            context("%05X",isunicode)
+                        end
+                    end
+                NC()
+                    if tounicode then
+                        tttf()
+                        context(tounicode)
+                    end
+                NC()
+                    tttf()
+                    context("%05X",index)
+                NC()
+                if gname ~= "" then
+                    tttf()
+                    escaped(gname)
+                end
+                NC()
+                if aname ~= "" then
+                    tttf()
+                    context(aname)
+                end
+                NC()
+                if cname ~= "" then
+                    tttf()
+                    context(cname)
+                end
                 NC() NR()
             end
             context.stoptabulate()
@@ -100,14 +153,13 @@
    \font\TestFont=#1 at #2
    \setuplayout[style=\TestFont]
    \setupheadertexts[]
-   \setupfootertexts[#1 -- \pagenumber]
-   \setupfootertexts[pagenumber]
+   \setupfootertexts[#1\space\endash\space\pagenumber]
    \setuplayout[width=middle,height=middle,topspace=1cm,backspace=1cm]
    \TestFont
    \nonknuthmode
    \startcolumns[n=#3]
-   \TestFont
-   \ctxlua { moduledata.fonts.complete.all() }
+       \TestFont
+       \ctxlua { moduledata.fonts.complete.all() }
    \stopcolumns
    \page
    \endgroup}
@@ -125,14 +177,16 @@
    \TestFontB \setupinterlinespace[line=1.2\dimexpr#2\relax] \raggedcenter
    \nonknuthmode
    \startcolumns[n=#3]
-   \TestFontB
-   \ctxlua { moduledata.fonts.complete.glyphs() }
+       \TestFontB
+       \ctxlua { moduledata.fonts.complete.glyphs() }
    \stopcolumns
    \page
    \endgroup}
 
 \continueifinputfile{s-fonts-complete.mkiv}
 
+\usemodule[art-01] \setuplayout[overview] \setupbodyfont[8pt]
+
 \starttext
 
 % \ShowCompleteFont{name:dejavusansmono}{10pt}{1}
@@ -140,7 +194,7 @@
 % \ShowCompleteFont{name:officinasansbookitcregular}{10pt}{2}
 % \ShowCompleteFont{name:officinaserifbookitcregular}{10pt}{2}
 % \ShowCompleteFont{name:serpentineserifeflight}{10pt}{2}
-\ShowCompleteFont{name:lmroman10-regular}{10pt}{1}
+% \ShowCompleteFont{name:lmroman10-regular}{10pt}{1}
 % \ShowCompleteFont{name:lmtypewriter10-regular}{10pt}{2}
 % \ShowCompleteFont{lt55485}{10pt}{2}
 % \ShowCompleteFont{lmr10}{10pt}{2}
@@ -157,4 +211,13 @@
 % \ShowCompleteFont{name:palatinonovaregular}{11pt}{2}
 % \ShowCompleteFont{pirat.ttf}{12pt}{1}
 
+\setuplayout[overview][footer=1cm] \setuplayout[overview]%  \setupheadertexts[aegean.ttf]
+
+\ShowCompleteFont{file:aegean}               {8pt}{1}
+% \ShowCompleteFont{file:tsukurimashouminchops}{8pt}{1}
+% \ShowCompleteFont{file:tsukurimashoumincho}  {8pt}{1}
+% \ShowCompleteFont{file:tsukurimashoukakups}  {8pt}{1}
+% \ShowCompleteFont{file:tsukurimashoukaku}    {8pt}{1}
+% \ShowCompleteFont{file:akkadian}             {8pt}{1}
+
 \stoptext
diff --git a/tex/context/modules/mkiv/s-fonts-system.lua b/tex/context/modules/mkiv/s-fonts-system.lua
index e05eef0fa..5d2692473 100644
--- a/tex/context/modules/mkiv/s-fonts-system.lua
+++ b/tex/context/modules/mkiv/s-fonts-system.lua
@@ -39,6 +39,8 @@ local sortedhash = table.sortedhash
 local formatters = string.formatters
 local concat = table.concat
 local lower = string.lower
+local gsub = string.gsub
+local find = string.find
 
 local function allfiles(specification)
     local pattern = lower(specification.pattern or "")
@@ -202,3 +204,88 @@ function moduledata.fonts.system.showinstalledglyphnames(specification)
     end
     table.save("s-fonts-system-glyph-names.lua",names)
 end
+
+-- -- --
+
+-- local skip = {
+--     "adobeblank",
+--     "veramo",
+--     "unitedstates",
+--     "tirek",
+--     "svbasicmanual",
+--     "sahel",
+--     "prsprorg",
+--     "piratdia",
+--     "notoserifthai",
+--     "coelacanthsubhdheavy",
+-- }
+
+-- local function bad(name)
+--     name = lower(name)
+--     for i=1,#skip do
+--         if find(name,skip[i]) then
+--             return true
+--         end
+--     end
+-- end
+
+-- function moduledata.fonts.system.showprivateglyphnames(specification)
+--     specification = interfaces.checkedspecification(specification)
+--     local paths   = caches.getreadablepaths()
+--     local files   = { }
+--     local names   = table.setmetatableindex("table")
+--     local f_u     = formatters["%04X"]
+--     for i=1,#paths do
+--         local list = dir.glob(paths[i].."/fonts/o*/**.tmc")
+--         for i=1,#list do
+--             files[list[i]] = true
+--         end
+--     end
+--     for filename in table.sortedhash(files) do
+--         logs.report("system","fontfile: %s",file.nameonly(filename))
+--         local data = table.load(filename)
+--         if data and data.format == "truetype" or data.format == "opentype" then
+--             local basename  = file.basename(data.resources.filename)
+--             local cleanname = gsub(basename," ","")
+--             if not bad(cleanname) then
+--                 local descriptions = data.descriptions
+--                 if descriptions then
+--                     local done = 0
+--                     for u, d in sortedhash(descriptions) do
+--                         local dn = d.name
+--                         local du = d.unicode
+--                         if dn and du and (u >= 0xF0000 or (u >= 0xE000 and u <= 0xF8FF)) and not find(dn,"notdef") then
+--                             if type(du) == "table" then
+--                                 local t = { }
+--                                 for i=1,#du do
+--                                     t[i] = f_u(du[i])
+--                                 end
+--                                 du = concat(t," ")
+--                             end
+--                             if done == 0 then
+--                                 logs.report("system","basename: %s",basename)
+--                                 context.starttitle { title = basename }
+--                                 context.start()
+--                                 context.definefont( { "tempfont" }, { "file:" .. cleanname })
+--                                 context.starttabulate { "|T||T|T|" }
+--                             end
+--                             NC() context("%U",u)
+--                             NC() context.tempfont() context.char(u) -- could be getglyph
+--                             NC() ctx_verbatim(dn)
+--                             NC() context(du)
+--                             NC() NR()
+--                             done = done + 1
+--                         end
+--                     end
+--                     if done > 0 then
+--                         logs.report("system","privates: %i",done)
+--                         context.stoptabulate()
+--                         context.stop()
+--                         context.stoptitle()
+--                     end
+--                 end
+--             end
+--         end
+--     end
+-- end
+
diff --git a/tex/context/modules/mkiv/s-fonts-system.mkiv b/tex/context/modules/mkiv/s-fonts-system.mkiv
index 5613701d9..03599b0df 100644
--- a/tex/context/modules/mkiv/s-fonts-system.mkiv
+++ b/tex/context/modules/mkiv/s-fonts-system.mkiv
@@ -27,22 +27,24 @@
 \installmodulecommandluasingle \showinstalledfonts      {moduledata.fonts.system.showinstalled}
 \installmodulecommandluasingle \cacheinstalledfonts     {moduledata.fonts.system.cacheinstalled}
 \installmodulecommandluasingle \showinstalledglyphnames {moduledata.fonts.system.showinstalledglyphnames}
+%installmodulecommandluasingle \showprivateglyphnames   {moduledata.fonts.system.showprivateglyphnames}
 
 \stopmodule
 
 \continueifinputfile{s-fonts-system.mkiv}
 
-\usemodule[art-01] \setuplayout[overview] \setupbodyfont[7pt]
+\usemodule[art-01] \setuplayout[overview] \setupbodyfont[6pt]
 
 \starttext
 
 %     \showinstalledfonts
 
-%     \enabletrackers[otf.keepnames]
+    \enabletrackers[otf.keepnames]
 
-%     \cacheinstalledfonts[threshold=4000000,suffixes={otf,ttf,afm,pfb}]
-%     \cacheinstalledfonts[threshold=2000000,suffixes={otf,ttf,afm,pfb}]
+    \cacheinstalledfonts[suffixes={otf,ttf,afm}]
+%     \cacheinstalledfonts[threshold=4000000,suffixes={otf,ttf,afm}]
+%     \cacheinstalledfonts[threshold=2000000,suffixes={otf,ttf,afm}]
 
-    \showinstalledglyphnames
+%     \showinstalledglyphnames
 
 \stoptext
diff --git a/tex/context/modules/mkiv/s-maps.mkiv b/tex/context/modules/mkiv/s-maps.mkiv
index c7541babc..28e88af98 100644
--- a/tex/context/modules/mkiv/s-maps.mkiv
+++ b/tex/context/modules/mkiv/s-maps.mkiv
@@ -135,11 +135,11 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %%% 3 versions of layout with matching headers
 
-\definepapersize 
+\definepapersize
   [maps]
   [width=21cm,height=26.5cm]
 
-\setuppapersize 
+\setuppapersize
   [maps][maps]
 
 \setuplayout[
@@ -360,9 +360,9 @@
       \xdef\MapsNumber{\the\numexpr (\the\year-1990)*2+1\relax}%
     \fi }%
   \doifnothing\MapsRunningAuthor
-    {\global\let\MapsRunningAuthor\MapsAuthor}%
+    {\glet\MapsRunningAuthor\MapsAuthor}%
   \doifnothing\MapsRunningTitle
-    {\global\let\MapsRunningTitle\MapsTitle}}%
+    {\glet\MapsRunningTitle\MapsTitle}}%
 
 \def\dostartArticle[#1]{%
   \MapsBibData[#1]
diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua
index 90f8f4f00..f97f82489 100644
--- a/tex/generic/context/luatex/luatex-fonts-merged.lua
+++ b/tex/generic/context/luatex/luatex-fonts-merged.lua
@@ -1,6 +1,6 @@
 -- merged file : c:/data/develop/context/sources/luatex-fonts-merged.lua
 -- parent file : c:/data/develop/context/sources/luatex-fonts.lua
--- merge date  : 10/08/18 17:44:41
+-- merge date  : 10/17/18 15:06:55
 
 do -- begin closure to overcome local limits and interference
 
@@ -9668,6 +9668,7 @@ function constructors.scale(tfmdata,specification)
     if isunicode then
       chr.unicode=isunicode
       chr.tounicode=tounicode(isunicode)
+    else
     end
     if hasquality then
       local ve=character.expansion_factor
@@ -23846,35 +23847,41 @@ local function checkmathreplacements(tfmdata,fullname,fixitalics)
       for unicode,replacement in next,changed do
         local u=characters[unicode]
         local r=characters[replacement]
-        local n=u.next
-        local v=u.vert_variants
-        local h=u.horiz_variants
-        if fixitalics then
-          local ui=u.italic
-          if ui and not r.italic then
+        if u and r then
+          local n=u.next
+          local v=u.vert_variants
+          local h=u.horiz_variants
+          if fixitalics then
+            local ui=u.italic
+            if ui and not r.italic then
+              if trace_preparing then
+                report_prepare("using %i units of italic correction from %C for %U",ui,unicode,replacement)
+              end
+              r.italic=ui 
+            end
+          end
+          if n and not r.next then
             if trace_preparing then
-              report_prepare("using %i units of italic correction from %C for %U",ui,unicode,replacement)
+              report_prepare("forcing %s for %C substituted by %U","incremental step",unicode,replacement)
             end
-            r.italic=ui 
+            r.next=n
           end
-        end
-        if n and not r.next then
-          if trace_preparing then
-            report_prepare("forcing %s for %C substituted by %U","incremental step",unicode,replacement)
+          if v and not r.vert_variants then
+            if trace_preparing then
+              report_prepare("forcing %s for %C substituted by %U","vertical variants",unicode,replacement)
+            end
+            r.vert_variants=v
           end
-          r.next=n
-        end
-        if v and not r.vert_variants then
-          if trace_preparing then
-            report_prepare("forcing %s for %C substituted by %U","vertical variants",unicode,replacement)
+          if h and not r.horiz_variants then
+            if trace_preparing then
+              report_prepare("forcing %s for %C substituted by %U","horizontal variants",unicode,replacement)
+            end
+            r.horiz_variants=h
           end
-          r.vert_variants=v
-        end
-        if h and not r.horiz_variants then
+        else
           if trace_preparing then
-            report_prepare("forcing %s for %C substituted by %U","horizontal variants",unicode,replacement)
+            report_prepare("error replacing %C by %U",unicode,replacement)
           end
-          r.horiz_variants=h
         end
       end
     end
@@ -31743,7 +31750,7 @@ if not modules then modules={} end modules ['font-otc']={
   license="see context related readme files"
 }
 local insert,sortedkeys,sortedhash,tohash=table.insert,table.sortedkeys,table.sortedhash,table.tohash
-local type,next=type,next
+local type,next,tonumber=type,next,tonumber
 local lpegmatch=lpeg.match
 local utfbyte,utflen=utf.byte,utf.len
 local sortedhash=table.sortedhash
@@ -31881,6 +31888,7 @@ local function addfeature(data,feature,specifications)
   if not specifications then
     return
   end
+  local p=lpeg.P("P")*(lpeg.patterns.hexdigit^1/function(s) return tonumber(s,16) end)*lpeg.P(-1)
   local function tounicode(code)
     if not code then
       return
@@ -31898,10 +31906,17 @@ local function addfeature(data,feature,specifications)
         return u
       end
     end
+    local u=lpegmatch(p,code)
+    if u then
+      return u
+    end
     if not aglunicodes then
       aglunicodes=fonts.encodings.agl.unicodes 
     end
-    return aglunicodes[code]
+    local u=aglunicodes[code]
+    if u then
+      return u
+    end
   end
   local coverup=otf.coverup
   local coveractions=coverup.actions
-- 
cgit v1.2.3