java图片表单转html_Java图片处理:网页转图片(HtmlToImage)

本文介绍了如何使用Java结合wkhtmltox工具将网页转换为图片,包括 wkhtmltox 的优缺点、安装与使用方法,以及处理网页转图片过程中遇到的问题,如设置JavaScript延迟加载、调整边距等。
摘要由CSDN通过智能技术生成

Java图片处理:网页转图片

需求来源于前端同事跟我反馈整天调试布局样式很难受,希望能有服务端网页转图片的方法。 记录一下研究过程。

可选方案及评价。

最终选取的方案

代码细节

不足之处

可选方案及评价

从以下三个方面考虑:

页面效果还原程度

是否支持复杂html/js解析

中文字体显示效果

JEditorPane

首先找到的方案是使用java内置的Html解释工具javax.swing.JEditorPane。

public void testHtml2Image() throws Exception

{

String html = "贝叶斯统计推断贝叶斯统计推断

最大后验概率MAP

最小均方误差LMS1.最大后验概率是在观测条件x下,寻求待估量最可能的值作为估计值,即最大后验概率时的值。

2.最小均方误差是在观测条件x下,以待估量的均值作为估计值。";

JEditorPane editPane = new JEditorPane("text/html", html);

editPane.setEditable(false);

Dimension prefSize = editPane.getPreferredSize();

BufferedImage img = new BufferedImage(prefSize.width,prefSize.height, BufferedImage.TYPE_INT_ARGB);

Graphics graphics = img.getGraphics();

editPane.setSize(prefSize);

editPane.paint(graphics);

graphics.dispose();

ImageIO.write(img, "png", new File("/Users/yourname/Documents/work/temp/20190219.png"));

}

这是最简单的HTML代码了,但显示效果却不太好,如下图所示:

6555eb8bc8fd6049946db48287eb32be.png

而且多尝试后发现JeditorPane解析稍微复杂一点的js页面就会出错。

html2image

这是百度来的,从maven上可以搜索到,下载之后发现其内部就是调用JEditorPane,只是作了简单的封装,同样不满意。

wkhtmltox

这是在StackOverFlow上搜索Html2Image时看到的一种方案。尝试以后,效果强于JEditorPane,考虑试用。如谷歌首页转化如下:

最终选取方案

wkhtmltox在三个方面均强于JEditorPane。wkhtmltox没有java版本,采用java代码调用linux命令的方式使用该工具包。

wkhtmltox分为wkhtmltoimage 和wkhtmltopdf,经过尝试wkhtmltoimage显示效果不太好,且可调参数较少。而wkhtmltopdf转化效果相当好,因此最终解决方案:

Created with Raphaël 2.2.0 html字符 pdf image 优化image

其中生成pdf使用wkhtmltopdf,pdf转化image使用pdfbox(apache出品,放心使用,效果也相当好).wkhtmltopdf是将整个浏览器显示效果转为为pdf,所以对于一些没有铺满整个浏览器的网页,此时的pdf含有一部分无用的空白,应当去掉。

先看最终效果:

bca8912439e28faec3e4c322fac09cf1.png

代码

安装wkhtmltox

在https://wkhtmltopdf.org/下载安装。linux系统可使用wget下载。

安装成功测试命令:

wkhtmltopdf http://google.com google.pdf

帮助文档:

wkhtmltopdf -H

wkhtmltoimage -H

代码

命令:

wkhtmltopdf --javascript-delay 1000 -B 0mm -L 0mm -R 0mm -T 0mm url qptest.pdf

说明:javascript-delay是指最多等待js加载1000ms;B\L\R\T参数均是与生成的pdf文件的边距有关,可自行尝试。

对应上面流程图的方法调用:

html->htmlToPdf()->pdfToImage()->cutOffInvliadPart()->image

代码实现:

package test.java.com.action;

import java.awt.image.BufferedImage;

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

import javax.imageio.ImageIO;

import org.apache.pdfbox.pdmodel.PDDocument;

import org.apache.pdfbox.pdmodel.encryption.InvalidPasswordException;

import org.apache.pdfbox.rendering.PDFRenderer;

public class HtmlToImage

{

public static void main(String[] args) throws Exception

{

Param0 param=new Param0();

param.setDpi("2");

param.setJavascriptDelay(1000);

param.setUrl("https://www.google.com/");

File pdf=htmlToPdf(param);

File image=pdfToImage(pdf, param);

}

/*

* 去掉无用的部分(pdf转成的图片有很大一部分是无用的白色背景)

* 找出图片的有效部分,把有效部分复制到另一张新图上。

*/

private static BufferedImage cutOffInvliadPart(BufferedImage image)

{

int width=image.getWidth();

int height=image.getHeight();

//记录原始图片每个像素的color

int[][] rgbs=new int[width][height];

//以下是图片有效部分的边界

int top=height;

int bottom=0;

int left=-1;

int right=-1;

for (int i = 0; i < width; i++)

{

for (int j = 0; j < height; j++)

{

int rgb=image.getRGB(i, j);

rgbs[i][j]=rgb;

int tempRgb=rgb & 0x00ffffff;

boolean isWhite=(tempRgb==0x00ffffff);

if(!isWhite)

{

if(j

{

top = j ;

}

if(j>bottom)

{

bottom=j;

}

if(left==-1)

{

left=i;

}

if(i>right)

{

right=i;

}

}

}

}

//留白

bottom=(bottom+10)>(height-1)?(height-1):(bottom+10);

left=(left>1)?(left-1):0;

System.out.println(String.format("left:%s right:%s top:%s bottom:%s", left,right,top,bottom));

//像素的坐标是从0算起的,所以宽高要+1.

BufferedImage newImage = new BufferedImage(right-left+1, bottom-top+1, BufferedImage.TYPE_INT_RGB);

for (int i = 0; i < width; i++)

{

for (int j = 0; j < height; j++)

{

if((j>=top) && (j<=bottom) && (i>=left) && (i<=right))

{

newImage.setRGB(i-left, j-top, rgbs[i][j]);

}

}

}

return newImage;

}

private static File pdfToImage(File pdf,Param0 param) throws InvalidPasswordException, IOException

{

String filePath=System.getProperty("java.io.tmpdir") + "/" + "test" + ".png";

System.out.println(filePath);

File file=new File(filePath);

try

{

PDDocument pdDoc=PDDocument.load(pdf);

PDFRenderer render=new PDFRenderer(pdDoc);

//1=72 dpi

BufferedImage image=render.renderImage(0,Float.parseFloat(param.getDpi()));

BufferedImage newImage = cutOffInvliadPart(image);

ImageIO.write(newImage, "png", new FileOutputStream(file));

return file;

}

finally

{

//如果上传到图片服务器上则删除本地文件

//if(file!=null && file.exists())

//{

//file.delete();

//}

if(pdf!=null && pdf.exists())

{

pdf.delete();

}

}

}

private static File htmlToPdf(Param0 param) throws IOException, InterruptedException

{

StringBuilder commandBuilder = new StringBuilder();

if (System.getProperty("os.name").contains("Mac") || System.getProperty("os.name").contains("mac"))

{

//我的本地配置

commandBuilder.append("/usr/local/bin/wkhtmltopdf");

}

else

{

//服务器配置

commandBuilder.append("/usr/local/bin/wkhtmltopdf");

}

//wkhtmltopdf --javascript-delay 1000 -B 1mm -L 1mm -R 1mm -T 1mm url qptest.pdf

commandBuilder.append(" --javascript-delay ").append(param.getJavascriptDelay() + " ")

.append(" -B 0mm -L 0mm -R 0mm -T 0mm ");

commandBuilder.append(param.getUrl());

String pdfPath = System.getProperty("java.io.tmpdir") + "/" + "test" + ".pdf";

File pdf = new File(pdfPath);

commandBuilder.append(" " + pdfPath);

String command = commandBuilder.toString();

System.out.println(command);

Process process = Runtime.getRuntime().exec(command);

process.waitFor();

return pdf;

}

/**

* 外部传入的参数

*/

private static class Param0

{

private String url;

private String dpi="2";

private int javascriptDelay=200;

public String getUrl()

{

return url;

}

public void setUrl(String url)

{

this.url = url;

}

public String getDpi()

{

return dpi;

}

public void setDpi(String dpi)

{

this.dpi = dpi;

}

public int getJavascriptDelay()

{

return javascriptDelay;

}

public void setJavascriptDelay(int javascriptDelay)

{

this.javascriptDelay = javascriptDelay;

}

}

}

不足之处

解决方案有以下不足:

需要在服务器上安装wkhtmltox

接口运行速度需要提高

pdf转图片时只取了第一页,严谨的做法遍历以后拼到一张图上

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值