好久没有更新过博客了,近期收到了一次匿名打赏和一次麦子学院的邀请,感觉还是非常有成就感的。本来是打算自己写点笔记,记录一下心境的地方,没想到还是有小小的帮助到别人,个人还是非常开心的。
这次的问题是制作pdf报表中遇到的,以前曾经也做过一些pdf报表,目前比较常见的方式主要有这样几种:
- 使用Flying Sauser结合itext将html转换成pdf,缺点比较明显,第一是Flying Sauser对html的要求非常严格,所以制作html模板的时候是非常耗时费力的,而且效率相对也比较低。
- 使用Adobe Acrobat,装好之后用Acrobat从一个word,excel或者pdf中转换一个pdf模板,直接写一个简单的word再生成一个pdf表单,之后编辑文本域的名字属性等,根据名字在Java中导入。这样可以很方便的实现pdf填空效率也比较高,但是缺点也是有的,对于去动态插入一些表格会相对比较麻烦。
- 第三就是直接使用itext来实现了,灵活效率也比较高,但是就是开发会比较麻烦。
为了照顾道项目中的灵活性,所以我打算将所有要用到的一些格式和组件进行封装,以方便调整和复用。其中比较麻烦的一点就是需要在pdf中插入统计图,类似于echarts的统计图形。jfreechats是JAVA上比较常用的一套统计图工具,但是图形实在是有点丑,为了满足和与页面echart的效果相似的要求,我决定用Graphics2D来实现绘图,制作成图片导入pdf。
但是之后无意中发现itext提供绘制矢量图的api,但是中文文档太少了,我这里简单介绍一下。
import com.itextpdf.awt.PdfGraphics2D;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfTemplate;
import com.itextpdf.text.pdf.PdfWriter;
import java.awt.Graphics2D;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class LargeTemplate {
public static final String DEST = "results/graphics2d/large_template.pdf";
public static void main(String[] args) throws IOException, DocumentException {
File file = new File(DEST);
file.getParentFile().mkdirs();
new LargeTemplate().createPdf(DEST);
}
public void createPdf(String dest) throws IOException, DocumentException {
float width = 602;
float height = 15872;
float maxHeight = 5000;
Document document = new Document(new Rectangle(width, maxHeight));
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(DEST));
document.open();
PdfContentByte canvas = writer.getDirectContent();
PdfTemplate template = canvas.createTemplate(width, height); //绘制图形模板
Graphics2D g2d = new PdfGraphics2D(template, width, height); //绘图接口,继承自Graphics2D
for (int x = 10; x < width; x += 100) {
for (int y = 10; y < height; y += 100) {
g2d.drawString(String.format("(%s,%s)", x, y), x, y);
}
}
g2d.dispose();
int pages = ((int)height / (int)maxHeight) + 1;
for (int p = 0; p < pages; ) {
p++;
canvas.addTemplate(template, 0, (p * maxHeight) - height);
document.newPage();
}
document.close();
}
}
所以其实是非常简单的,只需要实例化一个PdfGraphics2D,之后操作就见Graphics2D的api文档了,Graphics2D的文档还是比较好找的。图形的是绘制在PdfTemplate上的,这个就相当于一个图形框,图形在页面的位置就由该图形框来确定。PdfContentByte是相当于一个浮在整个pdf上面的一个透明图层,一个上层的元素容器。
我实现了一个绘制雷达图的api,效果见下图:
绘制在pdf内部的一个矢量图形,放大不会失真,效果还是非常不错的,之后打算用空余时间实现一些比较漂亮的常见统计图,当做自己的一个小开源项目吧~