I like to clip an arbitrary TeX box (\hbox
) but without using larger graphic related packages like PGF/TikZ or PSTricks. This is intended to be used in packages which should not force the user to also load one of that packages.
Here I mean the same as the clip
option (together with viewport
or trim
) of \includegraphics
does: some outer material is not displayed any longer. I just want to apply this to a TeX box. I realize that this is output driver dependent. I found a pdftex
solution already which uses PDF commands.
I'm now looking for a DVI/PS solution, i.e. some \special
instructions which clip a Tex box. Any hints about other drivers are very welcome.
I need this for two of my packages gincltex
and adjustbox
, which both extend the features of \includegraphics
to arbitrary TeX boxes.
What I do at the moment I simply use PGF for this: I place the content in a node and clip the picture accordantly. Because the content is boxed I can calculate the required size beforehand.
So basically I'm looking for the low level definition of a macro like:
\@clipbox{<llx>}{<lly>}{<urx>}{<ury>}{<boxnumber>}
which accepts a previously saved box and clips the four amounts from that box (ll
= lower left, ur
= upper right).
For pdftex
I found the related code in $TEXMF/tex/latex/pdftex-def/pdftex.def
(driver file for graphics
) which tells me trim the box first using normal TeX commands (i.e. to \lower
and \hskip
the lower left margin and to limit the box height (\ht
) and width (\wd
) dependent on the upper right corner. The depth \dp
is there set to zero for images, but I have to handle that differently.). After that it uses the following low level macros to actually clip the box:
\pdfxform<boxnumber>
\pdfrefxform\pdflastxform
I imagine that for DVI-mode (dvps
driver) I need a PostScript \special
command to do the same. How would such a command look like? Any ideas about a dvipdf
solution?
Best Answer
Both Herbert and Alexander have offered solutions for dvips. Here, I'm taking inspiration from those answers plus the more convenient approach available in pdfTeX, plus a modified version of the
pgf
method for XeTeX, and combining into a single approach. First, note that I'm assuming e-TeX and also using a somewhat 'LaTeX3-like' programming approach. I've also shared as much code as possible.I'll use a single example but add comments along the way. First, as there are packages for the driver detections I'll load those.
The main internal macro takes five arguments: the box to modify, then four dimension expressions to be clipped off the left, bottom, right and top respectively. You could also set up a similar approach to take a final size. The idea here is that the baseline is respected if possible, so there is a bit of care needed with the vertical placement so that the content only moves down while there is some depth available.
For each driver supported, there is an auxiliary. First, for dvips this is Herbert's method slightly altered (
pgf
makes things very complex):As I said, pdfTeX makes life very easy :-)
XeTeX is possibly the most complex one to tackle. The
pgf
approach is used, but here I've removed a lot of unnecessary transformations. After reading the dvipdfmx manual, it becomes clear that the best approach is as followsThe first special saves the current point and starts a new 'graphics level'. Using the
bcontent
operation saves the current location automatically.Draw a rectangle the size of the modified box: in
pgf
this is done using the lower-levelm
,l
andh
operations, but there is no gain in working that way. This will be located at 'current point' TeX-wise.The
W
operation specifies a clip, andn
finalises the path without any output (it's a 'no-op').Insert the box and tidy up.
A simple conversion taken from Is there a command to convert cm to bp?
Wrap everything up in a user macro and finish the code block
Now for some testing.
(I'll be adding this to LaTeX3 now I know how it works!) If you want to see the effect of various parts of the XeTeX code, comment out the
W
line to turn off the clipping. You can also replace then
operations bys
so that you get a box where the clipping path is.In earlier versions of the answer, for XeTeX I used the
content q
operation to save the current location, but this requires a series of manipulations to get the clip path and the box insert to line up. Using thebcontent
...econtent
pair is much clearer.While using the XForm implementation for pdfTeX is convenient, in a case where code is to be shared between branches an alternative approach is possible. (The above could be viewed as an abuse of the XForm object system in any case).
The zero width box here is used to keep placement correct in the
\pdfsave
/\pdfrestore
pair (which perform the same task as thebcontent
/econtent
pair for XeTeX but which should be places in the same output position.)