当前位置: 首页 > article >正文

纯前端实现发票二维码批量识别——PDF.js + jsQR 实战

最近在做财务报销相关的需求需要从大量电子发票 PDF 中提取发票号码、购买方、销售方、金额等信息。手动复制粘贴效率极低于是研究了一下能不能纯前端实现自动识别。折腾了几天最终用PDF.js jsQR Tesseract.js实现了一个完全在浏览器端运行的发票批量识别工具不需要后端不上传文件隐私安全。本文记录一下核心实现思路。技术选型功能库说明PDF 解析pdf.jsMozilla 出品浏览器端解析 PDF二维码识别jsQR纯 JS 二维码解码图片 OCRTesseract.jsGoogle Tesseract 的 WebAssembly 版本核心流程1. PDF 文字层提取电子发票 PDF 本身带有文字层pdf.js 可以直接提取不需要 OCR准确率高async function extractPdfText(pdf) { let fullText ; for (let i 1; i pdf.numPages; i) { const page await pdf.getPage(i); const textContent await page.getTextContent(); // items.str 就是每个文字块的内容 const pageText textContent.items.map(item item.str).join( ); fullText pageText \n; } return fullText; }2. 扫描发票二维码把 PDF 页面渲染到离屏 canvas再用 jsQR 扫描像素数据async function scanPageForQR(pdf, pageNum, scale 2.0) { const page await pdf.getPage(pageNum); const viewport page.getViewport({ scale }); const canvas document.createElement(canvas); canvas.width viewport.width; canvas.height viewport.height; const ctx canvas.getContext(2d); await page.render({ canvasContext: ctx, viewport }).promise; const imageData ctx.getImageData(0, 0, canvas.width, canvas.height); const code jsQR(imageData.data, imageData.width, imageData.height, { inversionAttempts: dontInvert }); return code ? code.data : null; }注意 scale 建议设 2.0 以上分辨率太低二维码识别率会下降。3. 解析二维码内容增值税发票二维码格式是逗号分隔的字符串01,32,,26512000001023417645,38.69,20260317,,7147字段顺序版本, 类型码, 发票代码, 发票号码, 金额, 日期, 校验码function parseInvoiceQR(qrText) { const parts qrText.split(,); const invoiceTypeMap { 01: 增值税专用发票, 04: 增值税普通发票, 32: 电子发票普通发票, // ... }; const typeCode parts[1].trim(); return { invoiceType: invoiceTypeMap[typeCode] || typeCode, invoiceNumber: parts[3].trim(), invoiceDate: formatDate(parts[5].trim()), // 注意parts[4]金额parts[5]日期 amount: parts[4].trim(), }; }踩坑不同版本发票二维码字段顺序不同新版电子发票 parts[4] 是金额parts[5] 才是日期不要搞反。4. 从 PDF 文本中提取结构化字段这是最麻烦的部分。不同发票 PDF 的文本提取顺序差异很大新版电子发票标签和值分离名称标签在前半段公司名在后半段旧版专票标签值紧邻名称: XXX科技有限公司部分发票销售方在购买方前面出现布局不同针对这些差异我的处理策略// 优先匹配名称: XXX公司紧邻格式 const nameInline [...t.matchAll( /名称[:]\s*([\u4e00-\u9fa5()][^\d:\n]{2,40}?(?:有限公司|股份公司|分公司|个体工商户|餐厅))/g )]; // 通过购买方/销售方标签位置判断顺序 const buyerLabelPos t.search(/购\s*买\s*方/); const sellerLabelPos t.search(/销\s*售\s*方/); const sellerFirst buyerLabelPos sellerLabelPos; // 旧版专票销售方在前 if (nameInline.length 2) { result.buyerName sellerFirst ? nameInline[1][1] : nameInline[0][1]; result.sellerName sellerFirst ? nameInline[0][1] : nameInline[1][1]; }税号同理通过标签位置判断哪个是购买方哪个是销售方const taxRe /\b([0-9A-Z]{15,20})\b/g; const taxes [...t.matchAll(taxRe)]; if (buyerPos sellerPos) { // 销售方先出现 result.sellerTaxId taxes[0][1]; result.buyerTaxId taxes[1][1]; } else { result.buyerTaxId taxes[0][1]; result.sellerTaxId taxes[1][1]; }5. 图片发票走 OCR图片发票没有文字层用 Tesseract.js 识别const worker await Tesseract.createWorker(chi_simeng, 1, {}); const { data: { text } } await worker.recognize(canvas); await worker.terminate();OCR 识别出来的文本每个字之间有空格所以正则要先 text.replace(/\s/g, ) 去掉所有空白再匹配。批量处理核心是维护一个文件队列逐一处理async function startBatchScan() { const pending fileQueue.filter(q q.status pending); for (let i 0; i pending.length; i) { const item pending[i]; item.status processing; try { const data await processFile(item.file, item.type); item.status done; results.push({ fileName: item.file.name, data }); } catch (e) { item.status error; results.push({ fileName: item.file.name, error: e.message }); } renderResultTable(); // 每识别一张就更新表格 } }效果实测下来新版电子发票 PDF 识别准确率很高发票号码、金额、购买方/销售方基本都能正确提取。图片识别因为 OCR 精度问题税号偶尔会有字符识别错误。识别结果支持导出 CSV带 BOM 头Excel 直接打开中文不乱码const blob new Blob([\uFEFF csv], { type: text/csv;charsetutf-8 });总结整个方案完全在浏览器端运行核心依赖pdf.js 解析 PDF 文字层和渲染页面jsQR 扫描二维码Tesseract.js 处理图片 OCR最麻烦的是不同发票格式的兼容需要针对各种布局写不同的正则策略。如果你也有类似需求可以参考这个思路或者直接用我做好的在线工具试试效果发票批量识别工具。如有问题欢迎评论区交流。

相关文章:

纯前端实现发票二维码批量识别——PDF.js + jsQR 实战

最近在做财务报销相关的需求,需要从大量电子发票 PDF 中提取发票号码、购买方、销售方、金额等信息。手动复制粘贴效率极低,于是研究了一下能不能纯前端实现自动识别。 折腾了几天,最终用 PDF.js jsQR Tesseract.js 实现了一个完全在浏览器…...

面试绝杀!大模型必考题:多轮对话+上下文优化,满分答案直接背

做过大模型应用开发的都懂,面试只要聊到对话系统,这道题100%会被问到:面试官:大模型多轮对话怎么实现?聊久了上下文太长,该怎么优化?身边太多求职者栽在这道题上:要么答得零零散散没…...

四轮独立驱动汽车自动轨迹跟踪+横向稳定性控制:CarSim与Simulink联合控制之MPC控...

四轮独立驱动汽车自动轨迹跟踪横向稳定性控制 CarSim与Simulink联合 控制目标为对给定轨迹进行跟踪(不带轨迹规划)同时进行横向稳定性控制 上层控制器为MPC控制器,输出为附加横摆力矩和方向盘转角,采用了二自由度车辆模型 MPC控制器采用代码编写,原理一目…...

为什么共享 IP 会放大误封风险?

很多平台在面对刷号、爬虫、攻击流量时,最顺手的动作就是“先封 IP 再说”。这个动作在单用户、单出口的理想环境里看起来合理,但在今天的真实互联网里,一个 IP 往往并不只代表一个人。一旦出口被共享,IP 封禁就从“打击异常行为”…...

从零开始:OpenClaw汉化版v2026.4.1-zh.3 详细安装指南

适用版本:OpenClaw中文汉化版 v2026.4.1-zh.3(2026年4月最新稳定版) 支持系统:Ubuntu 22.04/Debian 11/macOS 14/Windows 10/11(WSL2推荐) 核心优势:100%全中文界面、国内网络优化、兼容所有官方…...

力扣热门100题之跳跃游戏

核心思路维护一个变量:当前能跳到的最远位置 maxReach遍历每一位:如果当前位置 已经跳不到了(i > maxReach),直接 return false更新 maxReach如果 maxReach > 最后一位下标,提前 return true解释i n…...

机器人全覆盖路径规划技术挑战与ROS BSA算法解决方案

机器人全覆盖路径规划技术挑战与ROS BSA算法解决方案 【免费下载链接】full_coverage_path_planner Full coverage path planning provides a move_base_flex plugin that can plan a path that will fully cover a given area 项目地址: https://gitcode.com/gh_mirrors/fu/…...

把 Running IDE Actions 真正用进 ADT 日常开发

很多人第一次在 ADT 里看到 IDE Action,会把它当成一个偏演示性质的小功能,觉得无非是在 Eclipse 里多塞了一个菜单项。真到项目里开始高频写 ABAP,尤其是做 RAP、CDS view entity、行为定义、扩展点实现、对象导航这些工作时,才会发现它其实很像一个可编排的开发入口。SAP…...

LEETCODE HOT 100 二分查找 C‘s Log

二分查找也是最重要的就是明确自己变换的前提,也就是到底是哪个闭,哪个开, 转化成下面这句话可以这么思考:关键不在于区间里的元素具有什么性质,而是区间外面的元素具有什么性质,这个也是我在刷B站的灵神课…...

伺服驱动器编码器信号(A+/A-,B+/B-,Z+/Z-)差分接线详解:从高创CDHD2到雷赛L8EC

伺服驱动器编码器差分信号接线实战指南:从原理到避坑 在工业自动化领域,伺服系统的精度和稳定性很大程度上取决于编码器信号的质量。A/A-、B/B-、Z/Z-这些看似简单的差分信号线,却是整个位置反馈系统的命脉。我曾亲眼见过一个价值数十万的生产…...

【仅限头部AI产品团队内部流通】:生成式AI A/B测试SOP 2.3版(含GPT-4o/ Claude-3实测对比模板与统计功效计算器)

第一章:生成式AI应用A/B测试方法论概览 2026奇点智能技术大会(https://ml-summit.org) 生成式AI应用的A/B测试远非传统Web界面实验的简单迁移——其核心挑战在于评估不可预测、多模态、上下文敏感的输出质量,而非仅统计点击率或转化率。需同步度量功能…...

Android 渲染引擎——SurfaceFlinger 合成流程与性能优化

1. SurfaceFlinger 的核心工作机制 SurfaceFlinger 是 Android 图形系统的中枢神经,负责将所有应用界面最终合成到屏幕上。想象它就像一个高效的餐厅后厨,接收各路厨师(应用)做好的菜品(图形缓冲区)&#…...

生成式AI容灾不是加台备用服务器!资深SRE拆解3类典型故障场景下的备份盲区

第一章:生成式AI容灾不是加台备用服务器!资深SRE拆解3类典型故障场景下的备份盲区 2026奇点智能技术大会(https://ml-summit.org) 生成式AI系统容灾的常见误区,是将传统无状态服务的“冷备负载均衡”模型直接套用到大模型推理/微调栈上。然…...

HP iLO4报错自救指南:Embedded Flash/SD-CARD故障的3种修复方案(附详细截图)

HP iLO4嵌入式存储故障深度修复手册:从应急处理到长效预防 当你看到iLO控制台右上角跳出"Self-Test reports a problem with: Embedded Flash/SD-CARD"的红色警告时,服务器管理界面突然变得不可靠——这种场景足以让任何运维人员心跳加速。作为…...

从广播星历到精密星历与钟差:GNSS数据文件格式解析与应用场景

1. GNSS数据文件入门:从广播星历到精密产品 刚接触GNSS数据处理时,我完全被各种文件格式搞晕了——brdc、sp3、clk这些后缀名就像天书。直到有次项目定位误差超标,才发现用错星历文件会导致厘米级误差。今天我们就用最直白的语言,…...

3.2 Java 运算符(字符串和字符的加操作)

一、核心概念在 Java 中, 运算符 不仅仅用于数值相加,它还具有 字符串拼接功能。 当表达式中包含 String 类型时, 会优先执行 字符串拼接 操作。关键点: 只要有一个操作数是 String,整个表达式就变成字符串拼接&#x…...

【C 语言系统入门教程】第 14 讲:深入理解指针 (4) | 零基础学习笔记

【C 语言系统入门教程】第 14 讲:深入理解指针 (4) | 零基础学习笔记 前言 本讲是指针进阶收官篇,聚焦字符指针、数组指针、二维数组传参、函数指针、函数指针数组、转移表六大高阶指针知识点,彻底打通 C 语言指针的最后壁垒,是…...

第17届蓝桥杯C语言B组省赛题目

2026年4月11日#include <stdio.h>int main() {long long N 2026202520242023;long long ans 0;for (long long i 0; i < 1013101260121012; i){if (N-i > i){ans;}else{return 0;}}printf("%lld", ans);return 0; }#include <stdio.h>long long…...

测试报告革命:用数据讲故事的艺术

在软件测试领域&#xff0c;一份标准的测试报告往往呈现为冰冷数据的堆砌&#xff1a;缺陷总数、严重等级分布、测试用例通过率、自动化覆盖率……这些数字精确地度量了测试活动&#xff0c;却常常在向产品经理、技术总监或业务方汇报时&#xff0c;遭遇尴尬的沉默。当汇报者逐…...

折腾Cursor这几周,我才发现之前编辑器都用错了

折腾Cursor这几周&#xff0c;我才发现之前编辑器都用错了 上个月还在用Codex的时候&#xff0c;朋友就天天安利Cursor。我心想不就是个套壳VS Code吗&#xff0c;能用出什么花来。 结果上周闲得无聊&#xff0c;装了一个试了试。 真香。 不是那种“哇好厉害”的感叹&#…...

Java全栈工程师面试实录:从技术到业务的深度解析

Java全栈工程师面试实录&#xff1a;从技术到业务的深度解析 1. 开场白 面试官&#xff1a;你好&#xff0c;很高兴见到你。我是负责技术评估的面试官&#xff0c;今天我们会围绕你的技术能力、项目经验以及对业务的理解来展开交流。你可以先简单介绍一下自己。 应聘者&#xf…...

2025最权威的AI论文助手横评

Ai论文网站排名&#xff08;开题报告、文献综述、降aigc率、降重综合对比&#xff09; TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek AI开题报告工具借助自然语言处理以及知识图谱技术&#xff0c;能够迅速剖析研究领域的热点之…...

长推理不一定更强:北航 × 字节提出SAGE-RL,挖出大模型隐藏天赋

大模型其实“心里有数”&#xff0c;天生具备高效推理的潜能。论文标题&#xff1a;Does Your Reasoning Model Implicitly Know When to Stop Thinking?研究团队&#xff1a;北航字节跳动联合研究论文地址&#xff1a;https://arxiv.org/abs/2602.08354项目主页&#xff1a;h…...

Houdini流体进阶:巧用VDB与Collision Source实现复杂容器碰撞(含静态对象设置)

Houdini流体进阶&#xff1a;巧用VDB与Collision Source实现复杂容器碰撞&#xff08;含静态对象设置&#xff09; 在影视级流体特效制作中&#xff0c;最令人头疼的莫过于液体与复杂几何体的交互问题。当你的咖啡需要流过一个镂空的金属滤网&#xff0c;或是红酒要注入造型奇特…...

避开这些坑,你的华为机考也能多拿100分:通软开发三道真题拆解与刷题策略

华为通用软件开发机考高分攻略&#xff1a;三道经典题型深度解析与实战技巧 第一次参加华为机考的程序员小王盯着屏幕上的三道题目&#xff0c;手指悬在键盘上方却迟迟敲不下去。距离考试结束还有40分钟&#xff0c;他的第一题代码已经反复修改了五次仍无法通过测试用例。这种场…...

告别自签名警告!用mkcert 1.4.1为本地开发环境一键搞定HTTPS证书(Windows/Linux保姆级教程)

告别自签名警告&#xff01;用mkcert 1.4.1为本地开发环境一键搞定HTTPS证书&#xff08;Windows/Linux保姆级教程&#xff09; 在本地开发Web应用时&#xff0c;HTTPS环境已经成为现代开发的标配需求。无论是测试PWA应用的Service Worker&#xff0c;调试OAuth 2.0授权流程&a…...

Python实战:打造高效GUI工具,实现BLF与ASC格式CAN数据的批量互转

1. 为什么汽车工程师需要BLF与ASC格式转换工具 在汽车电子开发和测试过程中&#xff0c;CAN总线数据记录是最基础也最重要的工作之一。工程师们每天都要处理大量的CAN日志文件&#xff0c;这些文件可能来自不同的测试设备、不同的软件工具&#xff0c;格式也各不相同。其中BLF&…...

超越Grad-CAM:用大核卷积论文技巧可视化你的CNN感受野(含Colab链接)

超越Grad-CAM&#xff1a;大核卷积时代的感受野可视化实战指南 当31x31大卷积核重新成为计算机视觉领域的热门话题时&#xff0c;我们突然发现传统可视化工具已经难以准确捕捉这种"巨无霸"卷积的真实感知能力。去年发表在CVPR上的突破性论文《Scaling Up Your Kernel…...

直播推流避坑指南:为什么你的抖音直播总卡顿?可能是选错了流类型

直播推流避坑指南&#xff1a;为什么你的抖音直播总卡顿&#xff1f;可能是选错了流类型 最近帮几个主播朋友排查直播卡顿问题&#xff0c;发现80%的案例都栽在同一个坑里——推流类型选择错误。明明用的是旗舰级设备&#xff0c;千兆宽带&#xff0c;OBS参数也调得飞起&#x…...

图卷积神经网络3-空域卷积:从GNN到PGC,核心思想与演进脉络解析

1. 空域图卷积的诞生背景 传统图像卷积操作在规则网格数据上表现出色&#xff0c;但当面对社交网络、分子结构这类不规则图数据时就会遇到根本性障碍。想象一下城市交通规划&#xff1a;图像处理就像在整齐的棋盘格上部署红绿灯&#xff0c;而图数据处理则要处理北京胡同里错综…...