7

I am writing (contributing to) a LuaLaTeX package where a Lua function is used to generate images that are inserted in the LaTeX document.

One piece of information we need is the current page number to determine if we're on an odd or even page (I know that this is not that trivial, and I know about some strategies beyond \thepage). We set a Lua variable when we're still in the LaTeX part, and so far this works pretty well.

However, now it turns out that the sequence of images we create may be distributed on several pages, and we would really like to reflect that because our images may behave differently on odd and even pages.

Basically what we have is a series of

tex.print('\\includegraphics{something}\\par')

statements, executed in a loop within one Lua function.

Now the question: is there any way to either directly detect a page change between two such graphics or repeatedly retrieve the current page within such a loop?

All the solutions I have found for determining current odd or even state are in LaTeX itself. I know how to use \directlua to retrieve a value for use in LaTeX, but is there a way to do the opposite - retrieve a LaTeX value from within LUa?

Edit: to respond to TeXnician's comment and answer: When I modify the example code so it produces repetitions of paragraphs it seems that the page counter won't get updated within one Lua chunk:

\documentclass{article}

\newcommand\printluapage{%
    \directlua{for i = 1, 60 do tex.print(tex.count['c@page']) 
        tex.print([[\par]]) end}
}

\begin{document}
\printluapage

New command

\printluapage

New command

\printluapage
\end{document}

The page number is only updated with each new call of \printluapage.

  • Are you satisfied by reading the page counter of LaTeX directly in Lua or should it be more "correct"? – TeXnician Feb 21 '18 at 16:45
  • 3
    even without lua you really need \pageref or equivalent. consider a long 5-page paragraph, the page counter will not increase until the entire paragraph has been set. During the evaluation of every macro (and every \directlua) within the paragraph the page counter will have the value it had at the start. – David Carlisle Feb 21 '18 at 19:17
8

You can almost never accurately reference the page counter from within the main document, only during the output routine where the page being shipped out is accurately known. Luatex does not change the basic model of the way TeX pages are output so the same applies in luatex.

In your lua loop you can use

mcount=mycount+1
tex.print('\\includegraphics{something}\\label{graphic-' .. mycount .. '}\\par')

Then every image will have a \label associated to it and on the next run you can pick up \pageref{graphic-5} (from Lua or TeX) which will tell you which page the 5th graphic ended up on.

a full example:

enter image description here

\documentclass{article}
\directlua{j=0}
\newcommand\printluapage{%
    \directlua{
for i = 1, 60 do
 j=j+1
 tex.print('\string\\pageref{foo' .. j .. '}\string\\label{foo' .. j .. '}') 
 tex.print([[\par]]) end}%
}

\begin{document}
\printluapage

New command

\printluapage

New command

\printluapage
\end{document}
  • Thank you for the clear and concise explanation. Maybe we will go that route (or try to avoid the complication by limiting the functionality ...). At least we don't have to resort to an arbitrary counter because our images already have hash filenames that can be used as labels. – uli_1973 Feb 21 '18 at 22:49
4

This is a very basic solution which just reads the value of the LaTeX counter page in Lua (printing is for testing, but the tex.count statement can be used at other places as well).

\documentclass{article}

\newcommand\printluapage{%
    \directlua{tex.print(tex.count['c@page'])}
}

\begin{document}
    \printluapage\clearpage\printluapage\clearpage\printluapage\clearpage\printluapage\clearpage\printluapage\clearpage\printluapage\clearpage\printluapage\clearpage\printluapage\clearpage\printluapage\clearpage\printluapage\clearpage\printluapage\clearpage\printluapage\clearpage\printluapage\clearpage\printluapage\clearpage\printluapage\clearpage\printluapage\clearpage\printluapage\clearpage\printluapage\clearpage\printluapage\clearpage\printluapage\clearpage\printluapage\clearpage\printluapage\clearpage\printluapage\clearpage\printluapage\clearpage
\end{document}
  • Thank you, this gives me at least a partial understanding of how I can access \thepage from Lua. However, this shows that I actually have a problem with my approach: at least like this the page counter seems not to change within one Lua chunk. I edit the question to show an example. – uli_1973 Feb 21 '18 at 17:13
4

There are two complications here.

Firstly, every call to \directlua runs immediately, so if you want TeX's usual processing to happen, you need to relinquish control to TeX (and use coroutines or something). So when you have

\directlua{for i = 1, 60 do tex.print(tex.count['c@page']) 
    tex.print([[\par]]) end}
}

as in the question, this simply puts 60 instances of 42 (or whatever the page number is) and \par on TeX's input stack, for TeX to read next after the entire \directlua call is done. (It doesn't result in TeX processing each \par and the rest of typesetting immediately, even before the loop ends.) Your exact problem is discussed, with solutions, at this question: Concurrently interleaving execution of Lua and TeX in LuaTeX.

Secondly, TeX simply appends items to its vertical lists until a page break becomes inevitable (e.g. there's no possible way to put all the so-far collected material on a single page), so the value of the page counter at the time the material is added isn't necessarily the page that it will end up on (it may end up on the next page for example). The page number is only finally determined when boxes are being shipped out. There are some tricks for dealing with this fact (e.g. have your Lua code run during shipout?), but I don't know these tricks; maybe someone else will answer. :-)

You can get some approximate results by using quantities like \pagetotal (or from Lua, tex.pagetotal) which shows how much material has been added to the current page. This is subject to caveats: the first point above about letting TeX do its thing (splitting your Lua code across different calls to \directlua), and also you may need to deal with shrinkable and stretchable glue, and account for them.

  • Thank you, this is interesting. Unfortunately it's also somewhat discouraging. The question you link to includes a link to tex.execute() as a feature request. It's a pity that this request from 2011 still seems to be open ... – uli_1973 Feb 21 '18 at 17:43
  • ad 1. is it possible to determine the remaining vertical space on a page when entering the Lua code (I'm afraid not). If that would be the case we could try some heurisitic approach since we do know the height of our generated images. – uli_1973 Feb 21 '18 at 17:45
  • @uli_1973 Yes indeed, it's possible to (approximately) determine the remaining vertical space on a page. I just remembered I did something like that for this huge answer, by comparing tex.pagetotal (what's been added to the page) against tex.vsize (the size at which TeX is going to try to break the page). That answer was tested only with straightforward paragraphs of text, so I suspect this crude approach misses a lot of cases e.g. in the presence of floats, and there may be something even better. – ShreevatsaR Feb 21 '18 at 17:52
  • @uli_1973 See the answer by David Carlisle — that's the “official”/expert answer, which should solve your problem (I think). – ShreevatsaR Feb 21 '18 at 19:42
4

The problem of interleaving is partly solved in ConTeXt. You can access the page number from within Lua and it is updated at some point but the problem David described in his comment persists.

\starttext

\startluacode
for i = 1, 60 do
    context(context.currentpage) 
    context.par()
end
\stopluacode

\stoptext

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.