summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/lpdf-lmt.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/mkiv/lpdf-lmt.lua')
-rw-r--r--tex/context/base/mkiv/lpdf-lmt.lua195
1 files changed, 146 insertions, 49 deletions
diff --git a/tex/context/base/mkiv/lpdf-lmt.lua b/tex/context/base/mkiv/lpdf-lmt.lua
index b46274b34..4cce7fc74 100644
--- a/tex/context/base/mkiv/lpdf-lmt.lua
+++ b/tex/context/base/mkiv/lpdf-lmt.lua
@@ -79,8 +79,6 @@ local properties = fonthashes.properties
local report = logs.reporter("backend")
-local trace_threshold = false trackers.register("backends.pdf.threshold", function(v) trace_threshold = v end)
-
-- used variables
local pdf_h, pdf_v
@@ -89,7 +87,7 @@ local need_width, need_mode, done_width, done_mode
local mode
local f_pdf_cur, f_pdf, fs_cur, fs, f_cur
local tj_delta, cw
-local usedfonts, usedxforms, usedximages
+local usedfonts, usedxforms, usedximages, usedxgroups
local getxformname, getximagename
local boundingbox, shippingmode, objectnumber
local tmrx, tmry, tmsx, tmsy, tmtx, tmty
@@ -132,6 +130,7 @@ local function reset_variables(specification)
usedfonts = setmetatableindex(usefont)
usedxforms = { }
usedximages = { }
+ -- usedxgroups = { }
boundingbox = specification.boundingbox
end
@@ -521,6 +520,8 @@ local flushcharacter do
return v
end)
+ local trace_threshold = false trackers.register("backends.pdf.threshold", function(v) trace_threshold = v end)
+
flushcharacter = function(current,pos_h,pos_v,pos_r,font,char,data,naturalwidth,factor,width,f,e)
if need_tf or font ~= f_cur or f_pdf ~= f_pdf_cur or fs ~= fs_cur or mode == "page" then
pdf_goto_textmode()
@@ -842,6 +843,11 @@ end
-- rules
+local f_font = formatters["F%d"]
+local f_form = formatters["Fm%d"]
+local f_group = formatters["Gp%d"]
+local f_image = formatters["Im%d"]
+
local flushedxforms = { } -- actually box resources but can also be direct
local localconverter = nil -- will be set
@@ -1040,6 +1046,37 @@ local flushrule, flushsimplerule, flushimage do
pdf.getximagename = getximagename
end)
+ -- Groups are flushed immediately but we can decide to make them into a
+ -- specific whatsit ... but not now. We could hash them if needed when
+ -- we use lot sof them in mp ... but not now.
+
+ usedxgroups = { }
+ local groups = 0
+ local group = nil
+
+ function lpdf.flushgroup(content,bbox)
+ if not group then
+ group = pdfdictionary {
+ Type = pdfconstant("Group"),
+ S = pdfconstant("Transparency"),
+ }
+ end
+ local wrapper = pdfdictionary {
+ Type = pdf_xobject,
+ Subtype = pdf_form,
+ FormType = 1,
+ Group = group,
+ BBox = pdfarray(bbox),
+ Resources = lpdf.collectedresources { serialize = false },
+ }
+ local objnum = pdfflushstreamobject(content,wrapper,false)
+ groups = groups + 1
+ usedxgroups[groups] = objnum
+ return f_group(groups)
+ end
+
+ -- end of experiment
+
local function flushpdfximage(current,pos_h,pos_v,pos_r,size_h,size_v)
local width,
@@ -1053,7 +1090,7 @@ local flushrule, flushsimplerule, flushimage do
yorigin,
xsize,
ysize,
- rotation,
+ rotation, -- transform / orientation / rotation : it's a mess (i need to redo this)
objnum,
groupref = pdfincludeimage(index) -- needs to be sorted out, bad name (no longer mixed anyway)
@@ -1064,6 +1101,8 @@ local flushrule, flushsimplerule, flushimage do
local rx, sx, sy, ry, tx, ty = 1, 0, 0, 1, 0, 0
+ -- tricky: xsize and ysize swapped
+
if kind == img_pdf or kind == img_stream or kind == img_memstream then
rx, ry, tx, ty = 1/xsize, 1/ysize, xorigin/xsize, yorigin/ysize
else
@@ -1364,15 +1403,70 @@ local function initialize(driver,details)
reset_buffer()
end
-local f_font = formatters["F%d"]
-local f_form = formatters["Fm%d"]
-local f_image = formatters["Im%d"]
-
-- This will all move and be merged and become less messy.
-- todo: more clever resource management: a bit tricky as we can inject
-- stuff in the page stream
+local compact = false
+
+do
+
+ -- This is more a convenience feature and it might even be not entirely robust.
+ -- It removes redundant color directives which makes the page stream look a bit
+ -- nicer (also when figuring out issues). I might add more here but there is
+ -- some additional overhead involved so runtime can be impacted.
+
+ local P, R, S, Cs, lpegmatch = lpeg.P, lpeg.R, lpeg.S, lpeg.Cs, lpeg.match
+
+ local p_ds = (R("09") + S(" ."))^1
+ ----- p_nl = S("\n\r")^1
+ local p_nl = S("\n")^1
+ local p_eg = P("Q")
+
+ local p_cl = p_ds * (P("rg") + P("g") + P("k")) * p_ds * (P("RG") + P("G") + P("K"))
+ ----- p_cl = (p_ds * (P("rg") + P("g") + P("k") + P("RG") + P("G") + P("K")))^1
+ local p_tr = P("/Tr") * p_ds * P("gs")
+
+ local p_no_cl = (p_cl * p_nl) / ""
+ local p_no_tr = (p_tr * p_nl) / ""
+ local p_no_nl = 1 - p_nl
+
+ local p_do_cl = p_cl * p_nl
+ local p_do_tr = p_tr * p_nl
+
+ local p_do_eg = p_eg * p_nl
+
+ local pattern = Cs( (
+ (p_no_cl + p_no_tr)^0 * p_do_eg -- transparencies and colors before Q
+ + p_no_tr * p_no_cl * p_do_tr * p_do_cl -- transparencies and colors before others
+ + p_no_cl * p_do_cl -- successive colors
+ + p_no_tr * p_do_tr -- successive transparencies
+ + p_no_nl^1
+ + 1
+ )^1 )
+
+ local oldsize = 0
+ local newsize = 0
+
+ directives.register("pdf.compact", function(v)
+ compact = v and function(s)
+ oldsize = oldsize + #s
+ s = lpegmatch(pattern,s) or s
+ newsize = newsize + #s
+ return s
+ end
+ end)
+
+ statistics.register("pdf pagestream",function()
+ if oldsize ~= newsize then
+ return string.format("old size: %i, new size %i",oldsize,newsize)
+ end
+ end)
+
+
+end
+
local pushmode, popmode
local function finalize(driver,details)
@@ -1386,6 +1480,10 @@ local function finalize(driver,details)
local content = concat(buffer,"\n",1,b)
+ if compact then
+ content = compact(content)
+ end
+
local fonts = nil
local xforms = nil
@@ -1399,7 +1497,7 @@ local function finalize(driver,details)
-- messy: use real indexes for both ... so we need to change some in the
-- full luatex part
- if next(usedxforms) or next(usedximages) then
+ if next(usedxforms) or next(usedximages) or next(usedxgroups) then
xforms = pdfdictionary { }
for k in sortedhash(usedxforms) do
-- xforms[f_form(k)] = pdfreference(k)
@@ -1408,6 +1506,9 @@ local function finalize(driver,details)
for k, v in sortedhash(usedximages) do
xforms[f_image(k)] = pdfreference(v)
end
+ for k, v in sortedhash(usedxgroups) do
+ xforms[f_group(k)] = pdfreference(v)
+ end
end
reset_buffer()
@@ -1951,9 +2052,15 @@ end)
local openfile, closefile do
- local f_used = formatters["%010i 00000 n \010"]
- local f_link = formatters["%010i 00000 f \010"]
- local f_first = formatters["%010i 65535 f \010"]
+ -- I used to do <space><lf> but then figured out that when I open and save a file in a mode
+ -- that removes trailing spaces, the xref becomes invalid. The problem was then that a
+ -- reconstruction of the file by a viewer gives weird effects probably because percent symbols
+ -- gets interpreted then. Thanks to Ross Moore for noticing this side effect!
+
+ local f_used = formatters["%010i 00000 n\013\010"]
+ local f_link = formatters["%010i 00000 f\013\010"]
+ local f_first = formatters["%010i 65535 f\013\010"]
+
local f_pdf = formatters["%%PDF-%i.%i\010"]
local f_xref = formatters["xref\0100 %i\010"]
local f_trailer_id = formatters["trailer\010<< %s /ID [ <%s> <%s> ] >>\010startxref\010%i\010%%%%EOF"]
@@ -2006,7 +2113,23 @@ local openfile, closefile do
end
closefile = function(abort)
- if not abort then
+ if abort then
+ f:close()
+ f = io.open(abort,"wb")
+ if f then
+ local name = resolvers.findfile("context-lmtx-error.pdf")
+ if name then
+ local data = io.loaddata(name)
+ if data then
+ f:write(data)
+ f:close()
+ return
+ end
+ end
+ f:close()
+ removefile(abort)
+ end
+ else
local xrefoffset = offset
local lastfree = 0
local noffree = 0
@@ -2188,9 +2311,10 @@ local openfile, closefile do
flush(f,f_trailer_no(trailer(),xrefoffset))
end
end
+ f:close()
end
- f:close()
io.flush()
+ closefile = function() end
end
end
@@ -2239,8 +2363,8 @@ updaters.register("backend.update.pdf",function()
specification.index = index
local xobject = pdfdictionary { }
if not specification.notype then
- xobject.Type = pdfconstant("XObject")
- xobject.Subtype = pdfconstant("Form")
+ xobject.Type = pdf_xobject
+ xobject.Subtype = pdf_form
xobject.FormType = 1
end
local bbox = specification.bbox
@@ -2322,8 +2446,8 @@ updaters.register("backend.update.pdf",function()
local bbox = specification.bbox
local xorigin = bbox[1]
local yorigin = bbox[2]
- local xsize = specification.width -- should equal to: bbox[3] - xorigin
- local ysize = specification.height -- should equal to: bbox[4] - yorigin
+ local xsize = bbox[3] - xorigin -- we need the original ones, not the 'rotated' ones
+ local ysize = bbox[4] - yorigin -- we need the original ones, not the 'rotated' ones
local transform = specification.transform or 0
local objnum = specification.objnum or pdfreserveobj()
local groupref = nil
@@ -2448,7 +2572,6 @@ do
local texgetbox = tex.getbox
local pdfname = nil
- local tmpname = nil
local converter = nil
local useddriver = nil -- a bit of a hack
@@ -2474,13 +2597,7 @@ do
-- end
--
pdfname = file.addsuffix(tex.jobname,"pdf")
- tmpname = "l_m_t_x_" .. pdfname
- removefile(tmpname)
- if isfile(tmpname) then
- report("file %a can't be opened, aborting",tmpname)
- os.exit()
- end
- openfile(tmpname)
+ openfile(pdfname)
--
luatex.registerstopactions(1,function()
if pdfname then
@@ -2507,35 +2624,15 @@ do
local function wrapup(driver)
if pdfname then
- local ok = true
- if isfile(pdfname) then
- removefile(pdfname)
- end
- if isfile(pdfname) then
- ok = false
- file.copy(tmpname,pdfname)
- else
- renamefile(tmpname,pdfname)
- if isfile(tmpname) then
- ok = false
- end
- end
- if not ok then
- print(formatters["\nerror in renaming %a to %a\n"](tmpname,pdfname))
- end
+ closefile()
pdfname = nil
- tmpname = nil
end
end
local function cleanup(driver)
- if tmpname then
- closefile(true)
- if isfile(tmpname) then
- removefile(tmpname)
- end
+ if pdfname then
+ closefile(pdfname)
pdfname = nil
- tmpname = nil
end
end