PDF(Portable Document Format的简称,意为“便携式文档格式”)
名称 |
描述 |
优缺点 |
---|---|---|
iText |
iText是一个能够快速产生PDF文件的java类库。iText的java类对于那些要产生包含文本,表格,图形的只读文档是很有用的。它的类库尤其与java Servlet有很好的给合。使用iText与PDF能够使你正确的控制Servlet的输出。 |
Api使用简单,官网提供的资料很多 许可协议:APGL 简单说:就是商业用途要收费 |
PDF Box |
PDFBox是一个Apache开源的x项目。可以操作PDF文档的Java PDF类库。它可以创建一个新PDF文档,操作现有PDF文档并提取文档中的内容。 |
文档少,表格不支持,api相对比较底层Apache License v2.0 免费使用,基本没有限制 |
FOP |
FOP是由James Tauber发起的一个开源项目,原先的版本是利用xsl-fo将xml文件转换成pdf文件。但最新的版本它可以将xml文件转换成pdf,mif,pcl,txt等多种格式以及直接输出到打印机,并且支持使用SVG描述图形 |
本人没使用过,不很清楚
|
为什么使用Pdfbox?
1)使用没有限制
2)基本的pdf操作都满足
3)学习啊,学习啊
要使用一个Java库,当然是先查看官网文档。
比较悲剧的是,pdfbox官网的资料很少,仅仅有功能特性的介绍。但是有一些使用案例:可以github上下载查看(https://github.com/apache/pdfbox)
依赖Jar(有这一个就够了哈,当然你也可以按需导入你需要的,pdfbox(核心)、fontbox、pdfbox-tools、pdfbox-debugger、xmpbox、preflight)
org.apache.pdfbox
pdfbox-app
2.0.18
输出一行文本(其他的基本操作可以参考: https://iowiki.com/pdfbox/pdfbox_quick_guide.html)
public void createPdf() throws IOException {
PDDocument document = new PDDocument();
PDPage page = new PDPage(PDRectangle.A4);
document.addPage(page);
try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
contentStream.beginText();
contentStream.newLineAtOffset(200, 700);
contentStream.setFont(PDType1Font.TIMES_ROMAN, 12.5f);
contentStream.showText("Hello PdfBox");
contentStream.endText();
}
document.save("target/pdfboxtest.pdf");
document.close();
}
介绍
平面直接坐标系,其中横轴为X轴,纵轴为Y轴。简称直角坐标系。分为第一象限,第二象限,第三象限,第四象限。从右上角开始数起,逆时针方向算起。
x的正方向是水平相右,y的正方向是垂直相上(没有旋转的页面)
PdfBox的坐标系统,也就是你能看到的部分在【第一象限】视图,x值从左到右增加,y从下到上增加。
因此,如果您使用new PDPage()或new PDPage(PDPage.PAGE_SIZE_*)创建页面,则坐标系的原点将从页面的左下角开始。
坐标:旋转、原点移动
http://www.voidcn.com/article/p-pfgyxuyl-btn.html
PDRectangle mediaBox = page.getMediaBox();
PDRectangle cropBox = page.getCropBox();
System.out.println("页面的高度:" + mediaBox.getHeight());
System.out.println("页面的宽度:" + mediaBox.getWidth());
//字体的高度
float fontCapHeight = font.getFontDescriptor().getCapHeight() / 1000f * fontSize;
//文字的宽度
float textWidth = font.getStringWidth(text);
PDDocument document = new PDDocument();
PDPage page = new PDPage(PDRectangle.A4);
document.addPage(page);
try (PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true, true)) {
float x = 30f;
float y = page.getMediaBox().getUpperRightY() - 30f;
//3行4列的表格
int rows = 3;
int cols = 4;
//行高
float rowHeight = 15.0f;
float colWidth = 40.0f;
contentStream.saveGraphicsState();
//线条颜色
contentStream.setStrokingColor(Color.RED);
//线条宽度
contentStream.setLineWidth(1.0f);
//drawTable
for (int row = 0; row <= rows; row++) {
float xStart = x;
float yStart = y - row * rowHeight;
float xEnd = xStart + cols * colWidth;
float yEnd = yStart;
contentStream.moveTo(xStart, yStart);
contentStream.lineTo(xEnd, yEnd);
}
for (int col = 0; col <= cols; col++) {
float xStart = x + col * colWidth;
float yStart = y;
float xEnd = xStart;
float yEnd = yStart - rows * rowHeight;
contentStream.moveTo(xStart, yStart);
contentStream.lineTo(xEnd, yEnd);
}
contentStream.stroke();
contentStream.restoreGraphicsState();
}
document.save("target/pdfboxtest.pdf");
document.close();
github: https://github.com/vandeseer/easytable
//引入easytable Jar
com.github.vandeseer
easytable
0.6.0
//3行4列的表格
PDDocument document = new PDDocument();
PDPage page = new PDPage(PDRectangle.A4);
document.addPage(page);
try (PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true, true)) {
PDFont font = PDType1Font.TIMES_ROMAN;
float fontSize = 12.5f;
Settings settings = Settings.builder()
.font(font)
.fontSize((int) fontSize)
.horizontalAlignment(HorizontalAlignment.CENTER)
.verticalAlignment(VerticalAlignment.MIDDLE)
.backgroundColor(Color.WHITE)
.wordBreak(true)
.build();
// Build the table
//3行4列的表格
int rows = 3;
int cols = 4;
float colWidth = 40.0f;
Table.TableBuilder tableBuilder = Table.builder().borderColor(Color.RED).wordBreak(true);
for (int col = 0; col < cols; col++) {
tableBuilder.addColumnOfWidth(colWidth);
}
for (int row = 0; row < rows; row++) {
Row.RowBuilder rowBuilder = Row.builder().wordBreak(true);
for (int col = 0; col < cols; col++) {
String colData = "text:" + col;
rowBuilder.add(TextCell.builder().settings(settings).text(colData).borderWidth(0.5f).build());
}
tableBuilder.addRow(rowBuilder.build());
}
Table myTable = tableBuilder.build();
float tableHeight = myTable.getHeight();
System.out.println("表格高度:" + tableHeight);
// Set up the drawer
float x = 30f;
float y = page.getMediaBox().getUpperRightY() - 30f;
TableDrawer tableDrawer = TableDrawer.builder()
.contentStream(contentStream)
.startX(x)
.startY(y)
.table(myTable)
.build();
// And go for it!
tableDrawer.draw();
contentStream.restoreGraphicsState();
}
document.save("target/pdfboxtest.pdf");
document.close();
字体下载网站: http://font.chinaz.com/
思源字体:思源黑体是Adobe与Google宣布推出的一款开源字体,https://www.google.com/get/noto/help/cjk/
NotoSansCJKtc字体:Google 开发的思源黑体,noto是谷歌取的名字,sans思源,cjk表示中文、日文、韩文,tc是中文繁体
PdfBox加载字体
PDType1Font.TIMES_ROMAN
PDDocument document = new PDDocument();
InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(fontPath);
//第一种
PDFont font = PDType0Font.load(document, inputStream)
//第二种
TrueTypeFont ttfFont = new TTFParser().parse(inputStream);
PDFont font = PDType0Font.load(document, ttfFont, true)
PDDocument document = new PDDocument();
InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(fontPath);
//只能这样加载
OpenTypeFont otfFont = new OTFParser(false, true).parse(inputStream);
PDFont font = PDType0Font.load(this.getDocument(), otfFont, false)
https://www.ojit.com/article/1798712
eg. 你好,Hello PdfBox,クーポン券手数料合計
PDDocument document = new PDDocument();
PDPage page = new PDPage(PDRectangle.A4);
document.addPage(page);
List fontList = new ArrayList<>();
fontList.add(PDType1Font.TIMES_ROMAN);
try (InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("fonts/NotoSansCJKtc-Regular.ttf")) {
fontList.add(PDType0Font.load(document, inputStream));
}
String text = "你好,Hello PdfBox,クーポン券手数料合計";
try (PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true, true)) {
int len = text.length();
contentStream.beginText();
contentStream.newLineAtOffset(200f, 200f);
for (int i = 0; i < len; i++) {
String s = String.valueOf(text.charAt(i));
System.out.println(s);
PDFont useFont = null;
for (PDFont font : fontList) {
try {
font.encode(s);
useFont = font;
} catch (Exception e) {
//ignore
continue;
}
}
contentStream.setFont(useFont, 12f);
contentStream.showText(s);
}
contentStream.endText();
}
document.save("target/pdfboxtest.pdf");
document.close();
https://zhuanlan.zhihu.com/p/53421567
https://my.oschina.net/u/1240964/blog/671178
https://github.com/mkl-public/testarea-pdfbox2
https://github.com/apache/pdfbox/blob/trunk/examples/src/main/java/org/apache/pdfbox/examples/util/PrintTextLocations.java
https://github.com/mkl-public/testarea-pdfbox2/blob/master/src/test/java/mkl/testarea/pdfbox2/content/AddTextWithDynamicFonts.java
https://zhuanlan.zhihu.com/p/53421567
https://github.com/dongdongdeng/iPDFBox
添加水印
public static void printWatermark(PDPage page, PDPageContentStream cs, List fontList, String text) {
try {
PDFont useFont = null;
for (PDFont font : fontList) {
try {
font.encode(text);
useFont = font;
break;
} catch (Exception e) {
continue;
}
}
if (useFont == null) {
logger.error("没有可以使用发字体");
useFont = PDType1Font.TIMES_ROMAN;
text = "Invalid Invalid Invalid";
}
PDRectangle mediaBox = page.getMediaBox();
float fontSize = 30.0f;
PDExtendedGraphicsState r0 = new PDExtendedGraphicsState();
// 透明度
r0.setNonStrokingAlphaConstant(0.1f);
r0.setAlphaSourceFlag(true);
cs.saveGraphicsState();
cs.setGraphicsStateParameters(r0);
cs.setNonStrokingColor(Color.RED);
float startPoint = -100f;
float step = 250f;
for (float i = startPoint; i < mediaBox.getWidth(); i += step) {
for (float j = startPoint; j < mediaBox.getHeight(); j += step) {
cs.beginText();
cs.setFont(useFont, fontSize);
// 获取旋转实例
cs.setTextMatrix(Matrix.getRotateInstance(Math.toRadians(30f), i, j));
cs.showText(text);
cs.endText();
}
}
cs.restoreGraphicsState();
} catch (Exception e) {
logger.error("添加水印异常", e);
}
}