Significantly improved image support

Except for te TeX interface, image inclusions are working (for PDF image
at least, but everything else can be converted)
This commit is contained in:
Marcel Krüger 2020-06-11 01:16:42 +02:00
parent 602bcb0583
commit 5c45cbc2e3
6 changed files with 112 additions and 114 deletions

View File

@ -1,65 +0,0 @@
%%
%% This is file `ltexpl.ltx',
%% generated with the docstrip utility.
%%
%% The original source files were:
%%
%% ltexpl.dtx (with options: `2ekernel')
%%
%% This is a generated file.
%%
%% The source is maintained by the LaTeX Project team and bug
%% reports for it can be opened at https://latex-project.org/bugs.html
%% (but please observe conditions on bug reports sent to that address!)
%%
%%
%% Copyright (C) 1993-2019
%% The LaTeX3 Project and any individual authors listed elsewhere
%% in this file.
%%
%% This file was generated from file(s) of the LaTeX base system.
%% --------------------------------------------------------------
%%
%% It may be distributed and/or modified under the
%% conditions of the LaTeX Project Public License, either version 1.3c
%% of this license or (at your option) any later version.
%% The latest version of this license is in
%% https://www.latex-project.org/lppl.txt
%% and version 1.3c or later is part of all distributions of LaTeX
%% version 2008 or later.
%%
%% This file has the LPPL maintenance status "maintained".
%%
%% This file may only be distributed together with a copy of the LaTeX
%% base system. You may however distribute the LaTeX base system without
%% such generated files.
%%
%% The list of all files belonging to the LaTeX base distribution is
%% given in the file `manifest.txt'. See also `legal.txt' for additional
%% information.
%%
%% The list of derived (unpacked) files belonging to the distribution
%% and covered by LPPL is defined by the unpacking scripts (with
%% extension .ins) which are part of the distribution.
%%% From File: ltexpl.dtx
\input luametalatex-baseregisters
\IfFileExists{expl3.ltx}
{%
\ifnum0%
\ifdefined\pdffilesize 1\fi
\ifdefined\filesize 1\fi
\ifdefined\luatexversion\ifnum\luatexversion>94 1\fi\fi
>0 %
\else
\message{Skipping expl3-dependent extensions}
\expandafter\endinput
\fi
}
{%
\message{Skipping expl3-dependent extensions}%
\endinput
}%
\input{expl3.ltx}
\endinput
%%
%% End of file `ltexpl.ltx'.

View File

@ -37,7 +37,6 @@ return function(name)
local setter = tex["set" .. name]
assert(getter and setter, "direction parameter undefined")
local idx = token.luacmd(name, set_xdir, "protected", "global", "value")
-- names[idx] = name
getters[idx] = getter
setters[idx] = setter
return idx

View File

@ -136,6 +136,7 @@ end
local basename = ((1-lpeg.S'\\/')^0*lpeg.S'\\/')^0*lpeg.C((1-lpeg.P'.tfm'*-1)^0)
return function(name, size)
local filename = kpse.find_file(name, 'tfm', true)
if not filename then return end
local f = io.open(filename)
if not f then return end
local buf = f:read'*a'

View File

@ -1,5 +1,5 @@
do
local ourpath = arg[0]:match('^%-%-lua=(.*)luametalatex%-init%.lua$')
local ourpath = arg[0]:match('^%-%-lua=(.*[/\\])[^/\\]*%.lua$')
kpse = assert(package.loadlib(ourpath .. 'kpse.so', 'luaopen_kpse'))()
end
do
@ -35,6 +35,7 @@ local read_tfm = require'luametalatex-font-tfm'
local read_vf = require'luametalatex-font-vf'
font.read_tfm = read_tfm
font.read_vf = read_vf
local callback_register = callback.register
require'module'
font.fonts = {}
function font.getfont(id)
@ -51,7 +52,7 @@ function font.define(f)
font.fonts[i] = f
return i
end
callback.register('define_font', function(name, size)
callback_register('define_font', function(name, size)
local f = read_tfm(name, size)
local id = font.define(f)
if status.ini_version then
@ -59,12 +60,26 @@ callback.register('define_font', function(name, size)
end
return id
end)
callback.register('find_log_file', function(name) return name end)
-- callback.register('find_read_file', function(i, name) return kpse.find_file(name, 'tex', true) end)
callback.register('find_data_file', function(name, ...) return kpse.find_file(name, 'tex', true) end)
callback.register('read_data_file', function(name) error[[TODO]]return kpse.find_file(name, 'tex', true) end)
callback_register('find_log_file', function(name) return name end)
do
local function normal_find_data_file(name)
return kpse.find_file(name, 'tex', true)
end
if status.ini_version then
callback_register('find_data_file', function(name)
if name == 'ltexpl.ltx' then
callback_register('find_data_file', normal_find_data_file)
name = 'luametalatex-ltexpl-hook'
end
return normal_find_data_file(name)
end)
else
callback_register('find_data_file', normal_find_data_file)
end
end
callback_register('read_data_file', function(name) error[[TODO]]return kpse.find_file(name, 'tex', true) end)
-- local file_meta = {\
callback.register('open_data_file', function(name)
callback_register('open_data_file', function(name)
local f = io.open(name)
return setmetatable({
reader = function() return f:read() end,
@ -73,13 +88,13 @@ callback.register('open_data_file', function(name)
__gc = function()f:close()end,
})
end)
callback.register('find_format_file', function(name) return kpse.find_file(name, 'fmt', true) end)
callback.register('handle_error_hook', function()
callback_register('find_format_file', function(name) return kpse.find_file(name, 'fmt', true) end)
callback_register('handle_error_hook', function()
repeat
texio.write_nl'? '
local line = io.read()
if not line then
error[[TODO: Handle EOL]]
tex.fatalerror'End of line encountered on terminal'
end
if line == "" then return 3 end
local first = line:sub(1,1):upper()
@ -102,10 +117,9 @@ callback.register('handle_error_hook', function()
\z H for help, X to quit.'
end
until false
-- print('handle')
return 3
end)
callback.register('pre_dump', function()
callback_register('pre_dump', function()
lua.prepared_code[1] = string.format("fixupluafunctions(%i)", fixupluafunctions())
lua.bytecode[1] = assert(load(table.concat(lua.prepared_code, ' ')))
end)

View File

@ -29,6 +29,7 @@ local getexpansion = direct.getexpansion
local getchar = direct.getchar
local rangedimensions = direct.rangedimensions
local traverse_id = direct.traverse_id
local getdata = direct.getdata
local dir_id = node.id'dir'
@ -97,8 +98,6 @@ local function totext(p, fid)
p.font.font = f
return false -- Return true if we need a new textmatrix
end
local inspect = require'inspect'
local function show(t) print(inspect(t)) end
function topage(p)
local last = p.mode
if last == page then return end
@ -218,19 +217,31 @@ function nodehandler.vlist(p, list, x, y0, outerlist, origin, level)
y = y - (d or 0)
end
end
do
local rulesubtypes = {}
for i, n in next, node.subtypes'rule' do
rulesubtypes[n] = i
end
local box_rule = rulesubtypes.box
local image_rule = rulesubtypes.image
local user_rule = rulesubtypes.user
local empty_rule = rulesubtypes.empty
local outline_rule = rulesubtypes.outline
local ship_img = require'luametalatex-pdf-image'.ship
function nodehandler.rule(p, n, x, y, outer)
if getwidth(n) == -1073741824 then setwidth(n, getwidth(outer)) end
if getheight(n) == -1073741824 then setheight(n, getheight(outer)) end
if getdepth(n) == -1073741824 then setdepth(n, getdepth(outer)) end
local sub = getsubtype(n)
if sub == 1 then
if sub == box_rule then
error[[We can't handle boxes yet]]
elseif sub == 2 then
error[[We can't handle images yet]]
elseif sub == 3 then
elseif sub == 4 then
elseif sub == image_rule then
if getwidth(n) <= 0 or getdepth(n) + getheight(n) <= 0 then return end
ship_img(getdata(n), p, n, x, y)
elseif sub == empty_rule then
elseif sub == user_rule then
error[[We can't handle user rules yet]]
elseif sub == 9 then
elseif sub == outline_rule then
error[[We can't handle outline rules yet]]
else
if getwidth(n) <= 0 or getdepth(n) + getheight(n) <= 0 then return end
@ -238,6 +249,7 @@ function nodehandler.rule(p, n, x, y, outer)
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+ ', ' ')
end
end
end
function nodehandler.boundary() end
function nodehandler.disc(p, n, x, y, list, ...) -- FIXME: I am not sure why this can happen, let's assume we can use .replace
for n in traverse(getreplace(n)) do

View File

@ -1,4 +1,9 @@
local rawset = rawset
local setdata = node.direct.setdata
local nodenew = node.direct.new
local getwhd = node.direct.getwhd
local setwhd = node.direct.setwhd
local tonode = node.direct.tonode
local reserve
@ -18,8 +23,8 @@ local boxmap = {
}
-- FIXME:
local function to_sp(bp) return bp*65536//1 end
local function to_bp(sp) return sp/65536 end
local function to_sp(bp) return bp*65781.76//1 end
local function to_bp(sp) return sp/65781.76 end
local function get_box(page, box)
box = boxmap[box]
@ -63,16 +68,12 @@ local function scan_pdf(img)
local page = pdfe.getpage(file, img.page)
local bbox = img.bbox or get_box(page, img.pagebox or 'crop') or {0, 0, 0, 0}
img.bbox = bbox
img.rotation = (page.Rotation or 0) % 360
if img.rotation < 0 then img.rotation = img.rotation + 360 end
if img.rotation % 2 == 0 then
img.rotation = (360 - (page.Rotate or 0)) % 360
assert(img.rotation % 90 == 0, "Invalid /Rotate")
img.rotation = img.rotation / 90
if img.rotation < 0 then img.rotation = img.rotation + 4 end
img.xsize = bbox[3] - bbox[1]
img.ysize = bbox[4] - bbox[2]
else
img.xsize = bbox[4] - bbox[2]
img.ysize = bbox[3] - bbox[1]
end
img.transform = img.transform or 0
end
local pdfe_deepcopy = require'luametalatex-pdfe-deepcopy'
@ -151,11 +152,12 @@ local function scan(img)
scan_pdf(real)
setmetatable(img, restricted_meta)
end
img.transform = img.transform or 0
-- (Re)Set dimensions
if img.depth and img.height and img.width then
return img
end
local flipped = img.transform % 2 == 1
local flipped = (img.transform + real.rotation) % 2 == 1
if not (img.depth or img.height) then img.depth = 0 end
if not img.width and not (img.height and img.depth) then
local total_y
@ -186,42 +188,76 @@ local function scan(img)
return img
end
local img_by_objnum = {}
local function img_from_objnum(objnum, img)
img = img or {}
real_images[img] = assert(img_by_objnum[objnum])
return setmetatable(img, restricted_meta)
end
-- Noop if already reserved
function reserve(img, pfile)
local real = assert(real_images[img])
local obj = real.objnum or pfile:getobj()
real.objnum = obj
return img, obj
img_by_objnum[obj] = real
return obj
end
local function write_img(pfile, img)
local _, objnum = reserve(img, pfile)
local objnum = reserve(img, pfile)
local real = real_images[img]
if not real.written then
real.written = true
write_pdf(real, pfile)
end
end
local function do_img(prop, p, n, x, y, outer)
local img = prop.img
img.height, img.depth, img.width = prop.height, prop.depth, prop.width
scan(img)
local function do_img(data, p, n, x, y)
local img = {}
img_from_objnum(data >> 3, img)
-- scan(img)
write_img(p.file, img)
local real = real_images[img]
local total_height = img.height + img.depth
local mirror = data & 4 == 4
local rotate = (data + img.rotation) % 8
local width, height, depth = getwhd(n)
height = height + depth
local bbox = real.bbox
x, y = to_bp(x - bbox[1]), to_bp(y - img.depth + bbox[2])
p.resources.XObject['Im' .. tostring(real.objnum)] = real.objnum
pdf.write('page', string.format('q 1 0 0 1 %f %f cm /Im%i Do Q', x, y, real.objnum), nil, nil, p)
local xsize, ysize = img.xsize, img.ysize
local a, b, c, d, e, f = 1, 0, 0, 1, -bbox[1], -bbox[2]
if mirror then
a, e = -a, -e+xsize
end
print(img.rotation, rotate, data, a, b, c, d, e, f)
for i=1,rotate do
a, b, c, d, e, f = -b, a, -d, c, -f+ysize, e
xsize, ysize = ysize, xsize
end
print(a, b, c, d, e, f)
local xscale, yscale = width / xsize, height / ysize
a, c, e = a*xscale, c*xscale, e*xscale
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(real.objnum)] = real.objnum
pdf.write('page', string.format('q %f %f %f %f %f %f cm /Im%i Do Q', a, b, c, d, e, f, real.objnum), nil, nil, p)
end
local ruleid = node.id'rule'
local ruletypes = node.subtypes'rule'
local imagerule
for n, name in next, ruletypes do
if name == 'image' then
imagerule = n
break
end
end
assert(imagerule)
local function node(img, pfile)
pfile = pfile or pdf.__get_pfile()
local n = _ENV.node.new('whatsit', 42) -- image
_ENV.node.setproperty(n, {
handle = do_img,
img = img,
})
return n
scan(img)
local n = nodenew(ruleid, imagerule) -- image
setdata(n, (reserve(img, pfile) << 3) | ((img.transform or 0) & 7))
setwhd(n, img.width or -0x40000000, img.height or -0x40000000, img.depth or -0x40000000)
return tonode(n)
end
--[[
@ -237,4 +273,5 @@ return {
scan = scan,
write = write,
node = node,
ship = do_img,
}