You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ZXing的BrowserMultiformatReader在React中解码失败原因排查

问题:ZXing无法解码上传的条码图片

组件可正常上传条码图片,但解码失败,报错:

Uncaught (in promise) NotFoundException2: No MultiFormat Readers were able to detect the code.

需求为上传任意格式的条码图片,在页面展示图片并返回条码文本内容,但ZXing无法识别目标条码格式。

原代码

import React, { useRef, useState } from 'react';
import { BrowserMultiFormatReader, BarcodeFormat, DecodeHintType, Result } from '@zxing/library';
import './BarcodeScanner.css'; // Importamos los estilos CSS

const BarcodeScanner: React.FC = () => {
    const fileInputRef = useRef<HTMLInputElement>(null);
    const [capturedImage, setCapturedImage] = useState<string | null>(null);
    const [barcodeResult, setBarcodeResult] = useState<string | null>(null);

    const captureImageFromFile = (file: File) => {
        try {
            const reader = new FileReader();
            reader.onload = async () => {
                console.log(reader.result);
                if (typeof reader.result === 'string') {
                    setCapturedImage(reader.result);
                    decodeBarcode(reader.result);
                }
            };
            reader.readAsDataURL(file);
         } catch (error) {
             setBarcodeResult("Error al decodificar");
             console.error('Error al decodificar el código de barras:', error);
         }
     };

    const decodeBarcode = async (imageSrc: string) => {
        try {
            const img = new Image();
            img.onload = async () => {
                const formats = [BarcodeFormat.EAN_13, BarcodeFormat.EAN_8];
                const hints = new Map();
                hints.set(DecodeHintType.POSSIBLE_FORMATS, formats);
                const codeReader = new BrowserMultiFormatReader(hints);
                codeReader.timeBetweenDecodingAttempts = 300;
                const result = await codeReader.decodeFromImage(img as HTMLImageElement);
                setBarcodeResult(result.getText());
            }
            img.src = imageSrc;
        } catch (error) {
            setBarcodeResult("Error al decodificar");
            console.error('Error al decodificar el código de barras:', error);
        }
    };

    const handleFileInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
        const file = event.target.files && event.target.files[0];
        if (file) {
            captureImageFromFile(file);
        }
    };

    return (
        <div>
            <h1>Captura de Imagen desde Archivo</h1>
            <div style={{ marginTop: '20px', textAlign: 'center' }}>
                <input type="file" accept="image/*" onChange={handleFileInputChange} ref={fileInputRef} style={{ display: 'none' }} />
                <button onClick={() => fileInputRef.current?.click()}>Seleccionar Archivo</button>
            </div>
            {capturedImage && (
                <div style={{ marginTop: '20px', textAlign: 'center' }}>
                    <h2>Captura Realizada</h2>
                    <img src={capturedImage} alt="Captura" style={{ maxWidth: '320px' }} />
                </div>
            )}
            {barcodeResult && (
                <div style={{ marginTop: '20px', textAlign: 'center' }}>
                    <h2>Resultado del Código de Barras</h2>
                    <p>{barcodeResult}</p>
                </div>
            )}
        </div>
    );
};

export default BarcodeScanner;

解决方案

1. 解除条码格式限制

原代码仅指定了EAN_13和EAN_8两种格式,若上传的条码不属于这两类,ZXing会直接识别失败。有两种处理方式:

  • 添加更多常用格式:把需要支持的条码类型加入formats数组(如QR_CODE、CODE_128等)
  • 自动检测所有格式:移除POSSIBLE_FORMATS的设置,让ZXing自动尝试所有支持的条码类型

示例(自动检测所有格式):

const decodeBarcode = async (imageSrc: string) => {
    try {
        // ... 其他代码
        const hints = new Map();
        // 移除这行格式限制代码:hints.set(DecodeHintType.POSSIBLE_FORMATS, formats);
        const codeReader = new BrowserMultiFormatReader(hints);
        // ... 其他代码
    } catch (error) {
        // ... 错误处理
    }
};

2. 修复图片加载的异步处理问题

原代码中img.onload的异步函数错误无法被外层try/catch捕获,改用Promise封装图片加载逻辑,确保错误能被正确处理:

const decodeBarcode = async (imageSrc: string) => {
    try {
        // 用Promise等待图片加载完成
        const img = await new Promise<HTMLImageElement>((resolve, reject) => {
            const imgElement = new Image();
            imgElement.onload = () => resolve(imgElement);
            imgElement.onerror = () => reject(new Error('图片加载失败'));
            imgElement.src = imageSrc;
        });
        // ... 解码逻辑
    } catch (error) {
        setBarcodeResult("解码失败");
        console.error('条码解码错误:', error);
    }
};

3. 优化解码兼容性

  • 若图片尺寸过大,可通过canvas压缩后再解码
  • 提示用户上传清晰、无反光、条码完整的图片

修改后的完整代码

import React, { useRef, useState } from 'react';
import { BrowserMultiFormatReader } from '@zxing/library';
import './BarcodeScanner.css';

const BarcodeScanner: React.FC = () => {
    const fileInputRef = useRef<HTMLInputElement>(null);
    const [capturedImage, setCapturedImage] = useState<string | null>(null);
    const [barcodeResult, setBarcodeResult] = useState<string | null>(null);

    const captureImageFromFile = (file: File) => {
        try {
            const reader = new FileReader();
            reader.onload = () => {
                if (typeof reader.result === 'string') {
                    setCapturedImage(reader.result);
                    decodeBarcode(reader.result);
                }
            };
            reader.readAsDataURL(file);
         } catch (error) {
             setBarcodeResult("解码失败");
             console.error('条码解码错误:', error);
         }
     };

    const decodeBarcode = async (imageSrc: string) => {
        try {
            const img = await new Promise<HTMLImageElement>((resolve, reject) => {
                const imgElement = new Image();
                imgElement.onload = () => resolve(imgElement);
                imgElement.onerror = () => reject(new Error('图片加载失败'));
                imgElement.src = imageSrc;
            });

            // 不限制格式,自动检测所有支持的条码类型
            const codeReader = new BrowserMultiFormatReader();
            
            const result = await codeReader.decodeFromImage(img);
            setBarcodeResult(result.getText());
        } catch (error) {
            setBarcodeResult("解码失败");
            console.error('条码解码错误:', error);
        }
    };

    const handleFileInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
        const file = event.target.files && event.target.files[0];
        if (file) {
            captureImageFromFile(file);
        }
    };

    return (
        <div>
            <h1>图片条码识别</h1>
            <div style={{ marginTop: '20px', textAlign: 'center' }}>
                <input type="file" accept="image/*" onChange={handleFileInputChange} ref={fileInputRef} style={{ display: 'none' }} />
                <button onClick={() => fileInputRef.current?.click()}>选择图片文件</button>
            </div>
            {capturedImage && (
                <div style={{ marginTop: '20px', textAlign: 'center' }}>
                    <h2>上传的图片</h2>
                    <img src={capturedImage} alt="上传的条码图片" style={{ maxWidth: '320px' }} />
                </div>
            )}
            {barcodeResult && (
                <div style={{ marginTop: '20px', textAlign: 'center' }}>
                    <h2>条码内容</h2>
                    <p>{barcodeResult}</p>
                </div>
            )}
        </div>
    );
};

export default BarcodeScanner;

内容的提问来源于stack exchange,提问作者Juan Carlos GIRARDINI

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 15:44:52