如何使用 Electron 和 JavaScript 构建桌面条形码、MRZ 和文档扫描仪

如何使用 Electron 和 JavaScript 构建桌面条形码、MRZ 和文档扫描仪

如何使用 Electron 和 JavaScript 构建桌面条形码、MRZ 和文档扫描仪

基于 Web 的视觉 SDK 与 Electron 非常契合:它们完全在 Chromium 渲染器进程中运行,无需任何原生插件,并且可以作为独立的桌面应用程序分发到 Windows、macOS 和 Linux 平台。Dynamsoft Capture Vision (DCV) SDK 底层使用 WebAssembly,这使其成为 Electron 沙盒渲染器的理想之选。

本教程将引导您完成将 Dynamsoft 条形码、MRZ 和文档扫描功能封装到可用于生产环境的 Electron 外壳中的步骤。您将学习 Electron 进程模型的工作原理、如何授予摄像头访问权限、如何放宽 CDN 资源的 Content-Security-Policy 标头,以及如何使用electron-builder.

演示视频:Electron 条形码、MRZ 和文档检测

先决条件

理解电子过程模型

Electron 将你的应用程序拆分成两种类型的进程:

过程角色使用权
主要流程Node.js;管理窗口、操作系统 API 和权限完整的 Node.js + Electron API
渲染进程Chromium;每个BrowserWindow;渲染 HTML/JS仅限 Web API(除非显式桥接)

Dynamsoft SDK 完全在渲染器内部运行。主进程负责:

  1. 创建具有正确窗口webPreferences
  2. 授予getUserMedia(相机)权限
  3. 修改响应头以放宽默认内容安全策略 (CSP)。

项目结构

<span><span><span><code>electron/ ├── main.js # Electron main process ├── preload.js # Context bridge – runs before renderer ├── package.json └── src/ ├── index.html # Renderer HTML ├── renderer.js # All scanning / SDK logic ├── utils.js # MRZ helper ├── styles.css └── full.json # DCV MRZ capture template </code></span></span></span>

主要进程:浏览器窗口和权限

main.js是 Electron 应用程序的入口点(由"main"`<input>`引用package.json)。创建一个 ` BrowserWindow<input>`contextIsolation: truenodeIntegration: false保持渲染器沙箱化:

<span><span><span><code><span><em>// main.js</em></span> <span><strong>const</strong></span> { app, BrowserWindow, session } <span>=</span> <span>require</span>('<span>electron</span>'); <span><strong>const</strong></span> path <span>=</span> <span>require</span>('<span>path</span>'); <span><strong>function</strong></span> <span>createWindow</span>() { <span><strong>const</strong></span> win <span>=</span> <span><strong>new</strong></span> <span><strong>BrowserWindow</strong></span>({ <span>width</span>: <span>1280</span>, <span>height</span>: <span>900</span>, <span>webPreferences</span>: { <span>preload</span>: path.<span>join</span>(__dirname, '<span>preload.js</span>'), <span>nodeIntegration</span>: <span><strong>false</strong></span>, <span><em>// best-practice: never expose Node in renderer</em></span> <span>contextIsolation</span>: <span><strong>true</strong></span>, <span><em>// required for contextBridge</em></span> <span>webSecurity</span>: <span><strong>true</strong></span>, }, }); <span><em>// Grant camera and microphone for Dynamsoft Camera Enhancer</em></span> session.defaultSession.<span>setPermissionRequestHandler</span>( (webContents, permission, callback) <span>=></span> { <span>callback</span>(['<span>media</span>', '<span>camera</span>', '<span>microphone</span>'].<span>includes</span>(permission)); } ); win.<span>loadFile</span>(path.<span>join</span>(__dirname, '<span>src</span>', '<span>index.html</span>')); } app.<span>whenReady</span>().<span>then</span>(createWindow); app.<span>on</span>('<span>window-all-closed</span>', () <span>=></span> { <span><strong>if </strong></span>(process.platform <span>!==</span> '<span>darwin</span>') app.<span>quit</span>(); }); app.<span>on</span>('<span>activate</span>', () <span>=></span> { <span><strong>if </strong></span>(BrowserWindow.<span>getAllWindows</span>().length <span>===</span> <span>0</span>) <span>createWindow</span>(); }); </code></span></span></span>
安全提示: nodeIntegration: false对于任何加载远程内容的 Electron 应用,建议至少启用“+”contextIsolation: true选项。除非您了解 XSS 的潜在风险,否则请勿禁用这些选项。

上下文隔离和预加载脚本

预加载脚本在特权上下文中执行(在渲染页面之前且 Node.js API 可用之后)。contextBridge.exposeInMainWorld它创建一个安全的、冻结的对象,该对象可window.electronAPI在渲染器中访问,而不会泄露完整的 Node.js API:

<span><span><span><code><span><em>// preload.js</em></span> <span><strong>const</strong></span> { contextBridge } <span>=</span> <span>require</span>('<span>electron</span>'); contextBridge.<span>exposeInMainWorld</span>('<span>electronAPI</span>', { <span>platform</span>: process.platform, <span>versions</span>: { <span>electron</span>: process.versions.electron, <span>node</span>: process.versions.node, <span>chrome</span>: process.versions.chrome, }, }); </code></span></span></span>

渲染器现在可以读取window.electronAPI.versions.electron并在用户界面中显示运行时版本——这对于支持和调试非常有用:

<span><span><span><code><span><em><!-- src/index.html – display Electron version in the header --></em></span> <span><strong><p</strong></span> <span>class=</span><span>"electron-badge"</span><span><strong>></strong></span> 🖥️ Desktop App – Electron v<span><strong><span</strong></span> <span>id=</span><span>"electron-version"</span><span><strong>></span></strong></span> <span><strong></p></strong></span> <span><strong><script></strong></span> <span><strong>if </strong></span>(<span>window</span>.electronAPI) { <span>document</span>.<span>getElementById</span>('<span>electron-version</span>').textContent <span>=</span> <span>window</span>.electronAPI.versions.electron; } <span><strong></script></strong></span> </code></span></span></span>

渲染器:正在加载 Dynamsoft SDK

DCV 包通过 jsDelivr CDN 加载,并使用<script>标签src/index.html。由于 Electronfile://默认使用 origin,一些浏览器会阻止混合内容请求,但 Electron 的 Chromium 会file://在主进程修改Content-Security-Policy响应头时放宽对 origin 的限制(参见CSP 部分):

<span><span><span><code><span><em><!-- src/index.html --></em></span> <span><strong><script </strong></span><span>src=</span><span>"https://cdn.jsdelivr.net/npm/[email protected]/dist/dcv.bundle.min.js"</span><span><strong>></script></strong></span> <span><strong><script </strong></span><span>src=</span><span>"utils.js"</span><span><strong>></script></strong></span> ... <span><strong><script </strong></span><span>src=</span><span>"renderer.js"</span><span><strong>></script></strong></span> </code></span></span></span>

renderer.js它与浏览器版本的原生 JavaScript 应用程序逻辑完全一致。唯一的代码路径差异在于:

  1. 文件路径(./full.json)解析为相对于src/index.html--correct 符合 Electronfile://协议。
  2. save()函数使用了<a download>DOM 技巧;它在 Electron 的 Chromium 中也能正常工作。
  3. showMessage()使用来自utils.js.

在 Electron 中处理摄像头访问

默认情况下,Electron 会session.defaultSession拒绝所有getUserMedia阻止后台静默录制的请求。您的主进程必须显式授予该media权限类型。

setPermissionRequestHandler每当渲染器调用时,都会触发回调函数。Dynamsoft navigator.mediaDevices.getUserMedia()Camera Enhancer 会在内部触发此回调,因此不需要渲染器端的权限代码:

<span><span><span><code><span><em>// main.js – already shown above</em></span> session.defaultSession.<span>setPermissionRequestHandler</span>( (webContents, permission, callback) <span>=></span> { <span>callback</span>(['<span>media</span>', '<span>camera</span>', '<span>microphone</span>'].<span>includes</span>(permission)); } ); </code></span></span></span>
生产提示:webContents.getURL()在调用之前,通过检查是否与预期来源匹配来缩小权限授予范围callback(true)

跨平台相机行为

平台行为
macOS首次启动时系统会提示是否授予相机权限(macOS隐私权政策要求)
视窗权限由 Electron 处理;默认情况下,桌面应用程序不会出现系统提示。
LinuxV4L2;通常无需提示即可授予访问权限。

在 macOS 上,将NSCameraUsageDescription密钥添加到您的(当您在构建选项中设置它时,Info.plist会自动处理)。electron-buildermac.extendInfo

CDN资产的内容安全策略

Electron 添加了一个默认的 CSP,会阻止外部脚本、工作进程和 WASM 线程。由于 Dynamsoft SDK 会在运行时加载工作进程脚本和 WASM 代码块,因此必须放宽此默认策略。

Content-Security-Policy使用以下方式覆盖响应头session.webRequest.onHeadersReceived

<span><span><span><code><span><em>// main.js</em></span> session.defaultSession.webRequest.<span>onHeadersReceived</span>((details, callback) <span>=></span> { <span>callback</span>({ <span>responseHeaders</span>: { ...details.responseHeaders, '<span>Content-Security-Policy</span>': [ "<span>default-src 'self' 'unsafe-inline' 'unsafe-eval' blob: data: </span>" <span>+</span> "<span>https://cdn.jsdelivr.net https://*.dynamsoft.com; </span>" <span>+</span> "<span>script-src 'self' 'unsafe-inline' 'unsafe-eval' blob: </span>" <span>+</span> "<span>https://cdn.jsdelivr.net https://*.dynamsoft.com; </span>" <span>+</span> "<span>worker-src 'self' blob:;</span>", ], }, }); }); </code></span></span></span>

指令解释:

指示目的
'unsafe-inline'内联<script><style>并由 SDK UI 组件使用
'unsafe-eval'instantiate某些 Chromium 配置中的WASM路径
blob:blob:WASM 工作线程以URL 的形式生成。
https://cdn.jsdelivr.netDCV捆绑包的CDN源
https://*.dynamsoft.comDynamsoft 许可证服务器和模型下载来源
生产环境加固:如果您自行托管 DCV 软件包和模型文件,则可以移除 CDN 源'unsafe-eval'。您还可以添加一个noncehash来替换'unsafe-inline'内联脚本。

通过 DOM 锚点保存文档

保存修正后的文档图像与浏览器版本的操作完全相同。Electron 的 Chromium 内核会识别该<a download>属性并触发原生保存对话框:

<span><span><span><code><span><em>// src/renderer.js – identical to browser version</em></span> <span><strong>async</strong></span> <span><strong>function</strong></span> <span>save</span>() { <span><strong>const</strong></span> a <span>=</span> <span>document</span>.<span>createElement</span>('<span>a</span>'); a.href <span>=</span> rectifiedImage.src; a.download <span>=</span> <span>`document_</span>${<span>Date</span>.<span>now</span>()}<span>.png`</span>; <span>document</span>.body.<span>appendChild</span>(a); a.<span>click</span>(); <span>document</span>.body.<span>removeChild</span>(a); } </code></span></span></span>

在 Electron 中,默认情况下,此操作会打开操作系统文件保存对话框,并指向用户的“下载”文件夹。如果您需要自定义路径(例如,始终保存到特定目录),请使用主进程dialog.showSaveDialogAPI 并通过进程间通信 (IPC) 将路径发送回进程。

使用 electron-builder 进行构建和封装

package.json已预先配置electron-builder。目标:

平台格式命令
视窗NSIS 安装程序npm run dist -- --win
macOS伤害npm run dist -- --mac
LinuxAppImagenpm run dist -- --linux
<span><span><span><code>// package.json (excerpt) { <span>"build"</span>: { <span>"appId"</span>: <span>"com.dynamsoft.visionscanner"</span>, <span>"productName"</span>: <span>"Vision Scanner"</span>, <span>"win"</span>: { <span>"target"</span>: <span>"nsis"</span> }, <span>"mac"</span>: { <span>"target"</span>: <span>"dmg"</span> }, <span>"linux"</span>: { <span>"target"</span>: <span>"AppImage"</span> } } } </code></span></span></span>

针对当前平台构建:

<span><span><span><code>npm run dist </code></span></span></span>

构建完成后的工件会出现在dist/目录中。Dynamsoft SDK 包会在运行时从 CDN 加载,从而保持分发包体积较小。如需完全离线分发,请将包复制到指定位置src/<script src>在构建前更新相关设置。

电子条形码、MRZ 和文档扫描仪

源代码

https://github.com/yushulx/javascript-barcode-qr-code-scanner/tree/main/examples/electron

Read more

飞算Java在线学生成绩综合统计分析系统的设计与实现

飞算Java在线学生成绩综合统计分析系统的设计与实现

目录 * 引言 * 技术栈 * 一.需求分析与规划 * 功能需求 * 核心模块 * 技术选型 * 二.环境准备 * 1. 下载IntelliJ IDEA * 2. 安装IntelliJ IDEA * 3. 安装飞算JavaAI插件 * 4. 登录飞算JavaAI * 三.模块设计与编码 * 1. 飞算JavaAI生成基础模块 * 2. 核心代码展示 * entity包下实体类示例 * `Student.java`(学生实体) * `Score.java`(成绩实体) * dto包下数据传输对象示例 * `ScoreAddDTO.java`(成绩录入请求DTO) * `StudentRankQueryDTO.java`(个人排名查询DTO) * vo包下视图对象示例 * `StudentRankVO.java`(个人排名返回VO) * mapper包下数据访问接口示例 * `ScoreMappe

By Ne0inhk
基于python的电影推荐系统的设计与实现-附源码201341

基于python的电影推荐系统的设计与实现-附源码201341

摘 要 随着社会的快速发展和人们生活水平的不断提高,电影已逐渐成为人们生活的重要组成部分,用户能够获取 电影信息的渠道也随信息技术的广泛应用而增加。大量未经过滤的信息在展示给用户的同时,也淹没了用户真正感兴趣的信息。为了方便用户快速定位自己感兴趣的信息,个性化电影推荐系统应运而生。 本系统的前端界面涉及的技术主要有Django, HTML,jQuery等等,通过这些技术可以实现前端页面的美观和动态效果使之符合广大群众的审美观,后台主要使用的技术主要有Python编程语言,MySQL数据库,Ajax异步交互,根据Ajax异步模式的 电影推荐系统解决了传统 电影推荐方式中数据分析所带来的人力、物力和时间上的虚耗和交流深度的限定,这让交流的过程更快捷、准确、便利,同时完成 电影推荐系统的基本功能:用户管理、电影交流、电影信息、电影分类、电影评分等。本次报告,首先分析了研究的背景、作用、意义,为研究工作的合理性打下了基础。针对电影推荐系统的各项需求以及技术问题进行分析,证明了系统的必要性和技术可行性,然后对设计系统需要使用的技术软件以及设计思想做了基本的介绍,最后来实现电影推荐系统和部

By Ne0inhk
【C++高阶系列】:线程库和多线程

【C++高阶系列】:线程库和多线程

🔥 本文专栏:c++ 🌸作者主页:努力努力再努力wz 💪 今日博客励志语录: 选择决定了方向,勇气决定了能走多远。没有勇气的选择是纸上蓝图,没有选择的勇气是迷失的航船。 ★★★ 本文前置知识: 线程(上) 线程(下) 引入 在上一篇文章中,我们详细介绍了在 Linux 平台下如何进行线程管理,包括线程的创建、等待与退出等操作。具体而言,主要是通过调用 Linux 原生 pthread 线程库提供的接口,例如 pthread_create 和pthread_join 等。 需要注意的是,pthread 线程库所提供的接口遵循 POSIX 标准,因此主要适用于 Linux 及其他类 Unix 系统,例如 Unix 和 macOS。然而,在 Windows

By Ne0inhk

C++异步编程迎来里程碑:std::future超时支持正式敲定(仅限C++26)

第一章:C++26中std::future超时支持的里程碑意义 C++26标准即将为并发编程带来一项关键增强:对 std::future 原生支持超时机制。这一改进解决了长期以来开发者必须依赖 std::future::wait_for 或 std::future::wait_until 轮询判断结果是否就绪的痛点,显著提升了异步任务管理的效率与可读性。 更直观的异步等待体验 在C++26之前,若要实现带超时的 future 等待,开发者需手动编写循环或使用 wait_for 配合状态检查。新标准将引入直接支持超时的 get 重载方法,使接口更加简洁自然。 // C++26 中 std::future 支持超时 get 调用 std::future<int> fut

By Ne0inhk