JavaScript實(shí)現(xiàn)讀取條碼中的二進(jìn)制數(shù)據(jù)
條碼是一種以機(jī)器可讀的可視形式表示數(shù)據(jù)的方法。條碼種類繁多,主要分為一維碼和二維碼。
我們可以從條碼獲取二進(jìn)制數(shù)據(jù),并通過不同方法去讀碼。例如,在EAN-13中,位于其右邊的代碼1110010代表數(shù)字0。而QR碼,它是二維的,可以存儲(chǔ)更多的數(shù)據(jù),有幾種表示數(shù)據(jù)的模式:
| 輸入模式 | 模式標(biāo)識(shí) | 最大字符數(shù) | 允許的字符,默認(rèn)編碼 |
|---|---|---|---|
| 僅數(shù)字 | 1 | 7,089 | 0、1、2、3、4、5、6、7、8、9 |
| 字母與數(shù)字 | 2 | 4,296 | 0-9、A-Z(僅限大寫)、空格、$、%、*、+、-、..、/、: |
| 二進(jìn)制/字節(jié) | 4 | 2,953 | ISO/IEC 8859-1 |
| 日語(yǔ)漢字/假名 | 8 | 1,817 | Shift JIS X 0208 |
| 結(jié)構(gòu)化追加 | 3 | 無限 | 沒有限定 |
PS:結(jié)構(gòu)化追加(Structured Append)是一種將數(shù)據(jù)分到多個(gè)條碼的模式。
在本文中,我們將創(chuàng)建一個(gè)用于讀取條碼二進(jìn)制數(shù)據(jù)的JavaScript庫(kù),并重點(diǎn)處理QR碼,因?yàn)檫@種碼型有多種模式。
Dynamsoft Barcode Reader會(huì)被用于讀取條碼。
新建項(xiàng)目
使用Vite創(chuàng)建一個(gè)新的TypeScript項(xiàng)目:
npm create vite@latest BarcodeDataReader -- --template vanilla-ts
編寫定義
為讀取條碼的二進(jìn)制數(shù)據(jù)定義幾個(gè)接口和一個(gè)枚舉。
定義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;
}
二進(jìn)制數(shù)據(jù)存儲(chǔ)為Uint8Array。
定義ReadingResult接口:
export interface ReadingResult {
text?:string;
img?:HTMLImageElement;
blob?:Blob;
}
我們可以得到純文本、HTML圖像元素或blob這三種類型的結(jié)果。
類型需要在DataType中指定。
export enum DataType {
text = 0,
image = 1,
unknown = 2
}
創(chuàng)建一個(gè)讀取二進(jìn)制數(shù)據(jù)的類
使用以下模板創(chuàng)建一個(gè)新的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;
}
}
根據(jù)不同模式讀取二進(jìn)制數(shù)據(jù)。
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;
}
實(shí)現(xiàn)對(duì)數(shù)字、字母與數(shù)字和日文漢字模式的讀取。這三種模式的數(shù)據(jù)都是純文本,它們可以共享類似的邏輯。
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;
}
以字節(jié)模式讀取數(shù)據(jù)。
由于字節(jié)模式下的數(shù)據(jù)類型未知,我們需要根據(jù)用戶指定的數(shù)據(jù)類型獲取讀取結(jié)果。
如果數(shù)據(jù)類型是文本,我們需要檢測(cè)編碼。這里使用chardet庫(kù)進(jìn)行檢測(cè)。
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)
})
}
以結(jié)構(gòu)化追加模式讀取數(shù)據(jù)。
需要根據(jù)頁(yè)碼對(duì)條碼進(jìn)行排序,將多個(gè)碼的數(shù)據(jù)合并成一個(gè)Unit8Array,然后得到結(jié)果。
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;
}
讀取測(cè)試
然后,我們可以更新index.html,使用Dynamsoft Barcode Reader讀取QR碼,并使用我們編寫的庫(kù)讀取二進(jìn)制數(shù)據(jù)。
以下是基本代碼:
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);
可以訪問在線演示進(jìn)行試用。
如果手頭沒有二維碼,可以使用此文中的二維碼和二維碼生成器。
下面是讀取兩個(gè)二維碼的測(cè)試截圖,一張圖片被編碼在這兩個(gè)二維碼中:

打包為庫(kù)
為了便于使用,我們可以將其作為庫(kù)發(fā)布到NPM上。
安裝devDependencies :
npm install -D @types/node vite-plugin-dts
創(chuàng)建一個(gè)新的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()],
});
將我們的包的入口點(diǎn)添加到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"
]
}
運(yùn)行npm run build。然后,我們可以在dist文件夾中看到打包好的文件。
源代碼
歡迎下載源代碼并嘗試使用:
github.com/tony-xlh/barcode-data-reader
以上就是JavaScript實(shí)現(xiàn)讀取條碼中的二進(jìn)制數(shù)據(jù)的詳細(xì)內(nèi)容,更多關(guān)于JavaScript讀取條碼二進(jìn)制數(shù)據(jù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
THREE.JS使用TransformControls對(duì)模型拖拽的代碼實(shí)例
拖拽是前端實(shí)現(xiàn)中比較常用的一種效果,下面這篇文章主要給大家介紹了關(guān)于THREE.JS使用TransformControls對(duì)模型拖拽的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-03-03
JavaScript使用PPTX2HTML實(shí)現(xiàn)PowerPoint轉(zhuǎn)HTML
PPTX2HTML是一個(gè)開源工具,用于將PowerPoint的.pptx文件轉(zhuǎn)換為HTML格式,支持多種對(duì)象類型和圖表的轉(zhuǎn)換,適用于企業(yè)培訓(xùn)、在線教育和團(tuán)隊(duì)技術(shù)文檔展示等場(chǎng)景,本文給大家詳細(xì)介紹了JavaScript如何使用PPTX2HTML實(shí)現(xiàn)PowerPoint轉(zhuǎn)HTML,需要的朋友可以參考下2025-12-12
javascript+mapbar實(shí)現(xiàn)地圖定位
地圖定位 圖吧地圖定位 附j(luò)avascript源碼每行都有注釋2010-04-04
javascript實(shí)現(xiàn)動(dòng)態(tài)側(cè)邊欄代碼
這篇文章主要介紹了javascript實(shí)現(xiàn)動(dòng)態(tài)側(cè)邊欄代碼,需要的朋友可以參考下2014-02-02
JS遠(yuǎn)程獲取網(wǎng)頁(yè)源代碼實(shí)例
獲取網(wǎng)頁(yè)源代碼的方法有很多,本文為大家介紹下使用JS是如何做到的,感興趣的朋友可以學(xué)習(xí)下哦2013-09-09
JavaScript取消Promise操作的常見實(shí)現(xiàn)方式
在 JavaScript 中,Promise 本身沒有內(nèi)置的取消機(jī)制,但我們可以通過一些模式來實(shí)現(xiàn)類似取消的功能,以下是幾種常見的實(shí)現(xiàn)方式,需要的朋友可以參考下2025-10-10

