JavaScript实现读取条码中的二进制数据

 更新时间:2024年03月21日 14:36:45   作者:xulihang  
条码是一种以机器可读的可视形式表示数据的方法,我们可以从条码获取二进制数据,并通过不同方法去读码,下面我们就来看看如何实现读取条码中的二进制数据吧
(福利推荐:【腾讯云】服务器最新限时优惠活动,云服务器1核2G仅99元/年、2核4G仅768元/3年,立即抢购>>>:9i0i.cn/qcloud

(福利推荐:你还在原价购买阿里云服务器?现在阿里云0.8折限时抢购活动来啦!4核8G企业云服务器仅2998元/3年,立即抢购>>>:9i0i.cn/aliyun

条码是一种以机器可读的可视形式表示数据的方法。条码种类繁多,主要分为一维码和二维码。

我们可以从条码获取二进制数据,并通过不同方法去读码。例如,在EAN-13中,位于其右边的代码1110010代表数字0。而QR码,它是二维的,可以存储更多的数据,有几种表示数据的模式:

输入模式模式标识最大字符数允许的字符,默认编码
仅数字17,0890、1、2、3、4、5、6、7、8、9
字母与数字24,2960-9、A-Z(仅限大写)、空格、$、%、*、+、-、..、/、:
二进制/字节42,953ISO/IEC 8859-1
日语汉字/假名81,817Shift JIS X 0208
结构化追加3无限没有限定

PS:结构化追加(Structured Append)是一种将数据分到多个条码的模式。

在本文中,我们将创建一个用于读取条码二进制数据的JavaScript库,并重点处理QR码,因为这种码型有多种模式。

Dynamsoft Barcode Reader会被用于读取条码。

新建项目

使用Vite创建一个新的TypeScript项目:

npm create vite@latest BarcodeDataReader -- --template vanilla-ts

编写定义

为读取条码的二进制数据定义几个接口和一个枚举。

定义BarcodeDetail接口:

export interface BarcodeDetail {
  mode?:number; //The data encoding mode
  model?:number; //Number of models
  errorCorrectionLevel?:number;
  columns?:number; //The column count
  rows?:number; //The row count
  page?:number; //Position of the particular code in structured append codes
  totalPage?:number; //Total number of structured append codes
  parityData?:number; //A value obtained by XORing byte by byte the ASCII/JIS values of all the original input data before division into symbol blocks.
  version?:number; //The version of the code.
}

定义Barcode接口:

export interface Barcode {
  bytes:Uint8Array;
  details:BarcodeDetail;
  barcodeType?:string;
}

二进制数据存储为Uint8Array

定义ReadingResult接口:

export interface ReadingResult {
  text?:string;
  img?:HTMLImageElement;
  blob?:Blob;
}

我们可以得到纯文本、HTML图像元素或blob这三种类型的结果。

类型需要在DataType中指定。

export enum DataType {
  text = 0,
  image = 1,
  unknown = 2
}

创建一个读取二进制数据的类

使用以下模板创建一个新的BarcodeDataReader.ts文件:

export class BarcodeDataReader{
  async read(barcodes:Barcode[],dataType:DataType):Promise<ReadingResult[]>{
    if (barcodes.length == 0) {
      throw new Error("No barcodes given");
    }
    let results:ReadingResult[] = [];
    return results;
  }
}

根据不同模式读取二进制数据。

async read(barcodes:Barcode[],dataType:DataType):Promise<ReadingResult[]>{
  if (barcodes.length == 0) {
    throw new Error("No barcodes given");
  }
  let results:ReadingResult[] = [];
  const mode = barcodes[0].details.mode;
  if (mode == 1) {
    results = this.readNumericBarcodes(barcodes);
  }else if (mode == 2) {
    results = this.readAlphaNumericBarcodes(barcodes);
  }else if (mode == 4) {
    results = await this.readByteEncodingBarcodes(barcodes,dataType);
  }else if (mode == 8) {
    results = this.readKanjiBarcodes(barcodes);
  }else if (mode == 3) {
    results = await this.readStructuredAppendBarcodes(barcodes,dataType);
  }else {
    results = await this.readByteEncodingBarcodes(barcodes,DataType.text);
  }
  return results;
}

实现对数字、字母与数字和日文汉字模式的读取。这三种模式的数据都是纯文本,它们可以共享类似的逻辑。

private readAlphaNumericBarcodes(barcodes:Barcode[]):ReadingResult[]{
  return this.decodeText(barcodes,"ASCII");
}

private readNumericBarcodes(barcodes:Barcode[]):ReadingResult[]{
  return this.decodeText(barcodes,"ASCII");
}

private readKanjiBarcodes(barcodes:Barcode[]):ReadingResult[]{
  return this.decodeText(barcodes,"SHIFT-JIS");
}

private decodeText(barcodes:Barcode[],encoding:string){
  let results:ReadingResult[] = [];
  for (let index = 0; index < barcodes.length; index++) {
    const barcode = barcodes[index];
    const decoder = new TextDecoder(encoding);
    const text = decoder.decode(barcode.bytes);
    let result = {
      text:text
    }
    results.push(result);
  }
  return results;
}

以字节模式读取数据。

由于字节模式下的数据类型未知,我们需要根据用户指定的数据类型获取读取结果。

如果数据类型是文本,我们需要检测编码。这里使用chardet库进行检测。

private async readByteEncodingBarcodes(barcodes:Barcode[],dataType:DataType):Promise<ReadingResult[]>{
  let results:ReadingResult[] = [];
  for (let index = 0; index < barcodes.length; index++) {
    const barcode = barcodes[index];
    let result:ReadingResult = await this.getResultBasedOnDataType(barcode.bytes,dataType);
    results.push(result);
  }
  return results;
}

async getResultBasedOnDataType(data:Uint8Array,dataType:DataType) {
  let result:ReadingResult;
  if (dataType == DataType.text) {
    const charset = chardet.analyse(data);
    const decoder = new TextDecoder(charset[0].name);
    const text = decoder.decode(data);
    result = {
      text:text
    }
  }else if (dataType == DataType.image) {
    const img = await this.getImageFromUint8Array(data);
    result = {
      img:img
    }
  }else{
    result = {
      blob:this.getBlobFromUint8Array(data)
    }
  }
  return result;
}

getBlobFromUint8Array(data:Uint8Array) {
  return new Blob([data]);
}
getImageFromUint8Array(data:Uint8Array):Promise<HTMLImageElement>{
  return new Promise<HTMLImageElement>((resolve, reject) => {
    const img = document.createElement("img");  
    const blob = this.getBlobFromUint8Array(data);
    img.onload = function(){
      resolve(img);
    }
    img.onerror = function(error) {
      console.error(error);
      reject(error);
    }
    img.src = URL.createObjectURL(blob);
    console.log(img.src)
  })
}

以结构化追加模式读取数据。

需要根据页码对条码进行排序,将多个码的数据合并成一个Unit8Array,然后得到结果。

private async readStructuredAppendBarcodes(barcodes:Barcode[],dataType:DataType):Promise<ReadingResult[]>{
  let results:ReadingResult[] = [];
  barcodes.sort((a, b) => (a.details.page ?? 0) - (b.details.page ?? 0))
  let concatedData:Uint8Array = new Uint8Array();
  for (let index = 0; index < barcodes.length; index++) {
    const barcode = barcodes[index];
    let merged = new Uint8Array(barcode.bytes.length + concatedData.length);
    merged.set(concatedData);
    merged.set(barcode.bytes, concatedData.length);
    concatedData = merged;
  }
  let result = await this.getResultBasedOnDataType(concatedData,dataType);
  results.push(result);
  return results;
}

读取测试

然后,我们可以更新index.html,使用Dynamsoft Barcode Reader读取QR码,并使用我们编写的库读取二进制数据。

以下是基本代码:

let router = await Dynamsoft.CVR.CaptureVisionRouter.createInstance();
//read barcodes from an image
let result = await router.capture(document.getElementById("image"),"ReadBarcodes_Balance");
let dataType = document.getElementById("dataTypeSelect").selectedIndex;
let barcodes = [];
for (let index = 0; index < result.items.length; index++) {
  const item = result.items[index];
  if (item.type === Dynamsoft.Core.EnumCapturedResultItemType.CRIT_BARCODE) {
    let data = new Uint8Array(item.bytes.length);
    data.set(item.bytes);
    let barcode = {
      bytes:data,
      details:item.details
    }
    barcodes.push(barcode);
  }
}

let results = await dataReader.read(barcodes,dataType)
console.log(results);

可以访问在线演示进行试用。

如果手头没有二维码,可以使用此文中的二维码和二维码生成器。

下面是读取两个二维码的测试截图,一张图片被编码在这两个二维码中:

打包为库

为了便于使用,我们可以将其作为库发布到NPM上。

安装devDependencies

npm install -D @types/node vite-plugin-dts

创建一个新的vite.config.ts文件:

// vite.config.ts
import { resolve } from 'path';
import { defineConfig } from 'vite';
import dts from 'vite-plugin-dts';
// https://vitejs.dev/guide/build.html#library-mode
export default defineConfig({
  build: {
    lib: {
      entry: resolve(__dirname, 'src/index.ts'),
      name: 'barcode-data-reader',
      fileName: 'barcode-data-reader',
    },
  },
  plugins: [dts()],
});

将我们的包的入口点添加到package.json

{
  "main": "./dist/barcode-data-reader.umd.cjs",
  "module": "./dist/barcode-data-reader.js",
  "types": "./dist/index.d.ts",
  "exports": {
    "import": {
      "types": "./dist/index.d.ts",
      "default": "./dist/barcode-data-reader.js"
    },
    "require": {
      "types": "./dist/index.d.ts",
      "default": "./dist/barcode-data-reader.umd.cjs"
    }
  },
  "files": [
    "dist/*.css",
    "dist/*.js",
    "dist/*.cjs",
    "dist/*.d.ts"
  ]
}

运行npm run build。然后,我们可以在dist文件夹中看到打包好的文件。

源代码

欢迎下载源代码并尝试使用:

github.com/tony-xlh/barcode-data-reader

以上就是JavaScript实现读取条码中的二进制数据的详细内容,更多关于JavaScript读取条码二进制数据的资料请关注程序员之家其它相关文章!

相关文章

  • 使用window.prompt()实现弹出用户输入的对话框

    使用window.prompt()实现弹出用户输入的对话框

    window对象的最后一种对话框是提示对话框,它显示了预先设置的信息并提供文本域供用户输入应答。它包括两个按钮,即Cancel和Ok,允许用户用两个相反的期望值来关闭这个对话框:取消整个操作或接收输入到对话框中的文本
    2015-04-04
  • JavaScript 继承详解及示例代码

    JavaScript 继承详解及示例代码

    本文主要介绍JavaScript 继承的知识,这里整理了详细的资料及简单示例代码,帮助大家学习参考,有兴趣的小伙伴可以参考下
    2016-09-09
  • 原生JS实现随机点名项目的实例代码

    原生JS实现随机点名项目的实例代码

    这篇文章主要介绍了原生JS实现随机点名项目的实例代码,非常不错,具有一定的参考借鉴价值,需要的朋友参考下吧
    2019-04-04
  • js模拟实现烟花特效

    js模拟实现烟花特效

    这篇文章主要为大家详细介绍了js模拟实现烟花特效,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-03-03
  • js实现贪吃蛇小游戏

    js实现贪吃蛇小游戏

    这篇文章主要为大家详细介绍了js实现贪吃蛇小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-10-10
  • 用XMLDOM和ADODB.Stream实现base64编码解码实现代码

    用XMLDOM和ADODB.Stream实现base64编码解码实现代码

    用 XMLDOM 和 ADODB.Stream 实现base64编码解码实现代码,需要的朋友可以参考下。
    2010-11-11
  • JavaScript+Canvas实现绘制音频可视化波形图

    JavaScript+Canvas实现绘制音频可视化波形图

    这篇文章主要为大家详细介绍了如何利用JavaScript和Canvas实现绘制音频可视化波形图,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-02-02
  • JavaScript ParseFloat()方法

    JavaScript ParseFloat()方法

    parseFloat()方法可以解析一个字符串,并返回一个浮点数。本文给大家分享javascript parsefloat()方法的相关知识,对javascript parsefloat相关知识感兴趣的朋友一起学习吧
    2015-12-12
  • 弹出广告特效(一个IP只弹出一次)的代码

    弹出广告特效(一个IP只弹出一次)的代码

    弹出广告特效(一个IP只弹出一次)的代码...
    2007-07-07
  • 微信小程序倒计时功能实例代码

    微信小程序倒计时功能实例代码

    这篇文章主要介绍了微信小程序倒计时功能实例代码,当单击按钮弹出一个半透明的弹出层,在规定时间内激活关闭按钮,关闭弹出层。需要的朋友可以参考下
    2018-07-07

最新评论

?


http://www.vxiaotou.com