This article is based on iText in Action, Second Edition, published on October, 2010. It is being reproduced here by permission from Manning Publications. Manning publishes MEAP (Manning Early Access Program,) eBooks and pBooks. MEAPs are sold exclusively through Manning.com. All pBook purchases include free PDF, mobi and epub. When mobile formats become available all customers will be contacted and upgraded. Visit Manning.com for more information. [ Use promotional code 'java40beat' and get 40% discount on eBooks and pBooks ]
Beginning with PDF 1.5, we can also add optional content: content that can be selectively viewed or hidden by document authors or consumers. Graphics and text that can be made visible or invisible dynamically are grouped in an optional content group (OCG). Content that belongs to a certain group is visible when the group is on and invisible when the group is off. Figure 1 demonstrates this functionality.
The text “Do you see me?” is added as normal content. The text “Peek-a-Boo!!!” is added as optional content. This text is visible in the upper window but not in the lower window. In both windows the Layers panel is opened. “Do you see me?” is the caption of a layer (which is another name for OCG). By clicking on the group’s checkbox in the Layers panel, end users can make the content visible or invisible.
Listing 1 shows how the “Do you see me?” layer was created using iText’s PdfLayer object and how the text “Peek-a-Boo!!!” was made optional using the PdfContentByte methods beginLayer() and endLayer().
Listing 1 PeekABoo.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Document document = new Document(); PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(filename)); writer.setViewerPreferences(PdfWriter.PageModeUseOC); writer.setPdfVersion(PdfWriter.VERSION_1_5); document.open(); PdfLayer layer = new PdfLayer("Do you see me?", writer); A layer.setOn(on); A BaseFont bf = BaseFont.createFont(); PdfContentByte cb = writer.getDirectContent(); cb.beginText(); cb.setFontAndSize(bf, 18); cb.showTextAligned(Element.ALIGN_LEFT, "Do you see me?", 50, 790, 0); B cb.beginLayer(layer); C cb.showTextAligned(Element.ALIGN_LEFT, "Peek-a-Boo!!!", 50, 766, 0); C cb.endLayer(); C cb.endText(); document.close(); A Creating a layer B Adding normal content C Adding optional content
Note that we’ve set the viewer preferences so that the optional content panel is shown when the document is opened. The state of the layers can be specified with the method setOn(). This method expects a Boolean value. If true, the layer will be visible (this is the default). If false, the layer will be hidden.
If you’d peek into the content stream of the resulting page, you’d see this construct:
1 2 3 4
/OC /Pr1 BDC 1 0 0 1 50 766 Tm (Peek-a-Boo!!!)Tj EMC
The optional content is put between the marked-content operators BDC and EDC. This marked content is recognized as optional because of the tag /OC. The operand /Pr1 was created by iText. You’ll find a reference to the OCG in the resources dictionary of the page:
/Properties<</Pr1 1 0 R>>
The indirect object 1 looks like this:
1 2 3
1 0 obj <</Type/OCG/Name(Do you see me?)>> endobj
The optional content groups and their properties are listed in the catalog:
1 2 3 4 5 6 7 8 9 10 11 12
<< /Type/Catalog /Pages 4 0 R /OCProperties<< /D<< /Order[1 0 R] /ListMode/VisiblePages >> /OCGs[1 0 R] >> /PageMode/UseOC >>
Optional content of a group can reside anywhere in the document. It doesn’t have to be consecutive in the drawing order or belong to the same content stream (or page).
In this article, we added structures that made part of the content optional, a feature that’s been available beginning with PDF 1.5.