浏览器里驱动扫描仪:20年了,换了三轮技术,本质没变

张开发
2026/4/14 2:40:08 15 分钟阅读

分享文章

浏览器里驱动扫描仪:20年了,换了三轮技术,本质没变
浏览器里驱动扫描仪20年了换了三轮技术本质没变非科班野生程序员深耕政务信息化20年。政务系统里有个绕不开的需求——浏览器里驱动扫描仪扫描材料直接上传。2010年我用VC写了个ActiveX控件通过TWAIN协议驱动扫描仪扫描完灰度化压缩后HTTP POST上传。现在IE死了ActiveX不能用了新的方案是什么在客户电脑上装一个本地HTTP服务前端通过WebSocket调用。本质还是那件事只是绕了个更远的路。最后感谢豆包、智谱、OpenCode决策是我做的代码是我搓的文字是他们总结的。政务场景政务大厅窗口办事群众递过来一张材料工作人员放进扫描仪点一下页面上的扫描按钮材料直接进系统。听起来简单做起来要命。浏览器出于安全考虑不能直接访问本地硬件。这个限制从网景时代就有了到现在也没变。2010年的方案ActiveX TWAIN那时候政务系统全跑在IE上IE支持ActiveX控件——一个COM组件可以嵌入网页拥有本地权限能直接调硬件。我用VC 6.0写了一个叫CommonScan的ActiveX控件核心功能1. TWAIN协议驱动扫描仪TWAIN是扫描仪的标准通信协议几乎所有扫描仪都支持。控件继承CTwain类封装了TWAIN的数据源管理器DSM调用// CommonScanCtl.hclassCCommonScanCtrl:publicCOleControl,publicCTwain{// ...afx_msglongScanImage();// JS调这个开始扫描afx_msgvoidCancalScan();// JS调这个取消扫描voidCopyImage(HANDLE hBitmap,TW_IMAGEINFOinfo);// 扫描回调voidcallend();// 扫描完成回调};JS调用ScanImage()控件通过TWAIN打开扫描仪逐张获取图像longCCommonScanCtrl::ScanImage(){i0;m0;piccount0;if(!this-SourceSelected()){SelectSource();// 弹出扫描仪选择对话框}Acquire(TWCPP_ANYCOUNT,m_bUI);// 开始采集数量不限return0;}2. 图像处理扫描出来的图是DIB格式设备无关位图直接存文件太大了。控件内用GDI做了处理缩放宽度超过1191px的等比缩放到1191pxA4纸300DPI的宽度灰度化24位RGB转8位灰度用加权公式val (R*76 G*150 B*30) 8二值化灰度值大于220的变白小于的变黑——政务档案材料通常是白纸黑字二值化后文件更小更清晰JPEG压缩质量设为80文件大小可控// 缩放到1191px宽度if(srcWidth1191){dstWidth1191;dstHeightsrcHeight*1191/srcWidth;}// JPEG质量80quality80;encoderParameters.Parameter[0].GuidEncoderQuality;encoderParameters.Parameter[0].Valuequality;bitmap.Save(filename,encoderClsid,encoderParameters);3. HTTP POST上传扫描完自动上传到服务端用CSendData类封装了 multipart/form-data 的HTTP POST// 扫描完自动上传sendfile(m_url,m_action,m_port,filename1);上传成功后删除本地临时文件。上传失败服务端返回101-500错误码则记入errFilesJS可以通过getErrFiles()获取失败列表。4. JS交互前端JavaScript这样调用// 设置参数scan.SetFileName(C:\\scan\\);// 扫描文件保存路径scan.SetURL(http://192.168.1.1);scan.SetAction(/upload);scan.SetPot(8080);scan.SetUI(1);// 显示扫描仪界面scan.SetMode(1);// 模式scan.SetFileType(jpg);// 输出格式// 开始扫描scan.ScanImage();// 扫描完成事件functionscan::endwithnum(picCount){alert(扫描完成共picCount张);varfilenamesscan.getFilenames();varerrFilesscan.getErrFiles();}整个流程JS调ScanImage → TWAIN驱动扫描仪 → CopyImage回调处理图像 → sendfile上传 → callend触发JS事件。5. 安装ActiveX控件编译成.cab包用户第一次访问页面时IE自动提示安装装完就能用。不需要单独启动什么服务不需要配置端口不需要担心进程崩溃。现在的方案本地HTTP服务IE死了ActiveX不能用了。Chrome、Edge都不支持浏览器插件直接访问硬件。现在的做法在客户电脑上装一个本地HTTP服务或者Electron应用前端通过WebSocket/HTTP调用这个服务服务再去调TWAIN驱动扫描仪。以前浏览器 → ActiveX控件 → TWAIN → 扫描仪 现在浏览器 → WebSocket → 本地HTTP服务 → TWAIN → 扫描仪多了一层。而且这一层带来了新的问题问题ActiveX方案本地HTTP服务方案安装浏览器自动提示一键安装要单独安装一个服务程序启动浏览器打开页面自动加载要确保服务在运行用户关了就没了端口不需要要分配端口可能和其他服务冲突进程崩溃不存在控件和浏览器同进程服务挂了要重启用户不知道怎么重启防火墙不存在要放行本地端口维护基本不需要要处理服务异常、日志、自动重启本质没变不管是ActiveX还是本地HTTP服务做的事情一模一样突破浏览器沙箱— 获取本地硬件访问权限驱动扫描仪— 通过TWAIN协议处理图像— 缩放、灰度化、压缩上传到服务端— HTTP POST回调前端— 告诉JS扫描完了2010年ActiveX → 做这5件事 2020年本地服务 → 做同样的5件事 2026年还是本地服务 → 还是这5件事技术栈换了三轮本质是同一个问题浏览器不能直接访问硬件只能绕道。以前绕道的方式是浏览器插件现在绕道的方式是本地服务。绕的路更远了但终点一样。为什么写这篇文章不是为了怀念ActiveX。ActiveX绑死IE安全性差该淘汰。而是想说有些问题是技术栈解决不了的。浏览器的安全模型决定了它不能直接访问硬件这个限制从第一天就有到现在没有变。不管前端框架换了多少轮jQuery → Angular → React → Vue扫描仪、打印机、读卡器这些政务大厅里的硬件永远需要一个浏览器外面的东西来桥接。以前这个东西是ActiveX现在是本地HTTP服务。以后可能是WebUSB也许吧但政务大厅的扫描仪厂商什么时候支持WebUSB天知道。硬件集成的坑20年了还在踩。政务系统里硬件集成大家都是怎么做的评论区聊聊。标签#ActiveX #TWAIN #扫描仪 #政务信息化 #硬件集成 #浏览器 #VC #图像处理 #本地服务

更多文章