0

I'm creating a PDF document using iTextSharp, what I'm doing is generating all of my content in a c# List<Chapter> where the Chapters contain one or more Sections, and the Chapters have not yet been added to the document. I then enumerate through my List<Chapter> to generate a table of contents at the start of the document, and then add the Chapters to the document after my TOC.

That works great when my Sections contain text and images, but now I need to generate a Section containing boxes and lines. I don't want to draw my boxes and lines into an image and drop the image into the Section, that won't look as good as if I have actual PDF boxes and lines.

The Sections containing graphical elements can be intermixed with Sections containing text, so I need a way to add some kind of element to a Section such that that graphical Section works like text Sections in terms of going onto a new page only if necessary.

What's the best way to do this? I feel like it somehow involves PdfTemplates but I'm not sure how. Or maybe I need to create a PdfPTable and create my graphical elements in an IPdfPCellEvent?

Betty Crokker
  • 3,001
  • 6
  • 34
  • 68
  • 1
    Off the top of my head, you might be able to use a "generic tag" on a chunk along with a `PageEvent` on the `Writer`. Bruno has an [example here](http://stackoverflow.com/a/28067028/231316). However, I don't know if you can adjust "the current y" when doing this and there's further issues if this happens to land where your vector drawings would fall off the page. Drawing on a completely empty PDF and [importing it via `GetImportedPage()` might be easier](http://stackoverflow.com/a/16048243/231316). – Chris Haas Dec 10 '15 at 21:31

1 Answers1

2

You are on the right track when you want to involve PdfTemplate elements. PdfTemplate is an iText object that corresponds with the concept of Form XObjects in the PDF specification. We chose another name because the word Form is somewhat misleading (people confuse it with form fields, interactive forms, etc).

The content stream of a page in PDF is a sequence of PDF syntax, consisting of operands and operators. An XObject is an object that is external to this content stream. The content of an XObject is stored inside the PDF document only once, but it can be reused many times on the same page, on different pages.

There are different types of XObjects, but Image XObjects and Form XObjects are the most important ones.

  • Image XObjects are used when we work with raster images. You are absolutely right when you write: *"I don't want to draw my boxes and lines into an image and drop the image into the Section, that won't look as good as if I have actual PDF boxes and lines."
  • Form XObjects are used when we want to reuse PDF syntax. This is what you need: you want to define moveTo(), lineTo(), curveTo(), stroke(), fill(),... operations, and you want these lines and shapes to be stored as vector data.

The solution to your problem is to draw lines and shapes to a PdfTemplate object and to wrap the PdfTemplate object inside an Image object. When you add that Image object to a Section or a Chapter, it will be added as a Form XObject. You don't have to feat that it will be degraded into a raster image.

You can find some examples of this technique on the official web site. For instance in the answer to the question How to generate 2D barcode as vector image?

Here we create a PdfTemplate with a bar code and we return it as an Image object. The screen shot that shows you the internals of the resulting PDF proves that the bar code is added as a vector image.

public Image createBarcode(PdfContentByte cb, String text,
    float mh, float mw) throws BadElementException {
    BarcodePDF417 pf = new BarcodePDF417();
    pf.setText("BarcodePDF417 barcode");
    Rectangle size = pf.getBarcodeSize();
    PdfTemplate template = cb.createTemplate(
        mw * size.getWidth(), mh * size.getHeight());
    pf.placeBarcode(template, BaseColor.BLACK, mh, mw);
    return Image.getInstance(template);
}

To create a PdfTemplate object, you need a PdfContentByte instance (e.g. using writer.getDirectContent()) and use the createTemplate() method passing a width and a height as parameters. Then you draw content to the PdfTemplate and turn it into an Image object using Image.getInstance().

You'll find more info on drawing lines and shapes in the chapter on Absolute positioning of lines and shapes and in the example section of Chapter 3 and Chapter 14 of my book.

Bruno Lowagie
  • 75,994
  • 9
  • 109
  • 165
  • I was making good progress on this, but ran into a bug: http://stackoverflow.com/questions/34275946/itextsharp-bug-mixing-text-and-images-causes-incorrect-vertical-positioning – Betty Crokker Dec 14 '15 at 20:28