|
iTextSharp
Tutorial
|
|
iTextSharp, a Free C#-PDF library
|
| [Home] |
[Previous] |
[TOC] |
[Next] |
[PDF] |
Part III: Advanced iText
Chapter 10: Absolute Positioning of Graphics and Text
|
PdfContentByte
Uptil now, we have used Simple iText,
we have added text and images, chapters and sections, lists and tables,...
without bothering about layout. iText took care of dividing the text into pages
and positioning every word, sentence, paragraph on a page. But sometimes we
don't want this automatic formatting. Sometimes we want to put some graphic or
some text at some exact position on a page. To achieve this, we are going to
use the class PdfContentByte.
So instead of what was said in Chapter 1, it's not
sufficient to invoke the method getInstance on
class PdfWriter, you must actually have a
PdfWriter-object. You can obtain this object by using the method
getDirectContent() on this writer-object.
Example:
PdfWriter writer = PdfWriter.getInstance(document, new
FileOutputStream("test.pdf"));
PdfContentByte cb = writer.DirectContent;
Remark:
When you add high level objects, such as Table, 2 different
PdfContentByte-objects are used internally: one for text and one for graphics
(for instance the borders or the background of a cell). The text is drawn on
top of the graphics.
When you use a PdfContentByte-object directly using the
getDirectContent()-method, everything you add to this object, is written on top
of the text and graphics. If you want to avoid this and if you want to add
content under the internal graphics and text PdfContentByte-objects, you have
to use the method getDirectContentUnder().
Summarized: when a page is finished, 4 layers are drawn on top of eachother in
this order:
-
the PdfContentByte you can retrieve and with the method getDirectContentUnder()
-
the internal PdfContentByte-object that contains the graphics of high level
objects
-
the internal PdfContentByte-object that contains the text of high level objects
-
the PdfContentByte you can retrieve and with the method getDirectContent()
|
|
Simple Graphics
In example 1,
some simple graphics are drawn. We use methods such as moveTo
and lineTo to move to a certain position on the
page and draw a line to another position. We use methods such as
setLineWith and setLineDash to alter the
appearance of the line.
Example:
cb.LineWidth = 10f;
cb.moveTo(100, 700);
cb.lineTo(200, 800);
cb.stroke();
Remark:
When you change the properties such as color, linewidth,... these changes will
been taken into account on the moment you call one of the stroke-methods.
In the example with the triangle, we set the color to green, but before we
stroke the triangle we change it to red. The resulting triangle will be red,
not green.
|
As you can see in the resulting PDF some
other methods such as rectangle and
circle are used.
|
Text
When you want to write text to the
contentbyte, you have to use the methods beginText()
and endText(). You also have to set the font and
size. As in the graphics example, there are lots of methods that can be used to
write and position text, but the ones you will need the most are the method
showTextAligned and the method showText in
combination with setTextMatrix.
Example 1:
BaseFont bf = BaseFont.createFont(BaseFont.HELVETICA,
BaseFont.CP1252, BaseFont.NOT_EMBEDDED); cb.beginText();
cb.setFontAndSize(bf, 12);
cb.showTextAligned(PdfContentByte.ALIGN_CENTER, text + "This text is centered",
250, 700, 0);
cb.endText();
Example 2:
BaseFont bf = BaseFont.createFont(BaseFont.HELVETICA,
BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
cb.beginText();
cb.setFontAndSize(bf, 12);
cb.setTextMatrix(100, 400);
cb.showText("Text at position 100,400.");
cb.endText();
Please take a look at example 2 and its
resulting PDF.
|
Templates (Form
XObjects)
When we discussed the HeaderFooter object in
Chapter 4, we defined a piece of information that was added on each
page. In fact, this piece of information was written to the file on every new
page. This is not a very economic solution. It is better to add this piece of
information only once to the document (as a form XObject) and repeat only its
visualization. To achieve this, we are going to use templates.
Creation of a PdfTemplate
The best way to create a PdfTemplate, is to invoke
the method createTemplate on the PdfContentByte-object:
PdfTemplate template = cb.createTemplate(500, 200);
In this case, the width of the template is 500, the height 200.
With this template, we can do the same things as we did with the
PdfContentByte.
template.moveTo(0, 200);
template.lineTo(500, 0);
template.stroke();
template.beginText();
BaseFont bf = BaseFont.createFont(BaseFont.HELVETICA, BaseFont.CP1252,
BaseFont.NOT_EMBEDDED);
template.setFontAndSize(bf, 12);
template.setTextMatrix(100, 100);
template.showText("Text at the position 100,100 (relative to the template!)");
template.endText();
Adding a template to the document
You can add a template at an absolute position like this:
cb.addTemplate(template, 0, 400);
But you can also do some funny things with Templates, such as rotate or scale
them:
// rotate the template 90 degrees
cb.addTemplate(template, 0, 1, -1, 0, 500, 200);
// scale the template to 50%
cb.addTemplate(template, .5f, 0, 0, .5f, 100, 400);
// scale the template to 200%
cb.addTemplate(template, 2, 0, 0, 2, -200, 400);
This is demonstrated in example 3 (see
Chap1003.pdf).
The Transformation
Matrix:
If you want to translate, scale or rotate images or text, you need to use a
Transformation Matrix. In the code you are asked for the transformation matrix
parameters a, b, c, d, e and f. But what do these parameters exactly mean?
This is the Transformation Matrix:
With the parameters e and f, you can specify a translation. The following
matrix moves everything e pixels in x-direction and f pixels in y-direction.
You can use the a and d parameter to scale. The following matrix doubles
everything in x-direction and triples everything in y-direction:
If you want to rotate something, you have to change a, b, c and d. With angle
equals to the rotation angle in radians, you have a matrix like this:
| [ |
Math.cos(angle) |
Math.sin(angle) |
0 |
] |
| -Math.sin(angle) |
Math.cos(angle) |
0 |
| 0 |
0 |
1 |
There is one serious caveat when you rotate an object: the coordinate of the
rotation pivot is (0, 0). If you rotate something, you have to watch out that
it is not rotated 'off' your page. you may have to perform a translation to
keep the object on the page. Of course you can combine translation (tX, tY),
scaling (sX, sY) rotation (angle) in one matrix:
| [ |
sX * Math.cos(angle) |
sY * Math.sin(angle) |
0 |
] |
| -sX * Math.sin(angle) |
sY * Math.cos(angle) |
0 |
| tX |
tY |
1 |
So you will have to use these parameters:
-
a = sX * Math.cos(angle);
-
b = sY * Math.sin(angle);
-
c = -sX * Math.sin(angle);
-
d = sY * Math.cos(angle)
-
e = tX;
-
f = tY;
|
Page x of y
In some cases, you may want to add information that is not available yet at the
moment you write a certain page to the outputstream. For instance: on the first
page of a document, you don't know how many pages the document will count in
total. You only know the total number of pages once you have finished
generating the entire document. This is not a problem when you use templates.
In example 3, we added information to the template before we added the
template to the contentbyte. This is not necessary. We can add information to a
template at any moment because iText adds the form XObjects at the end of the
PDF file (when the close-method of the document is
called).
Example 4 shows how 4 pages are created
first and how the total number of pages is added afterwards (Chap1004).
This example is very simple and not very useful rightnow, but in
Chapter 12, we will refine this example.
|
Columns
Earlier in this chapter, you have learned
how to put text on an absolute position. In casu: we were able to enter a
coordinate where iText had to start writing text. If we wanted to know the
position where the text ended, we had to do some calculations.
Now we want to add some text within a given rectangle. We want the text to wrap
automatically when the right limit of the rectangle is reached. All text that
doesn't fit in the rectangle isn't shown. We can achieve this using class
ColumnText.
An example:
To show a certain phrase, centered in a rectangle between the coordinates (100,
300) and (200, 500), we write some code like this:
PdfContentByte cb = writer.DirectContent;
ColumnText ct = new ColumnText(cb);
ct.setSimpleColumn(phrase, 60, 300, 100, 500, 15, Element.ALIGN_CENTER);
ct.go();
If you take a look at example 5 (Chap1005.pdf),
you immediately notice that this functionality can be used to draw some complex
tables without using the Table-object.
Another example:
It isn't necessary to add the text all at once. You can first define the
rectangle, then add some text and finally show the column with the
go-method:
PdfContentByte cb = writer.DirectContent;
ColumnText ct = new ColumnText(cb);
ct.setSim7pleColumn(60, 300, 100, 500, 15, Element.ALIGN_CENTER);
ct.addText(phrase1);
ct.addText(phrase2);
ct.addText(phrase3);
ct.go();
This is demonstrated in example 6; the
resulting PDF of this example is identical to the result of example 5.
Multiple columns
Of course, if there is more text than space in the rectangle, we don't want to
loose the text that didn't fit. Maybe we want this text to be shown in another
column. That's why we are going to take a look at the return value of the
go-method. If this return value has the flag 'NO_MORE_COLUMN'
turned on, there wasn't enough room for the text in the column. If all the text
was shown, the flag 'NO_MORE_TEXT' is on.
Please take a close look at example 7 and
see how we obtain a result like this.
Irregular columns
It is also possible to define an non rectangular area with to visualize
columns. With the method setColumns, we can define
a left and right boundary for the text:
float[] left = {70,790, 70,60};
float[] right = {300,790, 300,700, 240,700, 240,590, 300,590, 300,106, 270,60};
ct.setColumns(left, right);
The left border is a straight line, but the right border is irregular. The
effect of this functionality can lead to very nice layouts: see
Chap1008.pdf and the code that
was used to generate this example. You will need the image
caesar_coin.jpg.
|
PdfPTable
(by Paulo Soares)
We already briefly mentioned the
PdfPTable object in Chapter 5. Now
we are going to discuss some more features of this object.
You can create a PdfPTable in 3 different ways:
PdfPTable(float[] relativeWidths);
PdfPTable(int numColumns);
PdfPTable(PdfPTable table);
You can set some parameters for this table, such as the width of the table,
widths of the columns, the horizontal alignment,... You can add cells with
these methods:
public void addCell(PdfPCell cell);
public void addCell(PdfPTable table);
public void addCell(Phrase phrase);
public void addCell(String text);
This is all very similar to the Table-object,
except for cellpadding and cellspacing. These parameters are set on the level
of each individual cell. Of course you can define the default behaviour of a
Cell; to change the defaults of a cell, just use the method getDefaultCell()
and invoke one or more methods of class PdfPCell on
it (you can set alignments, padding, borders, colors, even a minimum height).
Important remark: With PdfPTable you can change the colspan of a Cell,
but you can't change the rowspan! Internally a PdfPTable is a stack of
independent rows. Supporting rowspan would involve a massive restructuring of
the class PdfPTable. It is not expected that this will happen in the near
future. You can work around this problem by using nested tables.
You can add a PdfPTable to a document as we did in Chapter
5, but you can also add the table on an absolute position of the
current page:
public float writeSelectedRows(int rowStart, int rowEnd, float
xPos, float yPos, PdfContentByte canvas);
The parameter rowStart is the number of the row you want to start with, rowEnd
is the last row you want to show (if you want to show all the rows, use -1).
xPos and yPos are the coordinates of the table and canvas is the
PdfContentByte-object.
In example 9 (Chap1009),
we add a simple table at position (100, 600):
table.writeSelectedRows(0, -1, 100, 600,
writer.DirectContent);
With PdfPTables, you can't set a rowspan and/or colspan. You can work around
this by using nested tables. See example 10
(Chap1010.pdf).
Finally example 11 and
example 12 show you how PdfPTable can be
used in combination with templates and columns (Chap1011.pdf
and Chap1012.pdf). For example 12 you
will need image cover.png.
|
SpotColors and Patterns
(by Phillip Pan)
The use of spotcolors is demonstrated in
example 13 (Chap1013.pdf).
example 14 (Chap1014.pdf) and
15 (Chap1015.pdf) demonstrate
the use of patterns. This will be documented in the future.
|
| [Top] |
[Previous] |
[TOC] |
[Next] |
[PDF] |
|