读大学时,微博兴起,因为140个字有限,因而有人开发了长微博,当时但想着开发一个长微博的应用。试用了几款长微博工具,大部分都是只能输入文字和插件一两张图片,这种长微博工具实现不难。但若是想在长微博中支持富文本,例如插件表格之类的(http://www.changweibo.com/),那就没那么简单了。 javascript
实现支持富文本的长微博,原理以下: html
1.客户端提供一个富文本输入框(CKeditor,Ueditor之类的) java
2.把在输入框中输入的html代码发送到服务端,服务端解析html代码,生成图片返回客户端 linux
重点要解决的问题是后台如何解析html代码并生成图片。一个最初的想法是用htmlparse解析html代码,对于简单的html代码这个方法可行,但若是html代码的结构混乱就麻烦了。另外一个想法是在后台用一个浏览器渲染这段html代码,而后利用浏览器的功能把图片导出。基于这个想法,用了javafx2.0里面的Webview,Webview实质上就是一个浏览器,它用的是WebKit内核,用它能够渲染html和执行javascript。用Webview生成图片的代码以下: web
import java.io.File; import java.io.IOException; import javafx.application.Application; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.embed.swing.SwingFXUtils; import javafx.scene.*; import javafx.scene.image.Image; import javafx.stage.Stage; import javafx.scene.web.WebView; import javafx.scene.web.WebEngine; import javafx.concurrent.Worker.State; import javax.imageio.ImageIO; public class HtmlToImage extends Application { @Override public void start(Stage primaryStage) { final WebView view = new WebView(); Scene scene = new Scene(view, 800, 600); primaryStage.setScene(scene); final WebEngine webEngine = view.getEngine(); webEngine.load("http://www.huxiu.com/article/5840/1.html"); primaryStage.show(); //监听webEngine加载进度,可能页面加载不完整 webEngine.getLoadWorker().stateProperty() .addListener(new ChangeListener<State>() { @Override public void changed(ObservableValue<? extends State> ov, State oldState, State newState) { if (newState == State.SUCCEEDED) { snapshot(view); } } }); } public void snapshot(Node view) { Image image = view.snapshot(null, null); try { ImageIO.write(SwingFXUtils.fromFXImage(image, null), "png", new File("D:\\" + System.currentTimeMillis() + ".png")); System.out.println("图片已生成"); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) { launch(args); } }
生成的图片以下: windows
图1 api
这个方法能够把html代码渲染成图片而且导出,但只是一个简单的截屏功能,若是屏幕上出现滚动条,则只能导出屏幕上显示的那部分效果,因此这个方案也是不可行的。但它给咱们提供了一个很好的思路。即经过浏览器来渲染html,利用浏览器提供的api导出图片。Chrome和Firfox这两大浏览器的内核都是开源的,能够从这些开源的浏览器内核入手。看它们有没有提供对应的API。在谷歌上搜索了一番,找到了一个可用的开源目wkhtmltopdf,这个开源项目能够把html转换成pdf或者image,它也是基于webkit内核实现这些功能的。wkhtmltopdf提供了windows、linux、和Mac 三个版本,下面以windows版本为例,说明它的用法。 浏览器
1.先下载libwkhtmltox-0.11.0_rc1.zip,解压安装 app
2.在命令行下输入:wkhtmltopdf www.google.com.hk myhomepage.pdf 就能够把谷歌的首页导出为pdf文件, ide
同理,wkhtmltoimage www.google.com.hk myhomepage.jpg 能够把谷歌的首页导出为图片。
注意:wkhtmltopdf和wkhtmltoimage对中文编码支持不友好,若是网页是GBK编码,生成的图片或者pdf是乱码,因此最好先把网页下载到本地,改为UTF-8编码,再调用这两个工具生成图片或者pdf。
以上只是简单应用wkhtmltopdf的命令,事实上这两个命令能够带参数的,详细的参数说明能够看官方文档。
3.在java程序中调用wkhtmltoimage。由于wkhtmltoimage并无提供java api,因此只能经过java程序启动命令行,经过命令行调用wkhtmltoimage来完成任务。
public class HtmlToImage{ public static void main(String[] args){ ProcessBuilder pb = new ProcessBuilder("D:\\Program Files\\wkhtmltopdf\\wkhtmltoimage", "www.baidu.com", "D:\\test.jpg"); Process process; try { process = pb.start(); //注意,调用process.getErrorStream()而不是process.getInputStream() BufferedReader errStreamReader = new BufferedReader(new InputStreamReader(process.getErrorStream())); System.out.println("read errstreamreader"); String line = null; line = errStreamReader.readLine(); while(line != null) { System.out.println(line); line = errStreamReader.readLine(); } process.destroy(); System.out.println("destroyed process"); } catch (IOException e) { e.printStackTrace(); } } }
总结:wkhtmltopdf和wkhtmltoimage是一个功能强大的开源工具,能够实现不少相似的功能。例如,用谷歌搜索时,把鼠标移动到连接上面,会显示该网页的缩略图,这个功能能够用wkhtmltoimage来实现。若是想把博客导出为pdf,能够用wkhtmltopdf来实现。