More compact float representation
This commit is contained in:
parent
7ffc299c16
commit
463f240670
@ -1,9 +1,15 @@
|
||||
local pdf = pdf
|
||||
local pdfvariable = pdf.variable
|
||||
|
||||
local writer = require'luametalatex-nodewriter'
|
||||
local newpdf = require'luametalatex-pdf'
|
||||
local nametree = require'luametalatex-pdf-nametree'
|
||||
local build_fontdir = require'luametalatex-pdf-font'
|
||||
|
||||
local utils = require'luametalatex-pdf-utils'
|
||||
local strip_floats = utils.strip_floats
|
||||
local to_bp = utils.to_bp
|
||||
|
||||
local pdfname, pfile
|
||||
local fontdirs = setmetatable({}, {__index=function(t, k)t[k] = pfile:getobj() return t[k] end})
|
||||
local usedglyphs = {}
|
||||
@ -62,7 +68,7 @@ token.luacmd("shipout", function()
|
||||
local out, resources, annots = writer(pfile, list, fontdirs, usedglyphs, colorstacks)
|
||||
cur_page = nil
|
||||
local content = pfile:stream(nil, '', out)
|
||||
pfile:indirect(page, string.format([[<</Type/Page/Parent %i 0 R/Contents %i 0 R/MediaBox[0 %i %i %i]/Resources<<%s%s>>%s%s>>]], parent, content, -math.ceil(list.depth/65781.76), math.ceil(list.width/65781.76), math.ceil(list.height/65781.76), resources, pdfvariable.pageresources, annots, pdfvariable.pageattr))
|
||||
pfile:indirect(page, string.format([[<</Type/Page/Parent %i 0 R/Contents %i 0 R/MediaBox[0 %i %i %i]/Resources<<%s%s>>%s%s>>]], parent, content, -math.ceil(to_bp(list.depth)), math.ceil(to_bp(list.width)), math.ceil(to_bp(list.height)), resources, pdfvariable.pageresources, annots, pdfvariable.pageattr))
|
||||
node.flush_list(list)
|
||||
token.put_next(reset_deadcycles)
|
||||
token.scan_token()
|
||||
@ -190,9 +196,6 @@ function pdf.newcolorstack(default, mode, page)
|
||||
}
|
||||
return idx
|
||||
end
|
||||
local function sp2bp(sp)
|
||||
return sp/65781.76
|
||||
end
|
||||
local function projected(m, x, y, w)
|
||||
w = w or 1
|
||||
return x*m[1] + y*m[3] + w*m[5], x*m[2] + y*m[4] + w*m[6]
|
||||
@ -253,14 +256,15 @@ local function write_link(p, link)
|
||||
local quadStr = {}
|
||||
for i=1,#quads,8 do
|
||||
local x1, y1, x4, y4, x2, y2, x3, y3 = table.unpack(quads, i, i+7)
|
||||
x1, y1, x2, y2, x3, y3, x4, y4 = sp2bp(x1), sp2bp(y1), sp2bp(x2), sp2bp(y2), sp2bp(x3), sp2bp(y3), sp2bp(x4), sp2bp(y4)
|
||||
x1, y1, x2, y2, x3, y3, x4, y4 = to_bp(x1), to_bp(y1), to_bp(x2), to_bp(y2), to_bp(x3), to_bp(y3), to_bp(x4), to_bp(y4)
|
||||
quadStr[i//8+1] = string.format("%f %f %f %f %f %f %f %f", x1, y1, x2, y2, x3, y3, x4, y4)
|
||||
minX = math.min(minX, x1, x2, x3, x4)
|
||||
minY = math.min(minY, y1, y2, y3, y4)
|
||||
maxX = math.max(maxX, x1, x2, x3, x4)
|
||||
maxY = math.max(maxY, y1, y2, y3, y4)
|
||||
end
|
||||
pfile:indirect(link.objnum, string.format("<</Type/Annot/Rect[%f %f %f %f]/QuadPoints[%s]%s>>", minX-.2, minY-.2, maxX+.2, maxY+.2, table.concat(quadStr, ' '), attr))
|
||||
local boxes = strip_floats(string.format("/Rect[%f %f %f %f]/QuadPoints[%s]", minX-.2, minY-.2, maxX+.2, maxY+.2, table.concat(quadStr, ' ')))
|
||||
pfile:indirect(link.objnum, string.format("<</Type/Annot%s%s>>", boxes, attr))
|
||||
for i=1,#quads do quads[i] = nil end
|
||||
link.objnum = nil
|
||||
end
|
||||
@ -387,9 +391,9 @@ local dest_whatsit = declare_whatsit('pdf_dest', function(prop, p, n, x, y)
|
||||
local x, y = projected(p.matrix, x, y)
|
||||
local zoom = prop.xyz_zoom
|
||||
if zoom then
|
||||
data = string.format("[%i 0 R/XYZ %.5f %.5f %.3f]", cur_page, sp2bp(x-off), sp2bp(y+off), prop.zoom/1000)
|
||||
data = string.format("[%i 0 R/XYZ %.5f %.5f %.3f]", cur_page, to_bp(x-off), to_bp(y+off), prop.zoom/1000)
|
||||
else
|
||||
data = string.format("[%i 0 R/XYZ %.5f %.5f null]", cur_page, sp2bp(x-off), sp2bp(y+off))
|
||||
data = string.format("[%i 0 R/XYZ %.5f %.5f null]", cur_page, to_bp(x-off), to_bp(y+off))
|
||||
end
|
||||
elseif dest_type == "fitr" then
|
||||
local m = p.matrix
|
||||
@ -399,28 +403,28 @@ local dest_whatsit = declare_whatsit('pdf_dest', function(prop, p, n, x, y)
|
||||
local urx, ury = projected(x+prop.width, x + prop.height)
|
||||
local left, lower, right, upper = math.min(llx, lrx, ulx, urx), math.min(lly, lry, uly, ury),
|
||||
math.max(llx, lrx, ulx, urx), math.max(lly, lry, uly, ury)
|
||||
data = string.format("[%i 0 R/FitR %.5f %.5f %.5f %.5f]", cur_page, sp2bp(left-off), sp2bp(lower-off), sp2bp(right+off), sp2bp(upper+off))
|
||||
data = string.format("[%i 0 R/FitR %.5f %.5f %.5f %.5f]", cur_page, to_bp(left-off), to_bp(lower-off), to_bp(right+off), to_bp(upper+off))
|
||||
elseif dest_type == "fit" then
|
||||
data = string.format("[%i 0 R/Fit]", cur_page)
|
||||
elseif dest_type == "fith" then
|
||||
local x, y = projected(p.matrix, x, y)
|
||||
data = string.format("[%i 0 R/FitH %.5f]", cur_page, sp2bp(y+off))
|
||||
data = string.format("[%i 0 R/FitH %.5f]", cur_page, to_bp(y+off))
|
||||
elseif dest_type == "fitv" then
|
||||
local x, y = projected(p.matrix, x, y)
|
||||
data = string.format("[%i 0 R/FitV %.5f]", cur_page, sp2bp(x-off))
|
||||
data = string.format("[%i 0 R/FitV %.5f]", cur_page, to_bp(x-off))
|
||||
elseif dest_type == "fitb" then
|
||||
data = string.format("[%i 0 R/FitB]", cur_page)
|
||||
elseif dest_type == "fitbh" then
|
||||
local x, y = projected(p.matrix, x, y)
|
||||
data = string.format("[%i 0 R/FitBH %.5f]", cur_page, sp2bp(y+off))
|
||||
data = string.format("[%i 0 R/FitBH %.5f]", cur_page, to_bp(y+off))
|
||||
elseif dest_type == "fitbv" then
|
||||
local x, y = projected(p.matrix, x, y)
|
||||
data = string.format("[%i 0 R/FitBV %.5f]", cur_page, sp2bp(x-off))
|
||||
data = string.format("[%i 0 R/FitBV %.5f]", cur_page, to_bp(x-off))
|
||||
end
|
||||
if pfile:written(dests[id]) then
|
||||
texio.write_nl(string.format("Duplicate destination %q", id))
|
||||
else
|
||||
dests[id] = pfile:indirect(dests[id], data)
|
||||
dests[id] = pfile:indirect(dests[id], strip_floats(data))
|
||||
end
|
||||
end)
|
||||
local refobj_whatsit = declare_whatsit('pdf_refobj', function(prop, p, n, x, y)
|
||||
|
@ -31,6 +31,10 @@ local rangedimensions = direct.rangedimensions
|
||||
local traverse_id = direct.traverse_id
|
||||
local getdata = direct.getdata
|
||||
|
||||
local utils = require'luametalatex-pdf-utils'
|
||||
local strip_floats = utils.strip_floats
|
||||
local to_bp = utils.to_bp
|
||||
|
||||
local pdf_font_map = require'luametalatex-pdf-font-deduplicate'
|
||||
local get_whatsit_handler = require'luametalatex-whatsits'.handler
|
||||
|
||||
@ -72,14 +76,11 @@ local whatsithandler = (function()
|
||||
end)
|
||||
end)()
|
||||
local glyph, text, page, cm_pending = 1, 2, 3, 4
|
||||
local gsub = string.gsub
|
||||
|
||||
local function projected_point(m, x, y, w)
|
||||
w = w or 1
|
||||
return x*m[1] + y*m[3] + w*m[5], x*m[2] + y*m[4] + w*m[6]
|
||||
end
|
||||
local function sp2bp(sp)
|
||||
return sp/65781.76
|
||||
end
|
||||
local fontnames = setmetatable({}, {__index = function(t, k) local res = format("F%i", k) t[k] = res return res end})
|
||||
local topage
|
||||
local function totext(p, fid)
|
||||
@ -98,7 +99,7 @@ local function totext(p, fid)
|
||||
|
||||
local pdf_fid = pdf_font_map[fid]
|
||||
p.resources.Font[fontnames[pdf_fid]] = p.fontdirs[pdf_fid]
|
||||
p.strings[#p.strings+1] = format("/F%i %f Tf 0 Tr", pdf_fid, sp2bp(f.size)) -- TODO: Setting the mode, width, etc.
|
||||
p.strings[#p.strings+1] = strip_floats(format("/F%i %f Tf 0 Tr", pdf_fid, to_bp(f.size))) -- TODO: Setting the mode, width, etc.
|
||||
p.font.usedglyphs = p.usedglyphs[pdf_fid]
|
||||
|
||||
p.font.fid = fid
|
||||
@ -127,7 +128,7 @@ function topage(p)
|
||||
elseif last == cm_pending then
|
||||
local pending = p.pending_matrix
|
||||
if pending[1] ~= 1 or pending[2] ~= 0 or pending[3] ~= 0 or pending[4] ~= 1 or pending[5] ~= 0 or pending[6] ~= 0 then
|
||||
p.strings[#p.strings+1] = format("%f %f %f %f %f %f cm", pending[1], pending[2], pending[3], pending[4], sp2bp(pending[5]), sp2bp(pending[6]))
|
||||
p.strings[#p.strings+1] = strip_floats(format("%f %f %f %f %f %f cm", pending[1], pending[2], pending[3], pending[4], to_bp(pending[5]), to_bp(pending[6])))
|
||||
end
|
||||
else
|
||||
error[[Unknown mode]]
|
||||
@ -147,14 +148,14 @@ local function toglyph(p, fid, x, y, exfactor)
|
||||
end
|
||||
if totext(p, fid) or exfactor ~= p.font.exfactor then
|
||||
p.font.exfactor = exfactor
|
||||
p.strings[#p.strings+1] = gsub(format("%f 0.0 %f %f %f %f Tm", p.font.extend * (1+exfactor/1000000), p.font.slant, p.font.squeeze, sp2bp(x), sp2bp(y)), '%.?0+ ', ' ')
|
||||
p.strings[#p.strings+1] = strip_floats(format("%f 0.0 %f %f %f %f Tm", p.font.extend * (1+exfactor/1000000), p.font.slant, p.font.squeeze, to_bp(x), to_bp(y)))
|
||||
else
|
||||
-- To invert the text transformation matrix (extend 0 0;slant squeeze 0;0 0 1)
|
||||
-- we have to apply (extend^-1 0 0;-slant*extend^-1*squeeze^-1 squeeze^-1 0;0 0 1). (extend has to include expansion)
|
||||
-- We optimize slightly by separating some steps
|
||||
local dx, dy = sp2bp((x - p.pos.lx)), sp2bp(y - p.pos.ly) / p.font.squeeze
|
||||
local dx, dy = to_bp((x - p.pos.lx)), to_bp(y - p.pos.ly) / p.font.squeeze
|
||||
dx = (dx-p.font.slant*dy) / (p.font.extend * (1+exfactor/1000000))
|
||||
p.strings[#p.strings+1] = gsub(format("%f %f Td", dx, dy), '%.?0+ ', ' ')
|
||||
p.strings[#p.strings+1] = strip_floats(format("%f %f Td", dx, dy))
|
||||
end
|
||||
p.pos.lx, p.pos.ly, p.pos.x, p.pos.y = x, y, x, y
|
||||
p.mode = glyph
|
||||
@ -287,7 +288,7 @@ function nodehandler.rule(p, n, x, y, outer)
|
||||
error[[We can't handle outline rules yet]]
|
||||
else
|
||||
topage(p)
|
||||
p.strings[#p.strings+1] = gsub(format("%f %f %f %f re f", sp2bp(x), sp2bp(y - getdepth(n)), sp2bp(getwidth(n)), sp2bp(getdepth(n) + getheight(n))), '%.?0+ ', ' ')
|
||||
p.strings[#p.strings+1] = strip_floats(format("%f %f %f %f re f", to_bp(x), to_bp(y - getdepth(n)), to_bp(getwidth(n)), to_bp(getdepth(n) + getheight(n))))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -13,9 +13,10 @@ local boxmap = {
|
||||
art = "ArtBox",
|
||||
}
|
||||
|
||||
-- FIXME:
|
||||
local function to_sp(bp) return bp*65781.76//1 end
|
||||
local function to_bp(sp) return sp/65781.76 end
|
||||
local utils = require'luametalatex-pdf-utils'
|
||||
local strip_floats = utils.strip_floats
|
||||
local to_sp = utils.to_sp
|
||||
local to_bp = utils.to_bp
|
||||
|
||||
local function get_box(page, box)
|
||||
box = boxmap[box]
|
||||
@ -74,7 +75,8 @@ function pdf_functions.write(pfile, img)
|
||||
local file = open_pdfe(img)
|
||||
local page = pdfe.getpage(file, img.page)
|
||||
local bbox = img.bbox
|
||||
local dict = string.format("/Subtype/Form/BBox[%f %f %f %f]/Resources %s", to_bp(bbox[1]), to_bp(bbox[2]), to_bp(bbox[3]), to_bp(bbox[4]), pdfe_deepcopy(file, img.filepath, pfile, pdfe.getfromdictionary(page, 'Resources')))
|
||||
local dict = strip_floats(string.format("/Subtype/Form/BBox[%f %f %f %f]/Resources ", to_bp(bbox[1]), to_bp(bbox[2]), to_bp(bbox[3]), to_bp(bbox[4])))
|
||||
dict = dict .. pdfe_deepcopy(file, img.filepath, pfile, pdfe.getfromdictionary(page, 'Resources'))
|
||||
local content, raw = page.Contents
|
||||
-- Three cases: Contents is a stream, so copy the stream (Remember to copy filter if necessary)
|
||||
-- Contents is an array of streams, so append all the streams as a new stream
|
||||
|
@ -1,3 +1,5 @@
|
||||
local strip_floats = require'luametalatex-pdf-utils'.strip_floats
|
||||
|
||||
local function ignore() end
|
||||
local parse = setmetatable({
|
||||
-- IHDR = below,
|
||||
@ -131,11 +133,11 @@ function parse.cHRM(buf, i, after, ctxt)
|
||||
local X_C, Z_C = Y_C*x_B/y_B, Y_C*((1-x_B)/y_B-1)
|
||||
|
||||
local X_W, Y_W, Z_W = X_A+X_B+X_C, Y_A+Y_B+Y_C, Z_A+Z_B+Z_C
|
||||
ctxt.cHRM = string.format("/WhitePoint[%f %f %f]/Matrix[%f %f %f %f %f %f %f %f %f]",
|
||||
ctxt.cHRM = strip_floats(string.format("/WhitePoint[%f %f %f]/Matrix[%f %f %f %f %f %f %f %f %f]",
|
||||
X_W, Y_W, Z_W,
|
||||
X_A, Y_A, Z_A,
|
||||
X_B, Y_B, Z_B,
|
||||
X_C, Y_C, Z_C)
|
||||
X_C, Y_C, Z_C))
|
||||
end
|
||||
function parse.IDAT(buf, i, after, ctxt)
|
||||
ctxt.IDAT = ctxt.IDAT or {}
|
||||
@ -277,7 +279,7 @@ function png_functions.write(pfile, img)
|
||||
elseif colortype & 2 == 2 then -- RGB
|
||||
if t.cHRM then
|
||||
local gamma = t.gAMA or 2.2
|
||||
gamma = gamma and string.format("/Gamma[%f %f %f]", gamma, gamma, gamma) or ''
|
||||
gamma = gamma and strip_floats(string.format("/Gamma[%f %f %f]", gamma, gamma, gamma)) or ''
|
||||
colorspace = string.format("[/CalRGB<<%s%s>>]", t.cHRM, gamma)
|
||||
else
|
||||
if t.gAMA then
|
||||
|
@ -17,9 +17,9 @@ local imagetypes = setmetatable({}, {__index = function(t, k)
|
||||
return module
|
||||
end})
|
||||
|
||||
-- FIXME:
|
||||
local function to_sp(bp) return bp*65781.76//1 end
|
||||
local function to_bp(sp) return sp/65781.76 end
|
||||
local utils = require'luametalatex-pdf-utils'
|
||||
local strip_floats = utils.strip_floats
|
||||
local to_bp = utils.to_bp
|
||||
|
||||
local liberal_keys = {height = true, width = true, depth = true, transform = true}
|
||||
local real_images = {}
|
||||
@ -171,7 +171,7 @@ local function do_img(data, p, n, x, y)
|
||||
b, d, f = b*yscale, d*yscale, f*yscale
|
||||
e, f = to_bp(x + e), to_bp(y - depth + f)
|
||||
p.resources.XObject['Im' .. tostring(img.objnum)] = img.objnum
|
||||
pdf.write('page', string.format('q %f %f %f %f %f %f cm /Im%i Do Q', a, b, c, d, e, f, img.objnum), nil, nil, p)
|
||||
pdf.write('page', strip_floats(string.format('q %f %f %f %f %f %f cm /Im%i Do Q', a, b, c, d, e, f, img.objnum)), nil, nil, p)
|
||||
end
|
||||
local ruleid = node.id'rule'
|
||||
local ruletypes = node.subtypes'rule'
|
||||
|
@ -4,7 +4,9 @@ local pdfvariable = pdf.variable
|
||||
-- XForms currently have the form {width, height, depth, objnum, attributes, list, margin}
|
||||
local xforms = {}
|
||||
|
||||
local function to_bp(sp) return sp/65781.76 end
|
||||
local utils = require'luametalatex-pdf-utils'
|
||||
local strip_floats = utils.strip_floats
|
||||
local to_bp = utils.to_bp
|
||||
|
||||
local function shipout(pfile, xform, fontdirs, usedglyphs)
|
||||
local list, margin = xform.list, xform.margin
|
||||
@ -16,7 +18,8 @@ local function shipout(pfile, xform, fontdirs, usedglyphs)
|
||||
if pdfvariable.xformattr ~= '' or pdfvariable.xformresources ~= '' then
|
||||
texio.write_nl('term and log', 'WARNING (savedboxresource shipout): Ignoring unsupported PDF variables xformattr and xformresources. Specify resources and attributes for specific XForms instead.')
|
||||
end
|
||||
local dict = string.format('/Subtype/Form/BBox[%f %f %f %f]/Resources<<%s%s>>%s', -to_bp(margin), -to_bp(list.depth+margin), to_bp(list.width+margin), to_bp(list.height+margin), resources, xform.resources or '', xform.attributes or '')
|
||||
local bbox = strip_floats(string.format('/BBox[%f %f %f %f]', -to_bp(margin), -to_bp(list.depth+margin), to_bp(list.width+margin), to_bp(list.height+margin)))
|
||||
local dict = string.format('/Subtype/Form%s/Resources<<%s%s>>%s', bbox, resources, xform.resources or '', xform.attributes or '')
|
||||
node.flush_list(list)
|
||||
xform.list = nil
|
||||
local objnum = pfile:stream(xform.objnum, dict, out)
|
||||
@ -89,10 +92,10 @@ local function do_box(data, p, n, x, y)
|
||||
local width, height, depth = node.direct.getwhd(n)
|
||||
local xscale, yscale = width / xform.width, (height+depth) / (xform.height+xform.depth)
|
||||
p.resources.XObject['Fm' .. tostring(data)] = objnum
|
||||
pdf.write('page', string.format('q %f 0 0 %f %f %f cm /Fm%i Do Q',
|
||||
pdf.write('page', strip_floats(string.format('q %f 0 0 %f %f %f cm /Fm%i Do Q',
|
||||
xscale, yscale,
|
||||
to_bp(x), to_bp(y-depth+yscale*xform.depth),
|
||||
data), nil, nil, p)
|
||||
data)), nil, nil, p)
|
||||
end
|
||||
|
||||
return {
|
||||
|
23
luametalatex-pdf-utils.lua
Normal file
23
luametalatex-pdf-utils.lua
Normal file
@ -0,0 +1,23 @@
|
||||
local l = lpeg or require'lpeg'
|
||||
local trailing_zeros = l.P'0'^0 * -l.R'09'
|
||||
local strip_floats_patt = l.Cs((1-l.R'09' +
|
||||
(l.R'09')^1 * (l.P'.' * trailing_zeros / '' + l.P'.' * (l.R'09'-trailing_zeros)^1 * (trailing_zeros/''))^-1)^0)
|
||||
local match = l.match
|
||||
|
||||
local function strip_floats(s)
|
||||
return match(strip_floats_patt, s)
|
||||
end
|
||||
|
||||
local function to_bp(sp)
|
||||
return sp/65781.76
|
||||
end
|
||||
|
||||
local function to_sp(bp)
|
||||
return (bp*65781.76+.5)//1
|
||||
end
|
||||
|
||||
return {
|
||||
strip_floats = strip_floats,
|
||||
to_bp = to_bp,
|
||||
to_sp = to_sp,
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
local format = string.format
|
||||
local gsub = string.gsub
|
||||
local byte = string.byte
|
||||
local pack = string.pack
|
||||
local error = error
|
||||
|
@ -1,4 +1,5 @@
|
||||
local format = string.format
|
||||
local strip_floats = require'luametalatex-pdf-utils'.strip_floats
|
||||
local pdfe = pdfe
|
||||
local l = lpeg
|
||||
local regularchar = 1-l.S'\0\t\n\r\f ()<>[]{}/%#'
|
||||
@ -17,7 +18,7 @@ local deepcopy_lookup deepcopy_lookup = {
|
||||
return format("%d", i)
|
||||
end,
|
||||
function(_, pdf, f) -- 4: number
|
||||
return format("%f", f)
|
||||
return strip_floats(format("%f", f), "%.?0+[ %]]", "")
|
||||
end,
|
||||
function(_, pdf, name) -- 5: name
|
||||
return nameescape:match(name)
|
||||
|
Loading…
Reference in New Issue
Block a user