Java使用itext7生成PDF文件(三)
编辑本文深入讨论了Java中处理PDF的实用技巧,重点介绍了使用iText 7创建PDF文档的方法,以及运用Apache PDFBox将PDF文件转换成图片的技术,同时特别关注了中文字体显示问题的解决方案。
iText 7:生成 PDF
iText 7 是一个用于创建和操作 PDF 文档的开源 Java 库。它提供了丰富的功能来定制 PDF 的内容和格式。
先看下生成的pdf 和png最终效果
设置项目
-
在项目中添加 iText 7 依赖项。如果您使用 Maven,可以添加以下依赖到
pom.xml
: -
这里我们使用当前最新版
<!-- https://github.com/itext/itext7 --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itext7-core</artifactId> <version>8.0.2</version> <type>pom</type> </dependency>
配置中文字体
1.把字体放到resources/fonts下
2. 获取字体方法
/**
* 获取自定义字体
*
* @return 自定义字体
*/
public static PdfFont getChineseFont() {
try {
// 字体文件的路径
String fontPath = "/home/wxy/Desktop/STSong-Light.ttf";
// PdfDemo02 为当前类
String fontPath2 = PdfDemo02.class.getResource("/fonts/classicSongSiJian.ttf").getPath();
// 使用文件路径创建字体 并指定嵌入策略
return PdfFontFactory.createFont(fontPath2, "Identity-H",
PdfFontFactory.EmbeddingStrategy.PREFER_EMBEDDED);
} catch (IOException e) {
e.printStackTrace();
System.out.println("获取中文字体失败!");
return null;
}
}
字体下载: https://wangxy.lanzouw.com/b02rgxskh
EmbeddingStrategy 枚举是 iText 7 中 PdfFontFactory.createFont 方法的一部分,在这个枚举中,FORCE_EMBEDDED 和 PREFER_EMBEDDED 是最常用的选项,用于指定字体是否应该被嵌入到 PDF 文档中。
我们这里使用PREFER_EMBEDDED 嵌入字体,否则下文pdf生成图片时可能会中文乱码。
如果不考虑转图片,可以选择不嵌入字体,嵌入可能会稍微增大pdf文件。
绘制PDF
整体布局使用一个Table来布局,条码使绝对定位方式来确定位置
绝对定位时要注意:itextpdf的确定页面上的具体坐标是通过坐标来确定的。 它们的坐标轴是这样的:以左下角为原点的xy坐标轴。
完整绘制方法代码
/**
* @param document
*/
public static void drawBaseInfo(Document document) throws MalformedURLException {
// 黑色虚线边框
DeviceRgb black = new DeviceRgb(0, 0, 0);
SolidBorder solidBorder = new SolidBorder(black, 0.5F);
Table table = new Table(5);
table.useAllAvailableWidth();
table.setTextAlignment(TextAlignment.CENTER);
table.setFont(getChineseFont());
table.setFontSize(12);
table.setPadding(0);
// 条码
PdfDocument pdfDocument = document.getPdfDocument();
PdfPage page = pdfDocument.addNewPage();
Barcode128 barcode128 = new Barcode128(pdfDocument);
barcode128.setCode("072201130001EF");
barcode128.setCodeType(Barcode128.CODE128);
barcode128.fitWidth(180);
PdfFormXObject object =
barcode128.createFormXObject(ColorConstants.BLACK, ColorConstants.BLACK, pdfDocument);
float width = object.getWidth();
float height = object.getHeight();
float x = 200;
float y = 550;
PdfCanvas canvas = new PdfCanvas(page);
canvas.saveState();
canvas.setFillColor(ColorConstants.WHITE);
canvas.rectangle(x, y, width, height);
canvas.fill();
canvas.restoreState();
canvas.addXObjectAt(object, x, y);
// 顶部
Cell cell1 =
new Cell(1, 8).add(
new Paragraph("客运站结算单"));
// cell1.setBold();
cell1.setFontSize(14);
cell1.setBorder(Border.NO_BORDER);
table.addCell(cell1);
table.setMarginTop(20);
Cell cell2_1 =
new Cell(1, 5).add(
new Paragraph("无三品签字: "));
cell2_1.setTextAlignment(TextAlignment.RIGHT);
cell2_1.setBorder(Border.NO_BORDER);
cell2_1.setPaddingRight(80);
table.addCell(cell2_1);
Cell cell3_1 =
new Cell(1, 1).add(
new Paragraph("乘车站: "));
cell3_1.setTextAlignment(TextAlignment.RIGHT);
cell3_1.setBorder(Border.NO_BORDER);
table.addCell(cell3_1);
Cell cell3_1_v =
new Cell(1, 2).add(
new Paragraph("中心站"));
cell3_1_v.setTextAlignment(TextAlignment.LEFT);
cell3_1_v.setBorder(Border.NO_BORDER);
table.addCell(cell3_1_v);
Cell cell3_2 =
new Cell(1, 1).add(
new Paragraph("车次: "));
cell3_2.setTextAlignment(TextAlignment.RIGHT);
cell3_2.setBorder(Border.NO_BORDER);
table.addCell(cell3_2);
Cell cell3_2_v =
new Cell(1, 1).add(
new Paragraph("4038"));
cell3_2_v.setTextAlignment(TextAlignment.LEFT);
cell3_2_v.setBorder(Border.NO_BORDER);
table.addCell(cell3_2_v);
Cell cell4_1 =
new Cell(1, 1).add(
new Paragraph("发车时间: "));
cell4_1.setTextAlignment(TextAlignment.RIGHT);
cell4_1.setBorder(Border.NO_BORDER);
table.addCell(cell4_1);
Cell cell4_1_v =
new Cell(1, 2).add(
new Paragraph("2023-12-11 16:00"));
cell4_1_v.setTextAlignment(TextAlignment.LEFT);
cell4_1_v.setBorder(Border.NO_BORDER);
table.addCell(cell4_1_v);
Cell cell4_2 =
new Cell(1, 1).add(
new Paragraph("线路: "));
cell4_2.setTextAlignment(TextAlignment.RIGHT);
cell4_2.setBorder(Border.NO_BORDER);
table.addCell(cell4_2);
Cell cell4_2_v =
new Cell(1, 1).add(
new Paragraph("卫士"));
cell4_2_v.setTextAlignment(TextAlignment.LEFT);
cell4_2_v.setBorder(Border.NO_BORDER);
table.addCell(cell4_2_v);
Cell cell5_1 =
new Cell(1, 1).add(
new Paragraph("公司: "));
cell5_1.setTextAlignment(TextAlignment.RIGHT);
cell5_1.setBorder(Border.NO_BORDER);
table.addCell(cell5_1);
Cell cell5_1_v =
new Cell(1, 2).add(
new Paragraph("xxx公司"));
cell5_1_v.setTextAlignment(TextAlignment.LEFT);
cell5_1_v.setBorder(Border.NO_BORDER);
table.addCell(cell5_1_v);
Cell cell5_2 =
new Cell(1, 1).add(
new Paragraph("车辆: "));
cell5_2.setTextAlignment(TextAlignment.RIGHT);
cell5_2.setBorder(Border.NO_BORDER);
table.addCell(cell5_2);
Cell cell5_2_v =
new Cell(1, 1).add(
new Paragraph("豫A99999"));
cell5_2_v.setTextAlignment(TextAlignment.LEFT);
cell5_2_v.setBorder(Border.NO_BORDER);
table.addCell(cell5_2_v);
Cell cell6_1 =
new Cell(1, 1).add(
new Paragraph("单据号: "));
cell6_1.setTextAlignment(TextAlignment.RIGHT);
cell6_1.setBorder(Border.NO_BORDER);
table.addCell(cell6_1);
Cell cell6_1_v =
new Cell(1, 2).add(
new Paragraph("E36666"));
cell6_1_v.setTextAlignment(TextAlignment.LEFT);
cell6_1_v.setBorder(Border.NO_BORDER);
table.addCell(cell6_1_v);
Cell cell6_2 =
new Cell(1, 1).add(
new Paragraph("核定人数: "));
cell6_2.setTextAlignment(TextAlignment.RIGHT);
cell6_2.setBorder(Border.NO_BORDER);
table.addCell(cell6_2);
Cell cell6_2_v =
new Cell(1, 1).add(
new Paragraph("9999"));
cell6_2_v.setTextAlignment(TextAlignment.LEFT);
cell6_2_v.setBorder(Border.NO_BORDER);
table.addCell(cell6_2_v);
Cell cell7_1 =
new Cell(1, 1).add(
new Paragraph("内外: "));
cell7_1.setTextAlignment(TextAlignment.RIGHT);
cell7_1.setBorder(Border.NO_BORDER);
table.addCell(cell7_1);
Cell cell7_1_v =
new Cell(1, 2).add(
new Paragraph("内结"));
cell7_1_v.setTextAlignment(TextAlignment.LEFT);
cell7_1_v.setBorder(Border.NO_BORDER);
table.addCell(cell7_1_v);
Cell cell7_2 =
new Cell(1, 1).add(
new Paragraph("类别: "));
cell7_2.setTextAlignment(TextAlignment.RIGHT);
cell7_2.setBorder(Border.NO_BORDER);
table.addCell(cell7_2);
Cell cell7_2_v =
new Cell(1, 1).add(
new Paragraph("正常检票"));
cell7_2_v.setTextAlignment(TextAlignment.LEFT);
cell7_2_v.setBorder(Border.NO_BORDER);
table.addCell(cell7_2_v);
// 第8行
List<String> titleList =
Arrays.asList("到站", "票价", "全价", "优惠票", "售票站");
for (int i = 0; i < 5; i++) {
Cell cell =
new Cell(1, 1).add(new Paragraph(titleList.get(i)));
cell.setBorder(solidBorder);
table.addCell(cell);
}
// 模拟数据列表
ArrayList<Map> dataList = new ArrayList<>();
for (int i = 0; i < 6; i++) {
HashMap<String, String> map = new HashMap<>();
map.put("到站", "某某");
map.put("票价", "13");
map.put("全价", "1");
map.put("优惠票", "1");
map.put("售票站", "34");
dataList.add(map);
}
// 渲染数据
dataList.forEach(item -> {
titleList.forEach(title -> {
String value = String.valueOf(item.get(title));
Cell cell =
new Cell(1, 1).add(new Paragraph(value));
cell.setBorder(solidBorder).setFontColor(ColorConstants.RED);
table.addCell(cell);
});
});
Cell cell9_1 = new Cell(1, 1).add(
new Paragraph("总人数"));
table.addCell(cell9_1);
Cell cell9_2 = new Cell(1, 4).add(
new Paragraph("20"));
table.addCell(cell9_2);
Cell cell10_1 = new Cell(1, 1).add(
new Paragraph("结算金额"));
table.addCell(cell10_1);
Cell cell10_2 = new Cell(1, 4).add(
new Paragraph("¥204.99"));
table.addCell(cell10_2);
Cell cell11_1 = new Cell(1, 1).add(
new Paragraph(" "));
table.addCell(cell11_1);
Cell cell11_2 = new Cell(1, 4).add(
new Paragraph("xxxxxx"));
table.addCell(cell11_2);
Cell cell12_1 = new Cell(1, 2).add(
new Paragraph("检票员: "+"808-xxx"));
cell12_1.setBorder(Border.NO_BORDER);
cell12_1.setTextAlignment(TextAlignment.LEFT);
table.addCell(cell12_1);
Cell cell12_2 = new Cell(1, 3).add(
new Paragraph("打印时间: "+"2023-12-12 12:00:00"));
cell12_2.setTextAlignment(TextAlignment.RIGHT);
cell12_2.setBorder(Border.NO_BORDER);
table.addCell(cell12_2);
document.add(table);
}
Apache PDFBox:PDF 转图片
Apache PDFBox 是另一个开源的 Java 库,用于处理 PDF 文件。它可以用于将 PDF 页面转换为图像。
设置项目
-
添加 Apache PDFBox 依赖项,我们这里也使用当前最新版:
<!-- https://github.com/apache/pdfbox --> <dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>pdfbox</artifactId> <version>3.0.1</version> </dependency>
转换为图片
完整代码
public static void pdf2Image(String PdfFilePath, String dstImgFolder, int dpi) {
File file = new File(PdfFilePath);
try (PDDocument pdDocument = Loader.loadPDF(new File(PdfFilePath))) {
int dot = file.getName().lastIndexOf('.');
String imagePDFName = file.getName().substring(0, dot); // 获取图片文件名
PDFRenderer renderer = new PDFRenderer(pdDocument);
/* dpi越大转换后越清晰,相对转换速度越慢 */
int pages = 1;
StringBuffer imgFilePath = null;
for (int i = 0; i < pages; i++) {
String imgFilePathPrefix = dstImgFolder + File.separator + imagePDFName;
imgFilePath = new StringBuffer();
imgFilePath.append(imgFilePathPrefix);
imgFilePath.append(".png");
File dstFile = new File(imgFilePath.toString());
BufferedImage image = renderer.renderImageWithDPI(i, dpi);
ImageIO.write(image, "png", dstFile);
}
System.out.println("PDF文档转PNG图片成功!");
} catch (IOException e) {
e.printStackTrace();
}
}
如果pdf中文正常,转图片时图片中文乱码,可以把pdf字体策略修改为强制 EmbeddingStrategy.FORCE_EMBEDDED
运行测试
public static void main(String[] args) throws IOException {
//首先你需要一个writer对象
PdfWriter writer = new PdfWriter("/home/wxy/Desktop/test.pdf");
//需要一个pdf的对象来操作pdf
PdfDocument pdf = new PdfDocument(writer);
//需要一个document的对象来操作数据 指定为A4大小
try (Document document = new Document(pdf, PageSize.A5);) {
drawBaseInfo(document);
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
pdf2Image("/home/wxy/Desktop/test.pdf", "/home/wxy/Desktop/", 120);
}
结语
结合使用 iText 7 和 Apache PDFBox,您可以轻松地在 Java 应用程序中生成和操作 PDF 文件。通过适当地处理中文字体,您可以确保 PDF 文档在不同环境下都能正确显示中文内容。
这只是一个简单的介绍。iText 7 和 Apache PDFBox 都提供了许多高级功能,可以用于更复杂的 PDF 处理任务。探索这些功能,您可以创建更加丰富和动态的文档。
相关文章
- 8
- 0
-
分享