STM publishing: tools, technologies and change A WordPress site for STM Publishing

1Dec/11Off

Creating PDF pattern fills with LuaTeX nodes

Introduction

This is a short example to introduce two very useful LuaTeX API functions which let you work with low-level PDF objects. Here we'll use them to explore a PDF feature called pattern fills which (from the PDF specification) are a way to

"... apply “paint” that consists of a repeating graphical figure or a smoothly varying color gradient instead of a simple color. Such a repeating figure or smooth gradient is called a pattern. Patterns are quite general, and have many uses; for example, they can be used to create various graphical textures, such as weaves, brick walls, sunbursts, and similar geometrical and chromatic effects"

I'm not going to attempt any explanation of pattern fills because the PDF specification explains them, and their many options, in great detail. Hopefully, these small code examples will be helpful should you want to explore using them in your work with LuaTeX.

LuaTeX API

Here are the functions we'll be using:

pdf.immediateobj(...)
Quoting from The LuaTeX Reference Manual: This function creates a pdf object and immediately writes it to the pdf file. It is modelled after pdfTEX's \immediate\pdfobj primitives. All function variants return the object number of the newly generated object.

  • n = pdf.immediateobj( objtext)
  • n = pdf.immediateobj("file", filename)
  • n = pdf.immediateobj("stream", streamtext, attrtext)

pdf.pageresources =...
This lets you add named resources to the page /Resources dictionary so that they can be used within page content streams.

In outline...

There are two parts to the approach:

  1. Writing the appropriate pattern fill objects and data to the PDF file.
  2. Creating a pdf_literal node to use our newly defined pattern fills.

The code

Here's the \directlua code with in-line comments.

\directlua{
% If you want to quickly view the LuaTeX PDF data in a text editor you should 
% set the compression level to 0. 
tex.pdfobjcompresslevel=0

% We'll use the object number o to store the object reference in the page /Resources dictionary.
o = pdf.immediateobj("[/Pattern /DeviceRGB] ")

% Here we use pdf.immediateobj(...) write the data which actually defines the pattern fill. 
% We'll use the object number n to store the object reference in the page /Resources dictionary.
 
n = pdf.immediateobj("stream", "1 J
.5 w
1 1 4 4 re 5 5 3 3 re f", "/Type /Pattern
/PatternType 1
/PaintType 2
/TilingType 1
/BBox [0 0 10 10]
/XStep 5
/YStep 5
/Resources << >>")

% Here we add the appropriate named resources (for the pattern  fill) to the page /Resources dictionary so
% that we can use the pattern fill in content streams within any page.

pdf.pageresources =  "/Pattern << /P1 "..n.." 0 R >> /ColorSpace << /Cs12 "..o.." 0 R >> "

% Here we create a pdf_literal node which simply draws a box (0 0 12 12  re)
% and fills it using our pattern. Note that if you omit the q ... Q construct to save and 
% restore then the pattern fill will affect other content on your page, with very strange
% results...

pdfdata = node.new("whatsit","pdf_literal")
pdfdata.mode=0
pdfdata.data=" q 0 0 12 12  re  /Cs12 cs 0.77 0.20 0.00 /P1 scn f Q"

% Package our pdf_literal into a box so that we can use it with TeX
% code such as \copy999

tex.box[999]= node.vpack(pdfdata)
}

Full example minus comments

\pdfoutput=1
\pdfcompresslevel=0
\hoffset-1in
\voffset-1in
\pdfpageheight=200mm
\pdfpagewidth=300mm
\vsize=100mm
\hsize=200mm

\directlua{
tex.pdfobjcompresslevel=0

o = pdf.immediateobj("[/Pattern /DeviceRGB] ")

n = pdf.immediateobj("stream", "1 J
.5 w
1 1 4 4 re 5 5 3 3 re f", "/Type /Pattern
/PatternType 1
/PaintType 2
/TilingType 1
/BBox [0 0 10 10]
/XStep 5
/YStep 5
/Resources << >>")

pdf.pageresources =  "/Pattern << /P1 "..n.." 0 R >> /ColorSpace << /Cs12 "..o.." 0 R >> "

pdfdata = node.new("whatsit","pdf_literal")
pdfdata.mode=0
pdfdata.data=" q 0 0 12 12  re  /Cs12 cs 0.77 0.20 0.00 /P1 scn f Q"

tex.box[999]= node.vpack(pdfdata)
}

Hip \copy999 Hip Hooray \copy999

\bye

Resulting PDF

You can download the PDF output from the above example. It displays OK with my version of Adobe Reader (8.2.1 for Windows) and Evince (2.28 for Windows).