最近在项目(B/S)中客户要求页面中实现屏幕截图的功能(如WEB QQ屏幕截图那种),起初看了很多JS实现图片截取,如Jquery的插件Jcrop,但是功能和所需要的不一样。此类插件只是实现已有图片的剪切,实现原理一般是在客户端定位需要剪切的图片x,y坐标,然后将参数传给服务器,由服务器实现图片的截取, 实现类似新浪博客头像编辑的功能。[url]http://www.iteye.com/topic/510980[/url]
Google之后,目前做这种实现的一般有以下几种方式:
1. 使用AcitveX或者其他的浏览器插件。
看了下Web QQ,貌似是按照这种方式做的,不过测试了目前只有IE和FF可以支持屏幕截图,Chrome下连图标都没有。由于系统需要跨浏览器访问,如果为了实现这个功能分别为不同的浏览器开发插件的话就比较麻烦了。
2. Flash
不熟,请高手指点。
3. Java Applet
首先,在JAVA中做屏幕截图是可以的。感谢leesonhomme提供的源码[url]http://leesonhomme.iteye.com/blog/451840[/url]。
然后将用到的类打成jar包, Cmd 切换到web-info/classes目录下,通过如下命令打包:

jar -cvf snapshot.jar *.*



当然,也可以使用其它工具如Fatjar。


现在,可以编写页面了:


<HTML>
<BODY >
<APPLET
	code	= "Snapshot.class"
	ARCHIVE = "snapshot.jar"
	width	= "70"
	height	= "30"
	>
</APPLET>
</BODY>
</HTML>



此时访问该页面,会提示Access Denied错误,这是由于Java的沙盒安全模型的存在,使得未签名的applet在客户端被禁止执行某些操作,比如读写文件或者连接局域网。经过签名的applet能够向用户验证applet的编写者:他是否真的编写了这个applet;此jar文件离开 服务器后,内容是否被篡改过。如果没有这些最基本的保证,applet将不被允许执行任何有可能破坏用户机器,或者侵犯用户隐私的操作。要在互联网上安全地使用applet,这些限制非常重要,不过相对来说,这也限制了applet的能力。


为了使得applet能够访问本地的应用,比如剪切板,需要给它签名。


keytool -genkey -keystore snapshot.store -alias snapshot



这个命令用来产生一个密匙库,执行完毕后应该产生一个 hello.store的文件,这个名字你可以对它进行修改。另外在执行命令的时候还有提示你输入密匙库的密码,这里你一定要记住,否则后面要用的时候无法输入。输入密码后,它会提示你输入用户名,公司名等信息,这些都不是必须输入的,你可以直接回车跳过,最后问你输入是否正确,你可以输入y或n回答正确或错误。


keytool -export -keystore snapshot.store -alias snapshot -file snapshot.cert



这个命令用来产生签名时所要用的证书,这个命令执行完后产生一个pepper.cert的文件.


jarsigner -keystore snapshot.store snapshot.jar snapshot



这个命令用上面产生的证书将我们的jar文件进行了签名。最后把该jar包拷贝到jsp文件所在地目录下。


再访问网页,我们所需要的功能就有了。不过有一个缺陷:就是applet中的按键样式和页面统一风格不统一。


我们可以用JNLP的方式加载java文件。首先编写JNLP配置文件:


<?xml version="1.0" encoding="UTF-8"?>
<!-- file snapshot.jnlp -->
<jnlp codebase="http://localhost:8080/snapshot/" href="http://localhost:8080/snapshot/snapshot.jnlp">
	<information>
		<title>Snapshot</title>
		<vendor>Snapshot</vendor>
		<icon href="google.jpg"/>
	</information>
	<resources>
		<j2se version="1.2+"/>
		<jar href="snapshot.jar"/>
	</resources>
	<application-desc main-class="ScreenCapture"/>
</jnlp>



在上面的代码基础上,需要加上以下属性:


<security>
	   <all-permissions/>
	</security>



否则在运行时同样会报access denied错误。


编写页面文件:


<a href="snapshot.jnlp">Snapshot</a>



但这样做同样有个缺陷,就是每次点击它的时候都需要弹出下载窗口然后打开,用户体验很不好。


于是,修改之前的页面如下:


<a href="#" onclick="openSnapshot()">Snapshot2</a>
<div id="test">test</div>
<script type="text/javascript">
function openSnapshot() {
	//window.open("index2.html");
	$("#test").load("index2.html",function(){
		console.log("success");
	})
}
</script>



index2.html:


<HTML>
<BODY >
<APPLET
	code	= "Snapshot.class"
	ARCHIVE = "snapshot.jar"
	width	= "0"
	height	= "0"
	>
</APPLET>
</BODY>
</HTML>



applet的宽度和高度都为0,相当于是个隐藏的元素。



附上源码,供大家讨论指教。




修改【2011-4-8】:


当我将页面放到项目中时,出现一个诡异的问题:当从HTML文件使用AJAX加载Applet时运行正常;当从JSP文件中(Struts2中的Action)加载时一直出现classNotFoundException。经过不断的尝试,最终发现是ARCHIVE设置的问题。


如果从Action页面中加载,ARCHIVE需要从项目根路径开始找,于是将其修改为:


<HTML>
<BODY >
<APPLET name="screenshotApplet" id="screenshotApplet" code = "org.myproject.snapshot.Screenshot.class" 
	ARCHIVE = "/【项目名】/screenshot/snapshot.jar" codebase="." width = "0" height = "0">
</APPLET>
</BODY>
</HTML>





还有就是IE中有时出现JVM 加载失败,Firefox中有时打开后看到鼠标变成了叉,但是选取的时候没有任何反应,不晓得是怎么回事。。。