Creating reusable content (iText 5)

In this section, we’ll discuss two types of reusable content: Images and PdfTemplate objects.

Do you remember section 2.3.3 about the Image object? In an FAQ, I explained that you can add the same image to a document more than once, but that you should reuse the same Image instance if you want to avoid the image bytes being added more than once. In normal circumstances, the bits and bytes of an image are stored in separate stream objects in the PDF file. Pages that contain such an image refer to this external object. Such an object is also known as an XObject.

An external object (XObject) is an object defined (in ISO-32000-1, section 8.2) outside the content stream and referenced as a named resource. The interpretation of an XObject depends on its type. An image XObject defines a rectangular array of color samples to be painted; a form XObject is an entire content stream to be treated as a single graphics object.

There are other types of XObjects, but image and form XObjects are the most important ones.

Image XObjects

You’ve already worked with image XObjects when you added Images to a Document. In figure 3.2, you saw that iText adds these images under the text objects for which you’ve used document.add(). But what if you want to add an image on top of the text?

ADDING AN IMAGE TO THE TOP LAYER


Figure 3.15 shows a PDF document that resembles the one shown in figure 3.1. The code to create it is in listing 3.23. The Paragraph "Foobar Film Festival" was added to the Document, but the text is covered by an Image. Note that the text is present in the content stream: if you look closely at figure 3.15, you can see that I was able to select the text. If I copied the content to the clipboard, it would read: "Foobar Film Festival". Adobe Reader also offers to look up the word "Foobar".

Image covering text

Figure 3.15 Image covering text

Listing 3.23 ImageDirect.java

Listing 3.23 ImageDirect.java

If you look inside the PDF, you’ll see the following PDF syntax:

tmp17C130_thumb

The part between the first q/Q sequence is responsible for drawing the words "Foobar Film Festival". The part between the second q/Q changes the current transformation matrix (CTM). Using the Do operator, you add an image of 232 by 362 user space units at position x = 25.5 and y = 27. The content of the image (the bits and bytes) are kept outside the content stream.

Each page has a page dictionary with numerous key-value pairs. The value corresponding to the /Resources key will tell you where to find the resources that are used in the page:

tmp17C131_thumb

As you can see, there’s an entry for XObjects, and it tells you that /img0 can be found in object 1: the stream containing the image bytes. Note that I omitted some of the other types of resources, such as references to the fonts that were used.

In the previous topic, you learned how to translate, scale, and rotate Image objects, but adding an image to the direct content gives you more power: using the CTM, you can create any two-dimensional transformation you want. SKEWING IMAGES

If you want to know how I created figure 3.2, you should take a look at the code used to create figure 3.16, shown in listing 3.24.

There’s plenty of algebra involved in this skewing transformation. The details will be explained in section 14.3.3.

Skewing an image

Figure 3.16 Skewing an image

Listing 3.24 ImageSkew.java

Listing 3.24 ImageSkew.java

The extra parameters passed to the addImage() method in listing 3.24 are reflected in the PDF syntax.

tmp17C134_thumb

If you want to prevent the creation of an image XObject, you can add the image as an inline object.

INLINE IMAGES

An image is considered inline when its bits and bytes are part of the content stream.

Listing 3.25 ImageInline.java

Listing 3.25 ImageInline.java

Now if you look at the PDF syntax in the content stream of the page, you’ll see information about the image between the operators BI—begin image—and EI—end image. To keep this code to a reasonable length, I replaced the bits and bytes of the image with an ellipsis.

tmp17C136_thumb

It should be evident that inline image data can’t be reused, so this is probably not the best way for you to add images. It’s better to use an image XObject.

Another important type of XObject is a form XObject. This is an entire content stream that is treated as a single graphics object.

The PdfTemplate object

The use of the word form may be confusing in this context: we aren’t talking about forms that can be filled in. To avoid confusion with AcroForm and XFA forms, the iText object corresponding to a form XObject is called PdfTemplate.

PDFTEMPLATE: ANOTHER NAME FOR FORM XOBJECT

A PdfTemplate is a PDF content stream that is a self-contained description of any sequence of graphics objects. PdfTemplate extends PdfContentByte and inherits all its methods. A PdfTemplate is a kind of extra template layer with custom dimensions that can be used for different purposes.

Suppose that you would like to present all the posters of the movies in your film database on one page. As an extra visual element, you’d like to draw different strips of film, so that it looks as if the posters were photographed or filmed. See figure 3.17 for an example.

 Mimicking strips of film using a PdfTemplate

Figure 3.17 Mimicking strips of film using a PdfTemplate

There are 120 movie titles in the movie database, so if you put 12 movies on one strip, you’d need a page with 10 strips. You only need to create the strip once.

Listing 3.26 MoviePosters.java

Listing 3.26 MoviePosters.java

You create a PdfTemplate for a specific content layer, passing its dimensions. In O, you create a layer that will have the same width as the page, and one tenth of the height of the page. You draw one large rectangle and a series of small rounded rectangles representing the perforations. Line C is special. You probably expected celluloid.fill(), but that would also fill the perforations using the fill color. By using eoFill(), the shape is filled using the even odd rule; fill() uses the nonzero winding number rule. If you’re not familiar with these rules, they’ll be explained in detail in section 14.2.2.

The most important thing to know is that the XObject stream is stored in a separate object:

tmp17C-139_thumb

The complete stream is much longer than the snippet. If you look at the complete file, you’ll see that the XObject is the first object in the file, both logically—the object number is 1—and physically—the object starts on the 15th byte. This isn’t standard behavior in iText. Normally PdfTemplate objects are kept in memory until you invoke Document.close(), unless you explicitly use writer.releaseTemplate() as is done in line ©. This is done on purpose—you’ll find out the benefits of keeping form XObjects in memory in topic 5.

ADDING PDFTEMPLATE OBJECTS

Instead of adding this long sequence of PDF syntax 10 times to the content stream of the page, you refer to it like this:

tmp17C140_thumb

This snippet of PDF syntax is easy to interpret: the form XObject /Xf1 is added in its original size at position (0,Y) with Y being a value going from 0 to 757.8 in steps of 84.2 user units.

Here’s how you first add the strips of film, followed by the images. The method addTemplate() is used to add the PdfTemplate object celluloid at a specific x,y position.

Listing 3.27 MoviePosters.java

Listing 3.27 MoviePosters.java Listing 3.27 MoviePosters.java

Figure 3.18 demonstrates the use of another version of the addTemplate() method.

Adding the same PdfTemplate object using different transformations

Figure 3.18 Adding the same PdfTemplate object using different transformations

In figure 3.18, the strip of film is added four times, but it’s translated, scaled, skewed, and rotated.

Listing 3.28 MoviePosters.java

Listing 3.28 MoviePosters.java

The extra parameters of the addTemplate() method O are elements of the current transformation matrix, as discussed briefly in the previous subsection. You can use this method to compose complex transformations.

If you only need to move, scale, or rotate the template, you can improve the readability of your code by wrapping the PdfTemplate in an Image object C.

WRAPPING A PDFTEMPLATE INSIDE AN IMAGE

The syntax generated using addTemplate() looks like this:

tmp17C145_thumb

You’ll recognize the elements from the transformation matrix.

The syntax generated for the templates wrapped in an Image object looks like this:

tmp17C146_thumb

As you can see, the object is still treated as a form XObject; it’s not converted into an image XObject, nor is it rasterized. Wrapping a PdfTemplate inside an Image is an elegant way to avoid having to calculate the transformation matrix yourself.

To conclude this topic, we’ll reduce the file size of the film festival’s timetable— as promised.

ADAPTING THE TIMETABLE EXAMPLE

In section 3.1.3, you added a grid with locations and time slots to every page of your timetable document. It would have been a better idea to draw the grid with the locations to one PdfTemplate object, and the grid with the time slots to another.

Listing 3.29 MovieTemplates.java

Listing 3.29 MovieTemplates.javaListing 3.29 MovieTemplates.java

The MovieTemplates example (listing 3.29) extends MovieCalendar (listing 3.15) so that methods such as drawTimeTable() and drawTimeSlots() can be reused. If you open both PDFs in Adobe Reader, you’ll see no difference at all between them, except when you go to File > Properties > Description. The PDF generated with MovieCalendar has a size of 18.82 KB; the one generated with MovieTemplates has a size of 14.29 KB. This means we’ve saved almost 25 percent in file size by using form XObjects in this example. Isn’t that a nice way to conclude topic 3?

Summary

In the first section of this topic, you learned how iText adds content to a page. High-level objects are written to two layers in the middle. You have low-level access to an extra level on top of these layers and an extra level below. Low-level access means that you can change the graphics state to fill and stroke lines and shapes; you change the text state to draw glyphs.

You used this knowledge to make a visual representation of the data in the film festival database. You drew a grid with locations and time slots, on which you added blocks representing movie screenings. Movie titles were added with the ColumnText object. This object forms a bridge between the high-level objects and low-level access. You added content in columns, and you experienced the difference between text mode (Chunk and Phrase objects added with addText()) and composite mode (implementations of the Element interface added with addElement()). You also used ColumnText in simulation mode to keep content that belongs together in the same column.

Finally, the PdfTemplate object was introduced, allowing you to create extra layers that can be reused on the same page or on different pages.

In the next topic, you’ll learn how to organize the information about the film festival movies in tabular form using PdfPTable and PdfPCell. You’ll learn that each Pdf-PCell uses a ColumnText internally to draw the content of a cell at the correct position.

Next post:

Previous post: