Linux ip-172-26-7-228 5.4.0-1103-aws #111~18.04.1-Ubuntu SMP Tue May 23 20:04:10 UTC 2023 x86_64
Your IP : 18.218.63.176
#!/usr/bin/env texlua
local options = {
pdfoutput=true,
redoall=false,
multipicfile=false,
noborder=false,
dotypesetting=true,
nopostprocess=false,
}
local usagetext = 'Usage: cachepic [options] latexfile'
local tryhelp = "Try `cachepic --help' for more information"
local helptext = [[
Options start with '-' or '--' and can be any of:
-pdf output in (e)pdf format (default)
-eps output in eps format
-all regenerate all graphics
-multi all graphics in one file (implies -pdf)
-tight no 0.5bp margin around the graphic
-notex no typesetting, only graphic postprocessing
-nopic generate no graphics, only .cachepic file
-usage display usage message
-help,-h,-? display help message]]
local msg = {
MultipleInputFiles = "cannot process multiple files:\t%s\t%s",
NoInputFile = "no input file given\n" .. tryhelp,
UnknownOption = "unknown option: %s\n" .. tryhelp,
FileOpenFailed = "could not open file: %s",
NoGhostScript = "could not locate ghostscript interpreter",
WrongOutputMode = "expected %s output but got %s",
NoPreviews = "no cachepic previews found",
MultiPicOnlyInPDF = "option '-multi' for all graphics in one file supported only in pdf mode"
}
function die(msgfmt, ...)
error(string.format(msgfmt, ...))
end
function warn(msgfmt, ...)
print('warning: ' .. string.format(msgfmt, ...))
end
local function qfile(filename)
filename = string.gsub(filename, '"', '')
if string.find(filename, "[%s%&%(%)%[%]%{%}%^%=%;%!%'%+%,%`%~]") then
filename = '"' .. filename .. '"'
end
return filename
end
local function syscall(command)
print('system: ' .. command)
local ret = os.execute(command)
if ret > 0 then os.exit(ret)
else return ret end
end
local function copyfile(src, dst)
print('copy ' .. qfile(src) .. ' ' .. qfile(dst))
local buffer, bufsize = '', 1024
local fin = io.open(src, 'rb')
if not fin then die(msg.FileOpenFailed, src) end
local fout = io.open(dst, 'wb')
if not fout then die(msg.FileOpenFailed, dst) end
while buffer do
fout:write(buffer)
buffer = fin:read(bufsize)
end
fin:close()
fout:close()
end
local isfile = lfs and lfs.isfile or function (fname)
-- if we are not running under texlua, then do it the hard way
local fh = io.open(fname)
return (fh and (fh:close() or true) or false)
end
local function whichfile(fname, path)
if isfile(fname) then return fname end
-- make the best guess if it is Windows or Unix
local dirsep, pathsep = '/', ':'
if (os.type == 'windows') or string.find(path, '\\') or string.find(path, ';') then
dirsep, pathsep = '\\', ';' -- Windows
end
-- iterate path
for dir in string.gmatch(path, '[^' .. pathsep .. ']+') do
local f = dir .. dirsep .. fname
-- print(f)
if isfile(f) then return f end
end
return nil
end
local function findgs()
local path = os.getenv('PATH')
for _, fname in ipairs{'gs', 'gswin32c.exe', 'mgs.exe'} do
if whichfile(fname, path) then return fname end
end
die(msg.NoGhostScript)
end
-- Process options --
if #arg == 0 then
print(usagetext)
print(tryhelp)
os.exit(0)
end
local filename = nil
for _, argn in ipairs(arg) do
local opt, num = string.gsub(argn, '^%-%-?', '')
if num == 0 then -- not an option
if filename then die(msg.MultipleInputFiles, filename, opt)
else filename = opt end
elseif opt == 'eps' then options.pdfoutput = false
elseif opt == 'pdf' then options.pdfoutput = true
elseif opt == 'all' then options.redoall = true
elseif opt == 'multi' then options.multipicfile = true
elseif opt == 'tight' then options.noborder = true
elseif opt == 'notex' then options.dotypesetting = false
elseif opt == 'nopic' then options.nopostprocess = true
elseif (opt == 'usage') or (opt == 'help') or (opt == 'h') or (opt == '?') then
print(usagetext)
if opt == 'usage' then os.exit(0) end
print(helptext)
os.exit(0)
else die(msg.UnknownOption, argn) end
end
if not filename then
die(msg.NoInputFile)
end
if options.multipicfile and not options.pdfoutput then
warn(msg.MultiPicOnlyInPDF)
options.multipicfile = false
end
filename = string.gsub(filename, '\\', '/')
local noextname = string.gsub(filename, '%.[^./]*$', '')
local jobname = string.match(noextname, '[^/]+$')
local jobsuffix = (options.dotypesetting and '_cptmp' or '')
local multipicfilename = noextname .. '-cachepic.pdf'
-- Typeset document --
if options.dotypesetting then
local engine = (options.pdfoutput and 'pdflatex' or 'latex')
local psfixbb = (options.pdfoutput and '' or ',psfixbb')
local noborder = (options.noborder and ' \\PreviewBorder=0pt' or '')
local redoall = (options.redoall and ' \\makeatletter\\def\\cachepic@tryincludepic#1#2{\\xdef\\cachepic@name{#1}#2}\\makeatother' or '')
local command = engine .. ' -interaction=nonstopmode -jobname=' .. jobname .. jobsuffix ..
' \\def\\jobname{' .. jobname .. '}' ..
' \\RequirePackage[active,tightpage,delayed,cachepic' .. psfixbb .. ']{preview}' ..
noborder .. redoall .. ' \\input{' .. qfile(filename) .. '}'
syscall(command)
end
-- Process log file --
local iLines = io.lines(noextname .. jobsuffix .. '.log')
local pics = {}
local pdfmode = options.pdfoutput
local trim = '0 0 0 0'
for line in iLines do
local head, c1, c2, c3, c4, c5 = string.match(line,
'^Preview:%s*([A-Za-z]+)%s*(%-?%d*)%s*(%-?%d*)%s*(%-?%d*)%s*(%-?%d*)%s*(.*)')
if head == 'PDFoutput' then
pdfmode = (tonumber(c1) ~= 0)
elseif (head == 'Tightpage') and c1 and c2 and c3 and c4 then
trim = string.format('%dsp %dsp %dsp %dsp',
-tonumber(c1), -tonumber(c2), tonumber(c3), tonumber(c4))
elseif (head == 'CachePic') and c1 and c2 and c3 and c4 and c5 then
local picname = c5
local picpage = tonumber(c1)
local baseline = tonumber(c4) or 0
local texmacro = string.format('\\CachePicDefMacro{%s}{%d}{trim=%s}{%dsp}',
picname, picpage, trim, -baseline)
pics[#pics+1] = {name=picname, page=picpage, macro=texmacro}
end
end
if #pics == 0 then
warn(msg.NoPreviews)
return
end
if pdfmode ~= options.pdfoutput then
local expectedmode = options.pdfoutput and 'pdf' or 'dvi'
local actualmode = pdfmode and 'pdf' or 'dvi'
die(msg.WrongOutputMode, expectedmode, actualmode)
end
-- Write out cachepic macros --
io.output(noextname .. '.cachepic')
for i = 1, #pics do
io.write(pics[i].macro, '\n')
end
io.close()
if options.nopostprocess then return end
-- Postprocess pics --
if options.multipicfile then
if options.pdfoutput then
-- without option -all the file size will slowly grow
-- extra run through GhostScript seems to prevent that
-- but it degrades raster graphics or makes them much larger
-- no perfect solution it seems
copyfile(noextname .. jobsuffix .. '.pdf', multipicfilename)
else die(msg.MultiPicOnlyInPDF) end -- this should never happen
else
local ext, cmdtmpl
if options.pdfoutput then
ext = '.pdf'
filename = qfile(noextname .. jobsuffix .. '.pdf')
cmdtmpl = findgs() ..
' -sDEVICE=pdfwrite -dQUIET -dBATCH -dNOPAUSE -dCompatibilityLevel=1.4' ..
' -dFirstPage=%s -dLastPage=%s -sOutputFile=%s %s'
else
ext = '.eps'
filename = qfile(noextname .. jobsuffix .. '.dvi')
cmdtmpl = 'dvips -E -p %s -l %s -o %s %s'
end
for i = 1, #pics do
local outfile = string.gsub(pics[i].name, '"', '') .. ext
if not isfile(outfile) or options.redoall then
outfile = qfile(outfile)
syscall(string.format(cmdtmpl, pics[i].page, pics[i].page, outfile, filename))
end
end
end
--[[-- GS options preventing lossy image recompression
' -dMonoImageFilter=/CCITTFaxEncode' ..
' -dAutoFilterColorImages=false -dColorImageFilter=/FlateEncode' ..
' -dAutoFilterGrayImages=false -dGrayImageFilter=/FlateEncode' ..
]]
|