需求需要发送业务排名的钉钉消息,排名需要有一定的格式,又因为是动态生成,所以涉及到了HTML转图片的功能。目前调研下来Java有三种比较靠谱的方式
- Java内置的
JEditorPane 结合 Graphics2D 渲染图片
html2image 三方库渲染图片
FlyingSaucer 三方库渲染图片
本文就上面三种做测试比较。
结论
FlyingSaucer库的Graphics2DRenderer方式渲染效果最好,Java2DRenderer不支持背景图片。
html2image 设置的宽度一直不生效,效果中规中矩。
内置JEditorPane 渲染效果最差。
测试用HTML代码
测试代码(这里主要关注表格的渲染) htm2img.html:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"></meta> <meta name="viewport" content="width=device-width, initial-scale=1.0"></meta> <style> body { background-image: url('https://img.alicdn.com/imgextra/i4/O1CN0122Ph6S1FOVpfMvLxY_!!6000000000477-0-tps-850-360.jpg'); } table { margin: 50px auto; border-collapse: collapse; width: 80%; } table, th, td { border: 1px solid rgb(235, 8, 8); } th, td { padding: 10px; text-align: center; width: 80px; } th { background-color: #e9f40d; } h1 { text-align: center; } </style> </head> <body > <h1>人员得分项目排名</h1> <table> <thead> <tr> <th>姓名</th> <th>项目1</th> <th>项目2</th> <th>项目3</th> </tr> </thead> <tbody> <tr> <td>Alice⭐</td> <td>95</td> <td>88</td> <td>75</td> </tr> <tr> <td>Bob<img src="https://img.alicdn.com/imgextra/i4/O1CN01g1Du7X1I5gOV2ZJhh_!!6000000000842-2-tps-18-14.png"></img></td> <td>87</td> <td>92</td> <td>80</td> </tr> <tr> <td>Bob2</td> <td>87</td> <td>92</td> <td>80</td> </tr> <tr> <td>Bob3</td> <td>87</td> <td>92</td> <td>80</td> </tr> <tr> <td>Bob4</td> <td>87</td> <td>92</td> <td>80</td> </tr> <tr> <td>Bob5</td> <td>87</td> <td>92</td> <td>80</td> </tr> <tr> <td>Bob6</td> <td>87</td> <td>92</td> <td>80</td> </tr> <tr> <td>Bob7</td> <td>87</td> <td>92</td> <td>80</td> </tr> <tr> <td>Bob8</td> <td>87</td> <td>92</td> <td>80</td> </tr> </tbody> </table> </body> </html>
|
Chrome 浏览器渲染效果

Java 内置库渲染方案
有点: 无需引用任何第三方库
缺点: 渲染效果不尽人意
测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @Test public void testGraphics2D_native() throws IOException { long start = System.currentTimeMillis(); File xhtml = ResourceUtils.getFile("classpath:file/htm2img.html"); String fileContent = FileUtils.readFileToString(xhtml); int height = 800; BufferedImage image = new BufferedImage(width, height, TYPE_INT_ARGB_PRE); Graphics2D graphics = image.createGraphics();
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
JEditorPane jep = new JEditorPane("text/html;charset=UTF-8", fileContent); jep.setSize(width, height); jep.print(graphics);
File output = new File(OUTPUT_PATH_2); ImageIO.write(image, "png", output); long end = System.currentTimeMillis(); System.out.println("cost: " + (end - start) + " ms"); }
|
渲染效果

html2image库
官网地址: https://github.com/hkirk/java-html2image
maven坐标(最后更新时间2020年)
1 2 3 4 5
| <dependency> <groupId>gui.ava</groupId> <artifactId>html2image</artifactId> <version>0.9</version> </dependency>
|
测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Test public void testHtml2image() throws Exception {
long start = System.currentTimeMillis(); File xhtml = ResourceUtils.getFile("classpath:file/htm2img.html"); String fileContent = FileUtils.readFileToString(xhtml);
HtmlImageGenerator generator = new HtmlImageGenerator(); generator.loadHtml(fileContent); generator.setSize(new Dimension(width , 800)); File output = new File(OUTPUT_PATH_2); generator.saveAsImage(output); long end = System.currentTimeMillis(); System.out.println("cost: " + (end - start) + " ms"); }
|
渲染效果

FlyingSaucer
官网地址: https://github.com/flyingsaucerproject/flyingsaucer
maven坐标(持续有更新)
1 2 3 4 5
| <dependency> <groupId>org.xhtmlrenderer</groupId> <artifactId>flying-saucer-core</artifactId> <version>9.3.1</version> </dependency>
|
FlyingSaucer html转图片有两种方法
- Java2DRenderer
- Graphics2DRenderer
Java2DRenderer
Java2DRenderer测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Test public void testFlyingSaucerJava2DRenderer() throws Exception {
long start = System.currentTimeMillis(); File xhtml = ResourceUtils.getFile("classpath:file/htm2img.html"); String fileContent = FileUtils.readFileToString(xhtml);
XHTMLPanel xhtmlPanel = new XHTMLPanel(); xhtmlPanel.setDocumentFromString(fileContent, null, new XhtmlNamespaceHandler()); Java2DRenderer renderer = new Java2DRenderer(xhtmlPanel.getDocument(), 850, 1000); BufferedImage image = renderer.getImage(); File output = new File(OUTPUT_PATH); ImageIO.write(image, "png", output);
long end = System.currentTimeMillis(); System.out.println("cost: " + (end - start) + " ms"); }
|
渲染效果(不支持背景图片)

Graphics2DRenderer
Graphics2DRenderer测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Test public void testFlyingSaucerGraphics2DRenderer() throws Exception { long start = System.currentTimeMillis(); File xhtml = ResourceUtils.getFile("classpath:file/htm2img.html"); String fileContent = FileUtils.readFileToString(xhtml); XHTMLPanel xhtmlPanel = new XHTMLPanel(); xhtmlPanel.setDocumentFromString(fileContent, null, new XhtmlNamespaceHandler()); Graphics2DRenderer renderer = new Graphics2DRenderer(xhtmlPanel.getDocument(), 850, 1000); BufferedImage image = renderer.getImage(); File output = new File(OUTPUT_PATH); ImageIO.write(image, "png", output); long end = System.currentTimeMillis(); System.out.println("cost: " + (end - start) + " ms"); }
|
渲染效果

因为大多情况下html代码片段是通过 模板 生成的(项目中使用了beetl),生成的结果是个String而非文件,使用Graphics2DRenderer也是支持的,需要额外写成:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| @Test public void testFlyingSaucerGraphics2DRenderer2() throws Exception {
long start = System.currentTimeMillis(); File xhtml = ResourceUtils.getFile("classpath:file/htm2img.html"); String fileContent = FileUtils.readFileToString(xhtml);
XHTMLPanel xhtmlPanel = new XHTMLPanel(); xhtmlPanel.setDocumentFromString(fileContent, null, new XhtmlNamespaceHandler());
Graphics2DRenderer g2r = new Graphics2DRenderer(); g2r.setDocument(xhtmlPanel.getDocument(), null); Dimension dim = new Dimension(width, 1000);
BufferedImage buff = new BufferedImage((int) dim.getWidth(), (int) dim.getHeight(), BufferedImage.TYPE_INT_ARGB); Graphics2D g = (Graphics2D) buff.getGraphics(); g2r.layout(g, new Dimension(width, 1000)); g.dispose();
Rectangle rect = g2r.getMinimumSize();
buff = new BufferedImage((int) rect.getWidth(), (int) rect.getHeight(), BufferedImage.TYPE_INT_ARGB); g = (Graphics2D) buff.getGraphics(); g2r.render(g); g.dispose();
File output = new File(OUTPUT_PATH); ImageIO.write(buff, "png", output);
long end = System.currentTimeMillis(); System.out.println("cost: " + (end - start) + " ms"); }
|