Flow layout API

From
Revision as of 17:22, 12 June 2018 by Adminko (talk | contribs) (Box model and layout basics)
Jump to: navigation, search

Overview

This API provides a new way to generate PDF files programmatically. In opposite to Fixed layout API, designed to be as close as possible to PDF specification, Flow layout API provides you with a number of high-level content building blocks e.g. TextBlock, Grid, Image which can be placed on a page and automatically positioned using so-called layout rules. The layout engine analyzes various properties of these content elements and then logically processes them according to the layout rules generating the resulting PDF document. Properties of these content elements can be assigned directly or defined by styles, thus it becomes possible to easily manage groups of objects with similar properties by changing corresponding style objects.

A process called style matching assigns a style to a particular object(content building block) based on style selector – a rule that defines which elements should be affected by this style. It works similar to HTML+CSS and one familiar with the latter can easily use one's experience and build PDF documents within a minute or even quicker. Actually, styles and content element are so native and easy to work with that we would recommend using it for generating of quickly changing and repetitive content, e.g. invoices, bills, reports, forms etc.

A list of supported features is rather big and we’d recommend checking code samples included along with the download package and showing the full power of Apitron PDF Kit and its Flow layout API in action. To name a few, it supports floating text, automatic pagination of grids and sections, ordered and unordered lists with various types of markers (including nested lists), text justification, dynamic content generation, automatic links and bookmarks creation and much more. It can even be mixed with elements from Fixed layout API.

This API is built around FlowDocument class and it’s possible to save created layout as XML template and load from it. It separates document design from actual processing and can be used to alter document appearance and introduce future changes without(!) recompiling the application.

Creating simple PDF document

Let's see how to create a simple PDF document with “Hello world” message on the first page using Flow layout API.

Consider the following code:

// create output file
using (Stream outputStream = File.Create("hello_world.pdf"))
{
    // create new document
    FlowDocument document = new FlowDocument()
    
    // add textual content element
    document.Add(new TextBlock("Hello world using flow layout API"));

    // save to output stream with page size A4
    document.Write(outputStream,new ResourceManager(), new PageBoundary(Boundaries.A4));    
}
 

Here you can see the basics of flow layout workflow, we create FlowDocument instance first, then we fill it with some content (simple TextBlock is used in this sample) and at the end we write it as PDF document to the output stream.

For writing we need an output stream, a ResourceManager instance that holds all resource objects used in the document (empty in our case) and PageBoundary object describing page dimensions. All pages in the target document will have the same dimensions unless they’re explicitly adjusted using techniques described in the article change page size and styles on the fly. As you can see, there is no notion of any style object or explicit property usage in this code sample. It was made intentionally to give you a very brief overview and a valid PDF document before moving on to more advanced topics.

And the results of the execution can be seen on the image below:

Create simple PDF file using flow layout API

Box model and layout basics

Flow Layout API uses a slightly modified traditional box model to define its content elements. Vertically infinite canvas limited by page width in horizontal dimension is used to layout them and to form the content of the resulting PDF document. The box model used by the Flow layout API assumes that margin, border and padding are inside the box defined by the element's width and height. See the image below:

Box model used by the Flow layout API


A content element gets rendered within its box and later placed on a page according to the layout rules and corresponding properties. It’s important to note that every element will always have implicit box even if you don’t specify its dimensions. One of the important properties, affecting the layout of the element, is Display. It specifies whether the element should be processed as:

  • Block – creating a line break before and after
  • Inline – added to the current line
  • InlineBlock – a special kind of Block element that doesn’t create line breaks
  • None - shouldn’t be processed at all

The main difference between Block, InlineBlock and Inline elements is that pure inline elements can’t be sized explicitly by setting their dimensions. It will be ignored the same way as HTML processors do. In addition several style properties can be inherited only by Block elements (actually a very few of them) and it will be discussed later in section Available style properties.

Main type used for specifying various elements' dimensions in Flow layout API is Length. Its constructor accepts values given in points, pixels, centimeters, inches, %'s and a special value Auto that depends on the context where it's used.

Style system

Style definition

Every content element or control element in Flow layout API has the same set of properties affecting its appearance and behavior at the time of processing. This set is called a style and can be of two kinds:

  • Internal style, holding the properties you can set directly using the object's instance. (inline styles are the closest alternative from the HTML/CSS world)
  • Matched style, provided by the style manager owned by the FlowDocument object instance and assigned using the specific selector

Style and StyleManager relationship

A Style class works as properties container and StyleManager class as document's style manager. FlowDocument class has a special property called StyleManager and all necessary styles should be added by means of this property.

A style however doesn’t come alone. It has a linked selector, an object that describes which elements should be affected by this particular style. In our case, a selector is a string written using the special syntax that defines which elements to match. If you ever worked with HTML and CSS then the syntax of these selectors will look familiar to you.

In short, the workflow is as follows:

  • Define styles and content elements that should be matched
  • Add styles to the flow document's StyleManager
  • Add content elements to the FlowDocument object
  • Save the result as PDF document or convert to FixedDocument instance if needed for further processing

It saves lots of time and code, and is a straightforward way to generate complex PDF content very quickly.

Selectors and style matching

Selector – is a rule that defines which elements should be matched and styled using the given style, it looks very similar to the notation used for CSS and is linked to a property set defined by the accompanying Style object.

Supported selectors:

  • Universal selector (“*”), selects all elements in a document or all children of a given element if used with child selector
  • Type selector (“_typename_”), selects all elements of the given type. E.g. “textbox”. It's possible to list several types using a comma, e.g. "textbox, section, image"
  • Class selector (“.classname”), selects all elements that belong to a specific class. E.g. “*.myclass” selects all elements with class “myclass”. Because element can have multiple classes set, it is possible to specify several classes in one selector, for example “*.myclass1.myclass2”
  • Id selector (“#elementID”). An element can have an id set - a special property usually used as a unique tag, and this selector matches the element with specific id.
    Sample:
    “texbox#help”, selects the textbox element with Id=“help”
  • Child selector (“[ancestor]>child”), selects all elements which are immediate children of specied ancestor element, square brackets indicate optionality of the ancestor, in case of absence it will behave as if a universal selector(“*”) was used instead
    Samples:
    “> textbox” – same as “textbox”, selects all textboxes which are children of any element,
    “section > textbox ” – select all textboxes which are placed in sections,
    “flowdocument > section> textbox.subheader” – selects all textboxes with the class ”subheader” set, nested in any section that is an immediate child of the document element(root)
  • Descendant selector (“element_1 element_2”) selects all elements which are descendants of a given element
    Sample:
    “section#header image” – selects all images in section with ID=”header” regardless of the inclusion level
  • Adjacent element selector (“predessor + element”), selects the element that precedes some element
    Sample:
    “image + textbox” – selects all images that precede a textbox.

How the styles are being resolved (rules of style matching):

  1. Directly assigned value is requested first. It's the value you set using any arbitrary property of the content element.
  2. If no value is set using p.1, the system tries to find the value using the registered selectors and styles
    1. look for all selectors that match given element
    2. select value according to matching rules (these rules are: specificity of the selector and order of addition, if specificity is the same, order is used)
  3. Request parent's value if property is inheritable using the same scheme

In general, this style system is close to CSS used with HTML, so one familiar with the latter can easily find similarities.

Available style properties

There are 36 different properties defined in Style class, plus some of the content elements may have their own specific properties which are not necessary related to style system but can be used to control their layout. It provides great flexibility and provides endless ways for the generation of PDF documents.

Each property defined in the Style class is explained below to give you an overview of the style system and how this properties interact with it, while custom content elements' properties are desctibed in the section Content elements and controls.

Layout-specific properties

  • Align - gets or sets the horizontal alignment of the element content, it can be Left, Right, Center or Justified. Only acceptable for block elements, this property will be ignored if the element is not a block-level element. Left, Right and Center values are supported by all elements. In case of Justify is used – only text elements will be affected. All elements inherit value from their block containers; only block elements can override parent's Align setting.
  • Clear - gets or sets the clear flag for the element indicating whether it should ignore floating elements (if any) and start a new line. Not inheritable.
  • Float - gets or sets the value indicating that element can float. Not inheritable.
  • Display - gets or sets the display setting for the element. Not inheritable.
  • Height - gets or sets the height of the element. Not inheritable.
  • Width - gets or sets the width of the element. Not inheritable.
  • LineHeight - gets or sets the height of the for the container line. For a block container element with content composed of inline-level elements, 'line-height' specifies the minimal height of line boxes within the element. On a non-inline element, 'line-height' specifies the height that is used in the calculation of the line box height. Inheritable.
  • Margin - gets or sets the margin around the element. Not inheritable.
  • Padding - gets or sets the padding. Not inheritable.
  • VerticalAlign - gets or sets the vertical align. Not inheritable.

Text-specific properties

  • Color - gets or sets the foreground color for the element. Inheritable.
  • CharacterSpacing - gets or sets the character spacing. Inheritable.
  • Font - gets or sets the font for the element. Inheritable.
  • ScriptLevel - gets or sets the value used to create subscripting or superscripting effect. It defines the level of effect, zero can be used for normal scripting, positive values are for superscripting, negative for subscripting. Affects textual elements. Not inheritable.
  • TextDecoration - gets or sets the text decoration. Inheritable.
  • TextIndent - gets or sets the text indent. Inheritable.
  • TextRenderingMode - gets or sets the text rendering mode used to draw textual elements. By default all text is being drawn using Fill setting. Inheritable.
  • WordSpacing - gets or sets the word spacing. Inheritable.

Background-specific properties

  • Background - gets or sets the background color. Not inheritable.
  • BackgroundImage - gets or sets the background image for the element. The background area of an element takes the total space occupied by the element content, including padding (but not the margin and border). By default, a background-image is placed at the top-left corner of the element, and repeated both vertically and horizontally. Not inheritable.
  • BackgroundPosition - gets or sets the background position value for the element. The background position property sets the starting position of a background image. Not inheritable.
  • BackgroundRepeat - gets or sets the background repeat value for the element. The background repeat property sets if/how a background image will be repeated. By default, background image is repeated both vertically and horizontally. Not inheritable.

Grid-specific properties

  • CellPadding - gets or sets the cell padding, affects only Grid elements. Not inheritable.
  • InnerBorder - gets or sets the inner border, affects only Grid elements. Not inheritable.
  • InnerBorderColor - gets or sets the color of the inner border affects only Grid elements. Not inheritable.

List-specific properties

  • ListCounter - gets or sets the list counter. Not inheritable.
  • ListMarker - gets or sets the list marker appearance. Inheritable.
  • ListMarkerPadding - gets or sets the list marker padding. Inheritable.
  • ListStyle - gets or sets the list style. Not inheritable.

Use type selector to style a text block

This code sample demonstrates basic usage of style system and assigns the same style to all textblocks in a flow document using the type selector:

// create output file
using (Stream outputStream = File.Create("selectors.pdf"))
{
    // create new document
    FlowDocument document = new FlowDocument();
    
    // register style that matches all textblocks and sets their text color
    document.StyleManager.RegisterStyle("textblock", new Style(){Color = RgbColors.Red});
    
    // add textual content element
    document.Add(new TextBlock("A textblock with red text"));
    
    // add textual content element and directly set its property overriding the matched style
    document.Add(new TextBlock("A textblock with black text"){Color = RgbColors.Black});
    // save to output stream with page size A4
    document.Write(outputStream, new ResourceManager(), new PageBoundary(Boundaries.A4));
}
 

You see from the code that we defined a type selector that matches all textblocks in the document. But according to the Rule #1 of style matching (see selectors and style matching) the second text box will have its color assigned to black, because any direct property assignment overrides the value provided by a matching style.

The results are shown on the image below:

Text block styled using type selector

Content elements and controls

Content elements, as the name suggests, are the building blocks for the flow document's content represented by the FlowDocument class. They all have the same set of properties, but may handle them differently depending on their nature. All content elements are inherited from a single base class ContentElement (even FlowDocument itself).

The following content elements are supported at the moment:

  • Textblock – for adding textual content
  • Image – for adding images
  • Br – indicates that line break should be created between the elements
  • Hr – creates a horizontal line much like in HTML
  • Section – container, for grouping elements together and creating lists
  • Grid - for a creation of grids, support column and row spans
  • PageCount – control that displays a number of pages in the document
  • PageBreak – indicates that a page break needs to be generated
  • ContentReference – used to place reusable pieces of content created with FlowContent, FixedContent or Image resource objects

Control elements, or simply controls are special content elements designed to build forms. From the PDF point of view, they produce widget annotation objects (see this article describing interactive forms for the details) and should have backing fields created for them. But you don’t have to worry about how content elements or controls are being wrapped to PDF entities, because almost all PDF specific operations are implemented under the hood and managed by the Apitron PDF Kit library automatically.

The following control elements are supported at the moment:

  • TextBox – used to create editable text fields that user can use for entering text
  • PushButton – a button that can have various Actions assigned (see Actions article to know more)
  • RadioButton – a control providing a way to choose a single item from a group
  • Choice – works much like a combo box or a list box depending on its properties
  • CheckBox – provides a way to create various check boxes in PDF form
  • SignatureControl – can be used to provide a visual representation for a signature field in Flow layout API context, see also this code sample explaining how signature mechanics are working implemented using Fixed layout API)

TextBlock

This element is designed to add text on page and has only one specific property Text for setting the text value. It’s also possible to create "dynamic" text objects using a delegate, which will be able to use some information present at the time of invocation for advanced text generation, e.g. one may use current time or page number.

Right to left and bidirectional text is supported automatically. Special characters supported are as follows: ‘&nbsp;’ (adds non-breaking space), ’&lt;’( adds ‘<’), ’&gt;’( adds ‘>’). By default this element is considered as Inline element unless its Display property has been changed.

See the code sample:

using (Stream outputStream = File.Create(“textblock.pdf”))
{
    // create new document with margin
    FlowDocument document = new FlowDocument(){Margin = new Thickness(5)};
    
    // create simple textblock
    TextBlock textBlock = new TextBlock(“Hello world!”);
    
    //create dynamic textblock and use PageGenerationContent for printing current page
    TextBlock textBlockDynamic = new TextBlock((ctx) => string.Format(“Hello world on page {0}!”,
    ctx.CurrentPage+1));
    
    // add created text blocks
    document.Add(textBlock);
    document.Add(new Br());
    document.Add(textBlockDynamic);
    
    // save to output stream with page size A4
    document.Write(outputStream, new ResourceManager(), new PageBoundary(Boundaries.A4));
}
 

Produced results are as follows:

Regular and dynamic TextBlocks


TextBlock content element uses one of the standard PDF fonts called Helvetica as default font. Default font size is set to 10pt. Font property can be used to change this behavior via inline or matched style.

Image

This element represents an image on PDF page. You have to create an image XObject first and register it using a ResourceManager that the FlowDocument instance uses for storing referenced resources. After these necessary preparation are done, you’ll be able to use it using the Image class from Flow layout API. Its ResourceId property can be used to check which resource this instance represents. By default this element is considered as Inline.

Note: Despite the fact that Image content element is Inline by default, its dimensions can be set explicitly and these settings will affect the final image size. It’s an exclusion from the common rule which however seems logical for such objects like image.

Consider the code below:

// create output file
using (Stream outputStream = File.Create(“image.pdf”))
{
    // create resource manager that will hold our resources
    ResourceManager resourceManager = new ResourceManager();
    // add image XObject to resource manager
    resourceManager.RegisterResource(new Apitron.PDF.Kit.FixedLayout.Resources.Xobjects.Image(“logo”,”apitron.png”));
    
    // create new document with margin
    FlowDocument document = new FlowDocument() { Margin = new Thickness(5) };
    
    // append image to the document
    document.Add(new Image(“logo”));
    
    // save to output stream with page size set to A4
    document.Write(outputStream, resourceManager, new PageBoundary(Boundaries.A4));
}
 

Result looks as follows:

Image content element added using Flow layout API

Br and Hr

Content element Br represents a line break and default height of the element is zero, it can be changed using its Height property. Content element Hr represents a horizontal line which is useful for visual formatting. Its default thickness is 1pt., but it can be changed using its Height property. Both elements are always considered as Block elements, thus producing a line break.

See the code sample below:

// create output file
using (Stream outputStream = File.Create(“br_and_hr.pdf”))
{
    // create new document with margin
    FlowDocument document = new FlowDocument() { Margin = new Thickness(5) };
    
    // add content
    document.Add(new TextBlock(“Text on line 1”));
    document.Add(new Hr());
    document.Add(new TextBlock(“Text on line 2”));
    document.Add(new Br());
    document.Add(new TextBlock(“Text on line 3”));
    
    // save to output stream with page size A4
    document.Write(outputStream, new ResourceManager(), new PageBoundary(Boundaries.A4));
}
 

Resulting image looks as follows:

Br and Hr elements usage


The Br element could be simulated by setting Display property for target element to Block in some cases. But if you’d like to create vertically spaced content lines with custom spacing between them, it just might be a better choice to use Br with a custom height set.

Section

Section is a container for logical grouping of content elements. It can be styled and added into other containers and also can be used to create ordered and unordered lists by setting its ListStyle property via a matching style or directly. By default this element is considered as Block. The closest alternative in the HTML world for the section is div merged with ol and ul elements.

Consider the following example, creating a basic section with two TextBlocks inside:

// create output file
using (Stream outputStream = File.Create(“section.pdf”))
{
    // create new document with margin
    FlowDocument document = new FlowDocument(){Margin = new Thickness(5)};
    
    // create a section and set its properties directly
    Section section = new Section()
    {
        Border = new Border(1),
        BorderColor = RgbColors.Red,
        Padding = new Thickness(Length.FromPoints(5)),
        Width = 150
    };
    
    // add some content to section
    section.Add(new TextBlock(“Inside the section (1)”));
    section.Add(new Br());
    section.Add(new TextBlock(“Inside the section (2)”));
    
    // add to the document
    document.Add(section);
    
    // save as a PDF document with page size A4
    document.Write(outputStream, new ResourceManager(), new PageBoundary(Boundaries.A4));
}
 

Resulting image is shown below:

Section content element

Grid

Grid content element can be used to group other elements in rows and columns. It’s a container for GridRow elements which you will use to create actual grid rows. This element has special proper

Navigation

Flow layout API supports all navigation features described in PDF specification and described in sections Document-level navigation and Add link annotations for quick navigation. Also there are many actions based samples in the chapter Actions usage samples. The concept behind the navigation techniques remain the same but, being different from Fixed layout API, Flow layout API provides its own implementation for these operations.

Each content element has two properties responsible for navigation:

  • Bookmark, which controls whether bookmark entry should be created for this element in the document bookmarks list. It’s of type BookmarkEntry and defines bookmark text as well as other properties needed to display it in bookmarks tab of the PDF viewer. Bookmarks set for content elements become naturally structured based on the element's nesting level and it in its turn will be reflected in the bookmarks tree of the document.
  • Link, which turns element to a link pointing to some destination. Can be of several types, see the chapter Links for the details. Please read the subparagraphs which contain descriptions for all mentioned properties and types with code samples and explanations.

Bookmarks

An object of type BookmarkEntry representing document bookmark can be attached to almost any content element; however there are a few exclusions: GridRow, Br and Hr elements. They were excluded because there makes no sense to create links to this content-less elements. The first one can be navigated using any of its cells, while the others have assume no meaningful content.

Bookmarks are organized hierarchically, so bookmark entries assigned to nested elements will be added as children to parent's element bookmark if it exists. If it doesn’t exist they’ll come to the upper level and so on, until they reach the root.

Every bookmark can have either static or dynamic caption assigned. Dynamic caption, as its name suggests, can be generated on the fly using a callback. It makes possible to customize the bookmarks creation according to the context state they are in. For example we can use current time or page number in bookmark's caption.

Consider the code below:

using (Stream outputStream = File.Create(“bookmarks.pdf”))
{
    // create new document with margin
    FlowDocument document = new FlowDocument() { Margin = new Thickness(5)};
    
    // add text element as immediate child of the document
    document.Add(new TextBlock(“Text element with bookmark”){Bookmark = new BookmarkEntry(“doc-level bookmark”)});
    
    // create nested text elements
    TextBlock nestedElement1 = new TextBlock(“Nested text element 1”){Bookmark = new BookmarkEntry(“child bookmark 1”)};
    TextBlock nestedElement2 = new TextBlock(“Nested text element 2”){Bookmark = new BookmarkEntry(“child bookmark 2”)};
    
    // add page break and move to second page
    document.Add(new PageBreak());
    
    // add section containing text elements and assign a bookmark to it
    document.Add(new Section(nestedElement1, new Br(), nestedElement2){Bookmark = new BookmarkEntry(“Section bookmark”)});
    
    // save to output stream with page size A4
    document.Write(outputStream, new ResourceManager(), new PageBoundary(Boundaries.A4));
}
 

The image below demonstrates the result:

Bookmark usage sample

Links

Links can be used to embed navigation elements into document page. Same limitations apply as for bookmarks, so GridRow, Br and Hr elements can’t act as links. Other content elements can be turned into links by assigning a target to their Link property. Once user clicks on such link, navigation will occur. Currently two link types are supported:

  • CrossReference, navigates to a location within the same document
  • LinkUri, based on URI and navigates to external resource

Note: An element can have both Bookmark and Link properties set.

Let’s see the code:

using (Stream outputStream = File.Create(“links.pdf”))
{
    // create new document with margin
    FlowDocument document = new FlowDocument(){Margin = new Thickness(5)};

    // add link to other element in document
    document.Add(new TextBlock(“Click here to see the element on second page”){Link = new CrossReference(“destination”)});
    document.Add(new Br(){Height = 5});
    
    // add external link to a website
    document.Add(new TextBlock(“www.apitron.com”){Link = new LinkUri(“http://www.apitron.com”), Color = RgbColors.Blue});
    
    // add page break and move to second page
    document.Add(new PageBreak());
    
    // create destination text block, set its id so it could be referenced by link
    document.Add(new TextBlock(“Destination element”) { Id = “destination”});
    
    // save to pdf document with page size A4
    document.Write(outputStream, new ResourceManager(), new PageBoundary(Boundaries.A4));
}
 

And resulting image:

Links creation sample

Markup parsing

Content elements defined in Flow layout API can be created based on some markup to reflect the desired document structure. It becomes especially useful when you have to create paragraphs containing blocks of text having different styles. So we designed and implemented a simple way to do it. A ContentElement class which serves as a base for all content elements contains a static method called FromMarkup(), it creates a collection of content elements using given paramater string as a text with certain markup.

This markup looks similar to XML, given that each element will have its Class property assigned to a name or a set of names derived from the enclosing tags. The resulting list will contain parsed content elements (mostly TextBlocks) with assigned classes. A single markup element can contain the following attributes:

  • Link, affects the Link property of the created element. If link destination starts with # then it will be considered to be a CrossReference element otherwise a LinkUri. There is an additional href attribute supported for convenience that works exactly the same.
  • Bookmark, affects the Bookmark property of the created element.
  • Id, affects the Id property of the created element, so it can be linked to.

A few tags in this markup have special meaning:

  • <img>, can be used for placing images, e.g. <img src='[path to file or resource id]' width='[image width][unit]' height='[image height][unit]'/> creates Image element entry. Measure unit can be omitted or can be one of the following: auto, pt, in, px, cm, %.
  • <br/>, creates Br element entry.

Note: Given that markup text is in XML format and its parsing is implemented using XML-aware utils, entries which don't exist in XML like &nbsp; should be entered differently. So instead of ‘<tag> mytext.&nbsp;</tag>’ one should use ‘<tag> mytext.&#160;</tag>’ or ‘<tag> mytext.&amp;nbsp</tag>’ which will produce the same result.

For the detailed sample please take a look at the SimpleHtmlToPDF sample included into the [www.apitron.com/downloads | Apitron PDF Kit download package]. Below is a small piece of code that shows some of the features of markup parsing in action.

// create output file
using (Stream outputStream = File.Create("create_from_markup.pdf"))
{
    // create resource manager and register image to be used further
    ResourceManager resourceManager = new ResourceManager();
    resourceManager.RegisterResource(new Apitron.PDF.Kit.FixedLayout.Resources.XObjects.Image("logo","apitron.png"));

    // create document and set margin
    FlowDocument document = new FlowDocument(){Margin = new Thickness(10)};
    
    // header style
    document.StyleManager.RegisterStyle(".h1", 
       new Style()
       {
           Display = Display.Block, 
           Font = new Font(StandardFonts.HelveticaBold,16), 
           Margin = new Thickness(0,3,0,3)
       });
    
    // italic text style
    document.StyleManager.RegisterStyle(".i", 
       new Style()
       {
          Font = new Font(StandardFonts.HelveticaOblique,12)
       });
       
    // bold text style
    document.StyleManager.RegisterStyle(".b",
        new Style()
        {
                Font = new Font(StandardFonts.HelveticaBold,12)
        });

    // link style
    document.StyleManager.RegisterStyle(".a", new Style() { Color = RgbColors.Blue, 
        TextDecoration = new TextDecoration(TextDecorationOptions.Underline)});

    // image style
    document.StyleManager.RegisterStyle(".img", new Style() { Float = Float.Left});
    
    string markup = "<h1>Markup parsing</h1><img src='logo'></img>One of the advantages of using <i>markup parsing</i> is that" +
    " styled text can be produced quckly and resulting PDF looks awesome." +
    "Just call <b>ContentElement.FromMarkup</b> static function and it's done." +
    "Xml-based markup makes it esy to define own tags which are being transformed to classes and style them using class selectors."+
    "Create floating text, bookmarks, links, images and other PDF content with this style-based and very easy to use API." +
    "Read more about Apitron PDF Kit for .NET and its features on our website <a href='http://www.apitron.com'>www.apitron.com</a>.";
    
    document.Add(new Section(ContentElement.FromMarkup(markup)));
    document.Write(outputStream, resourceManager, new PageBoundary(Boundaries.A4));
}
 

The code from previous page registers several styles for the text markup representing a small piece of text containing an image with a text floating on the right. It also shows how to define a weblink, make text bold or italic. Special class for header becomes defined as well (“h1”). Resulting file is shown on the image below:

Markup parsing sample

XML templates

FlowDocument model supports XML export and import features, and one can use it to separate PDF documents creation from the code. As an example one may have a set of PDF forms stored as XML templates (supported by Apitron PDF Kit) which require regular updating. In this case application doesn't need to be rebuilt and updated, it will just load the updated templates and work as it did.

Limitations: some resource objects can’t be saved to XML, e.g. image data (because images can be linked only), FixedContent or FlowContent objects, external font files data.

The code which saves document to XML and loads it from template is as follows:

// save document to XML template (1)
using (Stream outputStream = File.Create("document_template.xml"))
{
    // create document resource manager
    ResourceManager resourceManager = new ResourceManager();

    // create new document with margin
    FlowDocument document = new FlowDocument() { Margin = new Thickness(5) };
    
    // add content elements
    document.Add(new TextBlock("text element"));
    
    //...create your document structure here
    document.SaveToXml(outputStream, resourceManager);
}

// load XML template from file (2)
using (Stream inputStream = File.OpenRead("document_template.xml"), outputStream = File.Create("fromxml.pdf"))
{
    // create resource manager which will hold loaded references
    ResourceManager resourceManager = new ResourceManager();
    
    // load document
    FlowDocument document = FlowDocument.LoadFromXml(inputStream, resourceManager);
    
    // save to pdf
    document.Write(outputStream,resourceManager,new PageBoundary(Boundaries.A4));
}
 

Here we used SaveToXml instance method to save document as XML template (1) and LoadFromXml static method to load this template (2).

XML template example

Consider the following template generated using the code from XML templates:

<?xml version="1.0" encoding="utf-8"?>
    <FlowDocument xmlns="Apitron.PDF.Kit.FlowLayout.v1">
        <Resources />
        <Styles>
            <Style selector="flowdocument">
                <Color value="Black" />
            </Style>
            <Style selector="grid">
                <InnerBorder thickness="1" />
                <InnerBorderColor value="Black" />
            </Style>
        </Styles>
        <Elements>
            <TextBlock>
                <Properties>
                    <Text value="text element" /> (1)
                </Properties>
            </TextBlock>
        </Elements>
        <Properties>
            <Margin value="5,5,5,5" />
        </Properties>
</FlowDocument>
 

If you change the template by adding a section:

<Style selector="textblock">
    <Color value="Red"/>
</Style>
 

to the <Styles> node of the template and load it using part (2) of the code from the main chapter you’ll get the following color change:

Create PDF document using modified XML template


Integration with Fixed layout API

One may have noted that sometimes Flow layout API samples make use of many classes defined for the Fixed layout API. The decision behind this was not to create duplicating entities serving as alternatives to the existing classes where it was appropriate. However, while working with FixedDocument it is sometimes advantageous to use the flexibility Flow layout API can offer.

So a special AppendContentElement() method was added to a ClippedContent class inherited by every drawing context in Fixed layout API. This method accepts ContentElement objects defined in Flow layout API and allows using them directly(without preprocessing) for the generation of PDF content with Fixed layout API.

Note: As there is no StyleManager in FixedDocument model, style support is limited to inline styles only. That's is to modify the appearance of ContentElement objects used in Fixed layout API one has to set element's properties directly.

Consider the code:

using (Stream outputStream = File.Create("flow_in_fixed.pdf"))
{
    // create document and add one page to it
    FixedDocument fixedDocument = new FixedDocument();
    fixedDocument.Pages.Add(new Page());
    
    ClippedContent content = fixedDocument.Pages[0].Content;
    // add TextBlock content element to the page's content
    content.Translate(10,790);
    content.AppendContentElement(new TextBlock("This multiline text box was created using TextBlock element."), 190,40);
    
    // add text using regular textobject, you’ll have to layout all text yourself
    content.Translate(210,28);
    TextObject textObject = new TextObject(StandardFonts.Helvetica, 12);
    textObject.AppendText("This multiline text box was created");
    textObject.MoveToNextLine(0,-15);
    textObject.AppendText("using TextObject.");  
    content.AppendText(textObject);
    
    // save document
    fixedDocument.Save(outputStream);
}
 

And the resulting image:

Using ContentElement objects in Fixed layout API