Java处理PDF文档【上】( 全新 iText 8.0 基础入门 、元素)
一:iText简介
iText是一个开源的Java库,用于处理PDF文档的创建、修改和呈现。 它提供了一系列功能强大的 API,使开发人员能够在他们的应用程序中轻松地操作 PDF 文件。
它是由一家名为iText Group NV的公司开发和维护的,总部位于比利时。该公司专注于 PDF 技术,并致力于提供高质量的PDF处理解决方案。
iText套件提供的 一系列PDF相关的工具 、库和产品。这些工具包括开源项目和闭源产品, 涵盖了PDF文档的创建、处理、渲染、优化等多个方面。
具体iText套件如下:
■ pdfOCR('开源'):
用于在PDF文档中进行光学字符识别(OCR),从扫描的文档中提取文本内容。
■ pdfSweep('开源'):
用于在PDF文档中进行敏感信息的清除和保护,例如删除敏感数据或者隐藏个人信息。
■ iText Core('开源'):
用于创建和处理PDF文档。它提供了丰富的API,可以用来创建、操作和处理PDF文件。
■ pdfHTML('开源'):
用于将HTML内容转换为PDF文档。它可以帮助开发人员将网页内容快速转换为可打印和分享的PDF文件。
▢ pdfCalligraph(闭源):
用于在 PDF 中实现高质量的字体渲染和排版。
▢ pdfXFA(闭源):
用于处理PDF中的XFA表单数据,支持生成和填充 XFA 表单。
▢ pdfRender(闭源):
用于高质量的PDF渲染,支持在应用程序中显示 PDF 文档的内容。
▢ pdfOptimizer(闭源):
用于优化 PDF 文档的大小和性能,包括压缩图像、删除无用对象等。
▢ pdfOffice(闭源):
用于在Java应用程序中生成和编辑PDF文档,支持丰富的文本和图形操作
\(\color{#f00}{关于iText开源协议(必看)}\)
使用 iText5 及 iText 所有后续版本必须开源(AGPLv3协议)自己的源代码,若不想开源则必须获得iText公司提供的商业许可协议。具体参考iText开源协议
AGPLv3开源协议的要求主要针对直接使用、修改或与AGPLv3许可的代码结合的情况。则必须开源。
假如是大公司且项目还是商业性质的则去申请商业许可,也不贵。
\(\color{#f00}{关于作者写的iText8.0文章说明}\)
关于Java操作PDF的文章一共分为2篇,上篇为基础,下篇为高级(其实也不算高级啦,好多都没讲到)
Java处理PDF文档【上】( 全新 iText 8.0 基础入门、元素 )
Java处理PDF文档【下】( 全新 iText 8.0 画布、条形码、渲染器 )
二:iText使用准备
下面主要介绍iText 8.0的版本,它和iText 7.0有语法的小差异,但是不影响两者的使用,官方表示iText 8.0在使用上要比之前的版本简便;下文主要针对几个开源的iText的套件使用。
官方iText 8.0.4 API
官方文档(现在只有iText7版本文档)
针对 iText7 --> iText8 的改进内容请看这里
\(\color{#00f}{下文主要以如下几点来介绍:}\)
- 创建PDF文档: 从头开始设计每一页的内容、样式和布局。
- 操作PDF文档: 添加、删除和修改文本、图像、表格等内容。
- 文本处理: 可以对文本进行格式化、添加链接、插入特殊字符等。
- 图像处理: 它支持添加图像到PDF文件中,并提供了对图像进行调整、裁剪和压缩的功能。
- 表格处理: 创建和编辑PDF中的表格,包括设置表格的大小、行高、列宽等。
- 字体和样式: 控制文本的字体、大小、颜色和样式,以及添加特殊效果如加粗、斜体等。
- 页面布局: 允许对页面进行布局,包括添加页眉、页脚、页码等。
- 加密与安全: 它支持PDF文档的加密和数字签名,以确保文档的安全性和完整性。
(一):Maven坐标准备
<!-- 导入iText核心坐标,主要操作PDF的读写功能 -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-core</artifactId>
<version>8.0.4</version>
<type>pom</type>
</dependency>
<!-- 导入iText加密依赖适配器,提供对PDF的加密功能 -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>bouncy-castle-adapter</artifactId>
<version>8.0.4</version>
</dependency>
<!-- 导入iText二维码和条形码生成功能坐标 -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>barcodes</artifactId>
<version>8.0.4</version>
</dependency>
三:入门案例
(一):简单使用
通过这个简单案例会发现,其实iText操作PDF挺简单的,其实一些样式就和CSS的关键字差不多,这里这是一个入门,后面会慢慢介绍更多的内容。
代码效果:
public class Test1 {
// 基本入门案例
public static void main(String[] args) {
Document document = null;
try {
// 创建并初始化一个PDF文档
PdfDocument pdf = new PdfDocument(new PdfWriter("D://简单示例.pdf"));
// 初始化文档
document = new Document(pdf);
// 添加一段英文
Paragraph paragraph1 = new Paragraph("Thank you for reading Ant Brother's blog!");
document.add(paragraph1);
// 添加一段中文(itext无法支持中文字体,需要设置字体)
PdfFont font = PdfFontFactory.createFont("STSongStd-Light", "UniGB-UCS2-H");
// 设置文本的字体、大小、颜色、背景颜色、对齐方式、垂直对其方式
Paragraph paragraph2 = new Paragraph("感谢您阅读蚂蚁小哥的博客!")
.setFont(font)
.setFontSize(18)
.setFontColor(new DeviceRgb(255, 0, 0))
.setBackgroundColor(new DeviceRgb(187, 255, 255))
.setTextAlignment(TextAlignment.CENTER)
.setVerticalAlignment(VerticalAlignment.BOTTOM);
document.add(paragraph2);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
//关闭文档
if (document != null) {
document.close();
}
}
}
}
(二):注意事项
- 关于PDF操作带有单位的值如:宽度、高度等等的值都是以 磅(pt) 为单位:
1 磅(pt) ≈ 1.33 像素(px) 1 像素(px) ≈ 0.75 磅(pt) - 关于PDF操作带有度数的值需要使用如下公式来指定具体度数:
旋转角度 = 旋转角度 * 圆周率 / 180度
(三):颜色类说明
关于下文中使用的一些常见类这里介绍了如:颜色。
关于颜色:
DeviceGray【不推荐】:
表示灰度图像或单色图像的颜色空间。
在DeviceGray中,颜色由单个灰度值表示,范围从0(黑色)到 1(白色)。
示例:
new DeviceGray(1f) 白
new DeviceGray(.5f) 灰
new DeviceGray() 黑
DeviceRGB【推荐】:
表示红、绿、蓝(RGB)颜色模型的颜色空间。
在DeviceRGB中,颜色由三个通道组成,分别表示红、绿、蓝的亮度,每个通道的取值范围从 0~255。
示例(和前端一样):
new DeviceRGB(255,0,0) 红
new DeviceRGB(255,255,0) 黄
也可以直接获取官方定义的RGB颜色:
ColorConstants.GRAY 灰
ColorConstants.RED 红
DeviceCMYK【不推荐】:
表示青、品红、黄、黑颜色模型的颜色空间。
在DeviceCMYK中,颜色由四个通道组成,每个通道的取值范围从 0~100。
示例:
new DeviceCmyk(100, 0, 0, 0) 青色
new DeviceCmyk(0, 100, 0, 0) 品红色
new DeviceCmyk(0, 0, 100, 0) 黄色的
new DeviceCmyk(0, 0, 0, 100) 黑色
四:文档构建和读取
PDF文档的构建也是我们本篇文章的正式开始,主要存在如下类:
PdfWriter、PdfReader、Document、PdfDocument;可以说有了这些基本类以后,我们就可以满足正常的PDF的构建和读取了;具体的使用方式则在下面依次介绍。
(一):对象说明
PdfWriter、PdfReader:
PdfWriter类用于将文档内容写入到PDF文件中。它负责创建和管理PDF文档的输出流,并将文档内容写入到指定的PDF文件或输出流中。通过PdfWriter,可以将创建的文档内容(如页面、文本、图像等)写入到PDF文件中,完成PDF文档的构建过程。
PdfReader类用于读取已存在的PDF文档内容,提取其中的信息并进行相应的操作。通过PdfReader,可以读取文档的页面、文本、图形以及元数据信息,进行文档内容的分析和提取操作。
正常情况下我们不会单独来使用此类来手动写入流和读取流操作,而是借助下面两个类来操作。
PdfDocument类:
说到PdfDocument,它可是iText中的一个重要类,主要用于表示PDF文档的实例。PdfDocument类在iText库中扮演着多种角色,包括创建新的PDF文档、打开现有的PDF文档进行读取和编辑、以及保存和关闭PDF文档等功能。:
Document类:
Document是iText库中用于创建PDF文档内容的类,通常与PdfDocument一起使用。它用于定义文档的逻辑结构,包括段落、章节、列表、表格等高级元素,并负责组织和格式化文本内容,使其在PDF文档中呈现出合适的样式和排版;还有就是它更侧重于高层次的文档内容创建,如添加段落、列表、表格、链接等。Document类还有一个父类RootDocument哟。
点击查看详情:PdfDocument常用对象和方法
'Ⅰ:获取文档元数据信息:'
getDocumentInfo():
获取文档的元数据信息,我们可以通过这个返回的PdfDocumentInfo来进行元数据的设置。
'Ⅱ:创建新的空白页:'
addNewPage():创建新页面并将其添加到文档末尾。
addNewPage(int index):创建新页面并将其插入到文档指定位置中。
addNewPage(PageSize pageSize):创建指定大小的新页面并将其添加到文档末尾。
addNewPage(int index, PageSize pageSize):创建指定大小的新页面并将其添加到指定位置中。
'Ⅲ:设置和获取文档页面默认大小:'
getDefaultPageSize():获取默认页面大小。
setDefaultPageSize(PageSize pageSize):设置默认页面大小。
'Ⅳ:获取文档页面(返回的都是 PdfPage 对象):'
getFirstPage():获取文档的第一页。
getLastPage():获取文档的最后一页。
getPage(int pageNum):按照页码获取页面。
'Ⅴ:删除文档已存在的页面:'
removePage(int pageNum):按页码从文档中删除页面。
removePage(PdfPage page):从此文档中删除第一次出现的指定页面。
'Ⅵ将页面从当前文档复制到别的文档上:'
copyPagesTo(int pageFrom, int pageTo, PdfDocument toDocument)
copyPagesTo(int pageFrom, int pageTo, PdfDocument toDocument, int insertBeforePage)
copyPagesTo(List﹤Integer﹥ pagesToCopy, PdfDocument toDocument)
copyPagesTo(List﹤Integer﹥ pagesToCopy, PdfDocument toDocument, int insertBeforePage)
参数说明:
pageFrom:待复制的页面起始页。
pageTo:待复制的页面结束页。
pagesToCopy:指定需要复制页面页号的列表。
toDocument:把复制的页面放到这个文档中。
insertBeforePage:把复制的页面放到目标文档指定位置的前面;(默认是复制到文档末尾)
'Ⅶ:获取常用的文档参数:'
getNumberOfPages():获取文档内总页数。
getDefaultFont():获取文档的默认字体:Helvetica、WinAnsi。
hasOutlines():校验当前文档是否有大纲,true代表有。
getOutlines(boolean updateOutlines):获取文档大纲,true为重新读取,false从缓存中读取。
getPdfVersion():获取PDF版本。
'Ⅷ:关闭文档资源:'
close():关闭PdfDocument对象
isClosed():查看PdfDocument对象是否被关闭
setCloseReader(boolean closeReader):是否关闭关联的PdfReader
setCloseWriter(boolean closeWriter):是否关闭关联的PdfWriter
isCloseReader():是否会关闭了关联的PdfReader
isCloseWriter():是否会关闭了关联的PdfWriter
点击查看详情:Document常用对象和方法
'文档内添加元素:'
add(Image image):将图像添加到根目录。
add(IBlockElement element):将元素添加到根目录。
注:它可以添加如段落(Paragraph)、列表和列表元素(List、ListItem)、Table(表格)...
add(AreaBreak areaBreak):终止当前页面,并跳到下一个页面。
'设置文档的边距(Margin)大小,单位是 磅(pt):'
setTopMargin(float topMargin)
setRightMargin(float rightMargin)
setBottomMargin(float bottomMargin)
setLeftMargin(float leftMargin)
setMargins(float topMargin,float rightMargin,float bottomMargin,float leftMargin)
设置完边距后,它可以使内容区域往内挤,内容区域会距离文档边缘越来越远。
别忘了它还有获取边距的四个方法哟。
getTopMargin()、getRightMargin()、getBottomMargin()、getLeftMargin()
'刷新PDF文档流的输出流:'
flush():强制所有已注册的呈现器(包括子元素呈现器)将其内容刷新到内容流。
当我们在文档中添加段落、图片、表格等内容时,这些内容会暂存起来,并不会立即写入到 PDF 文档中。
通过调用document.flush()方法,可以强制将这些暂存的内容写入到PDF文档中,然后再关闭文档。
'其它方法:'
close():关闭文档和关联的PdfDocument对象。
getPdfDocument():获取PdfDocument对象。
(二):PDF构建和读取
在下面的这两个案例中可以让大家直观的看出页面的创建和页面的复制,记住一点,我们不创建页面,文档会自动为我们创建页面,当写入的内容超出当前页面后,文档也会为我们创建下一张页面。所以在不确定页面的情况下我们不用手动创建新页面。但是若我们明确知道有几页则推荐提前创建,因为我们不确定我们在后面会进行指定页面的操作以及在指定页面上使用画布。
/***
* 创建PDF文件,创建了几张空白页
*/
public static void main(String[] args) throws IOException {
// 创建一个PDF文件并构建PDF文档
PdfDocument pdfDoc = new PdfDocument(new PdfWriter("D://简单示例.pdf"));
// 下面一共创建了 5 页,执行完代码会有五页
// 创建两张A4大小的页(默认A4)
pdfDoc.addNewPage();
pdfDoc.addNewPage(PageSize.A4);
// 创建一张A8大小的页
pdfDoc.addNewPage(PageSize.A8);
// 创建一张 400*200 磅大小的页
pdfDoc.addNewPage(new PageSize(400, 200));
// 创建一张 100*100磅 大小的页,并插入到页2的前面(这时就是两张A4页的中间咯)
pdfDoc.addNewPage(2, new PageSize(100, 100));
// 创建文档
Document document = new Document(pdfDoc);
document.close();
}
/***
* 创建PDF文件,并从其它文件内读取了几张页复制了过来
*/
public static void main(String[] args) throws IOException {
// 读取一个PDF文件并构建PDF文档
PdfDocument pdfRDoc = new PdfDocument(new PdfReader("D://DocPag.pdf"));
// 创建一个PDF文件并构建PDF文档
PdfDocument pdfWDoc = new PdfDocument(new PdfWriter("D://简单示例.pdf"));
// 创建3个新页
pdfWDoc.addNewPage(PageSize.A8);
pdfWDoc.addNewPage(PageSize.A7);
pdfWDoc.addNewPage(PageSize.A6);
// 从读取的Pdf中读取2~4(2,3,4)这几页,放到目标文档中的第2页前面
pdfRDoc.copyPagesTo(2, 4, pdfWDoc, 2);
// 从读取的Pdf中读取1,3,4这几页,放到目标文档中的末尾
pdfRDoc.copyPagesTo(Arrays.asList(1, 3, 4), pdfWDoc);
// 创建文档
Document document = new Document(pdfWDoc);
document.close();
}
(三):设置PDF背景
我们可以通过画布来对生成的每一个页创建背景,具体的画布canvas将在后面讲解。
public static void main(String[] args) throws IOException {
// 加载图片资源,并设置图片大小
Image image = new Image(ImageDataFactory.create("D:\\images\\pg2.jpg"));
image.setWidth(140);
image.setHeight(100);
// 创建PDF,并构建PDF文档,初始化一张A6的页面(默认是A4)
PdfDocument pdfDoc = new PdfDocument(new PdfWriter("D:\\简单示例.pdf"));
PageSize pageSize = PageSize.A6;
pdfDoc.addNewPage(pageSize);
// 获取文档first页面的 PdfCanvas 画布
PdfCanvas canvas = new PdfCanvas(pdfDoc.getFirstPage());
// 设置背景颜色
canvas.saveState()
.setFillColor(new DeviceRgb(200, 145, 0))
// 前2个参数代表页面的x和y,此时我定位在页面的左下角
// 后两个参数代表填充大小
.rectangle(0, 0, pageSize.getWidth() - 10, pageSize.getHeight() - 10)
.fill()
.restoreState();
// 构建文档
Document document = new Document(pdfDoc);
// 若设置0则代表当前的页里面的内容都贴着边缘
//document.setMargins(0, 0, 0, 0);
// 设置四边的边距为100
document.setMargins(50, 50, 50, 50);
// 插入段落(块级元素)、图片
document.add(new Paragraph("Hello World!"));
document.add(image);
// 关闭文档
document.close();
}
(四):元数据信息设置
元数据信息对于文档的管理、搜索和归档非常重要,比如描述文档的标题、作者、主题、关键字等内容,有助于对文档进行分类和组织,使得用户可以更容易地找到和识别所需的文档。
public class Test1 {
public static void main(String[] args) throws IOException {
create();
select();
}
// 设置PDF元数据
public static void create() throws FileNotFoundException {
// 创建一个PDF文件并构建PDF文档
PdfDocument pdfDoc = new PdfDocument(new PdfWriter("E://简单示例.pdf"));
// 获取文档信息对象
PdfDocumentInfo docInfo = pdfDoc.getDocumentInfo();
// 设置元数据信息
docInfo.setCreator("tom").setAuthor("蚂蚁小哥")
.setSubject("主题信息").setTitle("元数据案例");
// 创建文档
Document document = new Document(pdfDoc);
// 这个文档我就没创建任何内容,就一张空白页面....
// 关闭文档
document.close();
}
// 获取PDF元数据
public static void select() throws IOException {
// 读取一个PDF文件并构建PDF文档
PdfDocument pdfDoc = new PdfDocument(new PdfReader("E://简单示例.pdf"));
// 获取文档信息对象
PdfDocumentInfo docInfo = pdfDoc.getDocumentInfo();
// 具体请参考API,有好多元数据获取
System.out.println("作者:" + docInfo.getAuthor());
System.out.println("标题:" + docInfo.getTitle());
// 打印:作者:蚂蚁小哥
// 标题:元数据案例
}
}
"/* ********************** 补充说明 ********************** */"
PdfDocumentInfo方法说明(set和get是对应的,这里我只说set):
setAuthor(String author):设置文档的作者信息。
setTitle(String title):设置文档的标题或名称。
setCreator(String creator):设置文档的创建者信息。
setKeywords(String keywords):设置文档的关键字信息(描述内容的关键字,有助于文档的分类和搜索)。
setProducer(String producer):设置文档的生成器信息(生成文档的应用程序的名称)。
setSubject(String subject):设置文档的主题信息(文档所涉及的主题或主要内容的描述)。
setTrapped(PdfName trapped):设置文档的“trapped”状态,用于指示文档是否处于受限制状态。
True:指示文档已经进行了印前处理。False:指示文档未经过印前处理。
额外信息的设置(2种类型任意设置)
setMoreInfo (String key, String value)
setMoreInfo (Map<String,String> moreInfo)
(五):PDF加密解密
PDF的加密是必不可少的,Itext为我们提供了两种文档加密方式,分别是:标准加密(密码)、公钥加密;下面我们将基本的介绍这标准的加密方式。
点击查看详情:加密方法和EncryptionConstants类说明
WriterProperties的setStandardEncryption方法说明:
setStandardEncryption(byte[] userPassword, byte[] ownerPassword,
int permissions, int encryptionAlgorithm)
参数说明:
userPassword:可以为null或长度为零,等于省略用户密码
ownerPassword:所有者密码。如果为null或为空,iText将生成一个随机字符串用作所有者密码。
permissions:使用密码打开后用户会有哪些文档权限,(参考:文档权限描述)
encryptionAlgorithm:加密算法(参考:加密类型)
EncryptionConstants对象里面的一些常量:
加密类型(四个选一个):
ENCRYPTION_AES_128:使用128位AES加密进行加密。
ENCRYPTION_AES_256:使用256位AES加密进行加密。
STANDARD_ENCRYPTION_40:使用标准的40位加密进行加密。
STANDARD_ENCRYPTION_128:使用标准的128位加密进行加密。
加密类型(可选,使用 | 隔开)
DO_NOT_ENCRYPT_METADATA:将此添加到模式中以保持元数据为明文。
EMBEDDED_FILES_ONLY:将其添加到模式中,以仅加密嵌入的文件。
文档权限描述:
ALLOW_ASSEMBLY:允许用户在使用用户密码打开文档时进行文档的组合操作,如拼接多个文档为一个文档。
ALLOW_COPY:允许用户在使用用户密码打开文档时复制文档内容或选择性粘贴文档内容到其他应用程序中。
ALLOW_DEGRADED_PRINTING:允许用户在使用用户密码打开文档时进行低质量打印,例如打印水印等。
ALLOW_FILL_IN:允许用户在使用用户密码打开文档时填写表单域或进行表单内容的编辑。
ALLOW_MODIFY_ANNOTATIONS:允许用户在使用用户密码打开文档时修改文档中的注释(如批注、标记等)。
ALLOW_MODIFY_CONTENTS:允许用户在使用用户密码打开文档时修改文档内容等操作。
ALLOW_PRINTING:允许用户在使用用户密码打开文档时进行操作,包括高质量打印。
ALLOW_SCREENREADERS:允许用户在使用用户密码打开文档时使用屏幕阅读器软件来提供辅助阅读功能。
点击查看详情:PDF的标准加密和解码读取
public class Encryption {
// 需要进行加密操作的PDF文件
public static final String pdfPathA = "D:\\PDF文件A.pdf";
public static final String pdfPathB = "D:\\PDF文件B.pdf";
public static final String pdfPathC = "D:\\PDF文件C.pdf";
public static final String pdfPathD = "D:\\PDF文件D.pdf";
// 源PDF文件,无任何加密的文档。
public static final String notEncPath = "D:\\Not-Encryption.pdf";
public static void main(String[] args) throws IOException {
// encryptionATest();
// encryptionBTest();
// readATest();
// encryptionPDF();
// updatePwd();
}
/***
* 创建一个PDF,并将设置这个PDF的访问密码和操作密码
* 执行代码会创建一个 PDF文件A.pdf 的文件,这个pdf打开需要输入“123” 用户密码
* 当需要编辑PDF内容时需要输入 “456” 所有者密码
*/
public static void encryptionATest() throws FileNotFoundException {
// 创建写文档的一些配置信息,并设置加密的信息
WriterProperties wProps = new WriterProperties();
wProps.setStandardEncryption(
"123".getBytes(StandardCharsets.UTF_8),
"456".getBytes(StandardCharsets.UTF_8),
EncryptionConstants.ALLOW_PRINTING,
EncryptionConstants.EMBEDDED_FILES_ONLY
);
// 创建一个PDF文件并构建PDF文档(PDF文件A.pdf)
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(pdfPathA, wProps));
// TODO 因为这里我只是测试文档加密,我就不用Document对象为这个文档写入内容了,直接关闭。
// 关闭文档
pdfDoc.close();
}
/***
* 创建一个PDF,并将设置这个PDF的操作密码(所有者密码)
* 执行代码会创建一个 PDF文件B.pdf 的文件,打开无需密码
* 当需要编辑PDF内容时需要输入 “456” 所有者密码
*/
public static void encryptionBTest() throws FileNotFoundException {
// 创建写文档的一些配置信息,并设置加密的信息
WriterProperties wProps = new WriterProperties();
wProps.setStandardEncryption(
null,
"456".getBytes(StandardCharsets.UTF_8),
EncryptionConstants.ALLOW_PRINTING,
EncryptionConstants.EMBEDDED_FILES_ONLY
);
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(pdfPathB, wProps));
pdfDoc.close();
}
/***
* 通过所有者密码可以获取文档的密码,所以文档密码可不能忘了
*/
public static void readATest() throws IOException {
// 创建读文档的一些配置信息,并设置访问的密码信息
ReaderProperties rProps = new ReaderProperties();
// 千万需要注意,这个所有者密码获取的字节编码可不能错了
rProps.setPassword("456".getBytes(StandardCharsets.UTF_8));
// 构建PDF文档对象,并读取信息
PdfDocument pdfDoc = new PdfDocument(new PdfReader(pdfPathA, rProps));
// 获取的密码
byte[] bytes = pdfDoc.getReader().computeUserPassword();
System.out.println(new String(bytes, StandardCharsets.UTF_8));
pdfDoc.close();
}
/***
* 将一个没有密码的PDF文件复制并写出一个带有密码的PDF文件
*/
public static void encryptionPDF() throws IOException {
// 创建写文档的一些配置信息,并设置加密的信息
WriterProperties wProps = new WriterProperties();
wProps.setStandardEncryption(
"123".getBytes(StandardCharsets.UTF_8),
"456".getBytes(StandardCharsets.UTF_8),
EncryptionConstants.ALLOW_PRINTING,
EncryptionConstants.EMBEDDED_FILES_ONLY
);
// 读取没有密码的PDF
PdfReader pdfReader = new PdfReader(notEncPath);
// 构建一个全新的PDF
PdfWriter pdfWriter = new PdfWriter(pdfPathC, wProps);
// 将读取的文件重新构建一份,并通过pdfWriter写出去。
PdfDocument pdfDoc = new PdfDocument(pdfReader, pdfWriter);
pdfDoc.close();
}
/***
* 修改带密码的PDF文件,修改其实就是将带有密码的PDF读入,再通过写出的方式,写出一个新文件
* 这种间接达到修改密码,到时候再将读取的文件删除即可
*/
public static void updatePwd() throws IOException {
// 通过 所有者密码读取 PDF文件
PdfReader pdfReader = new PdfReader(pdfPathC, new ReaderProperties()
.setPassword("456".getBytes(StandardCharsets.UTF_8)));
// 构建一个全新的PDF,并设置全新的密码
PdfWriter pdfWriter = new PdfWriter(pdfPathD,
new WriterProperties().setStandardEncryption(
"111".getBytes(StandardCharsets.UTF_8),
"222".getBytes(StandardCharsets.UTF_8),
EncryptionConstants.ALLOW_PRINTING,
EncryptionConstants.EMBEDDED_FILES_ONLY));
// 将带密码的文件重新写出去,原来的文件没动,间接达到修改密码
PdfDocument pdfDoc = new PdfDocument(pdfReader, pdfWriter);
pdfDoc.close();
}
}
五:字体文本样式
(一):常用方法说明
字体的样式无非就是加粗、倾斜、下划线、颜色、行间距、缩进、字体等等操作,下面看一些常用的方法,针对这些方法下面案例会进行一个说明。
点看查看详情:关于字体操作的常用方法
'1:字体加粗'
setBold()
'2:字体样式'
setFont(PdfFont font)
'3:字体大小'
setFontSize(float fontSize)
'4:字体颜色'
setFontColor(Color fontColor)
setFontColor(Color fontColor, float opacity)
参数说明:
fontColor:颜色对象
opacity:透明度;0~1,如:.5f为半透明
'5:字体族'
setFontFamily(String... fontFamilyNames)
setFontFamily(List﹤String﹥ fontFamilyNames)
'6:设置文本的字距调整:'
setFontKerning(FontKerning fontKerning)
启用或禁用紧排。一些字体可以指定紧排对,即字形对,在紧排对之间调整水平空间的量。
这种调整通常是负的,例如,在“AV”对中,字形通常会彼此移动得更近。
可选值:FontKerning.YES、FontKerning.NO
'7:文本元素的书写系统'
setFontScript(Character.UnicodeScript script)
'8:文本首字符缩进:'
setFirstLineIndent(float indent)
正常缩进2个单位,字体默认12pt,所以缩进设置 12 * 2。
'9:设置文本间距:'
setCharacterSpacing(float charSpacing)
字符间距,正常也不会这么弄,除非如一个成语或者单词特意让字符间隔。
setWordSpacing(float wordSpacing)
设置只适用于单词间的间距,可不是每个字符间距哟,是单词与单词间距。
'10:设置文本的渲染模式:'
setTextRenderingMode(int textRenderingMode)
设置文本在PDF页面上的呈现方式。可以通过传入不同的参数来实现不同的效果,
例如正常显示、描边、填充等。具体渲染默认如下:
PdfCanvasConstants.TextRenderingMode常量:
FILL (0):填充
文本以实心形式呈现,即填充字体轮廓内部。
STROKE (1):描边
文本以轮廓形式呈现,只显示文字的边缘,字体内部不填充。
FILL_STROKE (2):填充加描边
文本同时以实心和轮廓形式呈现,即填充字体轮廓内部并显示文字的边缘。
INVISIBLE (3):不可见
文本不可见,即不会在页面上显示。
FILL_CLIP (4):填充并裁剪
文本以实心形式呈现,并将其添加到裁剪路径中,用于裁剪其他元素。
STROKE_CLIP (5):描边并裁剪
文本以轮廓形式呈现,并将其添加到裁剪路径中,用于裁剪其他元素。
FILL_STROKE_CLIP (6):填充加描边并裁剪
文本同时以实心和轮廓形式呈现,并将其添加到裁剪路径中,用于裁剪其他元素。
CLIP (7):裁剪
将文本添加到裁剪路径中,用于裁剪其他元素。
'11:设置文本的基础方向:'
setBaseDirection(BaseDirection baseDirection)
即文本的书写方向。可以将文本方向设置为从左到右或者从右到左,以适应不同的语言和排版需求。
BaseDirection枚举:
NO_BIDI:无双向性
文本没有双向性,即不需要考虑文字的书写方向。
DEFAULT_BIDI:默认双向性
文本使用默认的双向性,即根据文本内容自动确定文字的书写方向。
LEFT_TO_RIGHT:从左到右
文本的书写方向从左到右,适用于大部分的拉丁字母语言和数字。
RIGHT_TO_LEFT:从右到左
文本的书写方向从右到左,适用于一些阿拉伯字母语言、希伯来语等从右向左书写的语言。
'12:文本对齐方式:'
setTextAlignment(TextAlignment alignment)
可选值:TextAlignment.xx
LEFT(左对齐):文本左边缘与包含区域的左边缘对齐。
RIGHT(右对齐):文本右边缘与包含区域的右边缘对齐。
CENTER(居中对齐):文本在包含区域内水平居中对齐。
JUSTIFIED(两端对齐):文本在包含区域内两端对齐,
即使需要在单词之间插入额外的空格或拉伸单词以填满行宽度。
JUSTIFIED_ALL(完全两端对齐):类似于JUSTIFIED,但不仅在行末进行对齐,
而是在每个段落中的所有行末进行对齐。
'13:文本设置下划线(通过参数可以设置删除线、下划线、上划线...):'
setUnderline():默认就是下划线
setLineThrough():设置文本删除线
setUnderline(float thickness, float yPosition)
setUnderline(Color color, float thickness, float thicknessMul,
float yPosition, float yPositionMul, int lineCapStyle)
setUnderline(Color color, float opacity, float thickness, float thicknessMul,
float yPosition, float yPositionMul, int lineCapStyle)
参数说明:
color:下划线的颜色
opacity:下划线的透明度(0~1;.5f表示半透明)
thickness:表示下划线的粗细
thicknessMul:表示与字体大小相关的粗细调整因子。
如果你希望下划线的粗细随着字体大小的变化而变化,可以使用这个参数来实现。
例如,如果你希望下划线的粗细是字体大小的一半,可以将thicknessMul设置为0.5f。
yPosition 表示下划线相对于基线的垂直偏移量。
yPositionMul:表示与字体大小相关的垂直偏移量调整因子。
如果你希望下划线的位置随着字体大小的变化而变化,可以使用这个参数来实现。
例如,希望下划线的位置是字体大小的固定偏移量加上字体大小的一半,可以设置为0.5f。
lineCapStyle 参数表示线端的样式,如圆头、方头等。
可选值:
LineCapStyle.BUTT:直角线(在开头和结尾初超出一点点)
LineCapStyle.ROUND:圆角线
LineCapStyle.PROJECTING_SQUARE:直角线(在开头和结尾处超出比BUTT多些)
(二):基本样式示例
代码效果:
public static void main(String[] args) throws IOException {
// 创建并初始化一个PDF文档
PdfDocument pdf = new PdfDocument(new PdfWriter("D://基本示例.pdf"));
Document document = new Document(pdf);
// 创建第一个段落,并设置段落内容
Paragraph paragraph1 =
new Paragraph("Thank you for reading Ant Brother's blog!");
// 设置第一段文字样式
paragraph1.setBold() // 加粗文本
.setItalic() // 设置文本斜体
.setFontSize(26) // 设置文字大小 20pt
.setLineThrough() // 设置文本删除线
.setTextAlignment(TextAlignment.CENTER) // 设置字体居中
.setFontColor(new DeviceRgb(0, 0, 255), .5f) // 设置文本颜色
.setBorder(new SolidBorder(2)); // 元素边框为了和下面区分,后面有介绍
// 创建第二个段落,并设置段落内容
String str = "Thank you for reading Ant Brother's blog! " +
"I hope you are happy every day and make big money every day!";
Paragraph paragraph2 = new Paragraph(str);
paragraph2
.setFontSize(20) // 设置字体大小
.setFirstLineIndent(20 * 2); // 字体大小 * 2;代表缩进2个字符
// 把段落添加到文档里,并关闭文档
document.add(paragraph1);
document.add(paragraph2);
document.close();
}
(三):中文显示问题
上面说了字体文本的基本样式,但是上面的案例没有使用中文,英文这种会出现问题,ItextPDF对咱们亚洲字体的显示有问题,所以下面主要讲讲字体的显示问题以及字体族等信息。
点开查看详情:关于中文字体包的详细说明
'注:导入itext-core坐标它内部会自带字体坐标font-asian的,所以不用额外导入。'
'关于setFont(PdfFont font)方法详解:'
PdfFont字体格式对象(具体可以参考下面):
PdfFont createFont(fontProgram,encoding,embeddingStrategy,cached)
- 若使用的是Asian包提供的字体,我们需要设置前2个参数。
- 若使用的是路径字体,一般就设置第一个参数即可,后面的会自动识别。
四个参数说明:
fontProgram:这是字体文件的路径或者字体名称。
encoding:这是一个字符串,用于指定文本的编码格式。告诉iText如何解释文本的字节流。
embeddingStrategy:用于指定字体文件的嵌入策略。具体参考下面
cached:指示是否缓存创建的字体对象。
如果设置为true,则会缓存字体对象,提高性能。
如果设置为false,则每次调用 createFont 方法时都会重新创建字体对象。
通常情况下,建议将这个参数设置为true,以提高性能。
字体样式分为两种方式:使用Asian包提供的字体、使用系统自带的字体(或指定路径字体)。
Ⅰ:使用Asian包提供的字体
使用Asian包提供的则需要先导入font-asian坐标(不过itext-core坐标内部自带了)。
导入的这个包也被称为CJK,指的是汉字(简体或繁体)、日语、韩语的首字母缩写。
这个包内部包含了如下几种字体:
STSong-Light(宋体-细、简体)- UniGB-UCS2-H(编码)
MHei-Medium(微软雅黑-中黑、繁体)- UniCNS-UCS2-H(编码)
MSung-Light(微软雅黑-中宋、繁体)- UniCNS-UCS2-H(编码)
HeiseiKakuGo-W5(平成角-粗、日文)- UniJIS-UCS2-H(编码)
HeiseiMin-W3(平成明朝-细、日文)- UniJIS-UCS2-H(编码)
HYGoThic-Medium(汉阳角体-中、韩文)- UniKS-UCS2-H(编码)
HYSMyeongJo-Medium(汉阳新명조-中、韩文)- UniKS-UCS2-H(编码)
使用如下(语言和字体需要对应哟,否则报空):
PdfFont font = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H")
Ⅱ:使用系统自带的字体(或指定路径字体)
其实就是Windows(C:\Windows\Fonts)和Linux(/usr/share/fonts/)自带的字体;
也可以使用我们下载的字体,下载的字体可以存放在任意位置,只要路径可以找到即可。
关于字体的嵌入策略:PdfFontFactory.EmbeddingStrategy
是否嵌入当前的字体到pdf中,这块我也不太清楚,使用默认即可,能嵌入就嵌入。
FORCE_EMBEDDED:强制嵌入字体。如果字体无法嵌入,则会出现异常
FORCE_NOT_EMBEDDED:强制不嵌入字体。如果无法不嵌入字体,则会出现异常。
PREFER_EMBEDDED:(默认)如果可能,嵌入字体。
PREFER_NOT_EMBEDDED:如果可能的话,不嵌入字体。
关于字体的编码格式:PdfEncodings
字体编码我也没太深入研究,默认就是空着,
若使用的是系统字体则无需设置,会自动识别,若使用其它路径则想设置也行
IDENTITY_H = "Identity-H"
水平方向上的身份编码,也就是水平书写的Unicode编码。
当文本以水平方式书写时,通常会使用这种编码。
在PDF中,文本以水平方向排列,从左到右显示,这是最常见的排列方式。
IDENTITY_V = "Identity-V"
垂直方向上的身份编码,也就是垂直书写的Unicode编码。
当文本以垂直方式书写时,会使用这种编码。
在PDF中,有些语言或者排版风格可能会选择垂直书写,文本会从上到下、从右到左地排列显示,
这时就会使用垂直编码。
'关于setFontScript(Character.UnicodeScript script)方法详解:'
这个方法用于设置文本的脚本(Unicode脚本),用于指定文本中所包含字符的脚本类型。
这对于支持多种语言的文本排版非常重要,因为不同的语言使用不同的字符集和字形。
不同的语言需要设置不同的脚本(正常不用设置):
Character.UnicodeScript.HAN:汉语字符
Character.UnicodeScript.LATIN:英语字符
Character.UnicodeScript.LATIN:拉丁字符
Character.UnicodeScript.HANGUL:韩语字符
Character.UnicodeScript.ARABIC:阿拉伯字符
Character.UnicodeScript.HEBREW:希伯来字符
Character.UnicodeScript.HIRAGANA:日语字符
代码效果:
public static void main(String[] args) throws IOException {
// 创建并初始化一个PDF文档
PdfDocument pdf = new PdfDocument(new PdfWriter("D://基本示例.pdf"));
Document document = new Document(pdf);
// 创建第一个段落,并设置段落内容
Paragraph paragraph1 =
new Paragraph("感谢您阅读蚂蚁小哥的博客!希望你每天都快乐,每天都赚大钱!");
// 设置字体样式
// 添加一段中文(itext无法支持中文字体,需要设置字体)
// 使用Asian包提供的字体(中文简体)
// PdfFont font = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H");
// 使用系统自带的(或者指定字体路径)
String fontPath1 = "D:\\No.300-ShangShouGuHuangTi-2.ttf"; // 网上下载的
String fontPath2 = "C:\\Windows\\Fonts\\simfang.ttf"; // win自带的
PdfFont font = PdfFontFactory.createFont(
fontPath1,
PdfEncodings.IDENTITY_H,
PdfFontFactory.EmbeddingStrategy.PREFER_EMBEDDED, true);
// 设置样式
paragraph1
.setBold()
.setFontSize(30)
.setFont(font)
.setFontScript(Character.UnicodeScript.HAN)
.setFontColor(new DeviceRgb(255, 0, 0), .2f)
.setBorder(new SolidBorder(2));
// 把段落添加到文档里,并关闭文档
document.add(paragraph1);
document.close();
}
(四):文本线的样式
查看文档可以看到下划线和中划线的方法,但是其它划线的方式需要我们使用带有参数的方法来设置,下面将带大家基本了解这些方法:
代码效果:
public static void main(String[] args) throws IOException {
// 创建并初始化一个PDF文档
PdfDocument pdf = new PdfDocument(new PdfWriter("D://基本示例.pdf"));
Document document = new Document(pdf);
// 创建第一个段落,并设置段落内容
Paragraph paragraph1 =
new Paragraph("Thank you for reading Ant Brother's blog");
paragraph1
.setFontSize(20)
.setUnderline(1.5f, 20 / 4f)
.setBorder(new SolidBorder(1));
// 创建第二个段落,并设置段落内容
Paragraph paragraph2 =
new Paragraph("Thank you for reading Ant Brother's blog");
paragraph2
.setFontSize(20)
// 这里的加载因子需要调试,具体我也不知道咋计算,
// 反正这个要是设置好,他会根据字体大小自动变粗线
.setUnderline(ColorConstants.BLUE, .5f, .1f,
20 / 4f, .05f, PdfCanvasConstants.LineCapStyle.ROUND)
.setBorder(new SolidBorder(1));
// 把段落添加到文档里,并关闭文档
document.add(paragraph1);
document.add(paragraph2);
document.close();
}
(五):文本其它样式
这里主要将介绍文本的描边样式和字符间隔,还有就是需要注意 new Text() 它的样式其实基本上都有,可以针对某几个字符进行单独设置样式。
代码效果:
public static void main(String[] args) throws IOException {
// 创建并初始化一个PDF文档
PdfDocument pdf = new PdfDocument(new PdfWriter("D://基本示例.pdf"));
Document document = new Document(pdf);
// 创建第一个段落
Paragraph paragraph1 = new Paragraph();
// 我们也可以不用直接加入到段落,而是先通过new Text()创建文件,并加入
// new Text()的牛逼之处就是可以对里面的每个字符设置样式
paragraph1.add(new Text("蚂蚁小").setFontSize(25).setCharacterSpacing(25 * 2));
paragraph1.add(new Text("哥").setFontSize(25));
paragraph1.setBold()
.setFontSize(25)
.setFont(PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H"))
.setTextAlignment(TextAlignment.CENTER)
.setBorder(new SolidBorder(1));
// 创建第二个段落,并设置段落内容
Paragraph paragraph2 =
new Paragraph("蚂蚁小哥");
paragraph2
.setTextAlignment(TextAlignment.CENTER)
.setFontSize(60)
.setFont(PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H"))
.setFontColor(new DeviceRgb(255, 0, 255), .5f)
.setStrokeWidth(3f) // 设置字体元素的轮廓大小
.setStrokeColor(ColorConstants.BLUE) // 设置字体元素的轮廓颜色
// 开启文本渲染模式(开启填充加描边)
.setTextRenderingMode(PdfCanvasConstants.TextRenderingMode.FILL_STROKE)
.setBorder(new SolidBorder(1));
// 把段落添加到文档里,并关闭文档
document.add(paragraph1);
document.add(paragraph2);
document.close();
}
六:边框圆角样式
这玩意没啥好说的,但是用的也是挺多的,设置对应的边框和边框圆角可以看起来圆润,它和CSS的圆角一模一样,下面我就写个简单示例:
点开查看详情:关于元素边框和边框圆角详细说明
'关于块级元素边框的一些设置':
setBorder(Border border)
直接设置上下左右四个边框的颜色、宽度、边框图案类型样式
补充:设置指定某一边的边框设置样式
setBorderTop(Border border)、setBorderRight(Border border)
setBorderBottom(Border border)、setBorderLeft(Border border)
关于Border对象使用(创建Border的子类):
SolidBorder:实线边框
DashedBorder:虚线边框
DottedBorder:点虚线边框
DoubleBorder:双实线边框
RoundDotsBorder:圆形点边框
FixedDashedBorder:固定虚线边框
RidgeBorder:山脊边界
GrooveBorder:凹槽边框
InsetBorder:插入边框
关于Border对象创建的3个参数:
比如这个子类:DottedBorder(color, width, opacity)
color:边框颜色
width:边框宽度
opacity:边框透明度,可选值0~1;0为透明
示例使用的双实线:
Border border = new DoubleBorder(new DeviceRgb(255, 0, 0), 10, .3f);
'关于块级元素的边框圆角一些设置':
setBorderRadius(BorderRadius borderRadius)
直接设置此元素的所有四条边的边框圆角
补充:设置指定某一边的边框圆角
setBorderTopLeftRadius(BorderRadius borderRadius):左上角
setBorderTopRightRadius(BorderRadius borderRadius):右上角
setBorderBottomLeftRadius(BorderRadius borderRadius):左下角
setBorderBottomRightRadius(BorderRadius borderRadius):右下角
关于BorderRadius对象使用:
new BorderRadius(radius)
new BorderRadius(horizontalRadius, verticalRadius)
一个参数为水平半径和垂直半径都为 radius
两个参数为水平半径horizontalRadius、垂直半径verticalRadius
示例:
BorderRadius borderRadius = new BorderRadius(25);
代码效果:
public static void main(String[] args) throws IOException {
// 创建并初始化一个PDF文档
PdfDocument pdf = new PdfDocument(new PdfWriter("D://示例.pdf"));
// 初始化文档
Document document = new Document(pdf);
// 创建第一个段落,并设置段落内容
Paragraph paragraph1 =
new Paragraph("Thank you for reading Ant Brother's blog");
// 设置边框样式和圆角样式
Border border = new SolidBorder(new DeviceRgb(255, 0, 0), 10, .3f);
BorderRadius borderRadius = new BorderRadius(25);
// 段落设置
paragraph1
.setWidth(450)
.setHeight(120)
.setFontSize(30)
.setBorder(border) // 边框
.setBorderRadius(borderRadius) // 圆角
.setBackgroundColor(new DeviceRgb(187, 255, 255));
// 把段落添加到文档里,并关闭文档
document.add(paragraph1);
document.close();
}
七:背景相关样式
关于PDF操作背景的使用方式有许多种,他就像我们学前端一样,如背景图片、背景色、线性渐变等等操作,下面我就简单举几个例子:
(一):普通背景
代码效果:
public static void main(String[] args) throws IOException {
// 创建并初始化一个PDF文档
PdfDocument pdf = new PdfDocument(new PdfWriter("D://示例.pdf"));
// 初始化文档
Document document = new Document(pdf);
// 创建第一个段落,并设置段落内容
Paragraph paragraph1 =
new Paragraph("Thank you for reading Ant Brother's blog");
// 段落设置
paragraph1
.setWidth(450)
.setHeight(120)
.setFontSize(30)
.setBackgroundColor(new DeviceRgb(255, 0, 0), .2f);
// 把段落添加到文档里,并关闭文档
document.add(paragraph1);
document.close();
}
"/* ********************** 补充说明 ********************** */"
设置背景(有如下几种方法):
setBackgroundColor(color)
setBackgroundColor(color, opacity)
setBackgroundColor(color, extraLeft, extraTop, extraRight, extraBottom)
setBackgroundColor(color, opacity, extraLeft, extraTop, extraRight, extraBottom)
参数说明:
color:背景颜色
opacity:透明度;可选值0~1,0代表透明、1代表不透明、.5f代表半透明
extraLeft, extraTop, extraRight, extraBottom:
四个参数分别表示文本框的额外左内边距、上内边距、右内边距和下内边距。
它们用于指定文本框边界与背景颜色边界之间的额外空间,以便在文本框周围留出一定的间距。
这些额外的内边距可以帮助控制文本框的布局和外观。
示例:
setBackgroundColor(new DeviceRgb(255, 0, 0),.2f,40,20,30,40);
(二):图片背景、线性背景
这里的背景其实和CSS的背景基本一样,只是代码的编写方式不同,在了解前端的背景和线性渐变的话,会更快的入手。
补充前端背景:【腾讯文档】背景属性、【腾讯文档】线性渐变 linear-gradient()
代码效果:
点开查看详情:关于图片背景和线性背景代码
public static void main(String[] args) throws IOException {
// 创建并初始化一个PDF文档
PdfDocument pdf = new PdfDocument(new PdfWriter("D://示例.pdf"));
// 初始化文档
Document document = new Document(pdf);
// 创建第一个段落(背景图片)
Paragraph paragraph1 = new Paragraph("Thank you for reading Ant Brother's blog");
paragraph1(paragraph1);
// 创建第二个段落(线性渐变)
Paragraph paragraph2 = new Paragraph("Thank you for reading Ant Brother's blog");
paragraph2(paragraph2);
// 创建第三个段落(使用CSS的线性渐变)
Paragraph paragraph3 = new Paragraph("Thank you for reading Ant Brother's blog");
paragraph3(paragraph3);
// 把段落添加到文档里,并关闭文档
document.add(paragraph1);
document.add(paragraph2);
document.add(paragraph3);
document.close();
}
/***
* 设置第一段内容样式(背景图片)
* @param paragraph 段落
*/
public static void paragraph1(Paragraph paragraph) throws MalformedURLException {
// 创建ImageData对象(图片二进制数组、url方式都行)、并构建成图像
ImageData imageData = ImageDataFactory.create("D:\\images\\pg2.jpg");
// 创建PDF图像对象
PdfImageXObject pdfImageXObject = new PdfImageXObject(imageData);
// 背景图片大小
BackgroundSize bs = new BackgroundSize();
UnitValue uWitch = new UnitValue(UnitValue.POINT, 150);
UnitValue uHeight = new UnitValue(UnitValue.POINT, 32);
bs.setBackgroundSizeToValues(uWitch, uHeight);
// 设置背景排列方式
BackgroundRepeat bgr =
new BackgroundRepeat(BackgroundRepeat.BackgroundRepeatValue.SPACE);
// 构建图片背景,并设置一些其它样式
BackgroundImage build = new BackgroundImage.Builder()
.setImage(pdfImageXObject)
.setBackgroundClip(BackgroundBox.CONTENT_BOX) // 在内容区绘制背景
.setBackgroundOrigin(BackgroundBox.CONTENT_BOX) // 在内容区定位背景
.setBackgroundSize(bs) // 设置背景图片大小
.setBackgroundRepeat(bgr) // 背景排列方式
.build();
// 设置段落样式
paragraph.setWidth(400)
.setHeight(80)
.setBackgroundImage(build)
.setBorder(new SolidBorder(ColorConstants.PINK, 10, .3f));
}
/***
* 设置第二段内容样式(背景-线性渐变)
* @param paragraph 段落
*/
public static void paragraph2(Paragraph paragraph) {
// 创建线性渐变,使用代码的方式,设置颜色并设置渐变方向
AbstractLinearGradientBuilder gradientBuilder =
new StrategyBasedLinearGradientBuilder()
.setGradientDirectionAsCentralRotationAngle(90 * Math.PI / 180)
.addColorStop(new GradientColorStop(ColorConstants.RED.getColorValue()))
.addColorStop(new GradientColorStop(ColorConstants.GREEN.getColorValue()))
.addColorStop(new GradientColorStop(ColorConstants.BLUE.getColorValue()));
// 创建背景的大小
BackgroundSize backgroundSize = new BackgroundSize();
// 创建2个值(百分比)
UnitValue unitValue1 = new UnitValue(UnitValue.PERCENT, 50);
UnitValue unitValue2 = new UnitValue(UnitValue.PERCENT, 50);
backgroundSize.setBackgroundSizeToValues(unitValue1, unitValue2);
// 设置背景定位方式(这就代表居中)
BackgroundPosition bgp = new BackgroundPosition();
bgp.setXShift(new UnitValue(UnitValue.POINT, 50));
bgp.setYShift(new UnitValue(UnitValue.POINT, 20));
// 创建背景样式
BackgroundImage build = new BackgroundImage.Builder()
.setBackgroundSize(backgroundSize) // 背景大小
.setLinearGradientBuilder(gradientBuilder) // 线性渐变
.setBackgroundPosition(bgp) // 背景定位
.setBackgroundBlendMode(BlendMode.HARD_LIGHT)
.build();
// 设置段落样式
paragraph.setWidth(200)
.setHeight(80)
.setBorder(new SolidBorder(10))
.setBackgroundImage(build);
}
/***
* 设置第三段内容样式(背景使用CSS的方式来创建)
* @param paragraph 段落
*/
public static void paragraph3(Paragraph paragraph) {
// 使用CSS的线性渐变
String gradientValue = "linear-gradient(to left top, blue 50%, yellow 50%)";
// 设置渐变线性
StrategyBasedLinearGradientBuilder linearGradientBuilder
= CssGradientUtil.parseCssLinearGradient(gradientValue, 5, 5);
// 设置背景
BackgroundImage build = new BackgroundImage.Builder()
.setLinearGradientBuilder(linearGradientBuilder)
.build();
paragraph.setHeight(60)
.setFontSize(30)
.setBackgroundImage(build)
.setBorder(new SolidBorder(ColorConstants.PINK, 10, .3f));
}
点开查看详情:关于图片背景和线性背景详细说明
主要类:BackgroundImage.Builder
'常用方法:'
setImage(PdfXObject image)
设置背景图片的
setLinearGradientBuilder(AbstractLinearGradientBuilder linearGradientBuilder)
设置线性渐变的
setBackgroundClip(BackgroundBox clip)
setBackgroundOrigin(BackgroundBox origin)
第一个方法是用于指定背景图片绘制区域;
第二个方法是用于指定背景图片定位区域;
具体可选参数如下:
BackgroundBox.BORDER_BOX:边框开始
BackgroundBox.PADDING_BOX:内边框开始
BackgroundBox.CONTENT_BOX:内容区开始
setBackgroundSize(BackgroundSize backgroundSize)
用于指定背景图片的大小。它控制背景图片的尺寸。
setBackgroundRepeat(BackgroundRepeat repeat)
设置图片的排列重复方式。
setBackgroundPosition(BackgroundPosition position)
设置背景的定位方式。
setBackgroundBlendMode(BlendMode blendMode)
'注意事项:背景图片和线性渐变这两个方法不能同时指定,一次背景只能选一个。'
'关于BackgroundSize对象说明:'
创建对象:BackgroundSize bs = new BackgroundSize();
常用方法:
bs.setBackgroundSizeToCover();
表示背景图片尽可能覆盖整个背景区域,可能会被裁剪;
bs.setBackgroundSizeToContain();
表示背景图片尽可能放在背景区域内,保持完整且不会被裁剪。
bs.setBackgroundSizeToValues(u1, u2);
通过设置2个值(宽度、高度)来控制图片;传入UnitValue对象
创建一个50%的值
new UnitValue(UnitValue.PERCENT, 50);
创建一个50磅的值
new UnitValue(UnitValue.POINT , 50);
'关于BackgroundRepeat对象说明:'
创建对象的3种构造器:
BackgroundRepeat()
默认重复铺满整个空间
BackgroundRepeat(repeat)
一起设置X、Y轴的重复排列方式
BackgroundRepeat(xAxisRepeat,yAxisRepeat)
单独设置X轴和Y轴的重复排列方式
常量参数选择(BackgroundRepeat.BackgroundRepeatValue):
NO_REPEAT:背景不会重复,而是以其原始大小显示一次。
REPEAT:背景会重复,将铺满整个可用空间上。
ROUND:
表示背景将拉伸或压缩的舍入值。最初可用空间由模块除以背景的大小,如果结果小于背景大小的一半,
则背景被拉伸,使得当重复时它将占据所有空间,否则背景被压缩以在可用空间中再适合一个背景。
SPACE:
会铺满,第一个和最后一个背景被附加到可用空间的相对边缘,并且白色空间均匀地分布在背景之间。
假如背景就四张图片,则会再四角显示,其它区域空白
'关于BackgroundPosition对象说明:'
创建对象:BackgroundPosition bgp = new BackgroundPosition();
有两种定位方式:
通过关键字设置位置(写两个值,用空格隔开):设置居中
bgp.setPositionX(BackgroundPosition.PositionX.CENTER);
bgp.setPositionY(BackgroundPosition.PositionY.CENTER);
PositionX可选值:LEFT,RIGHT,CENTER
PositionY可选值:TOP,BOTTOM,CENTER
通过长度指定坐标位置:设置居中
UnitValue xShift = new UnitValue(UnitValue.POINT, 50);
UnitValue yShift = new UnitValue(UnitValue.POINT, 50);
bgp.setXShift(xShift);
bgp.setYShift(yShift);
说明:
UnitValue.POINT为磅单位
UnitValue.PERCENT为百分比单位
注意:若是渐变效果的图片定位貌似只能使用UnitValue(UnitValue.POINT, 50)方式;具体没太深入研究
'关于线性渐变的渐变方向(可以使用常量值或者使用角度的方式):'
使用常量的渐变方向:
具体的常量都在这个常量类里:StrategyBasedLinearGradientBuilder.GradientStrategy
TO_BOTTOM、TO_BOTTOM_LEFT、TO_BOTTOM_RIGHT、
TO_LEFT、TO_RIGHT、TO_TOP、TO_TOP_LEFT、TO_TOP_RIGHT
使用角度的渐变方向:
需要调用 setGradientDirectionAsCentralRotationAngle(double radians) 方法设置
旋转角度 = 旋转角度 * 圆周率 / 180度
八:定位(子绝父相)
这玩意就和前端一样,有相对定位,也有绝对定位,下面我将对这两种定位来个简单的示例:
'设置元素的绝对定位信息(定位从页的左下角开始):'
setFixedPosition(float left, float bottom, float width)
setFixedPosition(float left, float bottom, UnitValue width)
setFixedPosition(int pageNumber, float left, float bottom, float width)
setFixedPosition(int pageNumber, float left, float bottom, UnitValue width)
参数说明:
left:元素左边缘距离页面左边缘的距离。(相当于X)
bottom:元素底部距离页面底部的距离。(相当于Y)
width:元素的宽度,可以是磅(pt)、百分比。
pageNumber:元素所在的页码,页码从1开始计数。
注意:
1:把整个页面看做成一个坐标系,坐标系的开始是从左下角开始(0,0)。
'设置元素的相对定位信息(定位找到上一级元素的左上角开始):'
setRelativePosition(float left, float top, float right, float bottom)
上下左右四边的定位值
(一):绝对定位
代码效果:
public static void main(String[] args) throws IOException {
// 创建并初始化一个PDF文档
PdfDocument pdf = new PdfDocument(new PdfWriter("E://基本示例.pdf"));
pdf.addNewPage(new PageSize(500, 200));
// 初始化文档
Document document = new Document(pdf);
// 创建第一个段落,并设置段落内容
Paragraph paragraph1 = new Paragraph("感谢您阅读蚂蚁小哥的博客!");
// 获取页面的大小
Rectangle pageSize = pdf.getPage(1).getPageSize();
// 需要将元素定位到页面的中间(计算参数)
float elHeight = 50;
float elWidth = 200;
float left = pageSize.getWidth() / 2 - elWidth / 2;
float bottom = pageSize.getHeight() / 2 - elHeight / 2;
// 设置样式
paragraph1
.setFontSize(14) // 字体大小
.setHeight(50) // 元素高
// 设置绝对定位
.setFixedPosition(1, left, bottom, elWidth)
// 字体颜色、字体、背景颜色设置
.setFontColor(new DeviceRgb(255, 0, 0), .8f)
.setFont(PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H"))
.setBackgroundColor(new DeviceRgb(187, 255, 255));
// 把段落添加到文档里,并关闭文档
document.add(paragraph1);
document.close();
}
(二):相对定位
代码效果:
public static void main(String[] args) throws IOException {
// 创建并初始化一个PDF文档
PdfDocument pdf = new PdfDocument(new PdfWriter("E://基本示例.pdf"));
pdf.addNewPage(new PageSize(600, 600));
// 初始化文档
Document document = new Document(pdf);
// 创建盒子,子元素
Div dvZi = new Div();
// 设置样式
dvZi
.setWidth(50) // 元素款
.setHeight(50) // 元素高
.setRelativePosition(50, 20, 0, 0) // 相对定位
.setBackgroundColor(new DeviceRgb(187, 255, 255));
// 创建盒子,父元素
Div dvFu = new Div();
// 把子元素装进去
dvFu.add(dvZi);
dvFu.setHeight(200)
.setFixedPosition(1, 100, 50, 200) // 绝对定位
.setBorder(new SolidBorder(2));
// 把盒子添加到文档里,并关闭文档
document.add(dvFu);
document.close();
}
九:文档块级元素
块级元素挺重要的,我们把iTextPDF当成前端来看,它是有块级元素的,如后面将介绍和使用到的块级元素如:段落(Paragraph)、列表和列表元素(List、ListItem)、表格和单元格(Table、Cell)、块级容器(Div) 、布局容器(FLexContainer)、分割线(LineSeparator)、多列布局(MulticolContainer)。
必要的API快捷跳转:
ElementPropertyContainer、BlockElement、Paragraph、List、ListItem、Div、Table、Cell、LineSeparator
可能使用的API快捷跳转:
文本(Text) 、样式(Style)
(一):父类(BlockElement)
BlockElement是一个块级元素的父类,它是一种用于构建PDF文档的元素类型。块级元素通常用于定义文档的整体结构,比如段落、标题、列表、表格等。通过使用BlockElement,可以创建各种不同类型的块级元素,并将它们添加到PDF文档中,以实现丰富多样的排版效果。例如,你可以使用BlockElement来创建包含文本内容的段落、标题,也可以创建表格、列表等复杂的结构。
还要注意的是,这个父类及其父级的父级定义了大部分排版的样式类,如内边距、外边距、宽高、边框、文本样式、背景等等。
点开查看详情:关于BlockElement的常用方法
下面是常用方法:
setWidth(width)
setHeight(height)
setMaxWidth(maxWidth)
setMinWidth(minWidth)
setMaxHeight(maxHeight)
setMinHeight(minHeight)
上面六个是设置宽高,最大或者最小宽高
若想设置盒子宽高为100%,则可以使用如下方式;
UnitValue.createPercentValue(100)
setMargin(commonMargin)
设置外边距,四边都设置一样的值。
setMargins(marginTop,marginRight,marginBottom,marginLeft)
设置外边距,和前端一样,分别是上右下左四个参数,也可以单独设置如下:
setMarginTop、setMarginLeft、setMarginRight、setMarginBottom
setPadding(commonPadding)
设置内边距,四边都设置一样的值。
setPaddings(paddingTop,paddingRight,paddingBottom,paddingLeft)
设置内边距,和前端一样,分别是上右下左四个参数,也可以单独设置如下:
setPaddingTop、setPaddingLeft、setPaddingRight、setPaddingBottom
setVerticalAlignment(verticalAlignment)
设置元素的垂直对齐方式,通过VerticalAlignment获取常量:
TOP(顶部对齐):元素的顶部与包含区域的顶部对齐。
MIDDLE(居中对齐):元素在包含区域内垂直居中对齐。
BOTTOM(底部对齐):元素的底部与包含区域的底部对齐。
setRotationAngle(angleInRadians)
设置元素旋转角度;旋转角度 = 旋转角度 * 圆周率 / 180度
setKeepWithNext(boolean keepWithNext)
用于设置当前块级元素与下一个元素是否保持在一起的方法。
true:当前元素将尽量与下一个元素放在同一页上,避免分页。
主要就是保证两个块级元素在一个页中,不想出现,这个div在第一页,而另外一个div在下一页。
setKeepTogether(boolean keepTogether)
用于设置当前块级元素里面的内容是否要求在同一页上显示。
true:文档布局会尝试在同一页上完整显示该块级元素的内容,避免在页面分割块级元素的内容。
保证一个块级元素在当前页显示不全时,会整个元素在下一页显示,不会一般在第一页,一般在第二页。
有的方法接收的数值有两种写法:
UnitValue写法:
它可以设置百分比、磅两种单位的值,比如:
new UnitValue(UnitValue.POINT, 50) :50pt
new UnitValue(UnitValue.PERCENT, 50) :50%
UnitValue.createPercentValue(100) :100%
float写法:
它就是一个float值,单位是磅(pt)
点开查看详情:关于ElementPropertyContainer的常用方法,它是BlockElement父类
'元素透明的:'
setOpacity(Float opacity):给定元素的不透明度。
'设置水平/垂直对齐方式:'
setTextAlignment(TextAlignment alignment):水平对齐
setHorizontalAlignment(HorizontalAlignment horizontalAlignment):垂直对齐
'设置描边信息:'
setStrokeColor(Color strokeColor):设置当前元素的描边颜色
setStrokeWidth(float strokeWidth):设置当前元素的描边宽度。
getStrokeColor():获取当前元素的描边颜色。
getStrokeWidth():获取当前元素的描边宽度。
'设置字体及文本相关样式(关于【文本字体样式】一章有详细介绍):'
setBold():
setFont(PdfFont font)
setFontColor(Color fontColor)
setFontFamily(String... fontFamilyNames)
setFontKerning(FontKerning fontKerning)
setFontScript(Character.UnicodeScript script)
setFontSize(float fontSize)
setUnderline()
setWordSpacing(float wordSpacing)
setCharacterSpacing(float charSpacing)
setTextRenderingMode(int textRenderingMode)
setBaseDirection(BaseDirection baseDirection)
setHyphenation(HyphenationConfig hyphenationConfig)
setSplitCharacters(ISplitCharacters splitCharacters)
'设置背景及背景图片相关样式(关于【背景相关样式】一章有详细介绍):'
setBackgroundColor(color)
setBackgroundImage(BackgroundImage image)
'设置边框及圆角相关样式(关于【边框圆角样式】一章有详细介绍)'
setBorder(Border border)
setBorderRadius(BorderRadius borderRadius)
'设置定位(关于【定位(子绝父相)】一章有详细介绍)'
setFixedPosition(float left, float bottom, float width)
setFixedPosition(float left, float bottom, UnitValue width)
setFixedPosition(int pageNumber, float left, float bottom, float width)
setFixedPosition(int pageNumber, float left, float bottom, UnitValue width)
setRelativePosition(float left, float top, float right, float bottom)
'其它方法:'
deleteOwnProperty(int property):删除此实体的own属性。
getDefaultProperty(int property):从此实体获取默认属性。
getProperty(int property):从此实体获取属性。
getOwnProperty(int property):从此实体获取自己的属性。
setProperty(int property, Object value):设置此实体的属性。
hasOwnProperty(int property):检查此实体是否具有指定的属性
hasProperty(int property):检查此实体是否具有指定的属性。
setDestination(String destination):设置将此元素绘制到内容中时将创建的目标名称。
(二):段落(Paragraph)
段落对象其实就和前端的p标签一样,它是块级元素且内部可以塞入各种元素,把它当前端看即可。
点开查看详情:关于段落(Paragraph)标签特有的常用方法
构建段落对象构造器:
Paragraph()、Paragraph(Text text)、Paragraph(String text)
构建对象可以传入字符串文本或者Text对象的文本,或者是空,后面通过add()方法加入。
常用方法:
add(String text)
添加一个字符串文本到段落元素中
add(IBlockElement element)
添加其它块元素到当前的元素中
add(ILeafElement element)
添加其它元素如:Text、Link、SvgImage、Tab、Image类型的元素
addAll(List elements)
向此段落添加布局元素列表。
addTabStops(TabStop... tabStops)
将未指定数量的制表符元素作为属性添加到此段落中。
addTabStops(List是<TabStop> tabStops)
将制表符元素列表作为属性添加到此段落中。
setFirstLineIndent(float indent)
设置段落第一行的缩进值。
setFixedLeading(float leading)
使用 Leading.FIXED 策略设置前导值。
setMultipliedLeading(float leading)
使用 Leading.MULTIPLIED 策略设置前导值。
代码效果:
public static void main(String[] args) throws IOException {
// 图片路径并加载到Image对象中
String imgPathA = "E:\\images\\2.png";
String imgPathB = "E:\\images\\3.png";
Image imageA = new Image(ImageDataFactory.create(imgPathA));
// 设置图片宽(pt)、设置图片宽(pt)
imageA.setWidth(120);
imageA.setHeight(80);
Image imageB = new Image(ImageDataFactory.create(imgPathB));
imageB.setWidth(120);
imageB.setHeight(80);
// 创建并初始化一个PDF文档
PdfDocument pdf = new PdfDocument(new PdfWriter("E://基本示例.pdf"));
// 初始化文档
Document document = new Document(pdf);
// 创建第一个段落并添加内容
Paragraph paragraph = new Paragraph();
paragraph.add("This is a beautiful picture!");
paragraph.add("\n"); // 在此处强制换行
paragraph.add(imageA);
paragraph.add("\n");
// 这里我单独设置了个Text传入进去
Text text = new Text("This is a Not good-looking picture!")
.setItalic() // 倾斜
.setBackgroundColor(new DeviceRgb(255, 0, 0));
paragraph.add(text);
paragraph.add("\n");
paragraph.add(imageB);
// 设置样式
paragraph.setHeight(210)
.setFirstLineIndent(100) // 设置缩进 120pt(120/12),文字默认12,缩减10个字符
.setTextAlignment(TextAlignment.CENTER) // 居中
.setBorder(new SolidBorder(2)) // 边框
.setBackgroundColor(new DeviceRgb(187, 255, 255));
// 把段落添加到文档里,并关闭文档
document.add(paragraph);
document.close();
}
(三):列表(List、ListItem)
其实列表在前端就相当于ul>li这些标签,但是在这里它以对象的方式来体现,下面详细说明:
点击查看详情:关于列表和列表元素(List、ListItem)标签的特有常用方法
######################### 列表(List)对象基本说明:#########################
添加列表子元素:
add(String text):在列表底部添加一个列表元素,传入String的列表元素。
add(ListItem listItem):在列表底部添加一个列表元素,传入ListItem的列表元素。
列表子元素的开头符号:
setListSymbol(Text text):设置要使用的列表符号(可以是字体符号)
setListSymbol(Image image):设置要使用的列表符号(可以是图片符号)
setListSymbol(ListNumberingType listNumberingType):自带的列表符号
关于自带的ListNumberingType枚举:
DECIMAL: 十进制数字,如 1, 2, 3, ...
DECIMAL_LEADING_ZERO: 带前导零的十进制数字,如 01, 02, 03, ...
ROMAN_LOWER: 小写罗马数字,如 i, ii, iii, ...
ROMAN_UPPER: 大写罗马数字,如 I, II, III, ...
ENGLISH_LOWER: 小写英文字母,如 a, b, c, ...
ENGLISH_UPPER: 大写英文字母,如 A, B, C, ...
GREEK_LOWER: 小写希腊字母,如 α, β, γ, ...
GREEK_UPPER: 大写希腊字母,如 Α, Β, Γ, ...
ZAPF_DINGBATS_1: 字体中的特殊字符,范围在 [172; 181](如:❶、➀、➔、➚、➦...)
ZAPF_DINGBATS_2: 字体中的特殊字符,范围在 [182; 191](如:❶、➀、➔、➚、➦...)
ZAPF_DINGBATS_3: 字体中的特殊字符,范围在 [192; 201](如:❶、➀、➔、➚、➦...)
ZAPF_DINGBATS_4: 字体中的特殊字符,范围在 [202; 221](如:❶、➀、➔、➚、➦...)
列表缩进:
getSymbolIndent():获取ListItem符号的缩进偏移量。
setSymbolIndent(float symbolIndent):设置ListItem符号的缩进偏移量。
列表子元素索引位置:
setItemStartIndex(int start):自定义列表中第一个项目的索引。
设置应添加在ListItem符号之后的一段文本。
getPostSymbolText():获取在ListItem符号之后添加的文本段。
getPreSymbolText():获取在ListItem符号之前添加的文本段。
setPreSymbolText(String preSymbolText):设置在ListItem符号之前添加的文本段。
setPostSymbolText(String postSymbolText):设置在ListItem符号之后添加的文本段。
比如列表是这样的
1. C++真的难学吗
加上setPreSymbolText("■")是这样的:
■1. C++真的难学吗
加上setPostSymbolText(":")是这样的:
1: C++真的难学吗
其它:
setListSymbolAlignment(ListSymbolAlignment alignment):包含列表符号的对齐属性的专用枚举。
######################### 列表(ListItem)对象基本说明:#########################
我们可以设置setListSymbol()方法;也可以为他们设置其它如背景、颜色、等样式,具体可以查看文档
代码效果:
public static void main(String[] args) throws IOException {
// 创建并初始化一个PDF文档,
PdfDocument pdfDocument = new PdfDocument(new PdfWriter("E://基本示例.pdf"));
// 中文字体对象
PdfFont font = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H");
// 创建文档
Document document = new Document(pdfDocument);
// 一个普通的段落
Paragraph paragraph1 = new Paragraph("新闻点击量排行榜:").setFont(font);
// 创建列表A
List listA = new List();
listA.setFont(font);
listA.add("34项重罪指控成立 特朗普成美国史上首位被判有罪的前总统");
listA.add("谁还不是个宝宝呢!儿童节做个快乐的超龄儿童");
listA.add(new ListItem("郑州:宋陵千年石像见证又一个丰收季"));
listA.add(new ListItem("大熊猫“金喜”“茱萸”正式与西班牙公众见面"));
// 一个普通的段落
Paragraph paragraph2 = new Paragraph("列表的其它应用:").setFont(font);
List listB = new List().setFont(font)
.setMarginLeft(12 * 2) // 列表左边边距设置2个字符的位置
//.setListSymbol("■") // 自定义了个图片(设置的图标,字体不支持也不行)
.setListSymbol(ListNumberingType.DECIMAL) // 使用系统自带的枚举符号
.setSymbolIndent(10) // 设置列表里的子元素距离符号的间距
.setItemStartIndex(5) // 设置元素的索引从5开始
.setListSymbolAlignment(ListSymbolAlignment.RIGHT);
listB.add("34项重罪指控成立 特朗普成美国史上首位被判有罪的前总统");
listB.add("谁还不是个宝宝呢!儿童节做个快乐的超龄儿童");
// 单独设置个 ListItem(正常不会这样,最多加个颜色)
ListItem listItem = new ListItem("郑州:宋陵千年石像见证又一个丰收季")
.setListSymbol("■:");
listItem.setFontColor(new DeviceRgb(255, 0, 0));
listItem.setBackgroundColor(ColorConstants.GREEN);
listB.add(listItem);
listB.add(new ListItem("大熊猫“金喜”“茱萸”正式与西班牙公众见面"));
// 添加元素到文档中
document.add(paragraph1);
document.add(listA);
document.add(paragraph2);
document.add(listB);
document.close();
}
(四):块级容器(Div)
大家把Div元素当前端的盒子来用就行,它也可以用来盒子套盒子。
代码效果:
public static void main(String[] args) throws IOException {
// 创建并初始化一个PDF文档
Document document = new Document(new PdfDocument(new PdfWriter("D://基本示例.pdf")));
// 构建一个盒子容器
Div divA = new Div();
divA
.setWidth(300) // 设置元素宽
.setHeight(100) // 设置元素高
.setBorder(new DashedBorder(2)) // 设置边框
.setBorderRadius(new BorderRadius(10)) // 设置圆角
.setVerticalAlignment(VerticalAlignment.MIDDLE) // 元素内的内容垂直居中
.setTextAlignment(TextAlignment.CENTER) // 文本元素水平居中(可以继承到子类)
.setHorizontalAlignment(HorizontalAlignment.CENTER); // 设置div元素水平居中
// 构建一个段落
Paragraph paragraph = new Paragraph("Hello World!");
paragraph
.setWidth(150) // 宽
.setHeight(50) // 高
.setBorder(new SolidBorder(2)) // 边框
.setVerticalAlignment(VerticalAlignment.MIDDLE) // 段落内的内容垂直居中
.setHorizontalAlignment(HorizontalAlignment.CENTER); // 段落元素水平居中
// 段落内的文本居中
divA.add(paragraph);
// 把元素添加到文档里,并关闭文档
document.add(divA);
document.close();
}
"/* ********************** 补充说明 ********************** */"
关于DIV元素中特有的方法:
setFillAvailableArea(boolean fillArea)
若当前Div元素未设置高,那么它会占据当前页面可用区域中的所有剩余空间。
setFillAvailableAreaOnSplit(boolean fillAreaOnSplit)
定义分区是否应占用可用区域中的所有剩余空间,以防该区域已被分割,
并且它是该区域分割部分中的最后一个元素。
(五):分割线(LineSeparator)
点开查看详情:关于分割线(LineSeparator)的基本使用
LineSeparator是一个分隔符对象,就是画分割线的,构建它需要传入具体的分割线对象:
'构造对象:'
LineSeparator(ILineDrawer lineDrawer)
说明:创建分割线对象时需要传入具体的ILineDrawer子类分割线线类型。
'ILineDrawer实现子类:'
SolidLine(实线)、DashedLine(虚线)、DottedLine(点虚线)
'关于这几种分割线对象共有的方法:'
getColor():获取分割线的颜色
getLineWidth():获取线的粗细值。
setColor(Color color):设置分割线颜色
setLineWidth(float lineWidth):设置线的粗细,数值越大线越粗。
draw(PdfCanvas canvas, Rectangle drawArea):使用画布画指定位置的线(在Canvas章节细说)
'DashedLine对象特有方法:'
getGap()、setGap(float gap)
获取和设置点虚线中间的点距离。
代码效果:
public static void main(String[] args) throws IOException {
// 创建并初始化一个PDF文档
Document document = new Document(new PdfDocument(new PdfWriter("D://基本示例.pdf")));
document.add(new Paragraph("SolidLine:"));
document.add(new LineSeparator(new SolidLine(3)));
document.add(new Paragraph("DashedLine:"));
document.add(new LineSeparator(new DashedLine(3)));
document.add(new Paragraph("DottedLine:"));
document.add(new LineSeparator(new DottedLine(3)));
// 设置其它样式
DottedLine dottedLine = new DottedLine(3);
dottedLine.setColor(ColorConstants.RED);
dottedLine.setGap(10);
LineSeparator lineSeparator = new LineSeparator(dottedLine);
// 以块级元素设置分割线
lineSeparator.setWidth(200).setMarginTop(20)
.setHorizontalAlignment(HorizontalAlignment.CENTER);
// 把元素添加到文档里,并关闭文档
document.add(lineSeparator);
document.close();
}
(六):表格(Table、Cell)
表格是个好东西,在这里的表格我们可以用来生成一些文档表格、合同等需要排版的内容,还有就是表格可以用来布局哟,它就像以前我们用前端的表格布局一样。
点击查看详情:关于表格(Table、Cell)对象的特有方法使用
'######################### 表格(Table)对象基本说明:#########################'
构造函数:
Table(int numColumns)
构建一个指定列的表格。
举例(构建一个3列的表格):
Table table = new Table(3)
Table(float[] pointColumnWidths)
构建一个指定磅宽的单元格的表格,若单元格内容超出则宽度会自动增加。
举例(构建一个3列的表格,分别是50磅、100磅、150磅):
float[] floats = {50f, 100f, 150f};
Table table = new Table(floats);
Table(UnitValue[] columnWidths)
构建一个指定百分比宽的单元格的表格,若单元格内容超出则宽度会自动增加。
举例(构建一个3列的表格,分别是20%、30%、50%;按照表格内容来设置百分比):
UnitValue lie1 = new UnitValue(UnitValue.PERCENT, 20);
UnitValue lie2 = new UnitValue(UnitValue.PERCENT, 30);
UnitValue lie3 = new UnitValue(UnitValue.PERCENT, 50);
UnitValue[] col = {lie1,lie2,lie3};
Table table = new Table(col);
Table(int numColumns, boolean largeTable)
Table(float[] columnWidths, boolean largeTable)
Table(UnitValue[] columnWidths, boolean largeTable)
上面这3个构造函数和之前3个一样,只不过多个largeTable参数,表格会占满页面宽度100%。
添加单元格元素:
addCell(Cell cell)
addCell(Image image)
addCell(String content)
addCell(BlockElement blockElement)
可以添加各种类型的元素,如单元格Cell、图片Image、字符串String、块级元素。
添加单元格标题:
addHeaderCell(Image image)
addHeaderCell(String content)
addHeaderCell(Cell headerCell)
addHeaderCell(BlockElement blockElement)
可以设置如上类型,具体和添加表格内容元素传入的元素是一样的。
添加单元格页脚:
addFooterCell(Image image)
addFooterCell(Cell footerCell)
addFooterCell(String content)
addFooterCell(BlockElement blockElement)
可以设置如上类型,具体和添加表格内容元素传入的元素是一样的。
设置表格标题:
setCaption(Div caption)
setCaption(Div caption, CaptionSide side)
设置表格标题,其中side是设置标题的位置
CaptionSide有两个选值,分别是:CaptionSide.TOP、CaptionSide.BOTTOM
设置单元格垂直和水平的间距:
setVerticalBorderSpacing(float spacing)
setHorizontalBorderSpacing(float spacing)
设置表格布局方式:
setAutoLayout():设置自动布局。
setFixedLayout():设置固定布局。
设置表格宽度为百分百:
useAllAvailableWidth()
表格会占用当前页宽度的100%(Property.WIDTH = 100%。)
开始新行:
startNewRow()
在指定table.addCell(xx)的中间设置,可以让下一个单元格将添加到下一行的开头。
常用获取方法:
getNumberOfRows()
返回行数(这里只返回使用addCell或startNewRow的行数)
getNumberOfColumns()
返回列数
getCaption()
获取表的标题
getCell(int row, int column)
返回由其位置指定的单元格
getColumnWidth(int column)
返回指定列的列宽
getFooter()
获取表的页脚
getHeader()
获取表的标头
getLastRowBottomBorder()
获取(当前)最后一行的下边框的标记属性
其它设置:
setBorderCollapse(BorderCollapsePropertyValue collapsePropertyValue)
设置边框折叠的类型
setExtendBottomRowOnSplit(boolean isExtended)
定义是否应扩展表以占用可用区域中的所有剩余空间,以防该区域已被分割;
比如说当前表格跨页了,若当前到页的最后面放不下一行列时,会自动延申上一列的高度,
放不下的列则在新的页显示。
setExtendBottomRow(boolean isExtended)
定义是否应扩展表以占用可用区域中剩余的所有空间,以防它是该区域中的最后一个元素。
setSkipFirstHeader(boolean skipFirstHeader)
当为true时则不显示表格开头的标题行
setSkipLastFooter(boolean skipLastFooter)
当为true时则不显示表格结尾的页脚行
isSkipFirstHeader()
告诉您是否需要跳过第一个标题(例如,如果标题显示“从上一页继续”)。
isSkipLastFooter()
告诉您是否需要跳过最后一个页脚(例如,如果页脚显示“在下一页继续”)
setDocument(Document document)
设置此元素绑定到的文档。
complete()
指示所有所需的内容都已添加到此大型元素中,并且不会添加更多内容。
createRendererSubTree()
在当前表元素中创建具有根的呈现器子树。
flush()
将新添加的内容写入文档。
flushContent()
刷新刚刚添加到文档中的内容。
getAccessibilityProperties()
获取辅助功能属性。
getRenderer()
获取此元素的表呈现器。
getRowGroups()
返回所有行组的列表。
isComplete()
检查元素是否已标记为完成。
'######################### 表格(Table)对象基本说明:#########################'
构造方法:
Cell()
创建单元格。
Cell(int rowspan, int colspan)
创建一个单元格,该单元格在表中占用自定义数量的单元格空间。
单元格元素添加:
add(Image element)
add(IBlockElement element)
有两种方式,分别是插入图片和块级元素
其它方法:
clone(boolean includeContent)
克隆单元格及其位置、属性以及(可选)其内容。
getAccessibilityProperties()
获取辅助功能属性。
getCol()
获取单元格所在的位置。
getColspan()
获取单元格的colspan。
getDefaultProperty(int property)
从此实体获取默认属性。
getRenderer()
获取此元素的单元格呈现器。
getRow()
获取单元格所在的位置。
getRowspan()
获取单元格的rowspan。
1:表格基本使用
这个案例的表格是设置的占用页面宽度的100%,若没设置占用页面全部宽的话,它会按照内容来划分列的百分比宽度。
代码效果:
public static void main(String[] args) throws IOException {
// 创建并初始化一个PDF文档
Document document = new Document(new PdfDocument(new PdfWriter("D://基本示例.pdf")));
// 构建表格(lie1~3代表表格列的宽度百分比,此时正好有3列)
UnitValue lie1 = new UnitValue(UnitValue.PERCENT, 20);
UnitValue lie2 = new UnitValue(UnitValue.PERCENT, 30);
UnitValue lie3 = new UnitValue(UnitValue.PERCENT, 50);
UnitValue[] col = {lie1, lie2, lie3};
Table table = new Table(col);
table.useAllAvailableWidth(); // 表格占用当前页面的所有宽度
// 添加表头
table.addHeaderCell(new Cell().add(new Paragraph("header1")));
table.addHeaderCell(new Cell().add(new Paragraph("header2")));
table.addHeaderCell(new Cell().add(new Paragraph("header3")));
// 添加数据行
table.addCell(new Cell().add(new Paragraph("1")));
table.addCell(new Cell().add(new Paragraph("2")));
table.addCell(new Cell().add(new Paragraph("3")));
table.addCell(new Cell().add(new Paragraph("4")));
table.addCell(new Cell().add(new Paragraph("5")));
table.addCell(new Cell().add(new Paragraph("6")));
// 把元素添加到文档里,并关闭文档
document.add(table);
document.close();
}
2:添加元素的几种方式
代码效果:
public static void main(String[] args) throws IOException {
// 创建并初始化一个PDF文档
Document document = new Document(new PdfDocument(new PdfWriter("D://基本示例.pdf")));
// 构建表格(lie1~3代表表格列的宽度百分比,此时正好有3列)
UnitValue lie1 = new UnitValue(UnitValue.PERCENT, 20);
UnitValue lie2 = new UnitValue(UnitValue.PERCENT, 30);
UnitValue lie3 = new UnitValue(UnitValue.PERCENT, 50);
UnitValue[] col = {lie1, lie2, lie3};
Table table = new Table(col);
table.useAllAvailableWidth(); // 表格占用当前页面的所有宽度
// 添加表头
table.addHeaderCell(new Cell().add(new Paragraph("header1")));
table.addHeaderCell(new Cell().add(new Paragraph("header2")));
table.addHeaderCell(new Cell().add(new Paragraph("header3")));
// 添加数据行
// 表格添加第一格元素(使用Cell方式)
table.addCell(new Cell().add(new Paragraph("1")));
// 表格添加第二格元素(使用Image格式)
// 创建ImageData对象(图片二进制数组、url方式都行)、并构建成图像
ImageData imageData = ImageDataFactory.create("D:\\images\\pg2.jpg");
Image image = new Image(imageData);
image.setWidth(70);
image.setHeight(40);
table.addCell(image);
// 表格添加第三格元素(使用String格式)
table.addCell("String Type");
// 表格添加第四格元素(使用BlockElement格式)
Div div = new Div()
.setBorder(new SolidBorder(1))
.setWidth(70).setHeight(40)
.setTextAlignment(TextAlignment.CENTER)
.setVerticalAlignment(VerticalAlignment.MIDDLE)
.setHorizontalAlignment(HorizontalAlignment.CENTER)
.setBackgroundColor(new DeviceRgb(255, 25, 14), .5f)
.add(new Paragraph("Hello"));
table.addCell(div);
// 单元格添加第五格元素(使用Image格式)
Image image1 = new Image(ImageDataFactory.create("D:\\images\\tupian.png"));
image1.setWidth(40);
image1.setHeight(60);
Cell cell = new Cell().add(image1).setPaddingLeft(20);
table.addCell(cell);
// 单元格添加第六格元素(使用BlockElement格式)
table.addCell(new Cell().add(new Paragraph("6")));
// 把元素添加到文档里,并关闭文档
document.add(table);
document.close();
}
3:合并单元格
代码效果:
点开查看详情:关于合并单元格详细代码
public static void main(String[] args) throws IOException {
// 创建并初始化一个PDF文档
Document document = new Document(new PdfDocument(new PdfWriter("E://基本示例.pdf")));
// 一定要记住我创建的是5列的表格
// 构建一个使用百分比创建的表格,并占满当前页所有宽
Table table = new Table(UnitValue.createPercentArray(5)).useAllAvailableWidth();
// 构建表格标题
Div div = new Div().add(new Paragraph("标题:演示单元格合并"))
.setBorder(new DashedBorder(1))
.setTextAlignment(TextAlignment.CENTER)
.setFont(PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H"))
.setFontColor(DeviceRgb.RED);
table.setCaption(div, CaptionSide.TOP);
// 添加表头
table.addHeaderCell(new Cell().add(new Paragraph("header1")));
table.addHeaderCell(new Cell().add(new Paragraph("header2")));
table.addHeaderCell(new Cell().add(new Paragraph("header3")));
table.addHeaderCell(new Cell().add(new Paragraph("header4")));
table.addHeaderCell(new Cell().add(new Paragraph("header5")));
// 添加页脚(故意放中间,其实这个页脚是一定会在最后面的)
table.addFooterCell(new Cell(1,5).add(new Paragraph("footer1")));
// 创建单元格(单元格高以当前行最高的单元格高为准)
// # 在1行上合并了2个单元格
Cell top1 = new Cell(1, 2);
top1.addStyle(new Style().setBackgroundColor(ColorConstants.RED, .2f)
.setHeight(30));
table.addCell(top1);
// # 在1行上合并了3个单元格
Cell top2 = new Cell(1, 3).add(new Paragraph("Top2"));
top2.setBackgroundColor(ColorConstants.YELLOW);
table.addCell(top2);
// # 在2行上合并1个单元格
Cell sn = new Cell(2, 1).add(new Paragraph("S/N"));
sn.setBackgroundColor(ColorConstants.YELLOW);
table.addCell(sn);
// # 在1行上合并3个单元格
Cell name = new Cell(1, 2).add(new Paragraph("Name"));
name.setBackgroundColor(ColorConstants.CYAN);
table.addCell(name);
// # 在2行上合并2个单元格
Cell age = new Cell(2, 2).add(new Paragraph("Age"));
age.setBackgroundColor(ColorConstants.GRAY);
table.addCell(age);
// # 把空出来的单元格补上,看的出效果
table.addCell(new Cell().add(new Paragraph("sup1")).setBorder(Border.NO_BORDER));
table.addCell(new Cell().add(new Paragraph("sup2")).setBorder(Border.NO_BORDER));
// # 在3行上合并4个单元格,并在里面设置一个盒子(一般用于布局)
Div div1 = new Div();
div1.add(new Paragraph("Hello World!"))
.setWidth(120)
.setHeight(40)
.setHorizontalAlignment(HorizontalAlignment.CENTER) // 左右居中
.setVerticalAlignment(VerticalAlignment.MIDDLE) // 文字上下居中
.setTextAlignment(TextAlignment.CENTER) // 文字左右居中
.setBackgroundColor(new DeviceRgb(25, 255, 200));
Cell firstname = new Cell(3, 4).add(div1);
firstname.setVerticalAlignment(VerticalAlignment.MIDDLE); // 单元格内容上下居中
table.addCell(firstname);
// # 把空出来的单元格补上,看的出效果,要不然合并的多行单元格高就和1行高一样
table.addCell(new Cell().add(new Paragraph("sup1")).setBorder(Border.NO_BORDER));
table.addCell(new Cell().add(new Paragraph("sup2")).setBorder(Border.NO_BORDER));
table.addCell(new Cell().add(new Paragraph("sup3")).setBorder(Border.NO_BORDER));
// 其它合并
table.addCell(new Cell(1, 2).add(new Paragraph("fo1"))
.setBackgroundColor(ColorConstants.GRAY));
table.startNewRow(); // 强行换一行新的单元行
table.addCell(new Cell(1, 3).add(new Paragraph("fo2"))
.setBackgroundColor(ColorConstants.GRAY));
table.startNewRow(); // 强行换一行新的单元行
table.addCell(new Cell(1, 4).add(new Paragraph("fo3"))
.setBackgroundColor(ColorConstants.GRAY));
// 把元素添加到文档里,并关闭文档
document.add(table);
document.close();
}
4:表格添加外边框
代码效果:
public static void main(String[] args) throws IOException {
// 创建并初始化一个PDF文档
Document document = new Document(new PdfDocument(new PdfWriter("E://基本示例.pdf")));
// 构建一个使用百分比创建的表格,并占满当前页所有宽
Table table = new Table(UnitValue.createPercentArray(5)).useAllAvailableWidth();
// 添加单元格
for (int aw = 0; aw < 10; aw++) {
table.addCell(new Cell().add(new Paragraph("hi" + aw))
.setBorder(Border.NO_BORDER));
}
table.setBorder(new DoubleBorder(2));
// 把元素添加到文档里,并关闭文档
document.add(table);
document.close();
}
5:案例学生证
代码效果:
public static void main(String[] args) throws IOException {
// 创建并初始化一个PDF文档
Document document = new Document(new PdfDocument(new PdfWriter("E://基本示例.pdf")));
// 创建线性渐变,使用代码的方式,设置颜色并设置渐变方向
AbstractLinearGradientBuilder gradientBuilder =
new StrategyBasedLinearGradientBuilder()
.setGradientDirectionAsCentralRotationAngle(60 * Math.PI / 180)
.addColorStop(new GradientColorStop(new DeviceRgb(51, 153, 255).getColorValue()))
.addColorStop(new GradientColorStop(new DeviceRgb(255, 250, 250).getColorValue()));
BackgroundImage build = new BackgroundImage.Builder()
.setLinearGradientBuilder(gradientBuilder) // 线性渐变
.setBackgroundBlendMode(BlendMode.HARD_LIGHT)
.build();
// 构建一个只有两列的表格并设置常用样式
float[] col = {90, 110};
Table table = new Table(col)
.setWidth(300)
.setHeight(170)
.setFixedLayout() // 表格固定布局
.setFont(PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H"))
.setBackgroundImage(build);
// 设置标题
Paragraph hd = new Paragraph("哈芙加里墩职业技术学院")
.setBold()
.setFontSize(18)
.setMarginRight(30)
.setTextAlignment(TextAlignment.RIGHT)
.setFontColor(new DeviceRgb(102, 0, 0));
table.addHeaderCell(new Cell(1, 2).add(hd).setBorder(Border.NO_BORDER));
// 设置左边图片头像
Image image = new Image(ImageDataFactory.create("E:\\images\\a\\tx.jpeg"));
image.setWidth(80).setHeight(100)
.setHorizontalAlignment(HorizontalAlignment.CENTER); // 行居中
Cell cell = new Cell(4, 1) // 合并单元格
.add(image)
.setBorder(Border.NO_BORDER)
.setVerticalAlignment(VerticalAlignment.MIDDLE);
table.addCell(cell);
// 设置基本信息
// 学生证字段
Paragraph p1 = new Paragraph("学 生 证")
.setBold()
.setFontSize(26)
.setPaddings(-5, 0, 0, 20)
.setStrokeWidth(3f) // 设置字体元素的轮廓大小
.setStrokeColor(ColorConstants.BLUE) // 设置字体元素的轮廓颜色
.setFontColor(ColorConstants.BLUE, .5f);
Cell cell1 = new Cell().add(p1)
.setBorder(Border.NO_BORDER)
.setVerticalAlignment(VerticalAlignment.MIDDLE);
table.addCell(cell1);
// 学生证右边信息
// ## 设置一些通用的Style样式
Style style = new Style().setBold()
.setPaddingLeft(20).setPaddingTop(-5)
.setFontColor(new DeviceRgb(51, 100, 255));
// 姓名
Paragraph xm = new Paragraph("姓 名:张三丰").addStyle(style);
table.addCell(new Cell().add(xm).setBorder(Border.NO_BORDER));
// 班级
Paragraph bj = new Paragraph("班 级:初二四班").addStyle(style);
table.addCell(new Cell().add(bj).setBorder(Border.NO_BORDER));
// 学号
Paragraph bh = new Paragraph("编 号:No20240901042").addStyle(style);
table.addCell(new Cell().add(bh).setBorder(Border.NO_BORDER));
// 把元素添加到文档里,并关闭文档
document.add(table);
document.close();
}
6:案例成绩表
此案例涉及到了画布的知识点,因为涉及到复杂表格和复杂样式基本上都是使用画布完成。本篇未讲述关于画布的知识,推荐阅读一下:Java处理PDF文档【下】( 全新 iText 8.0 画布、条形码、渲染器 )
代码效果:
public static void main(String[] args) throws IOException {
// 创建并初始化一个PDF文档并构建文档
PdfDocument pdfDocument = new PdfDocument(new PdfWriter("E://基本示例.pdf"));
Document document = new Document(pdfDocument);
// 中文显示字体
PdfFont font = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H");
// 构建一个使用指定百分比创建的表格;一定要记住我创建的是4列的表格
UnitValue lie1 = new UnitValue(UnitValue.PERCENT, 20);
UnitValue lie2 = new UnitValue(UnitValue.PERCENT, 20);
UnitValue lie3 = new UnitValue(UnitValue.PERCENT, 20);
UnitValue lie4 = new UnitValue(UnitValue.PERCENT, 20);
UnitValue lie5 = new UnitValue(UnitValue.PERCENT, 20);
Table table = new Table(new UnitValue[]{lie1, lie2, lie3, lie4, lie5})
.setWidth(400).setBorder(new SolidBorder(ColorConstants.GRAY, 1));
// ============================== 构建表格表头 ==============================
Div div = new Div().add(new Paragraph("季度考试成绩表"))
.setHeight(40).setBold().setFont(font).setFontSize(20)
.setBorder(new SolidBorder(ColorConstants.GRAY, 1))
.setBorderBottom(Border.NO_BORDER)
.setTextAlignment(TextAlignment.CENTER)
.setFontColor(DeviceRgb.RED);
table.setCaption(div, CaptionSide.TOP);
// ============================== 构建表格标题 ==============================
// 设置标题样式(语文、数学、英语)
Style styleHeader = new Style()
.setBold().setWidth(50).setHeight(20).setFont(font)
.setTextAlignment(TextAlignment.CENTER)
.setHorizontalAlignment(HorizontalAlignment.CENTER)
.setBorderRadius(new BorderRadius(10))
.setFontColor(ColorConstants.WHITE)
.setPaddingBottom(2)
.setBackgroundColor(new DeviceRgb(0, 128, 128));
// 设置单元格其它样式Cell
Style styleCell = new Style()
.setHeight(30)
.setVerticalAlignment(VerticalAlignment.MIDDLE)
.setBorder(new SolidBorder(ColorConstants.GRAY, 1));
// 单元格对象
Cell cellH1 = new Cell(1, 2);
Cell cellH2 = new Cell().addStyle(styleCell);
Cell cellH3 = new Cell().addStyle(styleCell);
Cell cellH4 = new Cell().addStyle(styleCell);
// 单元格里的内容信息
Paragraph ph2 = new Paragraph("语 文").addStyle(styleHeader);
Paragraph ph3 = new Paragraph("数 学").addStyle(styleHeader);
Paragraph ph4 = new Paragraph("英 语").addStyle(styleHeader);
// 内容信息添加到单元格里,并将单元格添加到表格中
// 标题的第一列不用设置任何东西,它需要使用渲染器渲染出指定内容到单元格里,
cellH1.setNextRenderer(setHeaderCellRenderer(cellH1)); // 设置渲染器
table.addHeaderCell(cellH1);
table.addHeaderCell(cellH2.add(ph2));
table.addHeaderCell(cellH3.add(ph3));
table.addHeaderCell(cellH4.add(ph4));
// ============================== 构建表格内容 ==============================
Paragraph paragraph = new Paragraph("上半年")
.setFont(font).setTextAlignment(TextAlignment.CENTER)
.setVerticalAlignment(VerticalAlignment.MIDDLE);
table.addCell(new Cell(2, 1).add(paragraph));
table.addCell(new Cell().add(new Paragraph("一季度").setFont(font)));
table.addCell(new Cell().add(new Paragraph("26")));
table.addCell(new Cell().add(new Paragraph("33")));
table.addCell(new Cell().add(new Paragraph("45")));
table.addCell(new Cell().add(new Paragraph("二季度").setFont(font)));
table.addCell(new Cell().add(new Paragraph("26")));
table.addCell(new Cell().add(new Paragraph("33")));
table.addCell(new Cell().add(new Paragraph("45")));
// 后面的就不写了,主要看标题部分,以及重点的标题斜线部分,后面的都是重复的不写了
// 关于内容的部分,有些样式丑的可以借助画布拓展,比如“上半年”,完全可以使用画布把文字树立着
// 把元素添加到文档里,并关闭文档
document.add(table);
document.close();
}
/***
* 根据现有的单元格绘制指定样式的单元格
* @param cell 单元格
* @return CellRenderer渲染器
*/
public static CellRenderer setHeaderCellRenderer(Cell cell) throws IOException {
// 中文显示字体
PdfFont font = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H");
// 构建单元格渲染器
return new CellRenderer(cell) {
/***
* 这里我就重写drawBorder,不重写draw了,因为我现在只是想单单画个线条
* @param drawContext 绘制上下文对象
*/
@Override
public void drawBorder(DrawContext drawContext) {
// 获取当前元素的位置信息和大小信息
Rectangle rect = getOccupiedAreaBBox();
// 获取画布PdfCanvas画布,这种画布常用于图形绘画
PdfCanvas pdfCanvas = drawContext.getCanvas();
// 对这个元素绘画一个斜线,左上角到右下角
pdfCanvas.saveState()
.setStrokeColor(ColorConstants.GRAY)
.moveTo(rect.getLeft(), rect.getTop())
.lineTo(rect.getRight(), rect.getBottom())
.fillStroke()
.stroke().restoreState();
// 在画布上写文字
Canvas canvas = new Canvas(pdfCanvas, rect);
// 基本文字样式
canvas.setFont(font).setFontSize(14).setBold().setFontColor(ColorConstants.GRAY)
// 写文字
.showTextAligned("科 目", rect.getRight() - 20,
rect.getTop() - 5, TextAlignment.RIGHT,
VerticalAlignment.TOP, 0)
.showTextAligned("时 间", rect.getLeft() + 20,
rect.getBottom() + 5, TextAlignment.LEFT);
// 关闭画布
canvas.close();
// 别忘了哟
super.drawBorder(drawContext);
}
};
}