I'm trying to see how far I can use the pure Lua interface of luatex to format my document. To do so, I'd like to know if it's possible to trim/crop a picture in pure lua. I tried the img library of lualatex, but it seems that bbox works only on pdf...

Thank you!



  local a = img.write({ filename = "simpson.jpg"; width="5cm"
    % Trim/clip ?

-- EDIT -- I tried the following code, but the output pdf contains 0 pages.

local image_fixed = img.scan({filename = "simpson.jpg"})
local image     = img.copy(image_fixed)

local a=node.new("whatsit","pdf_literal")
pdf_save = node.new("whatsit","pdf_save")
pdf_restore = node.new("whatsit","pdf_restore")

a.data = string.format("%g %g m %g %g l %g %g l %g %g l W n ",10,10,20,10,20,20,10,20)
i = img.node(image)

By the way, I'm not sure which unit I should use in the a.data, neither what are exactly these special whatsit nodes...

--EDIT 2--

Thank you for your code. It works great, and I just have some troubles to understand why I need these three pdf_* nodes, but at least it seems to work, and I also understood that the unit are inches/72. I just have some troubles to understand why the picture takes more place than expected. For example, if I wrap the \directlua code into \tcbox{...} (loaded with \usepackage[most]{tcolorbox}), the picture takes lot's of space, for a very small picture:

enter image description here

Thank you!

  • You must use PDF operators to crop an image. W clips an image, in conjunction with pdf_save and pdf_restore you can save the current position in the PDF. See github.com/speedata/publisher/blob/develop/src/lua/publisher/… for example.
    – topskip
    Nov 13, 2017 at 9:43
  • BTW: you are asking two questions here. Consider splitting this into two distinct questions.
    – topskip
    Nov 13, 2017 at 13:09
  • Thank your for your answer, I removed the second question. However I'm not sure to see how to use the code you linked. The image must be converted into PDF, or it's supposed to be already a PDF object? I've basically very few knowledge about how PDF work, so a minimal working example that crop a picture would be great... I tried to read the documentation, but there are (litterally) two lines on pdf_restore and pdf_save : luatex.org/svn/trunk/manual/luatex.pdf
    – tobiasBora
    Nov 15, 2017 at 18:21
  • @topskip I tried some code, but the output is empty. (see edited question)
    – tobiasBora
    Nov 15, 2017 at 18:57
  • To answer the question raised in edit 2: the pdf_literal just changes the viewport of the image, not the image itself. So you probably see the complete image clipped to a small area. If you leave out the line with the pdf_literal.data = ... the image doesn't get cropped. You have to put it into a box (hbox or vbox) and resize that box. (Use a follow-up question, this gets a bit cluttered...)
    – topskip
    Nov 15, 2017 at 20:32

1 Answer 1


I've split the file into a TeX and a Lua part. The “driver”



and the Lua file (foo.lua - adjust the file name of course):

local myimg = img.scan({filename = "hacker.jpg"; width="5cm"})
local imgnode = img.node(myimg)

local pdf_save = node.new("whatsit","pdf_save")
local pdf_restore = node.new("whatsit","pdf_restore")
local pdf_literal = node.new("whatsit","pdf_literal")

-- all in DTP points (1/72 inches)
local x,y,wd,ht = 10, 10, 30, 50

-- This creates a rectangle and uses it (W) as a clipping path.
-- Try S instead of n to see the path
pdf_literal.data = string.format("%g %g m %g %g l %g %g l %g %g l W n ",x,y,x + wd,y,x + wd,y + ht,x,y + ht)

local box = node.hpack(pdf_save)
box.depth = 0
box = node.vpack(box)

local glu1 = node.new("glue")
local glu2 = node.new("glue")

glu1.width = -x * 2^16
glu1 = node.insert_after(glu1,glu1,box)
box = node.hpack(glu1)

glu2.width = -myimg.height  + ( ht + y ) * 2^16
glu2 = node.insert_after(glu2,glu2,box)
box = node.vpack(glu2)

box.height = ht * 2^16
box.width =  wd * 2^16
box.depth = 0


This creates a few boxes around the pdf_* whatsits and inserts glue to shift the contents up and to the left.

One has to be aware that there are two layers here. The TeX layer and the PDF layer, and none of each has any knowledge of each other. The PDF layer is to clip the image to a given path. TeX does not understand the PDF operators, so TeX thinks that you insert the complete image. You have to move the image by inserting negative glue or negative kerns at the top and to the left and you have to change the box size, so the cropped image appears at the correct position.

There are other ways to do that, but they don't differ too much from this approach.

BTW: the units are in DTP points (1/72 inch, the pdf_* whatsit nodes) and in TeX points (1/72.27 in), so you must convert between them. I ignore the difference in the calculation below.

the scaled image

What I have done above is to create LuaTeX “nodes” that gets passed to TeX. The node list looks like this (click to enlarge):

enter image description here

You can read this from the bottom right to the top left (inner to outer). The last node is the image (technically a rule node), I prepend the pdf_literal to create a viewport. Around that I add a vbox with pdf_save and pdf_restore to keep the PDF position intact. Then I insert glues to shift the image to the left and up and the result that gets passed to TeX is the vbox that contains all of this.

  • Thank you for your code! However do you know why the picture takes lot's of space, even if the picture is small? I put some screenshot in my edited answer. Thanks again!
    – tobiasBora
    Nov 15, 2017 at 19:47
  • Thank you very much! It's a bit clearer now, even if I still need to read some stuff to clearly understand some parts, but it's clearer now. Thank you very much!
    – tobiasBora
    Nov 16, 2017 at 8:55
  • Just keep on asking question, @tobiasBora. Just mention me somewhere in the comments, so I'll see the question. I'll post a graph of the created nodes once I fix a bug in my software, so expect an edit on my answer during the day.
    – topskip
    Nov 16, 2017 at 10:56

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .