Java调用扫描仪2

2 篇文章 1 订阅

最近碰到的问题,客户端调用本地的扫描仪,将扫描的文件上传。

使用到的技术:applet,twain,HttpClient

当然也碰到很多问题,因为在这周之前我都不知道什么是applet

一.Applet操作本地资源

基于安全方面的原因,applet是不允许操作本地资源的。但是java提供了相应的为jar包签名的机制来提升applet的权限。相信很多人都碰到过这种对话框:

让用户来决定是否给applet提升权限,如果用户信任这个资源,applet将能操作本地资源。

 

1.为applet依赖的jar包签名

java提供了两个工具;

keytool用于生成存放key的库

jarsigner用于为jar进行签名

 

首先建立一个keystore(这是在当前路径上操作):

keytool -genkey -alias zengge -keystore zengge.keystore

keytool -genkey表示建库

-alias zengge是为要建立的key取一个别名

-keystore zengge.keystore是建立一个名字叫zengge.keystore的key库,key就存在里面.

如下图:



 这样一个keystore就建立好了,在当前目录下就多出了一个zengge.keystore的文件


 

有了keystore之后jarsigner就可以利用存放在keystore中的key来为jar签名



 这里有两个类,先打包

 


包里面的META-INFO里面只有一个文件,且内容为上图

 

接下来为jar包签名:

jarsigner -keystore zengge.keystore HelloWorld.jar zengge
zengge.keystore是keystore的路径/名字,这里是相对路径
HelloWorld.jar是要签名的jar包
zengge是存放在keystore中的密钥的别名


密码为建立keystore时的密码

 

再来看一下签过名的jar里面的情况有什么变化:


可以看到META-INFO里面现在是三个文件,.DSAG与.SF我想肯定是用来加解密用的,大家注意现在的MANIFEST.MF,

可以看出为每个类添加了一个SHA签名,用它来保证,这个jar里面的内容不会被其它人修改,用户可以相信这个jar。

 

2.将applet嵌入html

applet是通过浏览器来运行了,可能你会问,java的东西浏览器怎么能运行呢,难道客户端也要安装java?

实际上applet是通过嵌在浏览器中的jvm在运行,但是这个jvm是从那里来的呢?

对于IE,大家可以看一下,下图中的java如果选中,就表示会调用本地的jre来运行applet。


但是绝大部分情况下,客户端是不会安装java的啊,还有firefox下面没有类似的这种选项。那么要如何来解决这种问题呢?

早期的applet都是用applet标签来嵌入html的(当然现在也可以),例如:

<APPLET CODE = "HelloWorld" archive ="HelloWorld.jar" JAVA_CODEBASE = "." WIDTH = "320" HEIGHT = "240" NAME = "HelloWorld"></APPLET>

这里的CODE表示类名(类名后可以加上.class),archvie表示类所在的jar包,如果你有多个jar包,可以全加在archive里面,用,号分开(archive="a,jar,b.jar,c.jar",当然这些jar要签名的还得签名)。

如果用这种标签,在IE下,如果没选中用本地jre运行applet的话,是运行不了的,没安装插件的firefox也是不能运行的。

 

面对这种情况,升级版的标签出现了,java提供了一个工具名字叫HTMLconverter,通过它,能将html中的applet标签转换成标准的标签,如下

Html代码   收藏代码
  1. <object  
  2.     classid = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"  
  3.     codebase = "http://java.sun.com/update/1.6.0/jinstall-6u14-windows-i586.cab#Version=6,0,0,8"  
  4.     WIDTH = "320" HEIGHT = "240" NAME = "HelloWorld" >  
  5.     <PARAM NAME = CODE VALUE = "HelloWorld" >  
  6.     <PARAM NAME = CODEBASE VALUE = "." >  
  7.     <PARAM NAME = ARCHIVE VALUE = "applet_test.jar" >  
  8.     <PARAM NAMENAME = NAME VALUE = "HelloWorld" >  
  9.     <param name = "type" value = "application/x-java-applet;version=1.6">  
  10.     <param name = "scriptable" value = "false">  
  11.       
  12.     //上面是针对IE  
  13.     //下面的embed是针对firefox  
  14.       
  15.     <comment>  
  16.     <embed  
  17.             type = "application/x-java-applet;version=1.6" \  
  18.             CODE = "HelloWorld" \  
  19.             JAVA_CODEBASE = "." \  
  20.             ARCHIVE = "applet_test.jar" \  
  21.             NAME = "HelloWorld" \  
  22.             WIDTH = "320" \  
  23.             HEIGHT = "240"  
  24.         scriptable = false  
  25.         pluginspage = "http://java.sun.com/products/plugin/index.html#download">  
  26.         <noembed>   
  27.             </noembed>  
  28.     </embed>  
  29.     </comment>  
  30. </object>  
  31. <!--  
  32. <APPLET CODE = "HelloWorld" JAVA_CODEBASE = "." WIDTH = "320" HEIGHT = "240" NAME = "HelloWorld">  
  33. </APPLET>  
  34. -->  
  35. <!--"END_CONVERTED_APPLET"-->  
 

其中Object部分是针对IE的,embed是针对firefox的.classid与codebase都是表示相应的plugin的下载地址,如果codebase的版本高于classid将下载codebase版本的plugin。这样不管本地有没有安装java,applet都能正常运行了。

 

现在,在applet里面己经能调用本地的资源了,那么如何驱动扫描仪呢?

 

二.applet调用TWain驱动本地扫描仪

TWain是一个标准,用于获取扫描仪等设备的信息,它有很多实现(基本都是收费的),这里选择的是一个开源twain产品,mmsc twain(官网 http://www.mms-computing.co.uk/例子很丰富)。

只要本地安装有扫描仪驱动,twain就能找到并运行且获取到扫描的数据。

它里面有个Scanner类,Scanner scanner = Scanner.getDevice()能获取到相应的设备。然后为scanner添加一个监听器,ScannerListener,它里面有个方法public void update(ScannerIOMetadata.Type type, ScannerIOMetadata metadata){},第二个参数即为扫描得到的数据,而且这个方法是在扫描述的状态发生变变就会解发。具体可以看一些mmsc里面的例子。

 

三.applet与服务器通信

得到了扫描的数据,得把它上传到服务器。我这里用的是HttpClient(需要的jar包commons-codec-1.4.jar,commons-httpclient-3.0.jar,commons-io-1.4.jar,commons-logging-1.0.2.jar)。在使用时最好对这几个jar包都签名(我没有测试这种方式,我是将这几个jar全给解压了,最后连同我的类一起打成了一个jar,最后签名),上传代码位于update方法内即可。

因为扫描仪有多种状态,所以要进行判断,那次才是拿到了扫描数据。

Java代码   收藏代码
  1. public void update(ScannerIOMetadata.Type type, ScannerIOMetadata metadata){  
  2.   
  3.     if(type.equals(ScannerIOMetadata.ACQUIRED)){  
  4.       BufferedImage image=metadata.getImage();  
  5.       System.out.println("Have an image now!");  
  6.       HttpClient httpClient = new HttpClient();  
  7.       MultipartPostMethod mpm = new MultipartPostMethod("http://localhost:8086/ReiyenDMS/TestUploadServlet");  
  8. //      MultipartPostMethod mpm = new MultipartPostMethod("http://localhost:8086/applet_study/servlet/AppletServlet");  
  9.       File file = new File("c:/upload/abc"+index+".jpg");  
  10.       try{  
  11.         ImageIO.write(image, "jpg", file);  
  12.         index++;  
  13.        mpm.addParameter("aFile""haha.pdf", file);  
  14.         httpClient.executeMethod(mpm);  
  15.   
  16.       }catch(Exception e){  
  17.         e.printStackTrace();  
  18.       }  
  19.     }else if(type.equals(ScannerIOMetadata.NEGOTIATE)){  
  20.       ScannerDevice device=metadata.getDevice();  
  21. /* 
  22.       try{ 
  23.         device.setResolution(100); 
  24. //        device.setRegionOfInterest(0.0,0.0,40.0,50.0);       // top-left corner 40x50 mm 
  25.         device.setRegionOfInterest(0,0,400,500);               // top-left corner 400x500 pixels 
  26.         device.setShowUserInterface(false); 
  27.         device.setShowProgressBar(false); 
  28.       }catch(Exception e){ 
  29.         e.printStackTrace(); 
  30.       } 
  31. */  
  32.     }else if(type.equals(ScannerIOMetadata.STATECHANGE)){  
  33.       System.err.println(metadata.getStateStr());  
  34.     }else if(type.equals(ScannerIOMetadata.EXCEPTION)){  
  35.       metadata.getException().printStackTrace();  
  36.     }  
  37.   }  
 

 

完工

中间碰到最多的问题就是,applet签名及applet布署,开始老以为applet根平时的类布署是一样的,后来发现就应该把它当成一个独立的应用来对等。

 

中间可能有错,有问题请在家指出,谢谢

 

效果图(点击中间的acquire就能扫描了):

 

要使用 Java 调用扫描仪进行扫描,你需要使用 SANE(Scanner Access Now Easy) 或 TWAIN(Technology Without An Interesting Name) 等扫描仪接口。下面我将分别介绍如何使用这两种接口进行扫描。 1. 使用 SANE 接口进行扫描 SANE 接口是一种开放源代码的扫描仪接口,它可以用于 Linux、UNIX 和 macOS 等操作系统。如果你需要在 Windows 上使用 SANE 接口进行扫描,则需要使用 Cygwin 等工具模拟 Linux 环境。 要使用 SANE 接口进行扫描,你需要使用 SANE Java API,它是一个用于 Java 的 SANE 接口库。接下来是一个使用 SANE Java API 进行简单扫描的示例代码: ```java import ch.fh_aargau.scanner.Sane; public class SaneTest { public static void main(String[] args) { Sane.init(); SaneDevice device = Sane.getDevices()[0]; device.open(); SaneFrame frame = new SaneFrame(device); frame.setDepth((short)8); frame.setWidth(100); frame.setHeight(100); byte[] data = frame.getByteArray(); frame.start(); device.start(); device.read(data); device.cancel(); device.close(); Sane.exit(); } } ``` 2. 使用 TWAIN 接口进行扫描 TWAIN 接口是一种广泛使用于 Windows 平台的扫描仪接口,它可以用于访问 TWAIN 兼容的扫描仪设备。要使用 TWAIN 接口进行扫描,你需要使用 JavaTwain 库,它是一个用于 JavaTWAIN 接口库。 接下来是一个使用 JavaTwain 库进行简单扫描的示例代码: ```java import java.awt.image.BufferedImage; import java.io.File; import javax.imageio.ImageIO; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import com.fujitsu.twain.Twain; import com.fujitsu.twain.TwainSource; import com.fujitsu.twain.TwainSource.State; import com.fujitsu.twain.TwainTransfer; public class TwainTest { private static final Logger logger = LogManager.getLogger(TwainTest.class); public static void main(String[] args) throws Exception { Twain.init(); TwainSource source = Twain.select(); source.open(); source.enable(); source.setState(State.ACQUIRING); TwainTransfer transfer = source.getXferMech(); BufferedImage image = transfer.getImage(); File file = new File("scan.jpg"); ImageIO.write(image, "jpg", file); logger.info("Scan completed. Image saved to " + file.getAbsolutePath()); source.setState(State.IDLE); source.disable(); source.close(); Twain.exit(); } } ``` 以上就是使用 Java 调用扫描仪进行扫描的示例代码。不同的扫描仪接口和库可能有不同的实现方式,具体实现方式可以参考它们的官方文档。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值