相关文章推荐
腹黑的橙子  ·  CSS Background 與 ...·  2 天前    · 
爱听歌的手术刀  ·  【Android】[转] ...·  9 小时前    · 
精明的手套  ·  android int ...·  9 小时前    · 
小胡子的酱牛肉  ·  scrapy ...·  1 年前    · 
itext7学习笔记——第5章

itext7学习笔记——第5章

3 个月前 · 来自专栏 itext7系列教程
作者:CuteXiaoKe
微信公众号: CuteXiaoKe | 原文

前言

在之前的第1到第3章,我们总是从头开始用iText创建一个新的PDF文档。在第4章的最后几个例子中,我们使用了一个现有的PDF文档,利用现有的PDF来读取表单并填写了自己的表单或者预填充定义的表单。在本章,我们会使用 PdfReader 读取一个存在的PDF文件,或者使用 PdfWriter 对象来创建一个新的 PdfDocument

添加注释和内容

在前面的章节中,我们读取了一个带有表单的PDF文档,然后填充了里面的内容。在这个章节中,我们会进行深入的操作。我们首先添加一个文档注释,一些文本和一个新的复选框,如下图1:

图1. 更新后的表单

接下来就是我们在第四章里面添加注释和内容里面的代码一样了:

PdfDocument pdfDoc =
    new PdfDocument(new PdfReader(src), new PdfWriter(dest));
// add content
pdfDoc.close();

我们在//add content部分添加相应的内容,首先,我们通过 PdfDocument 实例来向一个页面里面添加注释:

PdfAnnotation ann = new PdfTextAnnotation(new Rectangle(400, 795, 0, 0))
    .setTitle(new PdfString("iText"))
    .setContents("Please, fill out the form.")
    .setOpen(true);
pdfDoc.getFirstPage().addAnnotation(ann);

如果我们想添加内容到内容流里面,我们需要创建一个 PdfCancas 对象。我们可以传入一个 PdfPage 对象传入 PdfCanvas 的构造函数:

PdfCanvas canvas = new PdfCanvas(pdfDoc.getFirstPage());
canvas.beginText().setFontAndSize(
        PdfFontFactory.createFont(FontConstants.HELVETICA), 12)
        .moveText(265, 597)
        .showText("I agree to the terms and conditions.")
        .endText();

添加文本的代码和我们在第2章写的代码差不多。无论您是从头开始创建文档还是将内容添加到现有文档,都可以使用我们写的代码。当然,向 PdfAcroForm 实例添加字段也是跟之前的例子一样的:

PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, true);
PdfButtonFormField checkField = PdfFormField.createCheckBox(
        pdfDoc, new Rectangle(245, 594, 15, 15),
        "agreement", "Off", PdfFormField.TYPE_CHECK);
checkField.setRequired(true);
form.addField(checkField);

最后,既然我们已经添加了一个多余的字段,我们想要改变reset的动作:

form.getField("reset").setAction(PdfAction.createResetForm(
    new String[]{"name", "language", "experience1", "experience2",
    "experience3", "shift", "info", "agreement"}, 0))

改变表单字段的属性

之前的第四章的例子中,我们是填充了表单的内容。在这里,我们可以尝试改变字段的属性,添加或者删除。

PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, true);
Map<String, PdfFormField> fields = form.getFormFields();
fields.get("name").setValue("James Bond").setBackgroundColor(Color.ORANGE);
fields.get("language").setValue("English");
fields.get("experience1").setValue("Yes");
fields.get("experience2").setValue("Yes");
fields.get("experience3").setValue("Yes");
List<PdfString> options = new ArrayList<PdfString>();
options.add(new PdfString("Any"));
options.add(new PdfString("8.30 am - 12.30 pm"));
options.add(new PdfString("12.30 pm - 4.30 pm"));
options.add(new PdfString("4.30 pm - 8.30 pm"));
options.add(new PdfString("8.30 pm - 12.30 am"));
options.add(new PdfString("12.30 am - 4.30 am"));
options.add(new PdfString("4.30 am - 8.30 am"));
PdfArray arr = new PdfArray(options);
fields.get("shift").setOptions(arr);
fields.get("shift").setValue("Any");
PdfFont courier = PdfFontFactory.createFont(FontConstants.COURIER);
fields.get("info")
    .setValue("I was 38 years old when I became a 007 agent.", courier, 7);

在这里我们关注下面的几行:

  • 行3:我们设置 name 字段的值为 James Bond ,同时我们设置这个字段的背景色为 Color.ORANGE
  • 行9-17:创建了一个Java List 来添加更多的选项(行8-15),然后把这个 List 转换成 PdfArray (行16),最后使用这个array来更新 shift 字段
  • 行19-21:我们创建了一个新的 PdfFont ,然后使用这个新的字体和新的字体大小作为 info 字段的设置值方法的参数。

让我们看看加入这些代码以后是否有所改变,如图2:

图2. 字段高亮后的表单

我们可以看到 shift 字段有了更多的选项,但是我们没有看见 name 字段的背景,我们是不能清楚 info 字段是否改变。是否发生错误了呢?其实是没有错误的,所有字段当前是被突出显示的而且蓝色的突出色覆盖了背景颜色,我们可以点击 Highlight Existing Fields 来看看还会发生什么,如图3:

图3. 字段没有高亮后的表单

一切跟我们期望的一样。但是我们没有遇到这样一种情况:在关闭 PdfDocument 之前,我们加入了 form.flattenFields(); 语句,这时候表单就锁定,我们就没有了表单,针对这种情况,我们会在下一章探讨。现在,我们来看看我们是不是还能对没有表单的pdf文档进行一些其他的操作。

添加页眉、页脚和水印

我们回忆在一下第三章里面的UFO信息的PDF,我们会创建一个相似的ufo.pdf文件,如图4:

图4. UFO观察表单

可以看出我们创建的ufo.pdf并没有第三章创建的那样炫酷,如果我们往里面添加一个页眉和一个页脚(显示第几页/总页数)还有水印,该如何做呢,如下图5:

itext5-5

在上图中,我们不像第三章那样在添加页脚的时候不知道总的页数,现在我们知道了总的页数,可以添加"1" of "4","2" of "4"等

从头创建文档时,可以为总页数创建一个占位符(placeholder)。一旦创建了所有的页面,我们就可以将该页面的总数添加到该占位符,但这不在本介绍性教程的范围之内。

如下代码展示了如何在已知的文档的每一页中添加内容:

PdfDocument pdfDoc =
    new PdfDocument(new PdfReader(src), new PdfWriter(dest));
Document document = new Document(pdfDoc);
Rectangle pageSize;
PdfCanvas canvas;
int n = pdfDoc.getNumberOfPages();
for (int i = 1; i <= n; i++) {
    PdfPage page = pdfDoc.getPage(i);
    pageSize = page.getPageSize();
    canvas = new PdfCanvas(page);
    // add new content
pdfDoc.close();

我们使用 pdfDoc 对象来创建一个 Document 实例。我们将要使用这个 document 对象来添加内容。我们同时也会使用 pdfDoc 对象来找到原始PDF的总页数。我们遍历所有所有的页数,获得每一页的 PdfPage 对象。以下代码是 //add new content 所做得东西:

//Draw header text
canvas.beginText().setFontAndSize(
        PdfFontFactory.createFont(FontConstants.HELVETICA), 7)
        .moveText(pageSize.getWidth() / 2 - 24, pageSize.getHeight() - 10)
        .showText("I want to believe")
        .endText();
//Draw footer line
canvas.setStrokeColor(Color.BLACK)
        .setLineWidth(.2f)
        .moveTo(pageSize.getWidth() / 2 - 30, 20)
        .lineTo(pageSize.getWidth() / 2 + 30, 20).stroke();
//Draw page number
canvas.beginText().setFontAndSize(
        PdfFontFactory.createFont(FontConstants.HELVETICA), 7)
        .moveText(pageSize.getWidth() / 2 - 7, 10)
        .showText(String.valueOf(i))
        .showText(" of ")
        .showText(String.valueOf(n))
        .endText();
//Draw watermark
Paragraph p = new Paragraph("CONFIDENTIAL").setFontSize(60);
canvas.saveState();
PdfExtGState gs1 = new PdfExtGState().setFillOpacity(0.2f);
canvas.setExtGState(gs1);
document.showTextAligned(p,
        pageSize.getWidth() / 2, pageSize.getHeight() / 2,
        pdfDoc.getPageNumber(page),
        TextAlignment.CENTER, VerticalAlignment.MIDDLE, 45);
canvas.restoreState();

总共的步骤分为四部:

  • 页眉(行2-6):我们使用第二章谈及的低等级的文本api来在每一页的最上方添加 "I want to believe"
  • 页脚线(行8-11):我们使用低等级的画图api来在每一页的底部画线
  • 包含页码的页脚(行13-19):我们使用低等级的文本api在每一页底部添加当前页号, "of" ,以及总的页数。
  • 水印(行21-28):我们创建一个带有文本的 Paragrah 来当做水印。然后我们改变画布的透明性。最后我们添加这个 Paragrah 到文档中,使用 showTextAligned() 方法使水印定位在每一页的中间,并45度倾斜。

在这里,我们添加水印的时候做了一些特殊的工作。我们改变了 canvas 对象的图像状态,然后我们在 document 的每一页中添加了文本,在内部,iText会发现我们已经使用了当前页的 PafCanvas 实例,同时 showTextAligned 会想同一个 canvas 写入内容,这种方式,我们可以使用低级api和一些简单方法(如高级api)的结合(可以和第三章的 添加水印 相比较,确实是方便了不少)。在本章最后的例子中,我们会改变页面的大小和upf.pdf的每一页的方向。

改变页面大小和方向

新的pdf文档效果如下图6:

图6. 改变页面大小和方向的文档

我们可以发现每一页面变得更大了,而且第二页的颠倒了,向下了。让我们来看看代码:

PdfDocument pdfDoc =
    new PdfDocument(new PdfReader(src), new PdfWriter(dest));
float margin = 72;
for (int i = 1; i <= pdfDoc.getNumberOfPages(); i++) {
    PdfPage page = pdfDoc.getPage(i);
    // change page size
    Rectangle mediaBox = page.getMediaBox();
    Rectangle newMediaBox = new Rectangle(
            mediaBox.getLeft() - margin, mediaBox.getBottom() - margin,
            mediaBox.getWidth() + margin * 2, mediaBox.getHeight() + margin * 2);
    page.setMediaBox(newMediaBox);
    // add border
    PdfCanvas over = new PdfCanvas(page);
    over.setStrokeColor(Color.GRAY);
    over.rectangle(mediaBox.getLeft(), mediaBox.getBottom(),
            mediaBox.getWidth(), mediaBox.getHeight());
    over.stroke();
    // change rotation of the even pages