vue,js,html,识别带二维码的发票前端支持pdf转图片

        由于业务需求需要做一个发票识别内容,然后就有了这个文章。首先这个思路是识别图片上的二维码信息,扫码二维码之后,我们就可以得到发票的基础信息:1、发票类型;2、发票代码;3、发票号码;4、发票效验码;5、发票开具时间;6、发票金额。这些信息就是发票二维码包含的所有的信息了。

其中使用的前端插件:qrcode-decoder,pdfjs-dist(如果你不考虑识别pdf的内容也可以忽略此内容)。

  1. 监听文件发生改变
<el-upload
	class="upload-demo mt5"
	style="height: 268px; width: 99%"
	drag
	:show-file-list="false"
	:auto-upload="false"
	action="#"
	method="POST"
	ref="fileUploadRef"
	accept=".pdf,.jpg,.png,.jpeg"
	:on-change="fileChange"
>
	<el-icon class="el-icon--upload" style="font-size: 90px; line-height: 90px">
		<upload-filled />
	</el-icon>
	<div class="el-upload__text">拖拽或点击上传发票 <em>仅能自动识别支持带有二维码的发票</em></div>
	<div class="el-upload__text">支持格式:pdf、jpg、png等文件</div>
</el-upload>

2.监听方法

async function fileChange(rawFile) {
	let fileTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/jpg', 'application/pdf'];
	if (!fileTypes.includes(rawFile.raw.type)) {
		console.log('存在不支持的格式');
		return false;
	}
    // ts写法 可换成this
	imgUrl.value = null;
	pdfUrl.value = null;
    // 可以用于在浏览器上预览本地图片或者视频,文件
	let fileUrl = getObjectURL(rawFile.raw);
    // 判断是否是pdf,如果是pdf就需要转成图片在扫码
	if (rawFile.raw.type === 'application/pdf') {
		pdfUrl.value = fileUrl;
		await pdfToImg(rawFile.raw, img => {
			dealScanQrCode(img);
		});
	} else {
        // 如果是图片就直接扫描二维码
		imgUrl.value = fileUrl;
		dealScanQrCode(imgSrc.value);
	}
	return true;
}

3.封装扫描二维码 

// 扫描识别二维码的方法封装
function dealScanQrCode(imgSrc) {
    // 具体的扫描方法
	scanQrCode(null, imgSrc, data => {
		let dealCode = [];
        // data 是返回的数据 判断data是否有异常
		if (data) {
            //解析后的数据是01,10,044002015551,94449434,548.13,20221117,7649489616555713831,7W7C,
			dealCode = data.split(',');
            // 如果分个后小于6说明不是发票信息
			if (dealCode.length < 6) {
				dealCode = [];
			}
		}
		//  [0]占位符 [1]、发票类型{01增值税专用发票,04增值税普通发票,10增值税普通发票(电子),08增值税专用发票(电子)};
		//  [2]、发票代码;[3]、发票号码;[4]开票金额;[5]、发票开具时间;[6]表示发票校验码,增值税专用发票是没有发票校验码的,没有则为空字符串;
        // 解析数据
        let row ={};
		// 发票类型
		row .invoiceType = dealCode[1] || null;
		// 发票代码
		row.invoiceCode = dealCode[2] || null;
		// 发票号码
		row.invoiceNo = dealCode[3] || null;
		let invoiceTotal = dealCode[4] || null;
		if (invoiceTotal) {
			invoiceTotal = parseFloat(invoiceTotal);
		}
		// 开票金额
		row.invoiceTotal = invoiceTotal;
        // 这里是价税合计的算法 首先你得有税率 一般都是13%
		let invoiceTaxRatio = row.invoiceTaxRatio || null;
		if (invoiceTaxRatio && invoiceTaxRatio > 0 && invoiceTotal) {
			// costInvoiceTotal价税合计
			let num = invoiceTaxRatio / 100;
			let invoiceTaxTotal = (invoiceTotal * num).toFixed(2);
			row.costInvoiceTotal = parseFloat(invoiceTotal) + parseFloat(invoiceTaxTotal);
			// invoiceTaxTotal税额
			row.invoiceTaxTotal = parseFloat(invoiceTaxTotal);
		}
		// 发票开具时间
		let invoiceTime = dealCode[5] || null;
		if (invoiceTime) {
            // 转换开票金额
			invoiceTime = invoiceTime.replace(/^(\d{4})(\d{2})(\d{2})$/, '$1-$2-$3');
		}
		row.invoiceTime = invoiceTime;
	});
}

4.封装工具 utils.js

// 扫码插件
import QrCode from 'qrcode-decoder';
// pdf转图片
import * as pdfJs from 'pdfjs-dist';
// pdfworker地址
import * as pdfWorkerMin from 'pdfjs-dist/build/pdf.worker.min?url';
// 这里要初始化一下路由防止异常,不然转换的时候会报错
pdfJs.GlobalWorkerOptions.workerSrc = pdfWorkerMin.default;
/**
 * 文件转成预览链接
 * @param file
 * @returns {null}
 */
export const getObjectURL = file => {
	let url = null;
	if (window.createObjectURL !== undefined) {
		// basic
		url = window.createObjectURL(file);
	} else if (window.URL !== undefined) {
		// mozilla(firefox)
		url = window.URL.createObjectURL(file);
	} else if (window.webkitURL !== undefined) {
		// webkit or chrome
		url = window.webkitURL.createObjectURL(file);
	}
	return url;
};

/**
 * 识别二维码
 * @param file 文件
 * @param url 地址
 * @param callback 回调函数
 */
export const scanQrCode = (file, url, callback) => {
	// 获取临时路径
	let tempUrl = url || '';
	if (file) {
		tempUrl = getObjectURL(file);
	}
	// 初始化
	const qr = new QrCode();
	// 解析二维码,返回promise
	qr.decodeFromImage(tempUrl).then(res => {
		if (callback) {
			callback(res.data);
		}
	});
};
/**
 *  pdf转图片
 * @param file 文件信息
 * @param callBack 回调函数
 */
export const pdfToImg = (file, callBack) => {
	// 文件转获取pdf地址
	let url = getObjectURL(file);
	//这里是重点,然后将流数据转换为url,CMapReaderFactory方法在进行处理
	pdfJs.getDocument(url).promise.then(pdf => {
		// pdf多个文件的情况下
		for (let num = 1; num <= pdf.numPages; num++) {
			// 分页查询
			pdf.getPage(num).then(async page => {
				// 获取pdf具体数据
				const viewport = page.getViewport({ scale: 1.0 });
				// 创建画布
				const canvas = document.createElement('canvas');
				const context = canvas.getContext('2d');
				// 处理画布高宽
				canvas.height = viewport.height;
				canvas.width = viewport.width;
				// 读取数据进行画布转换
				page.render({ canvasContext: context, viewport: viewport }).promise.then(() => {
					if (callBack) {
						// 出发回调函数
						callBack(canvas.toDataURL('image/jpeg'));
						// 释放资源
						canvas.remove();
					}
				});
			});
		}
	});
};

注意!注意!注意 !

这里pdf转图片的时候是没有处理字符库的(会抛出异常信息,不影响操作),转换的后的发票图片是空白的没有具体的内容但是有二维码信息,如果你需要处理的话,请自行查询方法。

异常截图:

Warning: loadFont - translateFont failed: "UnknownErrorException: The CMap "baseUrl" parameter must be specified, ensure that the "cMapUrl" and "cMapPacked" API parameters are provided.".

5.预览

<!-- 图片直接用element的图片插件-->
<el-image v-if="imgUrl" :src="imgUrl" style="width: 100%; height: 268px" fit="contain">
	<template #placeholder>
		<div class="image-slot">加载中<span class="dot">...</span></div>
	</template>
</el-image>
<!-- pdf直接调用浏览器的预览-->
<iframe v-if="pdfUrl" :src="pdfUrl + `#toolbar=0&zoom=50 `" width="100%" height="268" frameborder="0" />

 - 图片直接用element的图片插件

- pdf直接调用浏览器的预览 这里携带了参数信息toolbar=0&zoom=50  ,toolbar=0代表不需要工具栏,zoom=50 是代表缩放了50%

End;

        由于项目实际应用中,发现识别成功率过低,而且扫描件经常识别不到二维码,或者带有icon的二维码,识别率也惨不忍睹,后面引入了opencv-js-qrcode进行再次优化提升,提高了识别率。

vue,js,html 根据 opencv-js-qrcode 识别发票二维码信息-CSDN博客

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值