Flow layout API

From
Revision as of 17:44, 4 June 2018 by Adminko (talk | contribs)
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

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

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:

  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.