Chapter 11. Choosing the right font

This chapter covers

  • Font files, types, and classes
  • Writing systems and advanced typography
  • Automatic font creation and selection

We discussed two font classes in chapter 2: Font and BaseFont. You used the Font class in section 2.2.1 for the 14 standard Type 1 fonts. These fonts are supposed to be “known” by every PDF viewer and are therefore never embedded by iText. In section 2.2.2, you used the Font class in combination with BaseFont to embed fonts. You created a BaseFont object by telling iText where to find a font program; for instance, a .ttf file. In chapter 3, you needed the BaseFont class to set the font when writing text to the direct content. You’ve also learned how to measure Strings in a certain font, how to change the render mode, and so on.

You know how to use fonts in your applications, but how do you choose them? Which font files can be used with iText? How about special writing systems? In some languages, you have to write from right to left, and from top to bottom. Furthermore, there are some convenience classes that make it easier to select a font. You’ll find the answers to all these questions in this chapter.

11.1. Getting fonts from a file

Figure 11.1 shows a PDF containing a sentence written nine times using different fonts.

Figure 11.1. One sentence written in different fonts

The document also shows which font program and encoding was used, and which iText class was responsible for interpreting the font. In the next subsections, we’ll approach this example from different angles. First, let’s take a look at the font files that can be used.

11.1.1. Font files and their extensions

Table 11.1 lists the extensions of the files that contain the font metrics or the font program, or both. Type 1 was originally a proprietary specification owned by Adobe, but after Apple introduced TrueType as a competitor, the specification was published, and third-party font manufacturers were allowed to create Type 1 fonts, provided they adhered to the specification. In 1991, Microsoft started using TrueType as its standard font.

Table 11.1. Font files and their extension

Font type

Extension

Description

Type 1 font files .afm, .pfm, .pfb A Type 1 font is composed of two files: one containing the metrics (.afm or .pfm), and one containing the mathematical descriptions for each character (.pfb).
TrueType font files .ttf A font based on a specification developed by Apple to compete with Adobe’s Type 1 fonts.
OpenType font files .otf, .ttf, .ttc A cross-platform font file format based on Unicode. OpenType font files containing Type 1 outlines have an .otf extension. Filenames of OpenType fonts containing TrueType data have a .ttf or .ttc extension. The .ttc extension is used for TrueType collections.

For a long time, TrueType was the most common font on both Mac OS and MS Windows systems, but both companies, Apple as well as Microsoft, added their own proprietary extensions, and soon they had their own versions and interpretations of (what once was) the standard. When looking for a commercial font, you had to be careful to buy a font that could be used on your system. A TrueType font for Windows didn’t necessarily work on a Mac. To resolve the platform dependency of TrueType fonts, Microsoft started developing a new font format. Microsoft was joined by Adobe, and support for Adobe’s Type 1 fonts was added. In 1996, a new font format was born: OpenType fonts. The glyphs in an OpenType font can be defined using either TrueType or Type 1 technology.

This demonstrates how the PDF shown in figure 11.1 was created.

Listing 11.1. FontTypes.java

There are many things going on in this code snippet, but for now we’ll focus on the files that were used to create the BaseFont object.

11.1.2. Type 1 fonts

If you open the iText JAR, you’ll find a com/itextpdf/text/pdf/fonts folder containing 14 .afm files. These are the Adobe Font Metrics (AFM) files for the 14 standard Type 1 fonts: 4 Helvetica fonts (normal, bold, oblique, and bold-oblique), 4 Times-Roman fonts (normal, bold, italic, and bold-italic), 4 Courier fonts (normal, bold, oblique, and bold-oblique), Symbol, and Zapf Dingbats.

Adobe Font Metrics (AFM) Files

The AFM files are used when you create a Font like this:

Font f = new Font(FontFamily.COURIER, 10, Font.BOLD);

Or when you create a BaseFont like this:

BaseFont bf = BaseFont.createFont(
BaseFont.TIMES_ITALIC, BaseFont.WINANSI, BaseFont.EMBEDDED);

The former will fetch the Courier-Bold.afm file from the iText JAR; the latter will get the Times-Italic.afm file. The AFM files only contain metrics for each glyph: the bounding box, the character advance, and so on.

 

FAQ

Why do I get an IOException when I use the default or a standard font? If you get an exception with a message saying something like “Helvetica not found as resource.” this means that the AFM file containing the font metrics of the font Helvetica can’t be loaded as a resource. This will happen if you build the JAR from source code but forget to include the AFM file. Add them to the iText JAR, or check if you have access to the com/itextpdf/text/pdf/ fonts/*.afm files for the standard Type 1 fonts.

 

Note that the BaseFont.EMBEDDED parameter will be ignored for the standard Type 1 fonts. That’s because iText doesn’t ship with the PostScript Font Binary (PFB) files of these fonts.

Postscript Font Binary Files

The actual outlines of each glyph aren’t stored in the metrics file, but in a separate PFB file. In listing 11.1, the cmr10.afm AFM file is used. This is the metrics file for Computer Modern Regular, a font designed by Donald Knuth. When you tell iText to embed this font, it will check whether the cmr10.pfb file is present in the same directory as the AFM file. If that file is missing, you’ll get an exception saying “resources/ fonts/cmr10.pfb not found as file or resource.” Computer Modern Regular is used twice in our example: once with an AFM file and once with a PFM file.

Printer Font Metrics (PFM) Files

Printer Font Metrics (PFM) files are the Microsoft version of AFM, and iText is able to convert PFM into AFM. The same PFB file is used for both types of metrics files. Type 1 fonts aren’t subset by iText; when you choose to embed a Type 1 font, the outlines of all glyphs in the font are embedded, including those that aren’t used in the document.

Now let’s take a look at the difference between TrueType fonts and OpenType fonts.

11.1.3. TrueType and OpenType fonts

Files with the .ttf extension can be either a TrueType font, or an OpenType font with TrueType outlines. Figure 11.2 shows a fragment of the fonts folder on Windows. The snippet contains icons for two .ttc and four .ttf files.

Figure 11.2. TrueType fonts, TrueType collections, OpenType fonts with TrueType outlines

Thanks to the icon that’s used, you can distinguish the TrueType fonts—the ones with the TT icon—from the OpenType fonts with TrueType outlines—the ones with the O icon. This difference doesn’t matter much if you’re using iText; you only have to be careful if you’re using a TrueType collection—with the TC icon.

Truetype Collections

A TrueType collection is, as the name indicates, a collection of TrueType fonts bundled in one .ttc file. Figure 11.3 shows the fonts available in the file msgothic.ttc.

Figure 11.3. TrueType collection example

In the next example, you’ll use the enumerateTTCNames() method to find the names of the fonts inside the collection.

Listing 11.2. TTCExample.java
String[] names = BaseFont.enumerateTTCNames(FONT);
for (int i = 0; i < names.length; i++) {
bf = BaseFont.createFont(String.format("%s,%s", FONT, i),
BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
font = new Font(bf, 12);
document.add(new Paragraph("font " + i + ": " + names[i], font));
document.add(new Paragraph("Rashu00f4mon", font));
document.add(new Paragraph("Directed by Akira Kurosawa", font));
document.add(new Paragraph("u7f85u751fu9580", font));
document.add(Chunk.NEWLINE);
}

The FONT parameter contains the path to msgothic.ttc. Observe that you have to add the index of the font to the font file when you want to create a BaseFont object. For instance, if you want to use the font MS-PGothic, you need to add the index 1:

BaseFont bf = BaseFont.createFont("c:/windows/fonts/msgotic.ttc,1",
BaseFont.IDENTITY_H, BaseFont.EMBEDDED);

When you ask iText to embed a TrueType or an OpenType font with TrueType outlines, iText will not embed the complete font, as is the case with Type 1 fonts or OpenType fonts with Type 1 outlines. Instead, it will only embed a subset of the font, containing only those glyphs that were used in the document. iText will ignore the embedded parameter and always embed a subset of the font if you use the encoding IDENTITY_H or IDENTITY_V.

If you want to understand what this encoding means, you have to look at the different ways a font can be stored inside a PDF.

11.2. Examining font types from a PDF perspective

In this section, we’ll examine font types from a PDF perspective, and we’ll find out the difference between simple and composite fonts.

Table 11.1 looked at the way fonts can be organized in different files; table 11.2 lists the font subtypes that can be present in a PDF document. This table corresponds to Table 110 in ISO-32000-1, omitting the subtype MMType1. Multiple Master fonts have been discontinued. They can be present in a PDF document, but there’s no support for Multiple Master fonts in iText’s BaseFont class.

Table 11.2. Subtype values for fonts (ISO-32000-1 Table 110)

Subtype

Description

/Type1 A font that defines glyph shapes using Type 1 font technology
/Type3 A font that defines glyphs with streams of PDF graphics operators
/TrueType A font based on the TrueType font format
/Type0 A composite font—a font composed of glyphs from a descendant CIDFont
/CIDFontType0 A CIDFont whose glyph descriptions are based on the Compact Font Format (CFF)
/CIDFontType2 A CIDFont whose glyph descriptions are based on TrueType font technology

The first three subtypes are used in the context of simple fonts; Type 0 are fonts called composite fonts. Let’s start with simple fonts.

11.2.1. Simple fonts

Glyphs in a simple font are selected using a single byte. Each glyph corresponds to a character that has a value from 0 to 255. The mapping between the characters and the glyphs is called the character encoding. A Type 1 font can have a special built-in encoding, as is the case for Symbol and Zapf Dingbats. With other fonts, multiple encodings may be available. For instance, the glyph known as dagger (†) corresponds with (char) 134 in the encoding known as WinAnsi, aka Western European Latin (code page 1252), a superset of Latin 1 (ISO-8859-1). The same dagger glyph corresponds to different character values in the Adobe Standard encoding (178), Mac Roman encoding (160), and PDF Doc Encoding (129). Figure 11.4 shows the available code pages for three of the fonts used in figure 11.1.

Figure 11.4. Encodings available in different font files

These encoding names were obtained using the getCodePagesSupported() method. Code page is the traditional IBM term for character encoding.

Listing 11.3. EncodingNames.java
String[] encoding = bf.getCodePagesSupported();
for (int i = 0; i < encoding.length; i++) {
document.add(new Paragraph("encoding[" + i + "] = " + encoding[i]));
}

If you use a simple font, it’s up to you to decide which encoding to use. Some Western languages (for instance, French) have letters that get a cedilla (˘) or a circumflex (ˇ). Those letters are in code page 1252 (Latin 1). If you need a hacek or a caron (ˇ), you should use code page 1250 (Latin 2). Figure 11.5 shows examples using different encodings available in Arial-BoldMT, including examples in Cyrillic (code page 1251) and Greek (code page 1253).

Figure 11.5. Using different encodings of the same font

Listing 11.4, which produced what you see in figure 11.5, shows that four different BaseFont objects were created using the same font, but with different encodings. If you look at the document properties (see the window on the right in figure 11.5), you’ll find four embedded subsets of Arial-BoldMT: one using Ansi encoding (Cp1252) and three using a custom encoding.

Listing 11.4. EncodingExample.java
public static final String FONT = "c:/windows/fonts/arialbd.ttf";
public static final String[][] MOVIES = {
{ "Cp1252",
"A Very long Engagement (France)",
"directed by Jean-Pierre Jeunet",
"Un long dimanche de fianu00e7ailles" },
{ "Cp1250",
"No Man's Land (Bosnia-Herzegovina)",
"Directed by Danis Tanovic",
"Nikogaru0161nja zemlja" },
{ "Cp1251",
"You I Love (Russia)",
"directed by Olga Stolpovskaja and Dmitry Troitsky",
"u042f u043bu044eu0431u043bu044e u0442u0435u0431u044f" },
{ "Cp1253",
"Brides (Greece)",
"directed by Pantelis Voulgaris",
"u039du03cdu03c6u03b5u03c2" }
};
public void createPdf(String filename)
throws IOException, DocumentException {
Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream(filename));
document.open();
BaseFont bf;
for (int i = 0; i < 4; i++) {
bf = BaseFont.createFont(FONT, MOVIES[i][0], BaseFont.EMBEDDED);
document.add(new Paragraph("Font: " + bf.getPostscriptFontName()
+ " with encoding: " + bf.getEncoding()));
document.add(new Paragraph(MOVIES[i][1]));
document.add(new Paragraph(MOVIES[i][2]));
document.add(new Paragraph(MOVIES[i][3], new Font(bf, 12)));
document.add(Chunk.NEWLINE);
}
document.close();
}

Although this example uses characters that are expressed using more than one byte in the source code, the characters will be stored as single bytes inside the PDF file because you’re using Arial-BoldMT as a simple font. This is OK if you have a document that consists of only one language, but if you have a document where you constantly need to switch between languages, it would probably be easier if you didn’t have to worry about switching the encoding. You can achieve this by using Arial-BoldMT as a composite font.

11.2.2. Composite fonts

A composite font obtains its glyphs from a font-like object called a CIDFont. A composite font is represented by a font dictionary with subtype /Type0. The Type 0 font is known as the root font, and its associated CIDFont is called its descendant.

Please compare figure 11.6 with figure 11.5. The content of the page is identical, but now Arial-BoldMT only appears once in the list of fonts, as a CIDFont with Identity-H encoding.

Figure 11.6. Using Identity-H instead of different encodings

The code to create this PDF is almost identical to the code in listing 11.4; you need only to replace the encoding.

Listing 11.5. UnicodeExample.java
BaseFont bf;
for (int i = 0; i < 4; i++) {
bf = BaseFont.createFont(FONT, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
document.add(new Paragraph("Font: " + bf.getPostscriptFontName()
+ " with encoding: " + bf.getEncoding()));
document.add(new Paragraph(MOVIES[i][1]));
document.add(new Paragraph(MOVIES[i][2]));
document.add(new Paragraph(MOVIES[i][3], new Font(bf, 12)));
document.add(Chunk.NEWLINE);
}

CIDFonts are collections of glyphs that can’t be used directly. They can only be used as a component of a Type 0 font.

Character Collection

CID stands for character identifier. A character identifier is used as the index of the character collection to access the glyphs in the font. For simple fonts, you had an index ranging from 0 to 255; in contrast, a CID can be a number from 0 to 65,535. This is a great advantage when dealing with languages that have huge character sets, such as Chinese, Japanese, and Korean.

CMAP

Note that 65,535 is less than the number of code points available in Unicode (1,114,112). The association between the Unicode code points and their CIDs in the font is specified in a CMap, which is like a very large code page.

In listing 11.5, you have used the CMap named Identity-H. This is a generic identity mapping for 2-byte CIDs in a horizontal writing system. The same mapping also exists for vertical writing systems: Identity-V. You’ll use Identity-V when we discuss vertical writing systems. You’ll use other CMaps in an example that uses a CJKFont.

Cidfont Types

As you can see in table 11.2, there are two types of CIDFonts:

  • Type 0 CIDFonts— These contain glyphs based on the Compact Font Format (CFF; this is a Type 2 font in PostScript terms). If you want to embed such a font, you’ll need to buy an .otf file that supports this format. You won’t find many free fonts that support this format.
  • Type 2 CIDFonts— These contain glyphs based on the TrueType format. You can embed such a font if you have a file containing an OpenType font with TrueType outlines (.ttf) or a TrueType collection (.ttc).

Note that the way fonts are named can be very confusing: Type 0 in the context of CIDFonts has a different meaning than for Type 0 fonts; Type 2 in PostScript has a different meaning than for CIDFonts. Moreover, when you look at the Fonts tab in the Document properties, you’ll see that a font with subtype CIDFontType0 is listed as a Type 1 (CID) font.

Font technology isn’t simple, but it’s described in great detail in ISO-32000-1 and in additional technical notes published by Adobe. Right now, we’re more interested in the way iText deals with these different types of fonts.

11.3. Using fonts in iText

In the previous sections, we had a short overview of the different font files that can be used to create a BaseFont object, as well as the different font types one can find inside a PDF file. You saw some examples using different files resulting in different font types, but we’ve overlooked some types: we haven’t discussed Type 3 fonts yet, and we should also take a look at CMaps other than Identity-H. Before we can do this, we must have a look at the different iText classes that deal with fonts.

11.3.1. Overview of the Font classes

In the first column of table 11.3, you can find the most important font classes in iText. You already know Font and BaseFont, but more classes are used under the hood, most of which are subclasses of BaseFont (see the subclass column).

Table 11.3. iText Font classes

iText class

Subclass

Description

Font NA This is the most simple Font class. There are different constructors to create one of the standard Type 1 font types (not embedded). You can also create a Font instance using a BaseFont object and a font size as a parameter.
BaseFont NA This is the abstract superclass; the createFont() method returns an instance of one of its subclasses, depending on the font file used.
Type1Font Yes You’ll get a Type1Font instance if you create a standard Type 1 font, or if you pass an .afm or .pfm file. Standard Type 1 fonts are never embedded; for other Type 1 fonts, it depends on the value of the embedded parameter and the presence of a .pfb file.
Type3Font Yes Type 3 fonts are special: they don’t come in files. You need to create them using PDF syntax. Type 3 fonts are always embedded.
TrueTypeFont Yes In spite of its name, this class isn’t only used for TrueType fonts (.ttf), but also for OpenType fonts with TrueType (.ttf) or Type 1 (.otf) outlines. This class will create a TrueType or a Type 1 font subtype in a PDF document.
TrueTypeFontUnicode Yes Files with extension .ttf or .otf can also result in this subclass of TrueTypeFont if you use them as composite fonts. So will files with extension .ttc. Inside the PDF, you’ll find the subtype /Type0 along with /CIDFontType2 (.ttf and .ttc files) or /CIDFontType0 (.otf files). Contrary to its superclass, TrueTypeFontUnicode ignores the embedded parameter. iText will always embed a subset of the font.
CFFFont No OpenType fonts with extension .otf use the Compact Font Format (CFF). Although creating a font using an .otf file results in an instance of TrueTypeFont, it’s the CFFFont class that does the work.
CJKFont Yes This is a special class for Chinese, Japanese, and Korean fonts for which the metrics files are shipped in a separate JAR. Using a CJK font results in a Type 0 font; the font is never embedded.

Table 11.3 covers all the file types listed in table 11.1, as well as all the font subtypes listed in table 11.2. You don’t need to address classes such as Type1Font and TrueTypeFont directly; just as you used the Image class to select the correct image type in the previous chapter, you can let the BaseFont class decide which font class applies.

Table 11.3 is nevertheless useful for finding out about important implementation differences. For instance, the TrueTypeFontUnicode class always embeds a subset of the font. This reduces the file size.

Fonts and File Size

In this example, you use the font arial.ttf to write a document with the text “quick brown fox jumps over the lazy dog” using different settings for the font.

Listing 11.6. FontFileAndSizes.java

If you compare the file sizes of the different files that are created, you’ll see that the smallest file is the one for which you didn’t embed the font: 2 KB .

In , you embed a subset of the glyphs. You create a PDF containing 27 different glyphs (the 26 letters of the alphabet and the space character) with a file size of 24 KB. If you reduce the number of glyphs to two, the size is only 16 KB. The file size varies depending on the number of different glyphs used.

Setting the compression level as is done in doesn’t save space; the resulting file is also 24 KB.

 

FAQ

Can I prevent iText from creating a subset of the font? Yes, you can. If your requirements demand full embedding of the font, you can use the setSubset(false) method to change the default behavior . This comes at a cost: the resulting file is 414 KB.

 

Two classes in table 11.3 demand an extra example: Type3Font and CJKFont. See figure 11.7.

Figure 11.7. Type 3 and CJK font example

11.3.2. Type 3 fonts

In a Type 3 font, the glyphs are described using PDF graphics operators. You used these operators in chapter 3 when you wrote to the direct content. You can use this knowledge to create a user-defined font. Figure 11.7 shows custom characters created for the Greek capitals Delta and Sigma. They even use colors. This is how it was created.

Listing 11.7. Type3Example.java

There’s no createFont() method for Type 3 fonts; instead you need to use the Type3Font constructor. The first parameter is the PdfWriter to which the glyph descriptions will be written; the second parameter is a boolean indicating whether or not you want to use color. If you change this parameter to false, the glyphs in figure 11.7 will change into black and white. You define two characters using the defineGlyph() method. The first parameter of this method is the character that corresponds to the custom glyph. The other parameters contain the metrics for the glyph: the char advance and the coordinates of the bounding box of the glyph (lower-left X, lower-left Y, upper-right X, and upper-right Y).

The other PDF shown in figure 11.7 contains Chinese, Japanese, and Korean glyphs. This was achieved using the CJKFont class.

11.3.3. CJK fonts

If you look at the iText source code repository, you’ll see that the directory com/itextpdf/text/pdf/fonts doesn’t only contain fourteen AFM files, but also a series of *.properties and *.cmap files. These files aren’t shipped with the iText JAR, but you can download them separately. Look for iTextAsian.jar and add this JAR to your classpath if you want to use CJK fonts. The properties and CMap files in this JAR do not contain the glyph descriptions, which means that iText won’t embed these fonts.

 

Note

If you open a file using these CJK fonts in Adobe Reader, and if the fonts aren’t available, a dialog box will open. You’ll be asked if you want to update the Reader. If you agree, the necessary font packs will be downloaded and installed. You’ll find the font files in the folder where Adobe Reader was installed; for example, C:/Program Files/Adobe/Reader 9.0/ Resource/CIDFont/. These fonts are only licensed for use in combination with Adobe Reader; you’re not allowed to use them in any other application (unless you’ve bought a license from Adobe).

 

The files from iTextAsian.jar correspond with the values in the second and third column of table 11.4. You can use this table to create a CJKFont object. If you want to use a CJKFont in a different style, you can add one of the following modifiers to the font name: Bold, Italic, or BoldItalic. For instance, replace "STSong-Light" in listing 11.8 with "STSong-Light,Italic", and the title of the movie by Zhang Yimou will be printed in italics.

Table 11.4. CJK fonts in iTextAsian.jar

Language

Font

CMap name

Chinese (simplified) STSong-Light STSongStd-Light UniGB-UCS2-H UniGB-UCS2-V
Chinese (traditional) MHei-Medium MSung-Light MSungStd-Light UniCNS-UCS2-H UniCNS-USC2-V
Japanese HeiseiMin-W3 HeiseiKakuGo-W5 KozMinPro-Regular UniJIS-UCS2-H UniJIS-UCS2-V UniJIS-UCS2-HW-H UniJIS-UCS2-HW-V
Korean HYGoThic-Medium HYSMyeongJo-Medium HYSMyeongJoStd UniKS-UCS2-H UniKS-UCS2-V
Listing 11.8. CJKExample.java
public static final String[][] MOVIES = {
{ "STSong-Light", "UniGB-UCS2-H",
"Movie title: House of The Flying Daggers (China)",
"directed by Zhang Yimou", "u5341u950au57cbu4f0f" },
{ "KozMinPro-Regular", "UniJIS-UCS2-H",
"Movie title: Nobody Knows (Japan)", "directed by Hirokazu Koreeda",
"u8ab0u3082u77e5u3089u306au3044" },
{ "HYGoThic-Medium", "UniKS-UCS2-H",
"Movie title: '3-Iron' aka 'Bin-jip' (South-Korea)",
"directed by Kim Ki-Duk", "ube48uc9d1" }
};
public void createPdf(String filename) throws IOException, DocumentException
{
Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream(filename));
document.open();
BaseFont bf;
Font font;
for (int i = 0; i < 3; i++) {
bf = BaseFont.createFont(
MOVIES[i][0], MOVIES[i][1], BaseFont.NOT_EMBEDDED);
font = new Font(bf, 12);
document.add(new Paragraph(bf.getPostscriptFontName(), font));
for (int j = 2; j < 5; j++)
document.add(new Paragraph(MOVIES[i][j], font));
document.add(Chunk.NEWLINE);
}
document.close();
}

Observe that the CMaps come in pairs: one for horizontal writing systems (-H) and one for vertical writing systems (-V).

The Vertical Writing System

In figure 11.7, some Asian movie titles were written from left to right, but some Eastern languages were originally written from top to bottom, in columns from right to left. See, for instance, figure 11.8.

Figure 11.8. The vertical writing system

My knowledge of Japanese is limited to “konishiwa” and “arigato,” so I’ve used the title of a movie by Akira Kurosawa and the English translation of a quote from this movie for this example. The PDF shown to the left in figure 11.8 is created using this code.

Listing 11.9. VerticalTextExample1.java

You use the VerticalText object to achieve this. It’s very similar to the ColumnText object, but instead of defining a simple column, you define a layout. The first two parameters define the coordinates where the column has to start, in this case (390, 570). The second parameter defines the height of each column: 540. Then follows the maximum number of lines that may be written (12) and the leading. Observe that the leading is no longer the vertical distance between two horizontal baselines, but the horizontal distance between two vertical lines. Likewise, you also have to turn your head 90 degrees to the right if you want to set the alignment: ALIGN_RIGHT aligns the column to the bottom.

The PDF on the right in figure 11.8 is created in a slightly different way.

Listing 11.10. VerticalTextExample2.java
public void createPdf(String filename)
throws IOException, DocumentException {
...
BaseFont bf = BaseFont.createFont(
"KozMinPro-Regular", "Identity-V", BaseFont.NOT_EMBEDDED);
Font font = new Font(bf, 20);
VerticalText vt = new VerticalText(writer.getDirectContent());
vt.setVerticalLayout(390, 570, 540, 12, 30);
font = new Font(bf, 20);
vt.addText(new Phrase(convertCIDs(TEXT1), font));
vt.go();
vt.setAlignment(Element.ALIGN_RIGHT);
vt.addText(new Phrase(convertCIDs(TEXT2), font));
vt.go();
...
}
public String convertCIDs(String text) {
char cid[] = text.toCharArray();
for (int k = 0; k < cid.length; ++k) {
char c = cid[k];
if (c == ' ')
cid[k] = 'uff00';
else
cid[k] = (char) (c - ' ' + 8720);
}
return new String(cid);
}

You still use KozMinPro-Regular, but now you use Identity-V. This font contains Western characters that are rotated 90 degrees clockwise, as shown in figure 11.8. You use the custom-made formula in the convertCIDs() method to translate the normal characters into rotated characters. This example demonstrates more or less what needs to be done when you’re confronted with Strings in different encodings.

Using Other CMaps

The UCS2 in the CMap names listed in table 11.4 stands for Universal Character Set. There’s also a JAR named iTextAsianCmaps.jar with the contents of the com/itextpdf/text/pdf/cmaps/ directory. These CMaps can be used in combination with the PdfEncodings class to convert a String in a specific encoding to a String with 2-byte CIDs.

For example, if you have a char[]encoded in the GB 18030-2000 character set, you need to load the CMap GBK2K-H and convert it to a sequence of Identity-H CIDs like this:

PdfEncodings.loadCmap("GBK2K-H", PdfEncodings.CRLF_CID_NEWLINE);
byte text[] = my_GB_encoded_text;
String cid = PdfEncodings.convertCmap("GBK2K-H", text);
BaseFont bf = BaseFont.createFont(
"STSong-Light", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
Paragraph p = new Paragraph(cid, new Font(bf, 14));
document.add(p);

We’ve discussed Asian languages written vertically. Now let’s find out how to write Semitic languages such as Hebrew and Arabic; these are written from right to left.

11.3.4. Writing from right to left

Figure 11.9 shows an XML file with the text “Say Peace in all languages” in English, Arabic, and Hebrew. The XML is encoded using UTF-8, and in the top left of the figure it’s opened in WordPad, which assumes it’s plain text, hence the strange characters. You’ll use this XML file to create the PDF document shown in the foreground. But you’ll start by creating the PDF showing the movie title Nina’s Tragedies in Hebrew.

Figure 11.9. Writing from right to left

Writing from right to left is only supported when using ColumnText or PdfPCell objects.

Run Direction in Columntext Objects

If you don’t know Hebrew, you’ll probably try to read the glyphs of the Hebrew movie title from left to right. You see four glyphs, a space, two glyphs, a space, and the rest of the title. Let’s compare this with the original String here.

Listing 11.11. RightToLeftExample.java

The String that is passed to the ColumnText object includes seven 2-byte characters, a space, two characters, a space, and four characters. In reality, the first glyph on the title line in figure 11.9 is u05d4, followed by u05e0, and so on: iText has added the characters in reverse order because you changed the run direction with the setRunDirection() method. This method accepts one of the following options:

  • RUN_DIRECTION_DEFAULT Uses the default direction
  • RUN_DIRECTION_LTR Uses bidirectional reordering with a left-to-right preferential run direction
  • RUN_DIRECTION_NO_BIDI Doesn’t use bidirectional reordering
  • RUN_DIRECTION_RTL Uses bidirectional reordering with a right-to-left preferential run direction

The best way to understand what bidirectional means is to look at the message of peace in figure 11.9. In this text, the term I18N (Internationalization) is used. If you choose RTL as the run direction, you don’t want this term to be reordered as N81I; you want to preserve the order of the Latin text. Choosing the option RUN_DIRECTION_RTL means that the characters are reordered from right to left by preference, but if Latin text is encountered, the left-to-right order is preserved. The PDF containing the message of peace was created using a PdfPTable.

Run Direction in PdfPCell Objects

You can use the technique explained in chapter 9 to convert the XML file into a PDF document. This is what to do when an opening or a closing tag is encountered.

Listing 11.12. SayPeace.java
public void startElement(
String uri, String localName, String qName, Attributes attributes)
throws SAXException {
if ("message".equals(qName)) {
buf = new StringBuffer();
cell = new PdfPCell();
cell.setBorder(PdfPCell.NO_BORDER);
if ("RTL".equals(attributes.getValue("direction"))) {
cell.setRunDirection(PdfWriter.RUN_DIRECTION_RTL);
}
}
else if ("pace".equals(qName)) {
table = new PdfPTable(1);
table.setWidthPercentage(100);
}
}
public void endElement(String uri, String localName, String qName)
throws SAXException {
...
if ("message".equals(qName)) {
Paragraph p = new Paragraph(strip(buf), f);
p.setAlignment(Element.ALIGN_LEFT);
cell.addElement(p);
table.addCell(cell);;
buf = new StringBuffer();
}
else if ("pace".equals(qName)) {
try {
document.add(table);
} catch (DocumentException e) {
throw new ExceptionConverter(e);
}
}
}

The Arabic text produced by this example looks all right, but it’s important to understand that iText has done a lot of work behind the scenes. Not every character in the XML file was rendered as a separate glyph. Some characters or glyphs were combined and replaced.

To understand what happens, we need to talk about diacritics and ligatures.

11.3.5. Advanced typography

If you want to see a Thai cowboy movie about a poor hero who falls in love with a girl from the upper classes, you should buy a ticket for Tears of the Black Tiger at the Foobar Film Festival. Figure 11.10 shows the poster featuring the protagonists.

Figure 11.10. Using diacritics, ancillary glyphs added to a letter

As you can see in the figure, the Thai title is also printed:

public static final String MOVIE =
"u0e1fu0e49u0e32u0e17u0e30u0e25u0e32u0e22u0e42u0e08u0e23";

This String is written twice, using two different fonts: Angsana New and Arial Unicode MS.

public static final String[] FONTS = {
"c:/windows/fonts/angsa.ttf",
"c:/windows/fonts/arialuni.ttf"
};

This shows how the title was added to the Document.

Listing 11.13. Diacritics1.java
for (int i = 0; i < 2; i++) {
bf = BaseFont.createFont(
FONTS[i], BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
document.add(new Paragraph("Font: " + bf.getPostscriptFontName()));
font = new Font(bf, 20);
document.add(new Paragraph(MOVIE, font));
}

If you look at the poster, you’ll see that there’s a special curl above the first character. This curl is a diacritical mark.

Diacritical Marks

You’ve used diacritical marks before. In figure 11.5, you’ll find a cedilla, a hacek, and so on, but there’s a difference between listing 11.4 and listing 11.13. When you printed c cedilla (ç), you only used one Unicode character (u00e7). In listing 11.13, the diacritical mark is a separate character: u0e49 has to be combined with u0e1f.

That’s unusual for Western languages. Suppose that you want to type the French word être (to be) on a French keyboard (AZERTY instead of QWERTY); you’d need to hit five different keys: ^etre. If you save a text file with this String, only four bytes would be used, because there’s a character value for the e with a circumflex.

In other languages that use diacritics more frequently, it’s common to store both characters separately. For instance: ^etre or e^tre instead of être. That’s what happened in the Thai example. The fonts Angsana New and Arial Unicode MS used a negative character advance for this glyph to create the illusion that the two characters are actually one.

Changing the Character Advance

The character advance is stored in the font’s metrics, but you can change this value in the iText BaseFont object. The second example in figure 11.10 is somewhat artificial, but it demonstrates how the mechanism works. The original title of the best Swedish film of 1999 is written like this:

public static final String MOVIE = "Tomten ¨ ar far till alla barnen";

The title literally means “Santa Claus is the father of all children,” but it was translated into “In bed with Santa,” probably to prevent parents from bringing young children to the movie.

The next example shows how you can change the character advance of the ¨ character so that it’s positioned on top of the next character that is added.

Listing 11.14. Diacritics2.java

The width of the umlaut (or dieresis) glyph is 333 units in Arial (glyph space). To get the umlaut or dieresis above the letter that follows the diacritical mark, you change the advance to a negative value.

The value used here is ideal for the letter a, but there’s no guarantee that it will fit perfectly above the other vowels, because they may have a different width and character advance. Arial is a proportional font, meaning that different glyphs have different widths. This problem doesn’t occur when you use a fixed-width or monospaced font such as Courier. Every character in Courier has the same width (600 units in glyph space). To make the diacritical mark fit above the next character, it’s sufficient to set its advance to 0.

Changing the Character Width

In listing 11.15, a proportional font is changed into a fixed width font. You use the method getWidths() to get an array containing the widths of every character in the font (measured in glyph space). You then change the width to 600 units for every glyph with a width greater than 0.

Listing 11.15. Monospace.java
BaseFont bf3 = BaseFont.createFont(
"c:/windows/fonts/arialbd.ttf", BaseFont.CP1252, BaseFont.EMBEDDED);
Font font3 = new Font(bf3, 12);
int widths[] = bf3.getWidths();
for (int k = 0; k < widths.length; ++k) {
if (widths[k] != 0)
widths[k] = 600;
}
bf3.setForceWidthsOutput(true);

You force iText to use the changed widths with the method setForceWidthsOutput(). This feature is very useful if you want to print a Chinese text where every ideogram needs to have the same width, but it’s not very elegant when you use it for Western fonts. If you want to use it to attribute more space to every character to get t h i s e f f e c t, you should use the setCharacterSpacing() method.

Listing 11.16. ExtraCharSpace.java
Chunk chunk = new Chunk(MOVIE, font1);
chunk.setCharacterSpacing(10);
document.add(new Paragraph(chunk));

Ligatures are another example involving advanced typography.

Ligatures

A ligature occurs when a combination of two or more characters is considered to be one and only one glyph. A letter with a diacritic isn’t usually called a ligature, but the same principle applies. One of the ligatures we all know—though we may have forgotten it’s a ligature—is the & character. The ampersand sign was originally a ligature for the Latin word et (meaning and). Figure 11.11 shows a movie title with ligatures in Danish and Arabic.

Figure 11.11. Using ligatures, joining different glyphs into one

As is the case with diacritics, you usually don’t have to worry about ligatures in languages using Latin text. Usually, you’ll use only one character for the ligature:

document.add(
new Paragraph("Ku00e6rlighed ved fu00f8rste hik", font));

If you want to use more than one character, you’ll need to write code that makes the ligature for you. Suppose you want to add a String like this:

document.add(
new Paragraph(ligaturize("Kaerlighed ved f/orste hik"), font));

You need to write your own ligaturize() method as is done next.

Listing 11.17. Ligatures1.java
public String ligaturize(String s) {
int pos;
while ((pos = s.indexOf("ae")) > -1) {
s = s.substring(0, pos) + 'u00e6' + s.substring(pos + 2);
}
while ((pos = s.indexOf("/o")) > -1) {
s = s.substring(0, pos) + 'u00f8' + s.substring(pos + 2);
}
return s;
}

The combination “ae” is changed into “æ”, the combination “/o” into “ø”. Similar code, but much more complex than this small snippet, is present in iText to make Arabic ligatures.

Writing Arabic

In figure 11.11, the Arabic translation of the movie title Lawrence of Arabia has been added three times. The first version of the title is wrong because the glyphs are added from left to right, whereas Arabic is written from right to left (see section 11.3.4). In the second version, the glyphs are written in reverse order, but a space was added between all characters. No ligatures are made, so the title isn’t rendered correctly. Compare this line with the next one. The omission of the extra spaces is the only difference, but if you look closely, you can see that some character combinations were replaced by another glyph. That was done by the iText class ArabicLigaturizer.

If you study listing 11.18, you can see that you don’t have to do anything special to start up the ArabicLigaturizer. If the run direction is RTL and if iText detects Unicode characters in the Arabic character set, this is done automatically.

Listing 11.18. Ligatures2.java
public static final String MOVIE =
"u0644u0648u0631u0627u0646u0633 "
+ "u0627u0644u0639u0631u0628";
public static final String MOVIE_WITH_SPACES =
"u0644 u0648 u0631 u0627 u0646 u0633 "
+ " u0627 u0644 u0639 u0631 u0628";
...
document.add(new Paragraph("Wrong: " + MOVIE, font));
ColumnText column = new ColumnText(writer.getDirectContent());
column.setSimpleColumn(36, 730, 569, 36);
column.setRunDirection(PdfWriter.RUN_DIRECTION_RTL);
column.addElement(new Paragraph("Wrong: " + MOVIE_WITH_SPACES, font));
column.addElement(new Paragraph(MOVIE, font));
column.go();

Note that the setRunDirection() method only exists for the classes PdfPCell and ColumnText. Both classes also have a setArabicOption() method to tell iText how to deal with vowels in Arabic. These are the possible values for the parameter:

  • ColumnText.AR_NOVOWEL Eliminates Arabic vowels
  • ColumnText.AR_COMPOSEDTASHKEEL Composes the Tashkeel on the ligatures
  • ColumnText.AR_LIG Does extra double ligatures

None of these options has any effect on this example, but it can be useful information if you need advanced Arabic support.

This is highly specialized functionality; it’s time to return to everyday use of iText and look at some classes that make working with fonts easier.

11.4. Automating font creation and selection

In this section, you’ll add two classes that make it easier for you to select a font: the FontFactory and the FontSelector classes.

When you created Font objects in part 1, you mostly used one of the standard Type 1 fonts. In this chapter, you’ve always created Font objects in two steps. For example,

BaseFont bf = BaseFont.createFont(
"c:/windows/fonts/arial.ttf", BaseFont.CP1252, BaseFont.EMBEDDED);
Font font = new Font(bf, 12);

One of the major disadvantages of this approach is that you need to pass a path to a font program. I’m working on Windows XP and Vista, and I know that the font arial.tff is present in the directory c:/windows/fonts/. But this code won’t work if you try to run it on a Mac or a Linux machine. You may need to look for the font in the directory /Library/Fonts/ or /usr/share/X11/fonts/.

It would be nice if there were a more generic way to select fonts to make your code platform-independent. The FontFactory class can help you.

11.4.1. Getting a Font from the FontFactory

The FontFactory class has a series of static getFont() methods that allow you to get a Font object without explicitly creating a BaseFont instance:

Font font = FontFactory.createFont(
"c:/windows/fonts/arial.ttf", BaseFont.CP1252, BaseFont.EMBEDDED, 12);

This doesn’t solve the platform (in)dependence problem yet. But you should be able do something like this:

Font font = FontFactory.getFont("Times-Roman");
document.add(new Paragraph("Times-Roman", font));
Font fontbold = FontFactory.getFont("Times-Roman", 12, Font.BOLD);
document.add(new Paragraph("Times-Roman, Bold", fontbold));

This code snippet will work because Times-Roman is one of the font families that is supported by default by the font factory; so are all the standard Type 1 fonts. It won’t work with other fonts, unless they are registered.

Registering a Font

You can register an individual font like this:

FontFactory.register("c:/windows/fonts/garabd.ttf", "my_bold_font");
Font myBoldFont = FontFactory.getFont("my_bold_font");

This code registers the font Garamond Bold and gives it the alias my_bold_font. From now on, you can use this custom name to get the font from the factory.

The alias parameter is optional. You can also use one of the names that is stored in the font to retrieve a Font object. This bit of code shows how to read not only the PostScript name, but also the full font names in different languages.

Listing 11.19. FontFactory.java
BaseFont bf = myBoldFont.getBaseFont();
document.add(new Paragraph(bf.getPostscriptFontName(), myBoldFont));
String[][] name = bf.getFullFontName();
for (int i = 0; i < name.length; i++) {
document.add(new Paragraph(name[i][3] + " (" + name[i][0]
+ "; " + name[i][1] + "; " + name[i][2] + ")"));
}
Font myBoldFont2 = FontFactory.getFont("Garamond vet");
document.add(new Paragraph("Garamond Vet", myBoldFont2));

The output contains the following entries:

Garamond Bold (3; 1; 1033)
Garamond Gras (3; 1; 1036)
Garamond Vet (3; 1; 1043)

If i is an index of the two-dimensional name array, you’re interested in name[i][3], because that’s the String you can use to get the font from the FontFactory. In listing 11.19, the Dutch name of the font “Garamond Vet” is used. “Garamond Bold”, “Garamond Gras”, or any other of the names in the name array would also work.

 

Note

The other values in the array only make sense for fonts that contain a cmap (not to be confused with the CMap mapping Unicode characters to CIDs from section 11.2.2). A cmap is an internal structure that maps character codes directly to glyph descriptions. A cmap table may contain one or more subtables that represent multiple encodings intended for use on different platforms. Each subtable is identified by two numbers that represent a combination of a platform ID (name[i][0]) and a platform-specific encoding ID (name[i][1]). There’s also a language id (name[i][2]). You can find a full overview of all these codes in naming table pages published on the developer pages at adobe.com and microsoft.com (see appendix B.3.2 for the full URLs). If you look up the IDs from the output of listing 11.19, you’ll see that 3 is the platform ID for Microsoft encoding and that the encoding ID 1 means Unicode BMP only. The language IDs are expressed in hexadecimal, but if you convert them to decimal, you’ll find out that 1033 stands for English, 1036 for French, and 1043 for Dutch.

 

You probably won’t use the register() method directly; instead you could register a complete directory.

Registering a Font Directory

The examples in this book come with a resources directory; in this directory, there’s a fonts folder. You can register all the fonts in this folder at once like this:

FontFactory.registerDirectory("resources/fonts");

This method will call the register() method for every font file in the directory. You can list all the available names like this:

for (String f : FontFactory.getRegisteredFonts()) {
document.add(new Paragraph(
f, FontFactory.getFont(f, "", BaseFont.EMBEDDED)));
}

One of the fonts in the list that is produced has a very cryptic name: cmr10. You used this font in section 11.1.2, and you know that the real font name is Computer Modern Regular. If you want to use the full name as an alias, you can change the PostScript name of the BaseFont like this:

Font cmr10 = FontFactory.getFont("cmr10");
cmr10.getBaseFont().setPostscriptFontName("Computer Modern Regular");
Font computerModern = FontFactory.getFont(
"Computer Modern Regular", "", BaseFont.EMBEDDED);
document.add(new Paragraph("Computer Modern", computerModern));

This is an interesting way to get fonts that are shipped with an application, but what you really want is to register all the system fonts, be it on Windows, Mac, or Linux.

Registering System Fonts

The registerDirectories() method will attempt to register all the system fonts at once:

FontFactory.registerDirectories();

This method calls the method registerDirectory() using the following paths as a parameter:

  • c:/windows/fonts— A possible font directory on Windows
  • c:/winnt/fonts— A possible font directory on Windows
  • d:/windows/fonts— A possible font directory on Windows
  • d:/winnt/fonts— A possible font directory on Windows
  • /Library/Fonts— A possible font directory on OS X
  • /System/Library/Fonts— A possible font directory on OS X
  • /usr/share/X11/fonts— A possible font directory on UNIX/Linux
  • /usr/X/lib/X11/fonts— A possible font directory on UNIX/Linux
  • /usr/openwin/lib/X11/fonts— A possible font directory on UNIX/Linux
  • /usr/share/fonts— A possible font directory on UNIX/Linux
  • /usr/X11R6/lib/X11/fonts— A possible font directory on UNIX/Linux

The registerDirectory() method for the Linux directories is used with an extra boolean that tells iText also to scan the subdirectories.

 

Note

registerDirectories() is an “expensive” method if you have a lot of fonts on your system. Don’t use it in a servlet because it takes time to scan the font directories; it’s better to use it when the JVM starts up, so that you can use the font factory throughout your web application.

 

If you list the available font names now, you’ll see that the list is much longer. You can also list the font families.

Font Families

The first font you registered was Garamond Bold. This font belongs to a family of three different fonts: Garamond (gara.ttf), Garamond-Italic (garait.ttf), and Garamond-Bold (garabd.ttf). You can list the names of all the families just like you listed the names of all the individual fonts.

for (String f : FontFactory.getRegisteredFamilies()) {
document.add(new Paragraph(f));
}

Font family names are very useful when you want to switch between styles. Instead of using the full font name as the first parameter—for instance, Garamond-Italic—you could use the family name with an extra parameter for the style:

Font garamondItalic = FontFactory.getFont(
"Garamond", BaseFont.WINANSI, BaseFont.EMBEDDED, 12, Font.ITALIC);
document.add(new Paragraph("Garamond-Italic", garamondItalic));

Normally, the font factory would look for a font named “Garamond” and find the font gara.ttf. But if you pass an extra parameter saying you want an italic font, iText will search for an italic font in the Garamond family. You’ve registered all the system fonts, so if garait.ttf is present on your system, the font factory will return Garamond-Italic.

 

Note

If you look inside iText, you’ll see that FontFactory delegates most of the work to the FontFactoryImp class. This class implements the FontProvider interface, which is the interface you implemented when you converted HTML to PDF in chapter 9. The mechanism to switch between styles within the same font family is used frequently by HTMLWorker when the font family is defined with the font tag and the style with em, i, strong, or b tags.

 

We’ve solved several problems with the FontFactory class: you can make the creation of fonts platform-independent, and you can easily switch between styles using only the family name of the font. In the next section, we’ll solve another problem.

If you have a text that contains characters from many different languages, you have to switch between fonts, because there’s not a single font that contains every possible glyph for every possible language. Up until now, you’ve manually selected different fonts for different languages. In the next section, you’ll let iText select the appropriate fonts.

11.4.2. Automatic font selection

Imagine that you need to write text in Times-Roman, but the text contains a number of Chinese glyphs. The document in the background of figure 11.12 shows such an example. It lists the names of the protagonists in the movie Hero by Zhang Yimou.

Figure 11.12. Automatic font selection

It would be possible to construct this sentence using different Chunks or Phrases, with the English text in Times-Roman and the Chinese names in a traditional Chinese font. But there’s an easier way; you can use the FontSelector class to do this work for you.

Listing 11.20. FontSelectionExample.java

What happens in here? You have a String containing characters referring to glyphs from the Latin alphabet as well as to Chinese glyphs. You pass this String to a FontSelector object for processing, and the FontSelector will look at the String, character by character. If the corresponding glyph is available in the first font that was added (in this case, Times-Roman), the character is added to a Chunk with the Times-Roman font. If the character isn’t available, the selector looks it up in the next font that was added (in this case, MSung-Light). The selector goes on until the glyph is found, or until there are no fonts left.

 

Note

The order in which the fonts are added to the selector is important. If you switch and in listing 11.20, you get the PDF shown in the foreground of figure 11.12. All glyphs are printed in MSung-Light, because that font also has descriptions for Western characters.

 

Figure 11.13 shows an XML file with the word Peace in different languages. This XML was converted to PDF using iText. In this example, you see different mechanisms at work: font selection, but also bidirectional writing and ligatures.

Figure 11.13. Using iText for different languages

If you try this example (named Peace) on your own system, you’ll see that some translations for the word Peace are missing or wrong. If you see a question mark, it’s because the translation is unknown. You’ll also find a question mark in the XML file. (If you know the translation, feel free to post it to the iText mailing list.)

If you see an empty space where a translation was expected, it’s because the font selector couldn’t find the glyph in any of the fonts that were added to the selector.

 

FAQ

I’ve tried all the examples in the book, but as soon as I change the text into a String in language X, the text disappears. Why? That’s because the glyphs that are needed can’t be found in the font. You are either using the wrong encoding, or the glyphs just aren’t there. Try using another encoding or another font.

 

Some of the translations are rendered incorrectly because iText doesn’t have support for ligatures for Hindic languages. Just as we have the ArabicLigaturizer, we need a HindicLigaturizer, but so far we haven’t found anyone who could write such a class for iText. Maybe that’s something for the third edition of iText in Action.

Let’s take a look at what we’ve covered in this chapter.

11.5. Summary

First we approached fonts from three different angles:

  • Table 11.1 Lists the different types of font files that can be used to create a BaseFont object
  • Table 11.2 Lists the different font types that can be stored in a PDF file, divided into two groups: simple fonts and composite fonts
  • Table 11.3 Lists the different font classes that are available in iText

After looking at examples for every type that was discussed, we studied different writing systems: vertical text, written in columns from right to left, and horizontal text written from right to left. We also looked at some advanced typography issues, such as using diacritical marks and making ligatures.

Finally, you learned ways to make the font creation and selection easier. With the FontFactory class, you learned how to make your applications platform independent; with the FontSelector class you delegated the font selection process to iText.

We’ll conclude this part about essential iText skills with a chapter about protecting your documents by using encryption and digital signatures.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset