Developers guide

This guide helps you understand the TallPDF.NET 5.0 class library. It walks through the main concepts and illustrates them with code samples.

Features

TallPDF.NET 5.0 is a 100% managed (verifiable) .NET class library for dynamic generation of PDF documents. Central to TallPDF.NET is a consistent and highly intuitive object model consisting of classes like Document, Section, TextParagraph, Table, Header, Footer, etc. The focus of the development team is always to ease the task of integrating our class libray in a larger application.

These are TallPDF.NET’s primary features:

  • Generate PDF programmatically or from XML
  • Declarative flow-layout model that creates pages on the fly
  • Generate bookmarks
  • Generate internal and external links
  • Mix flow and grid layout
  • Generate tables and nest other content (including tables) in table cells
  • Embed raster images (BMP, PNG, TIFF, JPG and GIF)
  • Create form fields and JavaScript actions (Professional edition only)
  • Auto-number headings and caption and cross-references
  • Embed and subset TrueType fonts (Professional edition only)
  • Text formatting: justification, alignment, text color, text decoration (underline, strike-through)
  • Support for importing XHTML
  • Embed existing PDF pages
  • Weak and strong encryption
  • Embed simple or complex drawings consisting of primitive shapes such as lines, bezier curves and text

What is new in 5.0?

  • Support of ASP.NET Core
  • Support of Xamarin

Upgrade from TallPDF.NET 4.0

TallPDF 5.0 is backward compatible with TallPDF 4.0.

Document

The Document class is the top-level class of the TallPDF.NET object model.

Create and Save

A typical PDF generation scenario consists of the following basis steps: 1. instantiate a Document; 2. add content and configure document settings; 3. save the document to any stream (typically disk, memory or HTTP response). This is shown in the following code snippets:

// create document
Document doc = new Document();

// CODE OMITTED – CONTENT IS ADDED HERE

// save to disk
using ( FileStream file = new FileStream(
   "out.pdf", FileMode.Create, FileAccess.Write))
{
   document.Write( file );
}

Code sample: Create a new document, add content (omitted) and save it to disk in C#

' create a document
Dim doc As New Document

' CODE OMITTED – CONTENT IS ADDED HERE 

' save to disk
Using file As FileStream = New FileStream( _
   "out.pdf", FileMode.Create, FileAccess.Write)
   doc.Write( file )
End Using

Code sample: Create a new document, add content (omitted) and save it to disk in VB.NET

Write Overloads

Document.Write has a number of overloads. Depending on what overload you use, the PDF document is generated in either pull or push mode. This is explained in more detail in Event-Driven Generation

DocumentInfo

Property DocumentInfo lets you set document level information such as the author and title. This is shown in the next code:

Document doc;

doc.DocumentInfo.Author = "Chris Sharp";
doc.DocumentInfo.Title = "TallPDF.NET 4.0 Developer Guide";

Code sample: Set document info in C#

Dim doc As New Document

doc.DocumentInfo.Author = "Chris Sharp"
doc.DocumentInfo.Title = "TallPDF.NET 4.0 Developer Guide"

Code sample: Set document info in VB.NET

Security

The Security property lets you assign passwords and limit user privileges. The following code creates a document that requires a password to open and cannot be printed:

Document doc = new Document();

PasswordSecurity sec = new PasswordSecurity();
sec.Print = false;
sec.OwnerPassword = "gjh456j45";
sec.UserPassword = "egryt646g";
doc.Security = sec;

Code sample: Set security in C#

Dim doc As New Document

Dim sec As New PasswordSecurity()
sec.Print = False
sec.OwnerPassword = "gjh456j45"
sec.UserPassword = "egryt646g"
doc.Security = sec

Code sample: Set security in VB.NET

A typical scenario is to set the user password to the empty string and the owner password to a non-empty string. This will not prompt the user for a password when she opens the document, but a password is required to change security settings.

A common question is how to generate a PDF document that cannot be saved. Unfortunately. The PDF format does not foresee in this feature.

By default the Security property is null (or Nothing) meaning that the document has no security settings.

ViewerPreferences

The ViewerPreferences property allows you to control the way that a PDF reader application displays the PDF initially. E.g. you can set the initial zoom or hide toolbars or set the reader to fullscreen mode. Here are some typical code samples:

Document doc = new Document();

ViewerPreferences vp = new ViewerPreferences();
vp.PageLayout = PageLayout.TwoColumnLeft;
doc.ViewerPreferences = vp;

Code sample: Setting viewer preferences in C#

Dim doc As New Document

Dim vp As New ViewerPreferences
' display pages in 2 columns - odd page left
vp.PageLayout = PageLayout.TwoColumnLeft
doc.ViewerPreferences = vp

Code sample: Setting viewer preferences in VB.NET

Actions

PDF allows you to associate actions with events. Chapter Actions discusses this topic in more detail . For now it suffices to say that the following properties allow you to associate actions with document-level events:

  • AfterPrintAction: This action will be executed by the PDF reader application after the PDF document has been printed.
  • AfterSaveAction: This action will be executed by the PDF reader application after the PDF document has been saved.
  • BeforeCloseAction: This action will be executed by the PDF reader application just before the PDF document is closed.
  • BeforePrintAction: This action will be executed by the PDF reader application just before the PDF document is printed.
  • BeforeSaveAction: This action will be executed by the PDF reader application just before the PDF document is saved.
  • OpenActions: This sequence of actions will be executed by the PDF reader during opening the PDF document.

Notethat these actions are not executed by TallPDF.NET. They are only associated with events and the actions are executed by the PDF reader application when the corresponding event occurs.

 

The following code sample generates a PDF document so that a text field is filled with the current date just before it is printed. This way, you can always see on the print out when it was printed. (How to add fields to a PDF document is discussed in Section Field Shapes in Chapter Drawings and Shapes.)

Document document = new Document();

JavaScriptAction action = new JavaScriptAction( 
  string.Format( 
    "this.getField('printed').value = 'Printed: {0}'", DateTime.Now));
document.BeforePrintAction = action;

Section section = document.Sections.Add();

Drawing drawing = new Drawing(200, 100);
section.Paragraphs.Add(drawing);

TextFieldShape textField = new TextFieldShape(10, 50, 150, 30, "printed");
drawing.Shapes.Add(textField);

using (FileStream file = new FileStream(
   @"..\..\out.pdf", FileMode.Create, FileAccess.Write))
{
   document.Write(file);
}

Code sample: Add a BeforePrintAction to a document in C#

JavaScripts

The property JavaScripts lets you declare document level JavaScript. This typically contains common functions and constants that can be reused from other JavaScript actions. See JavaScript actions for more a more detailed discussion. The following code sample shows how to declare a JavaScript function at document level:

JavaScript javaScript = new JavaScript("function foo() { return 10; }");
document.JavaScripts.Add( javaScript );

Code sample: Declare a document-level JavaScript function in C#

Dim javaScript As New JavaScript("function foo() { return 10; }")
doc.JavaScripts.Add(javaScript)

Code sample: Declare a document-level JavaScript function in VB.NET

Sections

The property Sections lets you add Section objects to a document. A document has atleast one Section. A section contains the actual content as paragraph objects. Sections are discussed in more detaill in the next Chapter.

Sections

A document consists of one ore more sections. The content of a section is defined by one or more paragraphs. The paragraph are rendered into one or more pages. The section defines the settings for all these pages. These setting include headers and footers, page size and margins and columns. The figure below shows how sections relate to pages.

A Section Renders Its Paragraphs Into One Or More Pages

The following code snippets show how to create a new document and add sections to the document.

// create document
Document doc = new Document();

// add a section
Section section = new Section();
doc.Sections.Add(section);

Code sample: Create a new document and add a section in C#

' create a document
Dim doc As New Document

' add a section
Dim section As New Section
doc.Sections.Add(section)

Code sample: Create a new document and add a section in VB.NET

Page Size and Margins

All pages that are rendered from the same section have the same size and margins. The size is set through the PageSize property of Section. PageSize offers standard page formats through static (or shared) properties like PageSize.Letter and PageSize.A4.

The margins of the pages can be set through the Margins properties of Section. The paragraphs will be flowed inside these margins. The top margin and the bottom margin define the space reserved for the header and footer, respectively.

Page Size And Margins

The following code snippets show how to set the page size and the margins of a section.

Section section = document.Sections.Add();
section.PageSize = PageSize.A4;
section.Margin.Left = new Unit(1.25, UnitType.Inch);
section.Margin.Right = new Unit(1.25, UnitType.Inch);
section.Margin.Top = new Unit(1, UnitType.Inch);
section.Margin.Bottom = new Unit(1, UnitType.Inch);

Code sample: Set the page size and margins of a section in C#

Dim section As Section
section = doc.Sections.Add();
section.PageSize = PageSize.A4
section.Margin.Left = New Unit(1.25, UnitType.Inch)
section.Margin.Right = New Unit(1.25, UnitType.Inch)
section.Margin.Top = New Unit(1, UnitType.Inch)
section.Margin.Bottom = New Unit(1, UnitType.Inch)

Code sample: Set the page size and margins of a section in VB.NET

Headers and Footers

The Section class has 4 properties that allow you to define headers and footers:

  • EvenHeader: The content of this header will be repeated at the top of each even page.
  • OddHeader: The content of this header will be repeated at the top of each odd page.
  • EvenFooter: The content of this footer will be repeated at the bottom of each even page.
  • OddFooter: The content of this footer will be repeated at the bottom of each odd page.

This is illustrated in the following figure:

Headers And Footers

The content of both the header and the footer is defined by a collection of paragraphs that will be flowed from top to bottom in the header and footer areas. A header renders from the very top of the page down until the top margin of the section as shown in Figure . Because normally you want to have some whitespace above the header content, you should set the Header.Margin.Top property as shown in the code sample below.

Document doc = new Document();

Section section = new Section();
doc.Sections.Add(section);

Header oddHeader = new Header();
oddHeader.TopMargin = new Unit(0.2, UnitType.Inch);
section.OddHeader = oddHeader;

TextParagraph textParagraph = new TextParagraph();
textParagraph.Fragments.Add(new Fragment("odd header"));
oddHeader.Paragraphs.Add(textParagraph);

Code sample: Add headers and footers in C#

Columns

Associated with a section is an array of columns. These are accessed through the Section.Columns property. By default, a section has 1 column. You can specifiy the width of each column and the spacing between each column pair (if any). Column settings are made per section. Paragraph of a multi-column section flow from one column to the next. This is illustrated in the next figure.

Columns

The following code samples show how to add and configure columns.

Document doc = new Document();

Section section = doc.Sections.Add();

section.Columns.Count = 3;
section.Columns[0].Width = 200;
section.Columns[1].Width = 100;
section.Columns[2].Width = 100;
section.Columns[0].Spacing = 20; // spacing to the right of column 0
section.Columns[1].Spacing = 20; // spacing to the right of column 1

Code sample: Add columns in C#

Dim doc As New Document()

Dim section As New Section
doc.Sections.Add(section)

section.Columns.Count = 3
section.Columns(0).Width = 200
section.Columns(1).Width = 100
section.Columns(2).Width = 100
section.Columns(0).Spacing = 20 ' spacing to the right of column 0
section.Columns(1).Spacing = 20 ' spacing to the right of column 1

Code sample: Add columns in VB.NET

Page Boxes

In PDF you can define different boxes per page. The most common box is the media box which simply represents the entire page. Probably it is the only box you are interested in. You set the media box implicitly by setting Section.PageSize. The following figure illustrates the other boxes.

Page Boxes

Section.CropBox

The CropBox is the area that should be shown to PDF users and can be printed. It contains the desired ‘normal’ content of the page. Within the MediaBox, but outside the crop box, cutting marks could be present. Defaults to the media box values.

The following code samples show how to set the crop box.

Document doc = new Document();
Section section = doc.Sections.Add();
section.PageSize = new PageSize(612, 792);
section.CropBox = new Rectangle(20, 20, 572, 752);

Code sample: Set the crop box in C#

Dim section As New Section
doc.Sections.Add(section)
section.PageSize = New PageSize(612, 792)
section.CropBox = New Rectangle(20, 20, 572, 752)

Code sample: Set the crop box in VB.NET

Section.bleedbox

The bleed box defines the area outside the cropbox, which is ‘blank’ and intended for post-printing operations (cutting, folding…). This way cutting machines have some margin for error, without either loosing content (eg. footer: page number) or including production markers (cutting lines, color calibration areas).

Areas

An area is a rectangular region on a page. The content of an area consists of a collection of paragraphs. An Area is a generalization of header and footer. In fact, classes Header and Footer inherit from Area.Each section has a collection of foreground areas and a collection of background areas. They appear respectively in front of and behind the main content. An area is repeated on each page that matches the properties of the area.

A background area is typically used to add a stationary for a page (company logo, graphical borders), or a watermark. A foreground area can be used for stamping content (Confidential, Draft, etc).

The following code sample adds a foreground area that displays ‘Confidential’ across each page. Drawing and shapes are discussed in detail in Chapter Drawings and Shapes.

Document document = new Document();
Section section = document.Sections.Add();

// area spans the entire page
Area area = new Area(
   0, section.PageSize.Height,
   section.PageSize.Width, section.PageSize.Height);
section.ForegroundAreas.Add(area);

// drawing spans the entire area
Drawing drawing = new Drawing(area.Width, area.Height);
area.Paragraphs.Add(drawing);

// add text “Confidential”
TextShape textShape = new TextShape();
textShape.Text = "Confidential";
textShape.Font = Font.Courier;
textShape.FontSize = 72;
textShape.TextColor = RgbColor.Red;
textShape.Opacity = 128; // 50%
textShape.Rotation = -45; // clockwise
textShape.X = 130;
textShape.Y = 180;
drawing.Shapes.Add(textShape);

// add some dummy content
for (int i = 0; i < 100; i++)
{
   TextParagraph text = new TextParagraph();
   text.Fragments.Add(new Fragment("A background area is typically used to add a stationary for a page (company logo, graphical borders), or a watermark. A foreground area can be used for stamping content (Confidential, Draft, etc)."));
   text.SpacingAfter = 10;
   section.Paragraphs.Add(text);
}

// save PDF to disk
using (FileStream file = new FileStream(
   "out.pdf", FileMode.Create, FileAccess.Write))
{
   document.Write(file);
}

Code sample: Stamp ‘Confidential’ on each page using a foreground area in C#

CrossreferenceSection

CrossreferenceSection is a class that specializes Section. An instance of this class can be added to the Document.Sections collection just as a normal Section. The CrossreferenceSection lets you generated sections such as a ‘Table of Contents’, a ‘List of Tables’ or ‘List of Figures’. See Section CrossreferenceSection in Chapter Context Fields for more details.

Paragraphs

Paragraphs are the primary content building blocks of a document. All paragraph classes inherit from the abstract base class Paragraph. This base class has common properties such as HorizontalAlignment, SpacingBefore, SpacingAfter and KeepWithNext.

Paragraph specializations are Drawing, Image, Table, HorizontalLine, ParagraphCollection, RtfParagraph, XhtmlParagraph, TextParagraph, NumberedItem, BookmarkParagraph and Heading.

Paragraph Class Hierarchy

The content inside Section, Area and Cell (Defined in Chapter Tables) objects is defined as a collection of Paragraph objects. Paragraph is an abstract class from which a number of paragraphs derive. This Chapter discusses the commonality of all these classes. The following chapters discuss specific paragraphs such as TextParagraph, Image, Table and Drawing in more detail.

The following code samples show how to instantiate different paragraph objects and add them to a section.

Document doc = new Document();
Section section = new Section();
doc.Sections.Add(section);

TextParagraph textParagraph = new TextParagraph();
// ... add fragment objects
section.Paragraphs.Add(textParagraph);

Image image = new Image("some.jpg");
// ... set image properties
section.Paragraphs.Add(image);

Table table = new Table();
// ... add rows, cells, etc.
section.Paragraphs.Add(table);

Heading heading = new Heading();
// ... set heading properties such as level
section.Paragraphs.Add(heading);

Code sample: Add paragraph objects to a section in C#

Positioning

At what position a paragraph is rendered follows from the render process that precedes it; this is obviously beyond the control of an individual paragraph. However, when a paragraph is about to be rendered, there are a number of properties that control the position of the paragraph relative to the current position. These are:

  • Paragraph.SpacingBefore adds additional white space between this paragraph and its predecessor.
  • Paragraph.SpacingAfter adds additional white space between this paragraph and its successor. (Admittedly, this doesn’t control the position of the current paragraph but that of the next.)
  • Paragraph.LeftIndentation adds additional white space between the left edge of this paragraph and the left page margin.
  • Paragraph.RightIndentation adds additional white space between the right edge of this paragraph and the right page margin.
  • Paragraph.HorizontalAlignment aligns the paragraph with respect to the left and right margins of the page.

See: Paragraph positioning relative to the cursor

Paragraph Positioning Relative To The Cursor

Flow Constraints

It is possible to apply flow contraints to paragraphs. These properties are:

  • Paragraph.DoNotBreak instructs the layout engine to not break this paragraph across pages. Note that this property only applies to paragraphs that can be broken (text and tables)
  • Paragraph.KeepWithNext instructs the layout engine to keep atleast some of this paragraph on the same pages as some of the next paragraph.
  • Paragraph.StartOnNewPage instructs the layout engine to start this paragraph on a new page.

The DoNotBreak and KeepWithNext constraints are typically applied to headings (not by default). The KeepWithNext should also be applied to a Figure or Table that is followed by a caption. The StartOnNewPage constraint makes sense for e.g. a chapter heading.

The following three figures illustrate the DoNotBreak and KeepWithNext flow constraints.

Paragraph Flow Without Constraints

Do Not Break Flow Constraint

Keep With Next Flow Constraint

Text

Most likely, the major part of your document will consist of text. The primary class for adding text is TextParagraph. TextParagraph is a specialization of paragraph. Therefore, all members of paragraph are members of TextParagraph as well. So you can align it, apply text flow constraints and add it to a section, area, table cell, header and footer.

Formatting

TextParagraph is a specialization of Paragraph. It is the primary class for generating a block of text that spans one or more line. A text paragraph consists of one or more fragments. A fragment consists of text and format options like font and text color. If a paragraph consists of text that is formatted with a single font, font size and text color, you need only a single fragment. If you want to mix formatting, you need to add multiple fragments. The following code sample shows how to instantiate a text paragraph and add some text:

Document document = new Document();
Section section = document.Sections.Add();

TextParagraph text = new TextParagraph();
text.Fragments.Add(new Fragment("You can mix", Font.Helvetica));
text.Fragments.Add(new Fragment("bold", Font.HelveticaBold));
text.Fragments.Add(new Fragment("and", Font.Helvetica));
text.Fragments.Add(new Fragment("italic.", Font.HelveticaOblique));
section.Paragraphs.Add( text );

Code sample: Mix text formatting in C#

Layout

In addition to the layout options inherited from paragraph, you can set the following properties that control the layout of the text paragraph:

TextParagraph.Justification: If set, the word spacing is increased to fill each line. This is illustrated below.

Default Layout

Justified Text

TextParagraph.FirstLineIndentation: The amount by which the first line only is indented. This is illustrated below.

First Line Indentation

TextParagraph.FirstLineIndentation: The amount by which the first line only is indented. This is illustrated below.

Hanging Indentation

TextParagraph.FirstLineIndentation: The amount by which the first line only is indented. This is illustrated below.

Line Spacing

Preserve White Space

By default, each sequence of white space characters is substituted by a single space. You can cancel this behavior by setting the PreserveWhiteSpace option. This is especially useful when you include programming code in your document where you want to preserve spaces, tabs and line breaks. Set the TabSize property to specify the number of spaces that substitute each tab.

Note that if you set the Fragment.PreserverWhiteSpace property, then TextParagraph.Justification property has no effect.

Hyphenation or Line Breaking

By default, TallPDF.NET breaks text at whitespace. In some cases however this is not desired. Custom hyphenation or line breaking can be achieved by subscribing to the TextParagraph.LineBreak event.

The arguments of the event include the word to be broken and the current breaking position. Also the maximum position before which the word has to be broken is given. You can also specify wether a hyphen symbol should be used.

Cross-References

It is possible to add a cross-reference from a fragment to a paragraph. To do this add a GoToAction to the Actions property of Fragment. Alternatively, you can use the ID assigned to the Paragraph.ID and assign it to the GoToAction (This is primarily useful in XML code.) Referencing other paragraphs only works in Push-mode (not event-driven.)

You can embed context fields in the fragment text that will be resolved to attributes of the paragraph. Among these attributes are caption, label and the number of the page where the target paragraph is rendered.

You can also specify different types of destination, like links to external documents (RemoteDestination) or in-document links (InternalPageDestination). These handlers also work in event driven generation mode.

Typical uses of this feature are:

  • Cross-references<
  • Table of Content Entries
  • List of Figures, Tables, etc.
  • Auto-Numbering Figures, Tables, etc.

Auto Format A Cross Reference

NumberedItem

NumberedItem is a specialization of TextParagraph. You can use numbered items to compose a numbered or bulleted list. With respect to TextParagraph, it has an extra fragment collection called NumberFragments. This collection is used to format the number or bullet part of the item. Mostly, this collection will contain only a single fragment. However, if you want to use a mix of fonts or colors in the number part, you can do so.

Positioning the bullet or number part

NumberedItem has a number of extra layout properties that let you control the position of the number part with respect to the body of the item. The following figures make this clear.

Alignment

Layout Options Voor The Bullet Number Part Of A Numbered Item

Number format

Each numbered item is assigned one or more numbers. An item at level 0 is assigned a single number, an item at level 1 is assigned 2 numbers, etc. The render engine maintains a counter for each level and increments this counter after each assignment. When a counter is incremented, all counters at higher levels are automatically reset. Counters are 1-based. An item may reset the counter of its own level by setting its RestartNumbering property.

A fragment may include these numbers in its number fragment by using context fields (see Chapter Context Fields for more details). The following shows a typical item list with two levels. The table that follows shows examples of how the bold-faced item may be formatted and resolved.

  • first item at level 0
  • second item at level 0
    • first item at level 1
    • second item at level 1
    • third item at level 1
    • fourth item at level 1
  • third item at level 0

Context fields for the number part of a numbered item

Context field…Resolves to…
#02
#0.#12.3
#0/#12/3
#a0b
#A0.a1B.c
#A0 (i1)B (iii)
#I0-#a1II-c
\xb7 (font Symbol)Bullet symbol

Headings

Heading is a specialization of NumberedItem. The differences between heading and numbered item are:

  • A heading appears in the bookmarks tree of the PDF reader application.
  • Headings have their own set of counters that do not interfere with that of the numbered items, proper.
  • All fragments in the Fragments collection refer automatically to the heading itself.

Bookmark appearance

A heading automatically appears as a bookmark in the navigation pane of the PDF viewer. You control the text of this bookmark by setting the Bookmark property to some text that typically includes fields. Example: “#l #0.#1 #c” resolves to something like “Section 3.2 Bookmark”

Context fields

All fragments in the Fragments collection refer automatically to the heading itself. This means that fields like #c, #l and #0 will automatically resolve to attributes of this heading. What you will typically do is set the Caption property to the title of this heading and include the #c field in a fragment. The reason for this is that whenever you refer to the heading, e.g. from the TOC, you use fields instead of fragment text. So in order to avoid redundancy you set the text in the Caption and Label properties and refer from your fragments using the #c and #l fields.

The following code sample demonstrates using the Heading class.

Document document = new Document();
Section section = document.Sections.Add();

string[] chapters = new string[] {"Vector formats", "Raster formats"};
foreach ( string chapter in chapters )
{
  Heading heading = new Heading(0);
  heading.SpacingBefore = 8;
  heading.SpacingAfter = 4;
  heading.Label = "Chapter";
  heading.Caption = chapter;
  heading.Fragments.Add(new Fragment("#l #0 - #c", Font.HelveticaBold, 16));
  heading.Bookmark = "#0. #c";
  section.Paragraphs.Add(heading);

  string[] topics = new string[] { "X", "Y", "Z" };
  foreach ( string topic in topics )
  {
    heading = new Heading(1);
    heading.SpacingBefore = 4;
    heading.Caption = topic;
    heading.Fragments.Add(new Fragment("#0.#1 #c", Font.HelveticaBold, 12));
    heading.Bookmark = "#0.#1. #c";
    section.Paragraphs.Add(heading);

    for (int k = 0; k < 2; k++)
    {
      TextParagraph text = new TextParagraph();
      text.Fragments.Add(new Fragment("A background area is typically used to add a stationary for a page (company logo, graphical borders), or a watermark. A foreground area can be used for stamping content (Confidential, Draft, etc)."));
      text.SpacingAfter = 10;
      section.Paragraphs.Add(text);
    }
  }
}

Code sample: Generate multi-level headings

See the figure below for how the generated PDF document looks in Acrobat 8.0.

Result After Generating Multi Level Headings

Tables

A table is a specialization of Paragraph. Therefore, all members of paragraph are members of table as well. So you can align it, apply text flow constraints and add it to a section, header, footer and table cell.

A table consists of one or more rows. A rows consists of one or more cells. A cell may span more than one column. A cell consists of one or more paragraphs. Because a table is a paragraph, it is possible to nest tables.

Paragraph Table Rows En Cells

The following code snippet shows how to create a table, including rows, cells and paragraphs.

Document doc = new Document();
Section section = new Section();
doc.Sections.Add(section);

// add a table
Table table = new Table();
section.Paragraphs.Add(table);

// add a row
Row row = table.Rows.Add();

// add a cell
Cell cell = row.Cells.Add();

// add text to the cell
TextParagraph text = new TextParagraph();
cell.Paragraphs.Add(text);

Code sample: Build a table in C#

Borders and Background

You can apply both a background and a border to each table, row and cell. A background is represented by a brush. Therefore a backgound can be a solid color, a hatched pattern, etc. A border is represented by four pens that correspond to the four respective edges. The background or border(edge) can be null, meaning it does not exist.

Padding, Margins and Border Width

The extra space outside a border is set by a left, right, top and bottom margin. The extra space inside a border is set by a left, right, top and bottom padding. These attributes are part of the table, row or cell. The following figure makes this clear.

Table Border Padding And Margin

Flow Constraints

In addition to the flow constraints that can be applied to any paragraph, there are some extra flow contraints that can be applied to a table. These are Table.RepeatFirstRow and Row.DoNotBreak. If RepeatFirstRow is set, then the first row will be repeated on each page if the table spans multiple pages. If Row.DoNotBreak is set, the row is kept together and not broken across pages.

How to Size Cells

There are a number of properties that control the width of the table columns. Although table columns have no explicit representation in the DOM, they are a natural consequence of the fact that all cells that have the same position in a row have an equal width. Or stated otherwise, the vertical edges of these cells are aligned. Cells that span multiple columns are special in this regard but they do fit into this view.

The column widths are established in a multi-step process. This process and the rules that govern it, will now be discussed in detail. The following properties control this process:

  • Cell.FitToContent – an attempt is made to not break paragraphs
  • Cell.Fixed – the cell has a fixed width
  • Cell.PreferredWidth – the preferred width; ignored if fit-to-content
  • Table.ForceWidth – if true, the preferrences of the cells are overruled
  • Table.PreferredWidth – if ForceWidth is true, the table has this width, otherwise ignored

Step 1: Minimum Cell Width

In the first step, the minimum width of each cell is determined. Cell width includes border, margin and padding (see Borders and Background).

The minimum cell width has a lower bound equal to the minimum width of the included paragraphs. This width depends on the type of paragraph. The minimum width of a text paragraph is the width of the largest word. The width of both a drawing and image equals their Width property. The minimum width of a table follows from the sizing process that is described in this section.

The following cases exist:

  • a
  • b

 

  • Cell.Fixed property is setThe minimum width equals the preferred width of the cell. If the minimum width of the included paragraphs is larger than the preferred value, the minimum width is set to this value.
  • OtherwiseThe minimum width equals the the minumum width of the included paragraphs.

Step 2: Preferred Cell Width

In the next step, the preferred width of each cell is determined. The following cases exist:

  • Cell.FitToContent property is setThe preferred width is so that each paragraph in the Cell.Paragraphs collection fits on a single line. So if the collection contains 3 paragraphs, the preferred width is so that 3 unbroken lines result.
  • OtherwiseThe preferred width equals the PreferredWidth property, unless this is smaller than the minimum width as determined in the previous step.

Step 3: Minimum and Preferred Column Width

In the previous two steps the minimum and preferred width of each individual cell are determined. The largest minimum width of all cells in a column becomes the minimum width of that column. Similarly, the largest preferred width of all cells in a column becomes the preferred width of that column.

Step 4: Actual Column Width

Now that each column has a minimum and preferred width, the actual column widths can be determined. This is done as follows.

In most cases the preferred width of each column also becomes the actual width. However, in a number of cases the preferred width can or will not be respected. These are:

  • Table width is forcedIf the ForceWidth property of a table is set, then the table overrules the cells. Depending on whether the forced table width is either larger or smaller than the preferred width, the columns need to grow or shrink. These cases are described next in ‘Grow Columns’ and ‘Shrink Columns’, respectively.
  • Total preferred width is too largeIf the page width does not allow the preferred column widths, then the columns shrink to the maximum available space as described next in ‘Shrink Columns’.

either Step 5: Grow Columns …

The table has a forced width that is larger than the preferred width as determined by the collection of cells. Therefore, some cells need to grow relative to their preferred width. In a first attempt, only the none-fit-to-content cells grow. If the first attempt is not sufficient, then also the fit-to-content cells grow. Growth is distributed evenly.

… or Step 5: Shrink Columns

The table has a forced width that is smaller than the preferred width as determined by the collection of cells or the latter is larger than the available space. In this case, all cells shrink in an equally distributed manner. A cell never shrinks beyond its minimum width. Note that for a fixed cell, its preferred width is also its mimimum width, so it will not shrink below its preferred width.

Cells that Span Multiple Columns

The previous steps describe the process of establishing the size of each column. This involves minimum and preferred widths of cells inside these columns. How do cells that span multiple columns factor into this?

Steps 1, 2 and 3 as described above are really carried out from left to right. So these steps are first performed for the first column. Then they are performed for the next column, etc. Then, steps 4 and 5 follow for all columns.

In the first 3 steps, a multiple-column cell only contributes to a column if that column is the last of all spanned columns. In that case, its minimum and preferred width are reduced by the sum of the preferred and minimum width of the previous columns.

Table Exceeds Page Width

In a special case even the minimum width of all cells exceeds the page width. In this case the table will simply cross the right margin and possibly even the right edge of the paper.

Images

The Image class is a specialization of paragraph. So all members of paragraph are members of image as well. Like any paragraph, an image can be added to a section, table cell, area, header and footer. Image is a very simple class. It allows you to add a raster images like a BMP or JPEG image to the document.

Size

You can set the Width and Height properties to control the size. Furthermore, if the KeepAspectRatio property is set (default), the height property is calculated from the width and vice versa. If you do not explicitly set the size, the maximum width is used. If an image does not fit in the available/given space, by default an exception is generated. Set the property FitPolicy to FitPolicy.Shrink to force resizing the image in this case.

If both the height and width are set, the image will be stretched to fit in the given area. The KeepAspectRatio flag is honored when resizing, and the image will be best-fit inside the specified area.

Image Source

An Image object can be constructed from a file path, a URL, a System.IO.Stream and a System.Drawing.Bitmap.

Path

You set the path of the image either through the constructor or through the ‘Path’ property. The path can either be a file on disk or a URL. If the path points to a file on disk, it can be either virtual (ASP.NET), absolute or relative.

The following code samples demonstrate different scenarios.

Image image = new Image("tc-logo.gif");

Code sample: Construct an image from a relative file path (C#)

Image image = new Image(@"c:\images\tc-logo.gif");

Code sample: Construct an image from an absolute file path (C#)

Image image = new Image("http://www.tallcomponents.com/img/tc-logo.gif");

Code sample: Construct an image from a URL (C#)

System.Drawing.Bitmap

Sometimes you want to use a bitmap that is created in memory using the GDI+ image classes. In this case you can construct an Image object from a System.Drawing.Bitmap object.

Depending on what constructor overload is used, it is the responsibility of either the caller or callee to dispose the bitmap object. If the caller disposes, then the bitmap should not be disposed before Document.Write returns.

The following code samples demonstrate different scenarios.

using (Bitmap bitmap = new Bitmap("tc-logo.gif"))
{
   Image image = new Image(bitmap);
   section.Paragraphs.Add(image);

   using (FileStream file = new FileStream("out.pdf", FileMode.Create))
   {
      document.Write(file);
   }
}

Code sample: Construct an image from a Bitmap – caller disposes (C#)

System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap("tc-logo.gif");
Image image = new Image(bitmap, true);
section.Paragraphs.Add(image);

using (FileStream file = new FileStream("out.pdf", FileMode.Create))
{
   document.Write(file);
}

Code sample: Construct an image from a Bitmap – callee disposes (C#)

System.IO.Stream

In some cases you want to construct the image from a System.IO.Stream instance. A typical scenario is when the image is stored as a binary blob in a database. In this case you get the data from the database, wrap this in a MemoryStream and construct the Image from this stream.

Depending on what constructor overload is used, it is the responsibility of either the caller or callee to close the stream object. If the caller is responsible then the stream should not be closed before Document.Write returns.

The following code sample demonstrates a typical scenarios.

Document document = new Document();
Section section = document.Sections.Add();

using ( SqlConnection connection = new SqlConnection( "..." ) )
{
   connection.Open();

   string query = "SELECT data FROM images WHERE id=3";
   SqlCommand cmd = new SqlCommand( query, connection );
   byte[] blob = (byte[]) cmd.ExecuteScalar();

   Image image = new Image( new MemoryStream(blob) );
   section.Paragraphs.Add(image);
}

using (FileStream file = new FileStream("out.pdf", FileMode.Create))
{
   document.Write(file);
}

Code sample: Construct an image from a memory stream (C#)

Multi-frame images

For all constructor overloads that were discussed above, an additional overload exists that takes an extra integer argument. This is used as the frame index in case the image has multiple frames. This is typically the case in multi-page TIFF images. There is also a FrameIndex property to select the frame after construction. Finally there is a FrameCount property that returns the number of frames in the image.

Drawings and shapes

A drawing is a specialization of Paragraph. Therefore all members of paragraph are members of drawing as well and you can add it to a section, header, footer, area and table cell.

Drawing

A drawing is a canvas on which shapes are placed at exact locations. You access the collection of shapes through the Shapes property which is of type ShapeCollection. You compose a drawing by adding shapes to this collection.

The following code snippet shows how to add a drawing to a section and how to add shapes to a drawing.

Document doc = new Document();
Section section = new Section();
doc.Sections.Add( section );

// add a new drawing of size 200 x 200 pt
Drawing drawing = new Drawing( 200, 200 );
section.Paragraphs.Add( drawing );

// add a pie shape with a red outline and blue interior
PieShape pie = new PieShape();
pie.Pen = new Pen( System.Drawing.Color.Red, 2 );
pie.Brush = new SolidBrush( System.Drawing.Color.Blue );
drawing.Shapes.Add( pie );

Code sample: Add a drawing in C#

Shape

All shapes inherit directly or indirectly from Shape. It has members that control positioning and docking. Docking is explained in more detail in Section Docking. A shape is positioned using the X and Y properties. X and Y are interpreted in the coordinate space of the container. The container is either a ShapeCollection or a Drawing.

The figure below shows the partial shape class hierarchy. The sub hierarchies of the abstract classes BarcodeShape, PathShape and FieldShape are discussed later.

Partial Shape Class Hierarchy

Note that because ShapeCollection is a shape as well, it is possible to build a hierarchy of shapes. Especially interesting is that you can inherit a class called, let’s say, ChartShape from ShapeCollection. This new class will use other shapes to build a chart and expose convenient properties that are specific to a chart. We call such a specialized shape a Custom Shape. This mechanism allows you to extend TallPDF.NET and build your own custom shape library.

ContentShape

ContentShape is an abstract base class that adds the properties in Table Public properties specific to ContentShape to specify rotation.

Public properties specific to ContentShape

Public properties
RotationAmount of clockwise rotation in degrees.
RotationOffsetX,RotationOffsetYThe horizontal and vertical offset of the rotation center relative to Shape.X and Shape.Y. These let you set the point to rotate around.

This class organization reflects that the classes LinkShape, NoteShape and FieldShape cannot be rotated since they inherit directly from Shape.

ImageShape

An image shape allows you to add a raster image like a BMP or JPG bitmap. It is possible to set the width and rotate the image around its lower-left corner. By default the aspect ratio of the image is kept. In this case the Height property returns the image height as calculated from the width and the aspect ratio of the original image. If you set KeepAspectRatio to false, you can specify the height explicitly and the image will in general appear distorted.

TextShape

TextShape lets you draw a single line of text. The X and Y properties are inherited from Shape and correspond to the lower-left corner. It is possible to set the color, font and font size of the text. Furthermore, you can rotate the text since it inherits from ContentShape. Finally, it is also possible to retrieve the extend of the text through the read-only properties Width and Height. You should access these properties after setting Font, FontSize and Text.

The following table lists the public properties of TextShape.

Public properties specific to TextShape

Public properties
TextThe text that is displayed.
Width,HeightRead-only properties that reflect the size of the text with the current settings.
TextColor, Font, FontSize, Italic, BoldAppearance properties.
DirectionRead direction (left-to-right or right-to-left).
BoundingBoxThe bounding box after rotation is applied.

MultilineTextShape

MultilineTextShape lets you draw multiline text with mixed formatting. Just like TextParagraph it has a property Fragments. Each fragment has properties that specify both content and appearance. All fragments will be displayed concatenated and broken across lines as needed.

As opposed to the TextShape you can set the Width. This determines where lines wrap. In addition you can set the Height property but this is only useful if the multiline text shape is auto-sized. This is the case if and only if there is exactly one fragment that has a zero font size.

As opposed to most other shapes, the inherited X and Y properties coincide with the top-left corner. The property “MeasuredHeight” returns the height after all content has been rendered using the specified formatting properties and width.

SimpleXhtmlShape

SimpleXhtmlShape specialized MultilineTextShape. Basically, you can pass XHTML data which is then transformed into the Fragments collection of the base class.

PageShape

PageShape allows you to use a page from an existing PDF document on as a drawing primitive. The shape will retain all original data so the page can be sized without loosing any detail.

To include the page at original size in the document:

  • Create a Section with the the same page size as the original Page.
  • Set all margins to zero.
  • Add a Drawing paragraph to the section and make it span the entire page.
  • Add the PageShape to the Drawing and make it span the entire Drawing.

Ofcourse, you can vary the above steps to achieve any imposition scenario.

ShapeCollection

There is a special shape called ShapeCollection which is a group of shape objects. Because a ShapeCollection is a Shape, it allows nesting of shapes to any depth. The following table shows the properties that are specific to ShapeCollection.

Public properties specific to ShapeCollection

Public properties (typical collection members omitted)
Width,HeightWidth and Height of the shape collection with respect to the parent coordinate space. This parent is either a ShapeCollection or a Canvas.
VirtualWidth,VirtualHeightThese are the width and height of the shape collection as seen by the child shapes. If these are different than Width and Height, a scaling is applied. VirtualWidth and VirtualHeight decouple the dimensions of the child shapes from the actual size of the parent shape collection.
ClipClip the child shapes to the Width and Height.

Each shapes collection corresponds to a rectangle. This rectangle has its lower left corner at (X,Y) and its upper-right corner at (X+Width,Y+Height). This rectangle clips the child shapes if an only if ShapeCollection.Clip is set.

Each ShapeCollection collection, including the top-most, introduces a new coordinate system for all child shapes. The origin of this new coordinate system coincides with the lower-left corner of the shapes collection. The upper-right right corner of the shapes collection is seen by the child shapes as (VirtualWidth,VirtualHeight).

The top-most ShapeCollection collection inherits the Width and Height of the containing Drawing class. Setting the Width and Height of the top-most ShapeCollection collection has no effect.

Nesting Of Shapes

Pens and Brushes

Before we discuss the PathShape and its derived classes, you should understand pens and brushes. A pen is used to draw a line or curve. A brush is used to fill areas. You can attach a pen and a brush to a PathShape. So if you add a rectangle shape to a drawing, the four lines are drawn using a pen and the area inside is filled using a brush. The same holds for circles, ellipses and pies.

Pen

A pen is defined by a width, color, pattern and the cap and join styles. Width and color are obvious. The pattern is an array of integers that specifiy alternating lengths of ink followed by no-ink. The array is applied repeatedly to draw the full length of the line to which the pen is applied. You can also specifiy at which position in the array to start drawing.

The Pattern Of A Pen Is Defined By A Phase And A Dashes Array

The cap and join styles define how line ends are connected and how open line ends are drawn, respectively.

Brush

Brush is an abstract base class. The following concrete implementations are available:

  • SolidBrush fills the area with a single color. This brush has a single property Color.
  • GradientBrush is an abstract class for gradient filled areas with 2 colors:
    • AxialGradientBrushA brush that paints a gradient fill that changes from one color to another along a straight line.
    • RadialGradientBrushA brush that paints a gradient fill that changes from one color to another between an inner and an outer circle.

PathShape

PathShape allows you to build an arbitrary open or closed shape consisting of lines and bezier curves. PathShape has a property PathShapeCollection to which you can add LineShape and BezierShape objects. The Shape.X and Shape.Y properties of the segments are ignored. Instead, the end point of the previous segment is the start point of the next. The start point of the first segment is the position of the containing PathShape. PathShape uses both a pen and a brush.

The figure below shows the PathShape class hierarchy.

Pathshape Class Hierarchy

LineShape

LineShape is a straight line. It starts at (Shape.X,Shape.Y) and it ends at LineShape.X1,LineShape.Y1). LineShape uses a pen but does not use a brush.

BezierShape

A bezier shape has a starting point (Shape.X,Shape.Y) and an end point (BezierShape.X3,BezierShape.Y3). The start and end point are controled by (BezierShape.X1,BezierShape.Y1) and (BezierShape.X2,BezierShape.Y2), respectively. BezierShape uses a pen but does not use a brush.

ArcShape

An arc shape is a segment of an ellipse outline. (Shape.X,Shape.Y) is the center point of this ellipse. ArcShape.Start and ArcShape.Sweep mark the starting and sweeping angle. Angle 0 corresponds to the right-most point. The sweeping angle is counter-clockwise. 360 corresponds to a full ellipse. The ellipse has a horizontal radius, Rx, and a vertical radius, Ry. ArcShape uses a pen but does not use a brush.

RectangleShape

Draws a rectangle with a lower-left corner at (Shape.X,Shape.Y). The width and height are set using the RectangleShape properties Width and Height. RectangleShape uses both a pen and a brush.

PieShape

PieShape specializes ArcShape: a pie is formed by drawing two straight lines from the center to the start and end point of the arc. PieShape uses both a pen and a brush.

EllipseShape

EllipseShape draws an ellipse with its center at (Shape.X,Shape.Y) and horizontal and vertical radi of EllipseShape.Rx and EllipseShape.Ry, respectively. EllipseShape uses both a pen and a brush.

Field Shapes

Field shapes are used to add PDF forms fields to the generated document. The field shapes can be combined with the ‘normal’ drawing shapes to create complete forms. For example the TextShape can be used to add the caption for the forms’ field shapes, and rectangles can be used to draw groups of check boxes, etc. FieldShape is the abstract base class (derived from Shape) all other field shapes. The following paragraphs discuss the specific field shapes in turn.

TextFieldShape

Generates a single line text entry field. By setting the ‘Password’ property to true, the value of the field will be hidden.

RadioButtonFieldShape

Creates a radio button. In a radio button group (identified by the FullName) there can be only one selected radio button.

CheckBoxFieldShape

Creates a checkbox, which can be either selected or not.

ListBoxFieldShape

Creates a list, of which a item can be selected.

DropDownListFieldShape

Creates a drop-down box from which an item can be selected.

PushButtonFieldShape

Creates a button which allows to send the form content to a server, reset the form content or perform another action. When sending the form to a server several submit formats can be selected such as HTTP (get/put), FDF, PDF and XFDF.

SignatureFieldShape

This shape adds an unsigned digital signature field to the generated document.

BarcodeShape

BarcodeShape is the abstract base of a number of barcode shapes. The class hierarchy is shown in the figure below.

Barcodeshape Class Hierarchy

Docking

Sometimes you do not want to or you cannot specify exact positions. Instead you want shapes to be stacked or docked in some direction. The top-level class Shape has a property Dock of type DockStyle. The default value is DockStyle.None meaning that the shape is positioned at exact coordinates. Setting the Dock property to any of the other values turns on docking behavior that is similar to how Winforms controls can be docked.

Context Fields

Context fields are specially formatted pieces of text that are substituted during rendering.

For example, you may assign “See #l #0 on page #p” to the text property of a fragment.

(#l, #0 and #p are the fields.) If the fragment has its GoToAction or Reference pointing to a table that has its Label property set to “Table” and is rendered on page 6, then the fragment appears in PDF as “See Table 3 on page 6”.

The following sub-sections discuss the different cases in which context fields can be used.

Label and Caption Properties

The Label property of a Paragraph reflects the nature of the content. Typical examples are “Table” and “Code Sample”. The Caption property is normally a single line summarizing the content of the Paragraph. For example, if a table shows the telephone region numbers of say Spain, then a typical Caption would be “Telephone region numbers of Spain”. In TallPDF.NET you can set these properties so that you can include this text through a reference field in e.g. a cross references or a ‘List of Tables’ without duplicating these values.

The following code shows how to add an image and set its Caption and Label properties.

Image image = new Image( "c:\images\portraits\vincentvangogh.jpg" );
image.Label = "Figure";
image.Caption = "Self-portrait of Vincent van Gogh";
image.Width = section.PageSize.Width * 0.8;
image.HorizontalAlignment = HorizontalAlignment.Center;
image.KeepWithNext = true;
section.Paragraphs.Add( image );

Code sample: Add an image with a label and caption in C#

Next, you want to add a line below this image that is formatted like: “Figure 3. Self-portrait of Vincent van Gogh”. Without duplication the caption or the label values, you would use the following code:

TextParagraph text = new TextParagraph();
Fragment fragment = new Fragment("#l #0. #c");
Fragment.Reference = image;
text.Fragments.Add(fragment);
section.Paragraphs.Add(text);

Code sample: Add a text line below an image that uses context fields for formatting

Bookmark Property of Heading

The Bookmark property of class Heading is of type string and specifies the format of the heading as respresented in the bookmark/outline tree of the PDF reader application.

The following table shows the different reference fields you may use and how they are interpreted.

Context fields for the Heading.Bookmark property

Reference fieldReplaced by
#cCaption property of the Heading object.
#lLabel property of the Heading object.
#The i-level heading number of the Heading object (1, 2, etc.).
#aThe i-level heading number of the Heading object formatted alphabetically, lowercase (a, b, etc.).
#AThe i-level heading number of the Heading object formatted alphabetically, uppercase (A, B, etc.).
#iThe i-level heading number of the Heading object formatted as roman numerals, lowercase (i, ii, etc.).
#IThe i-level heading number of the Heading object formatted as roman numerals, uppercase (I, II, etc.).

The following code sample adds a heading and format the bookmark title.

Heading heading = new Heading(0); // level 0
heading.SpacingBefore = 8;
heading.SpacingAfter = 4;
heading.Label = "Chapter";
heading.Caption = "Conceptual Overview";
heading.Fragments.Add(new Fragment("#l #0 - #c", Font.HelveticaBold, 16));
heading.Bookmark = "#0. #c";
section.Paragraphs.Add(heading);

Code sample: Add a heading and format the bookmark

The following table shows some specific samples.

Heading.Bookmark samples

This …Resolves to …
#l #0 – #cChapter 3 – Advantages
#0.#1 #c2.3 Advantages
#I0.#1 #cII.3 Advantages
#0.#a1 #c2.c Advantages

Fragment with HasContextFields

This case applies to the fields in the Text property of a Fragment object that has its HasContextFields property set and has its Reference field set to null.

Context fields for fragments that do not refer to a paragrap

Context fieldReplaced by
#pCurrent page number (1-based).
#PTotal number of pages.
#cranges from 0 to 9. The caption of the last i-level heading.
#lranges from 0 to 9. The label of the last heading at level i.
#ranges from 0 to 9. The last heading number at level i (1, 2, etc.).
#aranges from 0 to 9. The last heading number at level i formatted alphabetically, lowercase. (a, b, etc.)
#Aranges from 0 to 9. The last heading number at level i formatted alphabetically, uppercase. (A, B, etc.)
#iranges from 0 to 9. The last heading number at level i formatted as roman numerals, lowercase. (i, ii, etc.)

Fragment that Refers to a Heading

This case applies to the Text property of a Fragment of which either the Reference property or the GoToAction points to a Heading.

Context fields for fragments that refer to a heading

Context fieldReplaced by
#cCaption of the heading.
#lLabel of the heading.
#pThe number of the page where the heading is rendered.
#The i-level heading number of the heading (1, 2, etc.).
#aThe i-level heading number of the heading formatted alphabetically, lowercase (a, b, etc.).
#AThe i-level heading number of the heading formatted alphabetically, uppercase (A, B, etc.).
#iThe i-level heading number of the heading formatted as roman numerals, lowercase (i, ii, etc.).
#IThe i-level heading number of the heading formatted as roman numerals, uppercase (I, II, etc.).

Context field samples for fragments that refer to a heading.

This …Resolves to …
See #l #0, #cSee Chapter 3, Advantages
See also #l #0.#1 on page #pSee also Section 2.3 on page 11

Fragment that Refers to a Paragraph

This case applies to the Text property of a Fragment that has a GoToAction or Reference that points to another paragraph such as a Table or Image. Note that in that case you always specify 0 as the level since paragraphs other than Heading paragraphs do not have a level.

Context fields for fragments that refer to a paragraph

Context fieldReplaced by
#cCaption property of the Paragraph object.
#lLabel property of the Paragraph object.
#pNumber of the page on which the Paragraph is rendered.
#0Label number of the Paragraph object.
#a0Label number of the Paragraph object formatted alphabetically, lowercase (a, b, etc.).
#A0Label number of the Paragraph object formatted alphabetically, uppercase (A, B, etc.).
#i0Label number of the Paragraph object formatted as roman numerals, lowercase (i, ii, etc.).
#I0Label number of the Paragraph object formatted as roman numerals, uppercase (I, II, etc.).

Context field samples for fragments that refer to a heading.

Context field samples for fragments that refer to a heading.

This …Resolves to …
#l #0 – #cFigure 3 – Big losses
See #l #0 on page #pSee Table 3 on page 11

Fragment as Part of a Heading

This case applies to the Text property of a Fragment that is part of a Heading. These fragments are treated as if they have a Reference that points to the enclosing Heading paragraph. See the Section Fragment that Refers to a Heading.

CrossreferenceSection

The CrossreferenceSection lets you generate sections such as a ‘Table of Contents’, a ‘List of Tables’ or a ‘List of Figures’. The CrossreferenceSection was already introduced shortly in Sections. Because it relies heavily on the concepts introduced in this Chapter, we will discuss it in more detail now.

The mechanism of the CrossreferenceSection is based on the ComposeEntry event. This event is fired for each paragraph in the document. The event handler decides whether and how an entry has to be added to the CrossreferenceSection. E.g. if you want to generate a table of contents, then you would ignore all paragraphs that are not of type Heading.

The following code sample shows how to generate a simple table of contents.

CrossreferenceSection toc = new CrossreferenceSection();
toc.ComposeEntry += new ComposeEntryEventHandler( renderTocEntry );
doc.Sections.Add( toc );

Code sample: Add a CrossreferenceSection to a document in C#

The code below references the event handler renderTocEntry. Its implementation is shown in the next code sample:

static void renderTocEntry(
   CrossreferenceSection section, ComposeEntryEventArgs args )
{
   // check to see if the paragraph is a heading – if not, ignore
   Heading heading = args.CurrentParagraph as Heading;
   if ( !( args.CurrentParagraph is Heading ) ) return;

   // only includes level 0 and level 1 entries
   int level = heading.Level;
   if ( level > 1 ) return;

   // add an entry for this heading
   TextParagraph text = new TextParagraph();
   section.Paragraphs.Add( text );

   // the entry is a clickable link to the heading
   Fragment fragment = new Fragment();
   fragment.Actions.Add( new GoToAction( args.CurrentParagraph ) );
   text.Fragments.Add( fragment );

   // the content of the entry is formatted using context fields
   switch (level)
   {
      case 0:
         fragment.Text = "#0 #c - #p";
         fragment.FontSize = 12;
         break;
      case 1:
         fragment.Text = "#0.#1 #c - #p";
         fragment.FontSize = 10;
         break;
   }
}

Code sample: Handle the CrossreferenceSection.ComposeEntry event in C#

Event-Driven Generation

It is possible to add content in an event-driven manner. While the PDF document is being generated, events are fired. In the event handlers you provide content to be rendered. Using this model, TallPDF.NET will flash out pages while generating. Consequently the memory consumption is limited to the resources of a single page. This make TallPDF.NET the ideal component for generating large documents in a heavy-load environment.

By default, TallPDF.NET does not generate in event-driven mode. To generate in event-driven mde, you should call the Document.Write overload that takes an extra boolean as follows:

Document document = ...;
System.Web.HttpResponse httpResponse = ...;
FileStream file = ...;

// NOT event-driven
document.Write( file );
document.Write( file, false );
document.Write( httpResponse );
document.Write( httpResponse, false );

// event-driven
document.Write( file, true );
document.Write( httpResponse, true );

Code sample: Generate in event-driven mode by selecting the Document.Write overload (C#)

Restrictions

If you choose to generate the PDF document in an event-driven manner, you should be aware of a number of restrictions. These restrictions are a consequence of the forward-only, non-cached nature of the generation process. They should be considered as a trade-off between functionality and speed/memory footprint.

  • Cell.ColSpan is ignored. If a cell should span multiple columns, set its PreferredWidth property to a larger value so that is spans multiple columns.
  • Cell.FitToContent is ignored. You must set the PreferredWidth property to a predefined value.
  • Each section starts on a new page. The Section.StartOnNewPage property is ignored. If you want to switch to a different page layout, you can do this by handling the QueryPageSettings event which is fired for each page. If you want to switch to different headers/footers, you can do this by handling the StartPage and EndPage events which are fired for each page.
  • You can not cross-reference paragraphs from fragments.
  • Context fields are not resolved.
  • You cannot use the CrossreferenceSection class to generate a table of contents or a list of figures/tables.

Section Events

The following events are fired by the Section class.

Events fired by Section

EventFired whenDo this in your handler
QueryPageSettingsJust before a new page will be addedProvide the page settings such as the size of the different page boxes (media box, bleed box, etc.).
StartPageJust after a new page has been addedDefine areas on this page.
EndPageJust before a new page will be added.Add some final content.

ParagraphCollection Events

The following events are fired by the ParagraphCollection class.

Events fired by ParagraphCollection

EventFired whenDo this in your handler
PrintFirstParagraphJust before the first paragraph on the current page is added.Provide a paragraph that should be the first on the current page.
PrintParagraphNew content is required.Provide a new paragraph.

Paragraph Events

The following events are fired by the Paragraph class.

Events fired by Paragraph

EventFired whenDo this in your handler
BreakParagraphBefore a paragraph is broken across pages.Application specific.
ContinueParagraphBefore a paragraph continues on the next page.Application specific.
EndParagraphAfter a paragraph has been fully rendered.Application specific.
RollbackParagraphAfter a paragraph has been rolled back due to a text flow contraint such as keep-with-next.Application specific.
TransformParagraphAfter a paragraph has been tranformed. E.g. due to a vertical alignment setting of a table cell.Application specific.

TextParagraph Events

The following events are fired by the TextParagraph class.

Events fired by TextParagraph

EventFired whenDo this in your handler
LineBreakWhen a text line needs to be broken.Specifiy where to break the line. If you do not handle this event, lines are broken at whitespace occurrence which is perfectly reasonable.

RowCollection Events

The following events are fired by the RowCollection class.

Events fired by RowCollection

EventFired whenDo this in your handler
PrintFirstRowJust before the first row on the current page is added to the current table. Note that this even is fired n times if the table spans n pages.Provide a row that should be the first on the current page.
PrintRowA new row is required.Provide a new row.

Example: Firehose Generation from SQL

Generating a PDF document from data stored inside a SQL database can very well be done in an event-driven manner. This way you can fully profit from the performance benefits of the forward-only SqlDataReader.

Create a SqlDataReader

A SqlDataReader provides a forward-only, read-only pointer over data retrieved from a SQL database. The following code sample shows you how to create a SqlDataReader instance. (The pubs database is installed together with the .NET Framework SDK.)

SqlConnection connection = new SqlConnection(
   @"server=(local)\NetSDK;database=pubs;Trusted_Connection=yes");
SqlCommand command = new SqlCommand(@"select * from Authors", connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();

Code sample: Create a SqlDataReader in C#

Prepare Table.Rows

The next step is to setup the Table.Rows class for generating rows that correspond to the records in the database. First pass the reader to the Data member of the RowCollection class. The Data member allows you to associate any data with the RowCollection collection. This data will be available in the event handler that will provide the rows. Next, the event handlers are connected to the RowCollection class.

Table table = new Table();
table.Rows.Data = reader;
table.Rows.PrintRow += new PrintRowEventHandler(PrintRow);
table.Rows.PrintFirstRow += new PrintRowEventHandler(PrintFirstRow);

Code sample: Prepare Table.Rows in C#

Handle PrintRow Event

When the Document.Write method is called with the pull argument set to true, the event handler PrintRow will be called somewhere during the generation process. The following shows how to pull the content from the SqlDataReader and pass it on to the generation process.

bool PrintRow( object sender, PrintRowEventArgs args )
{
  SqlDataReader reader = args.Data as SqlDataReader;
  if ( null != reader && reader.Read() )
  {
    args.Row = new Row();
    addCell(
      args.Row, 
      reader.GetValue(2).ToString() + " " + reader.GetValue(1).ToString() );
    addCell( args.Row, reader.GetValue(4).ToString() );
    addCell( args.Row, reader.GetValue(5).ToString() );

    args.MoreContent = true; // we have more content
  }
  args.MoreContent = false; // no more content
}

Code sample: Handle PrintRow Event in C#

addCell is a helper method that adds a cell to the row instance and is rather trivial.

Handle PrintFirstRow Event

The PrintFirstRow event is fired to allow the handler to add one or more header rows. This event is fired for each page that the table spans. The following shows how to provide a single header row.

void PrintFirstRow(object sender, PrintRowEventArgs args)
{
   args.Row = new Row();

   addCell(args.Row, "Author");
   addCell(args.Row, "Address");
   addCell(args.Row, "City");

   // Only one line, no more content
   args.MoreContent = false;
}

Code sample: Handle PrintFirstRow Event in C#

Finalize

After generation, the connection to the database is closed:

try
{
   Document document = new Document();
   //...
   //...
   document.Write( reader, true );
}
finally
{
   //...
   if ( null != connection ) connection.Close();
}

Code sample: After generation, close the SQL connection.

Extend TallPDF.NET

TallPDF.NET exposes its functionality through a set of cohesive .NET classes,You can extend all these classes by inheriting from them. These specialization can then be used both programmatically and from XML.

Inherit from a TallPDF.NET Class

The following class definition shows how you can create a special Heading called H1 that encapsulates all settings that are specific to level-1 headings.

using TallComponents.PDF.Layout.Paragraphs;

namespace MyCompany.TallPDF
{
  public class H1 : Heading
  {
    public H1() : base(0)
    {
      Label = "Chapter";
      Bookmark = "#l #0 #c";
      Fragments.Add(new Fragment("#l #0 #c",Font.HelveticaBold, 14));
    }

    public string Text
    {
      get { return Caption; }
      set { Caption = value; }
    }
  }
}

Code sample: Create a specialized Heading

The following client code shows how H1 would typically be used:

Document document = new Document();
Section section = document.Sections.Add();
H1 h1 = new H1();
h1.Text = "Extend TallPDF.NET";
section.Add(h1);

Code sample: Use the specialized Heading

Use Specialized Class in XML

Given the specialized class H1, you can now use it in XML as follows:

<document>
   <section>
      <paragraph type="MyCompany.TallPDF.H1">
         Hello Extended World
      </paragraph>
   </section>
</document>

Code sample: Use specialized class in XML

Note that the content of the text node is assigned to the Text property of H1. See also Section Text Properties in Chapter Generate PDF from XML.

NOTE: It is necessary to force the CLR to load the assembly that defines H1 before you do the conversion. Otherwise, the CLR will not be able to create a new instance of your custom type through the .NET reflection mechanisms. You can do this by referring a type inside this assembly or by loading the assembly explicitly by calling Assembly.LoadFrom(“path to my assembly.dll” ).

Actions

In order to make a document responsive to user input, you can add actions. These actions are provided through the Action class and its specializations.

The following actions are supported by TallPDF.NET:

  • GoToAction: Jump to a paragraph in the same document or to a page in the same or another PDF document
  • JavaScriptAction: Perform scripted operations against the document
  • UriAction:Jump to a URI
  • UriAction:Jump to a URI

Actions can be assigned to the following properties:

  • Document.AfterOpen: Executed after the document has been opened
  • Document.BeforePrint
  • Document.AfterPrint
  • Document.BeforeSave
  • Document.AfterSave
  • Document.BeforeClose
  • LinkShape,MouseUpActions
  • PushButtonFieldShape.MouseUpActions
  • Fragment.Actions
  • Paragraph.Actions

GoToAction

The GoToAction jumps to a Paragraph inside the current document or to a page in the current or external PDF document. The destination is set by assigning a Destination object to the GoToAction.Destination property.

The following types of Destination exist.

ParagraphDestination

The ParagraphDestination points to another paragraph in the same document. The referenced paragraph may either be specifed by object reference or by using the an identifier (this is useful when using XML to define the document).

InternalPageDestination

The InternalPageDestination points to a page inside the same document. The page is specified by index. Due to the flow layout model, the exact page where content will be rendered is not know beforehand so the usefullness of this destination is limited.

RemoteDestination

The RemoteDestination points to a page in an external PDF document. It is specifed by the path of the PDF document and a page index. You can also specify additional settings such as zoom factor and the exact scroll position after jumping to the location.

UriAction

The UriAction jumps to a given URI. This is typically a web site address.

FormAction

FormAction is the abstract base class of the following actions:

  • ResetFormAction: reset all form fields in the document to their default value
  • SubmitFormAction: Submits the form data to a given destination. The URL and submit options such as the format can be specified as properties of this action.

JavaScriptAction

This action execute JavaScript against the current document. A PDF document is fully scriptable on the client side. Typical usage includes setting a text field value after clicking a button or showing/hiding a field after entering/leaving a form field. Here is the full JavaScript reference.

JavaScript

It is possible to define document-level JavaScript. You typically define functions and constants at this level. You can then call and use these from JavaScriptAction objects.

Convert XHTML to PDF

As of version 4.0 TallPDF.NET has extensive XHTML + CSS2 support. This is available through the XhtmlParagraph class. The XhtmParagraph class fully supports XHTML 1.0 Strict, XHTML 1.1 and CSS 2.1 including page breaks, forms and links.

XhtmlParagraph is a specialization of paragraph. Therefore, all members of paragraph are members of XhtmlParagraph as well. You can add it to a section, table cell, header or footer.

The following code snippets show how to use the XhtmlParagraph.

Document document = new Document();
Section section = document.Sections.Add();

// create an XhtmlParagraph with static content
XhtmlParagraph xhtml1 = new XhtmlParagraph();
xhtml1.Text = "<html><body><b><i>Hello world</i></b></body></html>";
section.Paragraphs.Add(xhtml1);

s// create an XhtmlParagraph from a URL
XhtmlParagraph xhtml2 = new XhtmlParagraph();
xhtml2.Path = @"http://www.yourserver.com/xhtml/path/file.htm";
section.Paragraphs.Add(xhtml2);

// convert to PDF and save
using (FileStream fs = new FileStream("out.pdf", FileMode.Create))
{
   document.Write(fs);
}

Code sample: Import XHTML in C#

Disclaimer

XhtmlPargraph tries its best to convert any XHTML to PDF. The output may not be identical to that of a major browser. It is recommended to use XhtmlParagraph in a controlled environment where the features used by your XHTML documents can be tested before being used.

XHTML vs HTML

The XhtmlParagraph expects XHTML as opposed to HTML. While XHTML is well-formed XML, HTML generally is not. Common differences are:

  • All elements must be closed. Use either  or <img… />).
  • Opening and closing tags must be correctly balanced:bold bolditalicitalic should be: bold bolditalicitalic
  • All attribute values have to be enclosed in quotes: should be

    Conversion Settings

    You can specify conversion settings that control different aspects of the XHTML conversion. These settings are specified in the XhtmlParagraph.Settings propery. The following code shows how to specify conversion settings using the ConversionSettings class:

XhtmlParagraph xhtmlParagraph = new XhtmlParagraph();
xhtmlParagraph.Settings = new ConversionSettings();

You can use the same ConversionSettings instance and assign it to multiple XhtmlParagraph instances. If you do not set the Settings property of an XhtmlParagraph, it will use default settings. The following paragraphs discuss the difference settings that are exposed by the ConversionSettings class.

Style Sheets

The CSS 2.1 specification states the following about the precedence of styles depending on their origin (in ascending order of precedence):

  1. user agent declarations
  2. user normal declarations
  3. author normal declarations
  4. author important declarations
  5. user important declarations

User Agent Declarations

The user agent declaration are incorporated in the converter itself. These are described in Appendix D, “Default style sheet for HTML 4” of the CSS 2.1 Specification. E.g. one such style definition is:

strong { font-weight: bolder }

This defines the default meaning of the strong element.

Author Declarations

The author normal declarations and author important declarations are embedded or referenced in the XHTML document itself. Because the precedence of these declarations are higher than the user agent declarations, you can override the semantics of the strong element as follows:

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<style type="text/css" id="internalStyle">
  strong { 
    color: green;
    font-family: monospace;
    font-weight: bold;
  }
</style>
</head>
<body>
<p>
  This is text that uses our 
  <strong>internal stylesheet</strong>.
</p>
</body>
</html>

A declaration is said to be important if the delimiter token “!” and keyword “important” follow the declaration as follows:

<style type="text/css" id="Style1">
    p { color:green!important }
</style>
<p style="color:red">This text will be green.</p>

Otherwise, the declaration is normal.

User Declarations

The third origin of style sheets is user. TallPdf.NET allows you to specify user style sheets through the ConversionSettings.StyleSheets property. The following code shows how to add a user style sheet:

XhtmlParagraph xhtmlParagraph = new XhtmlParagraph();
xhtmlParagraph.Settings = new ConversionSettings();

CssStyleSheet styleSheet = new CssStyleSheet();
styleSheet.Text = "strong { color:red!important }";
xhtmlParagraph.Settings.StyleSheets.Add(styleSheet);

Just like the author declarations, user declarations can be normal or important. This is determined by the use of the !important syntax. Note that the code sample above is a user important declaration and has the highest precedence of all declarations.

UseDtd

If you set UseDtd to false, then the DTD that is referenced by the XHTML document will be ignored. The default value is true. If you set this property to false, then all XHTML 1.1 entities will be resolved by TallPdf.NET itself. Any entities in the XHTML document that are not part of the XHTML 1.1 standard will result in an exception. So you should only set UseDtd to false if you are absolutely certain that all used entities are covered by the XHTML 1.1 standard. Setting UseDtd to false will increase the speed of the converter.

FontPath

By default, the converter will search the system fonts folder for fonts that are referenced in the XHTML document. When running in a context such as ASP.NET it might not be allowed to access the Windows Fonts folder due to security restrictions. In that case you can set the FontPath-property to point to an accessible folder containing True-type fonts.

Property ConversionSettings.FontPath allows you to control this. If you set this property, then the converter will first look inside ConversionSettings.FontPath, next it will look inside the system fonts folder. The default value of FontPath is null.

As opposed to the rest of TallPDF.NET, fonts have to be specified in the XhtmlParagraph using the font family name.

BasePath

During conversion, the base path will be searched for loadable objects such as images and style sheets. This base path will be determined once before the conversion starts and then used throughout the conversion. It is determined as follows:

  1. If property ConversionSettings.BasePath has been set, then this path is used as the base path.
  2. If the above property is not set, then property Document.Path or Area.Path (depending on the context) will be used as the base path. (If you use a FileStream as the source of the XHTML document, then we will use the underlying path as the base path.)
  3. If the above property is not set (because you use a stream or verbatim text), then the current folder of the application will be used as the base path.

PDF Settings

Three properties of the ConversionSettings class control the PDF output. These are EnableForms, EnableLinks and EnableTooltips. All these properties default to true.

EnableForms converts HTML forms and fields into PDF fields.

EnableLinks converts HTML links (A element with an href attribute) into PDF links.

EnableTooltips converts HTML tooltips into PDF tooltips.

Credentials

Sometimes, a password is required to access a URL. You can specify such a password using the Credentials property as follows:

XhtmlParagraph xhtmlParagraph = new XhtmlParagraph();
xhtmlParagraph.Settings = new ConversionSettings();

NetworkCredential credential = new NetworkCredential("jim","1234");
xhtmlParagraph.Settings.Credentials = credential;

ContentFitBehavior

The ContentFitBehavior property lets you specify how the HTML content scales to the PDF page. These are the different values:

DoNotScale: The HTML will not be scaled. 96 pixels correspond to 72 points (96 DPI). Note that the content may run over the right edge of the page.

SpecifyWidth: The property ConversionSettings.FixedWidth specifies the number of pixels that the width of the XhtmlParagraph corresponds with.

ScaleToWidth: The HTML content is scaled to fit the width of the section.

ScaleToSinglePage: The HTML content is scaled to fit both the width and the height of the page. The XhtmlParagraph will never be larger than a single page.

CustomResourceLoader

This property lets you specify a resource loader that has the first opportunity to load a resource such as an image as specified by the  tag. You should create a class that implements the IResourceLoader interface and then assign an instance of this class to this property. Its method LoadResource will be called for each resource. Return null if you want the engine to handle the request.

The custom resource loader can be implemented for resources that require authentication.

Restrictions

  • Only a single form per document is supported.
  • Javascript and Dynamic content (HTML generated through JavaScript, events etc.) are not supported.
  • Aural features are not supported.
  • Direction and Unicode-bidi are not supported.
Download TallPDF.NET 5.0
We will send you a download link
Why do we ask your email address?
We send tips that speed up your evaluation
We let you know about bug fixes
You can always unsubscribe with one click
We never share your address with a 3rd party
Thank you for your download

We have sent an email with a download link. Alternatively, you may want to use the NuGet package manager to install our library.

Nuget ID

Use the NugetID and start right away, or download the package and install it handmatically