Java-iText7-(2) 绘制文字段落(使用构建模块)

使用iText封装的Paragraph类绘制文档中的文字

iText提供了两种位置文字的方式,一种是使用封装好的构建模块,相对简单方便;另一种是使用底层绘制接口,可以更加灵活地控制绘制过程。本文主要介绍使用构建模块绘制文字的方式。

0. 前置要求

1. 使用Paragraph对象承接需要绘制的文本

最基本的的用法是这样

PdfWriter writer = new PdfWriter("/path/to/pdf.pdf");
PdfDocument pdf = new PdfDocument(writer);
Document document = new Document(pdf);
document.add(new Paragraph("Hello World!"));
document.close();

第1、2、5行负责PDF文档的创建和关闭,它们都是底层接口的实现。第3行,创建了一个Document对象,它是iText封装好的对象,可以使用非底层的构建模块进行文档创建。第4行,创建了一个Paragraph段落,内容是Hello World,并且添加到创建的Document文档中。以上程序将会生成如下的PDF文档。

最基本的的文字绘制

对于很长的段落(超过一行),iText会自动进行换行,每一行的排版会按照水平对齐方式进行。这一点和Word的排版是相似的。水平对齐方式定义在TextAlignment枚举类中,有LEFT左对齐、CENTER居中对齐、RIGHT右对齐、JUSTIFY两端对齐。

Paragraph para1 = new Paragraph("Alignment=JUSTIFIED: This is a long long long long long long long long sentence with so many words and characters in order to show auto line-break.");
para1.setTextAlignment(TextAlignment.JUSTIFIED);
document.add(para1);
Paragraph para2 = new Paragraph("Alignment=LEFT: This is a long long long long long long long long sentence with so many words and characters in order to show auto line-break.");
para2.setTextAlignment(TextAlignment.LEFT);
document.add(para2);
两端对齐会拉伸单词之间的空格宽度,而左对齐会在右侧留出空间

2. 字体与中文字符处理

iText默认的绘制字体是Helvetica。如果我们想使用Times New Roman(新罗马)字体绘制,就需要在创建Paragraph后,指定其绘制字体。iText的字体类是PdfFont,通常使用工厂类PdfFontFactory来创建。

Paragraph para3 = new Paragraph("This is a sentence using Times New Roman font.");
try {
 document.add(para3.setFont(PdfFontFactory.createFont(StandardFonts.TIMES_ROMAN)));
} catch (IOException e) {
    System.out.println("Font not found.");
}

Times New Roman字体是官方预设的字体之一,同样的预设字体有:

  • StandardFonts.COURIER
  • StandardFonts.COURIER_BOLD
  • StandardFonts.COURIER_OBLIQUE
  • StandardFonts.COURIER_BOLDOBLIQUE
  • StandardFonts.HELVETICA
  • StandardFonts.HELVETICA_BOLD
  • StandardFonts.HELVETICA_OBLIQUE
  • StandardFonts.HELVETICA_OBLIQUE
  • StandardFonts.HELVETICA_BOLDOBLIQUE
  • StandardFonts.SYMBOL
  • StandardFonts.TIMES_ROMAN
  • StandardFonts.TIMES_BOLD
  • StandardFonts.TIMES_ITALIC
  • StandardFonts.TIMES_BOLDITALIC
  • StandardFonts.ZAPFDINGBATS

以上预设字体可以通过PdfFontFactory.createFont(String fontProgram)创建。如果需要使用其他字体,我们可以通过字体文件来创建。创建方法为PdfFontFactory.createFont(String fontProgram, String encoding, boolean embedded)。fontProgram为字体文件路径。encoding为字体对应的字符集,预设的字符集枚举类是PdfEncodings。对于中文,encoding通常使用PdfEncodings.IDENTITY_H,表示水平显示的Unicode字符集。embedded指定是否将字体嵌入PDF文档中。通常嵌入字体是一个比较好的选择,因为不嵌入字体的文档,在不具有此字体的计算机中将无法正常显示。

为Paragraph指定字体的方式很简单,只需调用Paragraph对象的setFont(PdfFont font)方法即可。CJK是中日韩语言的英文首字母。

PdfFont cjkFont = PdfFontFactory.createFont(
                "path/to/cjkFont.otf", PdfEncodings.IDENTITY_H, true);
document.add(new Paragraph("使用合适的字体,除了英语,中文字符也可以使用;中国語に加えて、日本語も使用できます。").setFont(cjkFont));
如果段落中的字符不在字体中,那么它将不会显示

这里可能有人会问,如果一篇文章都使用宋体,是不是每一个段落都需要setFont()一下呢。答案肯定是否定的,我们可以为Document对象设置一个默认字体,如果不在创建段落时显式地指定新字体,那么将会使用默认字体。上面的程序也等同于以下写法。

PdfFont cjkFont = PdfFontFactory.createFont(
                "path/to/cjkFont.otf", PdfEncodings.IDENTITY_H, true);
document.setFont(cjkFont);
document.add(new Paragraph("使用合适的字体,除了英语,中文字符也可以使用;中国語に加えて、日本語も使用できます。"));

3. 字号

字号可以通过Paragraph对象的setFontSize(Float fontSize)方法设置。iText文字的默认字号是12.

Paragraph smallPara = new Paragraph("This is a small paragraph, font size is 8.").setFontSize(8.0F);
document.add(smallPara);
Paragraph largePara = new Paragraph("This is a large paragraph, font size is 18.").setFontSize(18.0F);
document.add(largePara);

同样地,我们可以通过document.setFontSize(Float fontSize)设置文档的默认字体大小。

4. 粗体、斜体、下划线

粗体、斜体、下划线可以分别使用paragraph.setBold(), paragraph.setItalic(), paragraph.setUnderline()来实现。

下划线除了基本下划线外,还可以指定下划线的厚度、颜色、位置等等。

Paragraph boldPara = new Paragraph("Bold paragraph 粗体").setBold().setFont(cjkFont);
document.add(boldPara);
Paragraph italicPara = new Paragraph("Italic paragraph 斜体").setItalic();
document.add(italicPara);
Paragraph underlinedPara = new Paragraph("Underlined paragraph 下划线").setUnderline();
document.add(underlinedPara);
Paragraph underlinedPara2 = new Paragraph("Underlined paragraph 自定义下划线").setUnderline(2.0F, -5.0F); // 指定下划线厚度为2,位置在基线下方5个单位
document.add(underlinedPara2);

粗体、斜体、粗斜体还可以通过使用只含粗体、斜体、粗斜体的字体文件实现。

5. 文字颜色

文字颜色可以通过paragraph.setFontColor(Color color)进行设置。iText提供了一些预设基本颜色,定义在ColorConstants枚举中,如下面的列表所示。

  • BLACK = RGB(0, 0, 0)
  • BLUE = RGB(0, 0, 255)
  • CYAN = RGB(0, 255, 255)
  • DARK_GRAY = RGB(64, 64, 64)
  • GRAY = RGB(128, 128, 128)
  • GREEN = RGB(0, 255, 0)
  • LIGHT_GRAY = RGB(192, 192, 192)
  • MAGENTA = RGB(255, 0, 255)
  • ORANGE = RGB(255, 200, 0)
  • PINK = RGB(255, 175, 175)
  • RED = RGB(255, 0, 0)
  • WHITE = RGB(255, 255, 255)
  • YELLOW = RGB(255, 255, 0)

iText预设的颜色均是按照RGB颜色空间设置的,适合屏幕的显示。iText还支持如适合印刷的CMYK颜色以及灰度颜色Gray。这里使用RGB作为介绍。

我们可以通过new DeviceRgb(Integer red, Integer green, Integer blue)的方式创建一个自定义颜色,并且通过setFontColor(color)方法为段落设置文字颜色。

Paragraph redPara = new Paragraph("Paragraph in red color").setFontColor(ColorConstants.RED);
document.add(redPara);
Paragraph purplePara = new Paragraph("Paragraph in purple color(#6A0DAD)").setFontColor(new DeviceRgb(106, 13, 173));
document.add(purplePara);

6. 自由位置的文字(文本框)

段落既可以按照一段一段从上向下排布,也可以像Word中的文本框一样,自由出现在文档的各个位置。我们可以使用paragraph.setFixedPosition(float left, float bottom, float width)来指定一个段落出现的横纵坐标以及文本宽度。需要注意,第一个参数left是文本框左下角距离页面左边缘的距离,第二个参数bottom是文本框左下角距离页面底部的距离

Paragraph floatPara = new Paragraph("This is a floating paragraph which is not aligned as normal...")
        .setFixedPosition(0, pdf.getDefaultPageSize().getHeight()-100, pdf.getDefaultPageSize().getWidth()/2);
document.add(floatPara);
红框圈出的是新绘制的文本框(left=0, bottom=页面宽度-100, width=页面长度一半),它可以与已绘制内容重叠

7. 多个样式的组合方式

前面讲到的每个方法具有一个特点,它们的返回值都是Paragraph对象本身(也就是this)。因此,我们可以利用这个特点将多个样式的设置语句链接式地写出来。

下面的代码设置了一个段落的字体是前面定义的cjkFont,字号是20,颜色是绿色,加粗,加下划线,自由位置为(100, 100),宽度为页面宽度减掉文档的左右边距。

Paragraph combinedPara = new Paragraph("Combined paragraph.")
        .setFont(cjkFont)
        .setFontSize(20.0F)
        .setFontColor(ColorConstants.GREEN)
        .setBold()
        .setUnderline()
        .setFixedPosition(100, 100, pdf.getDefaultPageSize().getWidth()-document.getLeftMargin()-document.getRightMargin())

8. 行间距

在iText中,行间距(Leading)指的是本行基线(baseline)与上一行基线之间的距离。基线主要用于在西欧文字中。学习英语时,书写英语字母的四线三格纸的红色线(从上面数第3条),就是英文字母的基线。一些字母,如p、q的一部分是在基线的下方。

红色的线是基线,字母p的一部分在基线以下

行间距可以使用paragraph.setFixedLeading(Float leading)paragraph.setMultipliedLeading(Float leading)进行设置。它的默认值是1.5倍的字体大小;由于默认字体大小为12,默认的固定行间距就是18. 根据定义,行间距是两行基线的距离,因此它需要大于等于本行的字体大小。setFixedLeading()使用绝对大小进行设置,不论使用的字体大小是多大;setMultipliedLeading()使用相对大小进行设置,设置值为字体大小的倍数。

这两种方法在使用时不能混用; 并且只有第一次设置的行间距会生效(可能是bug?)。

Paragraph basePara = new Paragraph("This is a base line paragraph.");
document.add(basePara);
Paragraph smallLineSpacePara = new Paragraph("Line space = 3.0 * font size").setMultipliedLeading(3.0F);
document.add(smallLineSpacePara);
红线是行的基线

9. 其他样式

  • paragraph.setFirstLineIndent(float indent): 首行缩进大小
  • paragraph.setBackgroundColor(Color color): 设置背景颜色
  • paragraph.setBorder(Border boder): 设置段落边框
  • paragraph.setMargin系列(Margin, MarginTop, MarginLeft, MarginBottom, MarginRight, Margins): 设置段落外缩进
  • paragraph.setMaxWidth(float width):设置段落最大宽度
  • paragraph.setMahHeight(float height): 设置段落最大高度
  • paragraph.setPadding系列:设置段落内缩进
  • paragraph.setRotationAngle(float angleInRaduis):设置段落旋转角度,以弧度为单位
  • 等等等等

10. 一个段落,多种样式的文本

前面我们是对段落Paragraph设置样式,那么这个段落的全部文字都会应用设置的样式。如果一个段落中要有多种样式的文本,我们依然需要Paragraph对象来承接一个段落中的文本。不同的是,我们不是直接为这个paragraph来设置样式,而是创建Text类的对象text,为这个text设置样式,最后将这些创建好样式的texts按顺序加入paragraph。用法参考下面的例子:

Paragraph combinedPara = new Paragraph();
Text boldText = new Text("I am bold. ").setBold();
combinedPara.add(boldText);
Text italicText = new Text("I am italic. ").setItalic();
combinedPara.add(italicText);
Text blueText = new Text("I am blue. ").setFontColor(ColorConstants.BLUE);
combinedPara.add(blueText);
Text largeText = new Text("I am large. ").setFontSize(20.0F);
combinedPara.add(largeText);
document.add(combinedPara);
粗体、斜体、蓝色、大字号的组合段落

留下评论