Monday, June 13, 2016

Creating Lists with PDFBox-Layout

The last article gave you a brief introduction on what you can do with PDFBox-Layout. The new release 0.6.0 added support for indentation and lists, and that’s what this article is about.

Indentation

Indentation is often used to structure content, and it is also the base for creating lists. Let’s start with some simple example using the Indent element.

paragraph.addMarkup(
    "This is an example for the new indent feature. Let's do some empty space indentation:\n",
        11, BaseFont.Times);
paragraph.add(new Indent(50, SpaceUnit.pt));
paragraph.addMarkup("Here we go indented.\n", 11, BaseFont.Times);
paragraph.addMarkup(
    "The Indentation holds for the rest of the paragraph, or... \n",
    11, BaseFont.Times);
paragraph.add(new Indent(70, SpaceUnit.pt));
paragraph.addMarkup("any new indent comes.\n", 11, BaseFont.Times);

So what do we do here: we add an indent of 50pt width. This indent will be automatically inserted after each newline until the end of the paragraph…or a new indent is inserted. That’s what we do here, we insert an indent of 70pt:

indention

An indent may also have a label (after all, this is the foundation for lists). By default the label is right aligned, as this makes sense for lists. But you may specify an alignment to fit your needs:

paragraph = new Paragraph();
paragraph
    .addMarkup(
        "New paragraph, now indentation is gone. But we can indent with a label also:\n",
        11, BaseFont.Times);
paragraph.add(new Indent("This is some label", 100, SpaceUnit.pt, 11,
    PDType1Font.TIMES_BOLD));
paragraph.addMarkup("Here we go indented.\n", 11, BaseFont.Times);
paragraph
    .addMarkup(
        "And again, the Indentation holds for the rest of the paragraph, or any new indent comes.\nLabels can be aligned:\n",
        11, BaseFont.Times);
paragraph.add(new Indent("Left", 100, SpaceUnit.pt, 11,
    PDType1Font.TIMES_BOLD, Alignment.Left));
paragraph.addMarkup("Indent with label aligned to the left.\n", 11,
    BaseFont.Times);
paragraph.add(new Indent("Center", 100, SpaceUnit.pt, 11,
    PDType1Font.TIMES_BOLD, Alignment.Center));
paragraph.addMarkup("Indent with label aligned to the center.\n", 11,
    BaseFont.Times);
paragraph.add(new Indent("Right", 100, SpaceUnit.pt, 11,
    PDType1Font.TIMES_BOLD, Alignment.Right));
paragraph.addMarkup("Indent with label aligned to the right.\n", 11,
    BaseFont.Times);
document.add(paragraph);

indentionWithLabel

Lists

As already said, indentations where introduced in order to support list, so let's build one. It's nothing but indentation with a label, where the label is a bullet character:

paragraph = new Paragraph();
paragraph.addMarkup(
    "So, what can you do with that? How about lists:\n", 11,
    BaseFont.Times);
paragraph.add(new Indent(bulletOdd, 4, SpaceUnit.em, 11,
    PDType1Font.TIMES_BOLD, Alignment.Right));
paragraph.addMarkup("This is a list item\n", 11, BaseFont.Times);
paragraph.add(new Indent(bulletOdd, 4, SpaceUnit.em, 11,
    PDType1Font.TIMES_BOLD, Alignment.Right));
paragraph.addMarkup("Another list item\n", 11, BaseFont.Times);
paragraph.add(new Indent(bulletEven, 8, SpaceUnit.em, 11,
    PDType1Font.TIMES_BOLD, Alignment.Right));
paragraph.addMarkup("Sub list item\n", 11, BaseFont.Times);
paragraph.add(new Indent(bulletOdd, 4, SpaceUnit.em, 11,
    PDType1Font.TIMES_BOLD, Alignment.Right));
paragraph.addMarkup("And yet another one\n", 11, BaseFont.Times);

list

Ordered Lists with Enumerators

Ordered lists are quite helpful to structure and reference text. You already have all ingredients to build an ordered lists; just use increasing numbers as labels, and that's it. What would I need an API for to do that?!? How about a list with roman numbers:
RomanEnumerator e1 = new RomanEnumerator();
LowerCaseAlphabeticEnumerator e2 = new LowerCaseAlphabeticEnumerator();
paragraph = new Paragraph();
paragraph.addMarkup("Also available with indents: Enumerators:\n", 11,
    BaseFont.Times);
paragraph.add(new Indent(e1.next() + ". ", 4, SpaceUnit.em, 11,
    PDType1Font.TIMES_BOLD, Alignment.Right));
paragraph.addMarkup("First item\n", 11, BaseFont.Times);
paragraph.add(new Indent(e1.next() + ". ", 4, SpaceUnit.em, 11,
    PDType1Font.TIMES_BOLD, Alignment.Right));
paragraph.addMarkup("Second item\n", 11, BaseFont.Times);
paragraph.add(new Indent(e2.next() + ") ", 8, SpaceUnit.em, 11,
    PDType1Font.TIMES_BOLD, Alignment.Right));
paragraph.addMarkup("A sub item\n", 11, BaseFont.Times);
paragraph.add(new Indent(e2.next() + ") ", 8, SpaceUnit.em, 11,
    PDType1Font.TIMES_BOLD, Alignment.Right));
paragraph.addMarkup("Another sub item\n", 11, BaseFont.Times);
paragraph.add(new Indent(e1.next() + ". ", 4, SpaceUnit.em, 11,
    PDType1Font.TIMES_BOLD, Alignment.Right));
paragraph.addMarkup("Third item\n", 11, BaseFont.Times);
document.add(paragraph);
enumerators
Enumerators ease the task of generating ordered lists programmatically (and the markup API could not live without 'em ;-). Currently the following enumerators are supported:
  • ArabicEnumerator (1, 2, 3, 4...)
  • RomanEnumerator (I, II, III, IV...)
  • LowerCaseRomanEnumerator (i, ii, iii, iv...)
  • AlphabeticEnumerator (A, B, C, D...)
  • LowerCaseAlphabeticEnumerator (a, b, c, d...)

Markup

The markup API eases the burden of creating features programatically, and for sure you can do indentation and lists with markup. We're gonna start with some simple indentation. You start the indentation with -- at the beginning of a new line:
"--At vero eos et accusam\n"

Indents run until the end of a paragraph, or until another indentation starts. But you can you can explicitly end the indentation with !-:
"-!And end the indentation.\n"
indentation-markup

The default indent is 4 characters, but you can customize this by specifying the desired indentation in pt or em, so the markup --{50pt} will give you an indent of 50pt. Be aware that this size is per indent level, so if you prefix a space, you will get 100pt in this case.

To create lists with bullets, use the -+ markup:
"-+This is a list item\n"
"-+Another list item\n"

You can specify different levels of indentation just be prefixing the indent markup with one or multiple spaces:
" -+A sub list item\n"

You can customize the indent size and the bullet character (after all, this is the indentation label). Let's do an indent of 8 characters and use >> as the bullet: -+{>>:8em}
list-markup

Enumerated lists are supported also, just use the -# markup:

"-#This is a list item\n"
"-#Another list item\n"
" -#{a:}A sub list with lower case letter\n"
"-#And yet another one\n\n"

enumerators-markup
Again, you can customize the indent size and also the enumeration type. The default type is arabic numbers, but let's use the roman enumerator: `-#{I:6em}. The following enumerator types are built in:
  • 1 arabic
  • I roman, upper case
  • i roman, lower case
  • A alphabetic, upper case
  • a alphabetic, lower case
So let's use some custom separators here:

"-#This is a list item\n"
"-!And you can customize it:\n"
"-#{I ->:5}This is a list item\n"
"-#{I ->:5}Another list item\n"
" -#{a ~:30pt}A sub list item\n"
"-#{I ->:5}And yet another one\n\n";
custom-lists-markup

But you may also write your own enumerator and use it in markup, see class EnumeratorFactoryfor more details on that.

Regards
Ralf
The human animal differs from the lesser primates in his passion for lists.
H. Allen Smith

7 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Hi. I think this is what I am looking for. How do I get this as a .jar file to include in my project? I'm very new to this please.

    ReplyDelete
  3. Hi. I think this is what I am looking for. How do I get this as a .jar file to include in my project? I'm very new to this please.

    ReplyDelete
  4. Most people use maven, gradle etc. dependency management. However, I've added some download links on the GitHub readme page, so you may directly download the jars :-)

    Regards
    Ralf

    ReplyDelete
    Replies
    1. Thanks for an amazing work, I am having an issue with creating a table based layout with multiple rows and columns using Paragraph and Indentation. Is there an example I can refer or is there any support for table based layout? Much appreciated.

      Delete
  5. Thank you very much.
    Very usefull library

    ReplyDelete
  6. Hi, thanks a lot for this very useful API.
    One enhancement to be considered in my opinion is the automatic first line indentation of paragraphs. I tried to add the tabulation character '\t' at the beginning of my paragraph but I got an error (IllegalArgumentException in PDType1Font.java line 425 in the 'encode' method).

    ReplyDelete