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:
parent
602bcb0583
commit
5c45cbc2e3
65
ltexpl.ltx
65
ltexpl.ltx
@ -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'.
|
|
@ -37,7 +37,6 @@ return function(name)
|
|||||||
local setter = tex["set" .. name]
|
local setter = tex["set" .. name]
|
||||||
assert(getter and setter, "direction parameter undefined")
|
assert(getter and setter, "direction parameter undefined")
|
||||||
local idx = token.luacmd(name, set_xdir, "protected", "global", "value")
|
local idx = token.luacmd(name, set_xdir, "protected", "global", "value")
|
||||||
-- names[idx] = name
|
|
||||||
getters[idx] = getter
|
getters[idx] = getter
|
||||||
setters[idx] = setter
|
setters[idx] = setter
|
||||||
return idx
|
return idx
|
||||||
|
@ -136,6 +136,7 @@ end
|
|||||||
local basename = ((1-lpeg.S'\\/')^0*lpeg.S'\\/')^0*lpeg.C((1-lpeg.P'.tfm'*-1)^0)
|
local basename = ((1-lpeg.S'\\/')^0*lpeg.S'\\/')^0*lpeg.C((1-lpeg.P'.tfm'*-1)^0)
|
||||||
return function(name, size)
|
return function(name, size)
|
||||||
local filename = kpse.find_file(name, 'tfm', true)
|
local filename = kpse.find_file(name, 'tfm', true)
|
||||||
|
if not filename then return end
|
||||||
local f = io.open(filename)
|
local f = io.open(filename)
|
||||||
if not f then return end
|
if not f then return end
|
||||||
local buf = f:read'*a'
|
local buf = f:read'*a'
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
do
|
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'))()
|
kpse = assert(package.loadlib(ourpath .. 'kpse.so', 'luaopen_kpse'))()
|
||||||
end
|
end
|
||||||
do
|
do
|
||||||
@ -35,6 +35,7 @@ local read_tfm = require'luametalatex-font-tfm'
|
|||||||
local read_vf = require'luametalatex-font-vf'
|
local read_vf = require'luametalatex-font-vf'
|
||||||
font.read_tfm = read_tfm
|
font.read_tfm = read_tfm
|
||||||
font.read_vf = read_vf
|
font.read_vf = read_vf
|
||||||
|
local callback_register = callback.register
|
||||||
require'module'
|
require'module'
|
||||||
font.fonts = {}
|
font.fonts = {}
|
||||||
function font.getfont(id)
|
function font.getfont(id)
|
||||||
@ -51,7 +52,7 @@ function font.define(f)
|
|||||||
font.fonts[i] = f
|
font.fonts[i] = f
|
||||||
return i
|
return i
|
||||||
end
|
end
|
||||||
callback.register('define_font', function(name, size)
|
callback_register('define_font', function(name, size)
|
||||||
local f = read_tfm(name, size)
|
local f = read_tfm(name, size)
|
||||||
local id = font.define(f)
|
local id = font.define(f)
|
||||||
if status.ini_version then
|
if status.ini_version then
|
||||||
@ -59,12 +60,26 @@ callback.register('define_font', function(name, size)
|
|||||||
end
|
end
|
||||||
return id
|
return id
|
||||||
end)
|
end)
|
||||||
callback.register('find_log_file', function(name) return name 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)
|
do
|
||||||
callback.register('find_data_file', function(name, ...) return kpse.find_file(name, 'tex', true) end)
|
local function normal_find_data_file(name)
|
||||||
callback.register('read_data_file', function(name) error[[TODO]]return kpse.find_file(name, 'tex', true) end)
|
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 = {\
|
-- local file_meta = {\
|
||||||
callback.register('open_data_file', function(name)
|
callback_register('open_data_file', function(name)
|
||||||
local f = io.open(name)
|
local f = io.open(name)
|
||||||
return setmetatable({
|
return setmetatable({
|
||||||
reader = function() return f:read() end,
|
reader = function() return f:read() end,
|
||||||
@ -73,13 +88,13 @@ callback.register('open_data_file', function(name)
|
|||||||
__gc = function()f:close()end,
|
__gc = function()f:close()end,
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
callback.register('find_format_file', function(name) return kpse.find_file(name, 'fmt', true) end)
|
callback_register('find_format_file', function(name) return kpse.find_file(name, 'fmt', true) end)
|
||||||
callback.register('handle_error_hook', function()
|
callback_register('handle_error_hook', function()
|
||||||
repeat
|
repeat
|
||||||
texio.write_nl'? '
|
texio.write_nl'? '
|
||||||
local line = io.read()
|
local line = io.read()
|
||||||
if not line then
|
if not line then
|
||||||
error[[TODO: Handle EOL]]
|
tex.fatalerror'End of line encountered on terminal'
|
||||||
end
|
end
|
||||||
if line == "" then return 3 end
|
if line == "" then return 3 end
|
||||||
local first = line:sub(1,1):upper()
|
local first = line:sub(1,1):upper()
|
||||||
@ -102,10 +117,9 @@ callback.register('handle_error_hook', function()
|
|||||||
\z H for help, X to quit.'
|
\z H for help, X to quit.'
|
||||||
end
|
end
|
||||||
until false
|
until false
|
||||||
-- print('handle')
|
|
||||||
return 3
|
return 3
|
||||||
end)
|
end)
|
||||||
callback.register('pre_dump', function()
|
callback_register('pre_dump', function()
|
||||||
lua.prepared_code[1] = string.format("fixupluafunctions(%i)", fixupluafunctions())
|
lua.prepared_code[1] = string.format("fixupluafunctions(%i)", fixupluafunctions())
|
||||||
lua.bytecode[1] = assert(load(table.concat(lua.prepared_code, ' ')))
|
lua.bytecode[1] = assert(load(table.concat(lua.prepared_code, ' ')))
|
||||||
end)
|
end)
|
||||||
|
@ -29,6 +29,7 @@ local getexpansion = direct.getexpansion
|
|||||||
local getchar = direct.getchar
|
local getchar = direct.getchar
|
||||||
local rangedimensions = direct.rangedimensions
|
local rangedimensions = direct.rangedimensions
|
||||||
local traverse_id = direct.traverse_id
|
local traverse_id = direct.traverse_id
|
||||||
|
local getdata = direct.getdata
|
||||||
|
|
||||||
local dir_id = node.id'dir'
|
local dir_id = node.id'dir'
|
||||||
|
|
||||||
@ -97,8 +98,6 @@ local function totext(p, fid)
|
|||||||
p.font.font = f
|
p.font.font = f
|
||||||
return false -- Return true if we need a new textmatrix
|
return false -- Return true if we need a new textmatrix
|
||||||
end
|
end
|
||||||
local inspect = require'inspect'
|
|
||||||
local function show(t) print(inspect(t)) end
|
|
||||||
function topage(p)
|
function topage(p)
|
||||||
local last = p.mode
|
local last = p.mode
|
||||||
if last == page then return end
|
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)
|
y = y - (d or 0)
|
||||||
end
|
end
|
||||||
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)
|
function nodehandler.rule(p, n, x, y, outer)
|
||||||
if getwidth(n) == -1073741824 then setwidth(n, getwidth(outer)) end
|
if getwidth(n) == -1073741824 then setwidth(n, getwidth(outer)) end
|
||||||
if getheight(n) == -1073741824 then setheight(n, getheight(outer)) end
|
if getheight(n) == -1073741824 then setheight(n, getheight(outer)) end
|
||||||
if getdepth(n) == -1073741824 then setdepth(n, getdepth(outer)) end
|
if getdepth(n) == -1073741824 then setdepth(n, getdepth(outer)) end
|
||||||
local sub = getsubtype(n)
|
local sub = getsubtype(n)
|
||||||
if sub == 1 then
|
if sub == box_rule then
|
||||||
error[[We can't handle boxes yet]]
|
error[[We can't handle boxes yet]]
|
||||||
elseif sub == 2 then
|
elseif sub == image_rule then
|
||||||
error[[We can't handle images yet]]
|
if getwidth(n) <= 0 or getdepth(n) + getheight(n) <= 0 then return end
|
||||||
elseif sub == 3 then
|
ship_img(getdata(n), p, n, x, y)
|
||||||
elseif sub == 4 then
|
elseif sub == empty_rule then
|
||||||
|
elseif sub == user_rule then
|
||||||
error[[We can't handle user rules yet]]
|
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]]
|
error[[We can't handle outline rules yet]]
|
||||||
else
|
else
|
||||||
if getwidth(n) <= 0 or getdepth(n) + getheight(n) <= 0 then return end
|
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+ ', ' ')
|
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
|
end
|
||||||
|
end
|
||||||
function nodehandler.boundary() 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
|
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
|
for n in traverse(getreplace(n)) do
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
local rawset = rawset
|
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
|
local reserve
|
||||||
|
|
||||||
@ -18,8 +23,8 @@ local boxmap = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
-- FIXME:
|
-- FIXME:
|
||||||
local function to_sp(bp) return bp*65536//1 end
|
local function to_sp(bp) return bp*65781.76//1 end
|
||||||
local function to_bp(sp) return sp/65536 end
|
local function to_bp(sp) return sp/65781.76 end
|
||||||
|
|
||||||
local function get_box(page, box)
|
local function get_box(page, box)
|
||||||
box = boxmap[box]
|
box = boxmap[box]
|
||||||
@ -63,16 +68,12 @@ local function scan_pdf(img)
|
|||||||
local page = pdfe.getpage(file, img.page)
|
local page = pdfe.getpage(file, img.page)
|
||||||
local bbox = img.bbox or get_box(page, img.pagebox or 'crop') or {0, 0, 0, 0}
|
local bbox = img.bbox or get_box(page, img.pagebox or 'crop') or {0, 0, 0, 0}
|
||||||
img.bbox = bbox
|
img.bbox = bbox
|
||||||
img.rotation = (page.Rotation or 0) % 360
|
img.rotation = (360 - (page.Rotate or 0)) % 360
|
||||||
if img.rotation < 0 then img.rotation = img.rotation + 360 end
|
assert(img.rotation % 90 == 0, "Invalid /Rotate")
|
||||||
if img.rotation % 2 == 0 then
|
img.rotation = img.rotation / 90
|
||||||
|
if img.rotation < 0 then img.rotation = img.rotation + 4 end
|
||||||
img.xsize = bbox[3] - bbox[1]
|
img.xsize = bbox[3] - bbox[1]
|
||||||
img.ysize = bbox[4] - bbox[2]
|
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
|
end
|
||||||
|
|
||||||
local pdfe_deepcopy = require'luametalatex-pdfe-deepcopy'
|
local pdfe_deepcopy = require'luametalatex-pdfe-deepcopy'
|
||||||
@ -151,11 +152,12 @@ local function scan(img)
|
|||||||
scan_pdf(real)
|
scan_pdf(real)
|
||||||
setmetatable(img, restricted_meta)
|
setmetatable(img, restricted_meta)
|
||||||
end
|
end
|
||||||
|
img.transform = img.transform or 0
|
||||||
-- (Re)Set dimensions
|
-- (Re)Set dimensions
|
||||||
if img.depth and img.height and img.width then
|
if img.depth and img.height and img.width then
|
||||||
return img
|
return img
|
||||||
end
|
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.depth or img.height) then img.depth = 0 end
|
||||||
if not img.width and not (img.height and img.depth) then
|
if not img.width and not (img.height and img.depth) then
|
||||||
local total_y
|
local total_y
|
||||||
@ -186,42 +188,76 @@ local function scan(img)
|
|||||||
return img
|
return img
|
||||||
end
|
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
|
-- Noop if already reserved
|
||||||
function reserve(img, pfile)
|
function reserve(img, pfile)
|
||||||
local real = assert(real_images[img])
|
local real = assert(real_images[img])
|
||||||
local obj = real.objnum or pfile:getobj()
|
local obj = real.objnum or pfile:getobj()
|
||||||
real.objnum = obj
|
real.objnum = obj
|
||||||
return img, obj
|
img_by_objnum[obj] = real
|
||||||
|
return obj
|
||||||
end
|
end
|
||||||
|
|
||||||
local function write_img(pfile, img)
|
local function write_img(pfile, img)
|
||||||
local _, objnum = reserve(img, pfile)
|
local objnum = reserve(img, pfile)
|
||||||
local real = real_images[img]
|
local real = real_images[img]
|
||||||
if not real.written then
|
if not real.written then
|
||||||
real.written = true
|
real.written = true
|
||||||
write_pdf(real, pfile)
|
write_pdf(real, pfile)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local function do_img(prop, p, n, x, y, outer)
|
local function do_img(data, p, n, x, y)
|
||||||
local img = prop.img
|
local img = {}
|
||||||
img.height, img.depth, img.width = prop.height, prop.depth, prop.width
|
img_from_objnum(data >> 3, img)
|
||||||
scan(img)
|
-- scan(img)
|
||||||
write_img(p.file, img)
|
write_img(p.file, img)
|
||||||
local real = real_images[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
|
local bbox = real.bbox
|
||||||
x, y = to_bp(x - bbox[1]), to_bp(y - img.depth + bbox[2])
|
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
|
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)
|
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
|
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)
|
local function node(img, pfile)
|
||||||
pfile = pfile or pdf.__get_pfile()
|
pfile = pfile or pdf.__get_pfile()
|
||||||
local n = _ENV.node.new('whatsit', 42) -- image
|
scan(img)
|
||||||
_ENV.node.setproperty(n, {
|
local n = nodenew(ruleid, imagerule) -- image
|
||||||
handle = do_img,
|
setdata(n, (reserve(img, pfile) << 3) | ((img.transform or 0) & 7))
|
||||||
img = img,
|
setwhd(n, img.width or -0x40000000, img.height or -0x40000000, img.depth or -0x40000000)
|
||||||
})
|
return tonode(n)
|
||||||
return n
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
@ -237,4 +273,5 @@ return {
|
|||||||
scan = scan,
|
scan = scan,
|
||||||
write = write,
|
write = write,
|
||||||
node = node,
|
node = node,
|
||||||
|
ship = do_img,
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user