转载请注明出处:https://blog.csdn.net/l1028386804/article/details/79955398
最近的项目中,需要实现一个将网页中显示的内容导出为图片的功能,故研究了一下可以实现这个功能的各种方式,整理在此,以供以后使用。
前台方式
1. 利用html2canvas实现前台截屏
html2canvas项目的gitHub地址
html2canvas示例
html2canvas可以将HTML代码块进行截取,并生成快照形式的canvas,然后可以利用html5的下载功能提供图片的下载接口,供用户下载。
优点:前台技术,实现比较容易。
缺点:此项目使用了html5的技术,因此在对IE的兼容上,只可以在IE9+的版本上使用。
使用时,需要引用jQuery.js和html2canvas.js。(html2canvas.js可以在github上下载)
具体JavaScript代码如下:
var canvas = function () {
html2canvas($("#chart"), {
onrendered: function (canvas) {
$("#class11").html(canvas);//将id为“class11”部分的代码转换为canvas
var type = 'png';//图片类型为png
var imgData = canvas.toDataURL('png');//将图片转换为png类型的流
var _fixType = function (type) {
type = type.toLowerCase().replace(/jpg/i, 'jpeg');
var r = type.match(/png|jpeg|bmp|gif/)[0];
return 'image/' + r;
};
var saveFile = function (data, filename) {
var save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
save_link.href = data;
save_link.download = filename;
var event = document.createEvent('MouseEvents');
event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
save_link.dispatchEvent(event);
};
//下载时的文件名
var filename = 'baidufe_' + (new Date()).getTime() + '.' + type;
// 下载文件
saveFile(imgData, filename);
}
});
};
后台方式(java)
1. 利用html2image实现
html2image的地址(google)
html2image是可以识别html标签并将html转换成图片的java项目。
优点:后台转换,故对浏览器的版本基本没有要求。
缺点:对样式的识别不是很好,转换出来的图片比较简单,基本没有可以兼容的样式。
使用方式:maven中引用如下依赖:
<dependency>
<groupId>com.github.xuwei-k</groupId>
<artifactId>html2image</artifactId>
<version>0.1.0</version>
</dependency>
2. 利用DJNativeSwing项目实现
纯java代码实现。使用DJNativeSwing这个项目,构建一个swing浏览器,打开网址,之后截取图片。(需要eclipse的swt库支持)
优点:纯java实现。
缺点:需要多线程的支持,只在控制台方式实现过
使用这个方法,需要引用的maven依赖如下:
<dependency>
<groupId>com.hynnet</groupId>
<artifactId>DJNativeSwing</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.hynnet</groupId>
<artifactId>DJNativeSwing-SWT</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.eclipse.swt.org.eclipse.swt.win32.win32.x86_64.4.3.swt</groupId>
<artifactId>org.eclipse.swt.win32.win32.x86_64</artifactId>
<version>4.3</version>
</dependency>
实现代码如下(引用自
http://blog.csdn.net/buddyuu/article/details/52699997):
public class PrintScreen4DJNativeSwingUtils extends JPanel {
private static final long serialVersionUID = 1L;
// 行分隔符
final static public String LS = System.getProperty("line.separator", "/n");
// 文件分割符
final static public String FS = System.getProperty("file.separator", "//");
// 当网页超出目标大小时 截取
final static public int maxWidth = 2000;
final static public int maxHeight = 1400;
/**
* @param file
* 预生成的图片全路径
* @param url
* 网页地址
* @param width
* 打开网页宽度 ,0 = 全屏
* @param height
* 打开网页高度 ,0 = 全屏
* @return boolean
*/
public PrintScreen4DJNativeSwingUtils(final String file, final String url, final String WithResult) {
super(new BorderLayout());
JPanel webBrowserPanel = new JPanel(new BorderLayout());
final JWebBrowser webBrowser = new JWebBrowser(null);
webBrowser.setBarsVisible(false);
webBrowser.navigate(url);
webBrowserPanel.add(webBrowser, BorderLayout.CENTER);
add(webBrowserPanel, BorderLayout.CENTER);
JPanel panel = new JPanel(new FlowLayout());
webBrowser.addWebBrowserListener(new WebBrowserAdapter() {
// 监听加载进度
public void loadingProgressChanged(WebBrowserEvent e) {
// 当加载完毕时
if (e.getWebBrowser().getLoadingProgress() == 100) {
String result = (String) webBrowser.executeJavascriptWithResult(WithResult);
int index = result == null ? -1 : result.indexOf(":");
NativeComponent nativeComponent = webBrowser.getNativeComponent();
Dimension originalSize = nativeComponent.getSize();
Dimension imageSize = new Dimension(Integer.parseInt(result.substring(0, index)),
Integer.parseInt(result.substring(index + 1)));
imageSize.width = Math.max(originalSize.width, imageSize.width + 50);
imageSize.height = Math.max(originalSize.height, imageSize.height + 50);
nativeComponent.setSize(imageSize);
BufferedImage image = new BufferedImage(imageSize.width, imageSize.height,
BufferedImage.TYPE_INT_RGB);
nativeComponent.paintComponent(image);
nativeComponent.setSize(originalSize);
// 当网页超出目标大小时
if (imageSize.width > maxWidth || imageSize.height > maxHeight) {
// 截图部分图形
image = image.getSubimage(0, 0, maxWidth, maxHeight);
// 此部分为使用缩略图
/*
* int width = image.getWidth(), height = image
* .getHeight(); AffineTransform tx = new
* AffineTransform(); tx.scale((double) maxWidth /
* width, (double) maxHeight / height);
* AffineTransformOp op = new AffineTransformOp(tx,
* AffineTransformOp.TYPE_NEAREST_NEIGHBOR); //缩小 image
* = op.filter(image, null);
*/
}
try {
// 输出图像
ImageIO.write(image, "jpg", new File(file));
} catch (IOException ex) {
ex.printStackTrace();
}
// 退出操作
System.exit(0);
}
}
});
add(panel, BorderLayout.SOUTH);
}
// 以javascript脚本获得网页全屏后大小
public static String getScreenWidthHeight() {
StringBuffer jsDimension = new StringBuffer();
jsDimension.append("var width = 0;").append(LS);
jsDimension.append("var height = 0;").append(LS);
jsDimension.append("if(document.documentElement) {").append(LS);
jsDimension.append(" width = Math.max(width, document.documentElement.scrollWidth);").append(LS);
jsDimension.append(" height = Math.max(height, document.documentElement.scrollHeight);").append(LS);
jsDimension.append("}").append(LS);
jsDimension.append("if(self.innerWidth) {").append(LS);
jsDimension.append(" width = Math.max(width, self.innerWidth);").append(LS);
jsDimension.append(" height = Math.max(height, self.innerHeight);").append(LS);
jsDimension.append("}").append(LS);
jsDimension.append("if(document.body.scrollWidth) {").append(LS);
jsDimension.append(" width = Math.max(width, document.body.scrollWidth);").append(LS);
jsDimension.append(" height = Math.max(height, document.body.scrollHeight);").append(LS);
jsDimension.append("}").append(LS);
jsDimension.append("return width + ':' + height;");
return jsDimension.toString();
}
public static boolean printUrlScreen2jpg(final String file, final String url, final int width, final int height) {
NativeInterface.open();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
String withResult = "var width = " + width + ";var height = " + height + ";return width +':' + height;";
if (width == 0 || height == 0)
withResult = getScreenWidthHeight();
JFrame frame = new JFrame("网页截图");
// 加载指定页面,最大保存为640x480的截图
frame.getContentPane().add(new PrintScreen4DJNativeSwingUtils(file, url, withResult),
BorderLayout.CENTER);
frame.setSize(640, 480);
// 仅初始化,但不显示
frame.invalidate();
frame.pack();
frame.setVisible(false);
}
});
NativeInterface.runEventPump();
return true;
}
public static void main(String[] args) {
PrintScreen4DJNativeSwingUtils.printUrlScreen2jpg("1122.jpg", "https://www.baidu.com", 1400, 900);
}
}
3. 利用phantomJs实现
phantomJs的GitHub地址
phantomJs官网
phantom利用的是webKit内核,全面支持web而不需浏览器支持,快速,原生支持各种Web标准。
优点:速度快,使用简单。
缺点:需要在项目的服务器端引用exe文件进行截图,并发性能有待考证。
使用这个方式,需要去官网下载最新的phantomJs脚本。官网地址在上面的链接中。
具体代码如下(引用自http://www.cnblogs.com/lekko/p/4796062.html):
/**
* 网页转图片处理类,使用外部CMD
*/
public class PhantomTools {
private static final Logger _logger = Logger.getLogger(PhantomTools.class);
private static final String _tempPath = "D:/data/temp/phantom_";
private String basePath;
private static final String _shellCommand1 = "phantomjs ";
private static final String _shellCommand2 = "rasterize.js ";
private String _file;
private String _size;
/**
* 构造截图类
* @param hash 用于临时文件的目录唯一化
* @param basePath phantomJs所在路径
*/
public PhantomTools(int hash, String basePath) {
_file = _tempPath + hash + ".png";
this.basePath = basePath;
}
/**
* 构造截图类
* @param hash 用于临时文件的目录唯一化
* @param size 图片的大小,如800px*600px(此时高度会裁切),或800px(此时 高度最少=宽度*9/16,高度不裁切)
* @param basePath phantomJs所在路径
*/
public PhantomTools(int hash, String size, String basePath) {
_file = _tempPath + hash + ".png";
if (size != null)
_size = " " + size;
this.basePath = basePath;
}
/**
* 将目标网页转为图片字节流
* @param url 目标网页地址
* @return 字节流
*/
public byte[] getByteImg(String url) throws IOException {
BufferedInputStream in = null;
ByteArrayOutputStream out = null;
File file = null;
byte[] ret = null;
try {
if (exeCmd(basePath + _shellCommand1 + basePath + _shellCommand2 + url + " " + _file + (_size != null ? _size : ""))) {
file = new File(_file);
if (file.exists()) {
out = new ByteArrayOutputStream();
byte[] b = new byte[5120];
in = new BufferedInputStream(new FileInputStream(file));
int n;
while ((n = in.read(b, 0, 5120)) != -1) {
out.write(b, 0, n);
}
file.delete();
ret = out.toByteArray();
}
} else {
ret = new byte[] {};
}
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
_logger.error(e);
}
try {
if (in != null) {
in.close();
}
} catch (IOException e) {
_logger.error(e);
}
if (file != null && file.exists()) {
file.delete();
}
}
return ret;
}
/**
* 执行CMD命令
*/
private static boolean exeCmd(String commandStr) {
BufferedReader br = null;
try {
Process p = Runtime.getRuntime().exec(commandStr);
if (p.waitFor() != 0 && p.exitValue() == 1) {
return false;
}
} catch (Exception e) {
_logger.error(e);
} finally {
if (br != null) {
try {
br.close();
} catch (Exception e) {
_logger.error(e);
}
}
}
return true;
}
}