网页扫描图像并以pdf格式上传到服务器端

news2024/10/5 17:24:42

本文描述如何通过网页驱动扫描仪、高拍仪等图像扫描设备进行图像扫描,扫描结果经编辑修改后以pdf压缩格式上传到后台java程序中进行服务器端落盘保存。

图像扫描上传如文字描述顺序所介绍,先要驱动扫描设备工作,进行纸张数据的光学扫描操作形成图像数据,之后对扫描结果进行剪切、旋转等编辑处理工作,最后的步骤是将加工处理好的结果上传到服务器端进行保存,这里面涉及到前端网页编程、后台服务器端编程等工作,以下按顺序介绍前后台如何具体是如何实现的。

一、准备工作

客户端计算机如果想进行图像扫描,首先需要连接硬件图像扫描设备,一般通过USB数据线与客户端电脑连接,当然如果局域网环境内有其他扫描仪设备,也可以使用局域网内的共享扫描设备,以上两种方式均需要安装扫描仪硬件设备对应的驱动程序,可以根据硬件设备的品牌型号到对应厂家下载驱动程序在客户端电脑安装配置。如果驱动程序有多种类型,选择包含twain驱动程序的下载使用。

二、设计交互网页界面

用户的电脑不一定只连接一台扫描设备,想让用户进行图像扫描时到底使用哪一台扫描设备需要有web交互界面供用户选择确定,另外在系统内有多个驱动程序的情况下windows并不能识别出来当前哪个设备处于可用状态,哪些设备已经断开与计算机的连接或者网络,所以需要由用户选择确认一下到底要使用哪个设备进行扫描,类似的,还有扫描时的分辨率DPI设置、扫描后图像是彩色还是灰度或黑白色的设置等等,这些都需要设计UI界面供用户设定。

这里给出读取系统连接的扫描仪并填充到下拉列表的关键核心代码示例:

        <form>
    。。。
            <div class="block">
                <label for="devices">扫描设备:</label>
                <select id="devices"></select>
            </div>
            <div class="block">
                <label for="dpi_x">设备输入分辨率:</label>
                <input type="text" id="dpi_x" value="300" style="width: 25px;" /> X
                <input type="text" id="dpi_y" value="300" style="width: 25px;" />
            </div>
            <div class="block">
                <label for="showDialog">是否显示内置对话框:</label>
                <select id="showDialog">
                    <option value="true">显示</option>
                    <option value="false" selected>不显示</option>
                </select>
            </div>
            <div class="block">
                <label for="feedEnable">自动进纸模式:</label>
                <select id="feedEnable">
                    <option value="true">是</option>
                    <option value="false" selected>否</option>
                </select>
            </div>
            <div class="block">
                <label for="autoFeed">自动装填纸张:</label>
                <select id="autoFeed">
                    <option value="true">是</option>
                    <option value="false" selected>否</option>
                </select>
            </div>
            <div class="block">
                <label>双面模式:</label>
                <select id="dupxMode">
                    <option value="true">是</option>
                    <option value="false" selected>否</option>
                </select>
            </div>
            <div class="block">
                <label>自动纠偏:</label>
                <select id="autoDeskew">
                    <option value="true">是</option>
                    <option value="false" selected>否</option>
                </select>
            </div>
            <div class="block">
                <label>自动边框检测:</label>
                <select id="autoBorderDetection">
                    <option value="true">是</option>
                    <option value="false" selected>否</option>
                </select>
            </div>
。。。。
        </form>

    <script src="./scanonweb.js" type="text/javascript"></script>
    <script type="text/javascript">
        var scanonweb = new ScanOnWeb();

        //响应返回扫描设备列表的回调函数
        scanonweb.onGetDevicesListEvent = function (msg) {
            var deviceListDom = document.getElementById('devices');

            //clear devices list
            deviceListDom.innerHTML = "";
            for (var i = 0; i < deviceListDom.childNodes.length; i++) {
                ardeviceListDomea.removeChild(deviceListDom.options[0]);
                deviceListDom.remove(0);
                deviceListDom.options[0] = null;
            }

            //add devices info
            for (var i = 0; i < msg.devices.length; ++i) {
                var opt = document.createElement("option");
                opt.innerHTML = msg.devices[i];
                if (i == msg.currentIndex) {
                    opt.selected = true;
                }
                deviceListDom.appendChild(opt);
            }
        }

上面的代码自动读取客户端计算机已经安装的扫描设备信息并自动填充到下拉列表框里面供用户选择使用。

三、驱动扫描设备进行图像扫描

前端网页添加“扫描”按钮,点击事件执行javascript代码去驱动扫描仪进行图像扫描,关键核心代码如下:

        //开始扫描命令
        function startScan() {
            if (document.getElementById("devices").selectedIndex == -1) {
                alert('请先刷新或者选中要使用的扫描设备后再开始扫描!');
                return;
            }

            //以下获取界面中的扫描参数设定
            scanonweb.scaner_work_config.dpi_x = document.getElementById("dpi_x").value;
            scanonweb.scaner_work_config.dpi_y = document.getElementById("dpi_y").value;
            scanonweb.scaner_work_config.deviceIndex = document.getElementById("devices").selectedIndex;
            scanonweb.scaner_work_config.showDialog = document.getElementById("showDialog").value;
            scanonweb.scaner_work_config.autoFeedEnable = document.getElementById("feedEnable").value;
            scanonweb.scaner_work_config.autoFeed = document.getElementById("autoFeed").value;
            scanonweb.scaner_work_config.dupxMode = document.getElementById("dupxMode").value;
            scanonweb.scaner_work_config.autoDeskew = document.getElementById("autoDeskew").value;
            scanonweb.scaner_work_config.autoBorderDetection = document.getElementById("autoBorderDetection").value;


            //开始发送扫描指令
            scanonweb.startScan();

        }

此时用户在网页里面点击扫描按钮触发该函数执行后,扫描仪即可开始进行图像扫描,扫描结果可以通过scanonweb的托盘服务程序进行所见即所得的编辑处理,如:

上面的示例是演示了选中某个区域后进行打马赛克处理,选区内的内容已经变成了马赛克。

四、将图像处理结果上传到服务器端保存

扫描后的图像最终一般都会上传到服务器端进行保存,如果为了预览查看方便,可以使用pdf格式将扫描图像上传到服务器端后进行保存,以下是示例代码:

        //按照pdf格式上传所有图像
        function uploadAllImageAsPdfFormat(){
            scanonweb.uploadAllImageAsPdfToUrl('http://localhost:8080/uploadDemo/fileUpload','1234','test');    
        }

服务器端接收的示例代码,以java为例:

package cn.brainysoft.uploaddemo;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import org.json.JSONObject;

@WebServlet("/fileUpload")
@MultipartConfig
public class FileUploadServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    private static final String SAVE_DIR = "uploadFiles";

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取字段数据
        String imageCount = request.getParameter("imageCount");
        String id = request.getParameter("id");
        String desc = request.getParameter("desc");

        //输出到控制台
        System.out.println("imageCount: " + imageCount);
        System.out.println("id: " + id);
        System.out.println("desc: " + desc);

        //获取文件数据
        Part filePart = request.getPart("image");
        String fileName = getFileName(filePart);
        InputStream fileContent = filePart.getInputStream();

        //保存文件到硬盘
        String appPath = request.getServletContext().getRealPath("");
        String savePath = appPath + File.separator + SAVE_DIR;
        File fileSaveDir = new File(savePath);
        if (!fileSaveDir.exists()) {
            fileSaveDir.mkdir();
        }
        String filePath = savePath + File.separator + fileName;
        FileOutputStream outStream = new FileOutputStream(filePath);
        byte[] buffer = new byte[4096];
        int bytesRead = -1;
        while ((bytesRead = fileContent.read(buffer)) != -1) {
            outStream.write(buffer, 0, bytesRead);
        }
        outStream.close();
        fileContent.close();
        System.out.println("文件保存路径:"+filePath);

        //构造返回的json数据
        Map<String, String> result = new HashMap<String, String>();
        result.put("url", request.getContextPath() + "/" + SAVE_DIR + "/" + fileName);
        JSONObject json = new JSONObject(result);
        String jsonString = json.toString();

        //设置返回的content type为json
        response.setContentType("application/json");

        //将json数据写入response
        response.getWriter().write(jsonString);
    }

    //获取上传文件的文件名
    private String getFileName(final Part part) {
        final String partHeader = part.getHeader("content-disposition");
        for (String content : partHeader.split(";")) {
            if (content.trim().startsWith("filename")) {
                return content.substring(content.indexOf('=') + 1).trim()
                        .replace("\"", "");
            }
        }
        return null;
    }
}

上面的示例代码中将收到的pdf图像数据写入硬盘后返回给前端js后续浏览器请求查看时的url路径,具体存盘时的文件名怎么命名大家可以根据自己的需要去计算生成,一般前端收到服务器返回的pdf文件url路径后会通过ajax写在数据库里面保存,例如:

        //响应上传pdf图像数据的回调函数
        scanonweb.onUploadAllImageAsPdfToUrlEvent = function (msg) {
            console.log("上传pdf图像数据到服务器端的响应结果:" + msg);
            if (msg.uploadResult) {
                //将msg.uploadResult转换为json对象
                var uploadResult = JSON.parse(msg.uploadResult);
                console.log("上传pdf图像数据保存到服务器端后的请求url地址:" + uploadResult.url);
                window.open("http://localhost:8080"+uploadResult.url);
            }
        }

以上示例较为零散,完整的前端示例代码可以从这里找到: https://www.brainysoft.cn/download/clientjs.zip

后台servlet接收代码完整工程压缩包地址:https://www.brainysoft.cn/download/servletUploadDemo.zip

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/363472.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Impacket工具使用

Impacket工具说明 Impacker是用户处理网络协议的Python类集合,用于对SAB1-3或IPv4/IPv6 上的TCP/UPD/ICMP/IGMP/ARP/IPv4/IPv6/SMB/MSRPC/NTLM/Kerberos/WMI/LDAP 等进行低级的编程访问,数据包可以从头开始构建,也可以从原始数据包中解析, 面向对象API使用处理协议的深层结构变…

Action Segmentation数据集介绍——Breakfast

文章目录简介细节Cooking actibitiesillustration of the actions论文讲解Breakfast&#xff08;The Breakfast Action Dataset&#xff09;简介 早餐动作数据集包括与早餐准备相关的10个动作&#xff0c;由18个不同厨房的52个不同的人执行。该数据集是最大的完全带注释的数据…

CCIE 350-401-实验全

实验 VRRP&#xff08;hello packettimes advertise&#xff09; This is a lab item in which tasks will be performed on virtual devices. Refer to the Tasks tab to view the tasks for this lab item.Refer to the Topology tab to access the device console(s) and p…

Spring Boot自动装配的原理

Spring Boot自动装配的原理自动装配的实现EnableAutoConfigurationAutoConfigurationImportSelectorSpring Boot中的自动装配&#xff0c;它是Starter的基础&#xff0c;也是Spring Boot的核心。那么什么叫自动装配呢&#xff1f;或者说什么叫装配呢&#xff1f; 简单来说&…

Vulnhub靶场----4、DC-4

文章目录一、环境搭建二、渗透流程三、思路总结一、环境搭建 DC-4下载地址&#xff1a;https://download.vulnhub.com/dc/DC-4.zip kali&#xff1a;192.168.144.148 DC-4&#xff1a;192.168.144.152 二、渗透流程 端口扫描&#xff1a;nmap -T5 -p- -sV -sT -A 192.168.144.1…

ISIS协议

ISIS协议基础简介应用场景路由计算过程地址结构路由器分类邻居Hello报文邻居关系建立DIS及DIS与DR的类比链路状态信息的载体链路状态信息的交互路由算法网络分层路由域![在这里插入图片描述](https://img-blog.csdnimg.cn/9027c43b614a4399ae1f54e87a37f047.png)区域间路由简介…

【MySQL】表操作和库操作

文章目录概念库操作1.创建数据库2.删除数据库3.选择数据库4.显示数据库列表表操作1.创建数据表CREATE2.删除数据表DROP3.插入数据INSERT4.更新数据UPDATE5.修改数据ALTER6.查询数据SELECT7.WHERE子句8.ORDER BY子句9.LIMIT子句10.GROUP BY子句11.HAVING子句使用注意事项概念 M…

Java集合(一)---List和set

1.Java集合有哪些&#xff1f;集合类型主要有3种&#xff1a;set(集&#xff09;、list(列表&#xff09;和map(映射)Map接口和Collection接口是所有集合框架的父接口&#xff1a;1. Collection接口的子接口包括&#xff1a;Set接口和List接口2. Map接口的实现类主要有&#xf…

【Python】批量采集原神表情包~

嗨害大家好鸭~我是小熊猫(✿◡‿◡) 最近迷上了原神&#xff0c; 不自觉中就很喜欢保存广大旅行者制作的表情包~ 真的很有意思诶~ 源码资料电子书:点击此处跳转文末名片获取 一个个保存的话&#xff0c;好像效率很低嘛… 那我就发挥我小熊猫的老本行直接给把他们全部采集下…

零基础机器学习做游戏辅助第十三课--原神自动钓鱼(三)labelimg的使用

一、什么是labelimg labelimg是一款开源的图像标注工具,标签可用于分类和目标检测,它是用python写的,并使用Qt作为其图形界面,简单好用(虽然是英文版的)。其注释以 PASCAL VOC格式保存为XML文件,这是ImageNet使用的格式。此外,它还支持 COCO数据集格式。 二、安装label…

大数据时代下的企业网络安全

在大数据技术迅猛发展的今天&#xff0c;网络安全问题已经发展成一个广受关注的热门研究方向。有人说&#xff0c;“大数据下&#xff0c;人人裸奔”&#xff0c;隐私保护、数据防护日益成为广大学者、企业研究的焦点。 面对这种安全威胁&#xff0c;企业必须实施一些有效的信…

Allegro无法看到金属化孔的钻孔的原因和解决办法

Allegro无法看到金属化孔的钻孔的原因和解决办法 用Allegro设计PCB的时候,希望同时看到金属化孔的盘以及钻孔,如下图 但是有时显示效果是这样的,看不到钻孔了 导致无法直观地区分是通孔是还是表贴的盘 如何解决,具体操作如下 点击Setup

27正定矩阵

这一节进入正定矩阵的内容&#xff0c;什么叫做正定矩阵&#xff1f;为什么我们对矩阵正定这么感兴趣&#xff1f; PS&#xff1a;这一节将前面所有的概念都融合在一起&#xff1a;主元、行列式、特征值、不稳定性 一、正定矩阵的判断方法 为了说明问题&#xff0c;我们先考…

低代码平台和无代码平台哪个更适合开发企业管理系统?

编者按&#xff1a;本文分析了开发企业管理系统所需要的平台特性&#xff0c;并根据这些特点和低代码无代码的优劣比较&#xff0c;得出低代码平台更适合开发企业管理系统。关键词&#xff1a;私有化部署&#xff0c;可视化设计&#xff0c;源码交付&#xff0c;数据集成&#…

研究人员在野外发现大量的信息窃取者 “Stealc “的样本

一个名为Stealc的新信息窃取者正在暗网上做广告&#xff0c;它可能成为其他同类恶意软件的一个值得竞争的对象。 "SEKOIA在周一的一份报告中说&#xff1a;"威胁行为者将Stealc作为一个功能齐全、随时可用的窃取者&#xff0c;其开发依赖于Vidar、Raccoon、Mars和Re…

LeetCode 73. 矩阵置零

LeetCode 73. 矩阵置零 难度&#xff1a;middle\color{orange}{middle}middle 题目描述 给定一个 KaTeX parse error: Double subscript at position 3: _m_̲ x _n_ 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法…

Power Query 再谈日期表

Power Query 再谈日期表 需要附件的朋友可以点赞关注后&#xff0c;在公众号(焦棚子)后台回复 日期表 三个字即可领取。 一、背景 在 Power BI 或者 Power Pivot 做业务分析中&#xff0c;必不可少的就是日期表。我们继续优化调制出符合国人习惯日期表。 本次更新&#xff…

harbor 仓库迁移升级

harbor 仓库迁移升级 harbor仓库安装数据传输仓库切换版本 v1.8.0 v2.3.5 harbor仓库安装 环境准备&#xff1a;安装docker详见&#xff1a;docker 的介绍和部署&#xff0c;并下载docker-compose详见&#xff1a;docker 三剑客compose。 现有支持的安装harbor仓库的方式有两…

犹太教、基督教、伊斯兰教的区别与联系

一、犹太教、基督教、伊斯兰教的简明关系图二、犹太教、基督教、伊斯兰教的主要区别注&#xff1a;弥赛亚&#xff08;希伯莱语&#xff09;就是基督&#xff08;希腊语&#xff09;&#xff0c;意思是“救世主”。注&#xff1a;伊斯兰教的观点是&#xff1a;穆罕默德不是伊斯…

华为OD机试 - 优雅数组(Python)【2023-Q1 新题】

华为OD机试300题大纲 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。 华为 OD 清单查看地址:blog.csdn.net/hihell/category_12199275.html 华为OD详细说明:https://dream.blog.csdn.net/article/details/128980730 优雅数组 | 华为…