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

ML Kit条码扫描报错:Invalid image data size 问题求助

解决Firebase ML Kit "Invalid image data size" 错误

这个错误的根源其实是你对Camera2输出的图像数据和Firebase ML Kit要求的输入格式理解有偏差,咱们一步步拆解问题:

错误原因分析

你现在的流程有两个关键错误:

  • Camera2图像数据处理错误:你从ImageReader获取的是YUV_420_888格式的图像,直接取planes[0]的buffer(这只是Y通道的灰度数据,不是完整图像),然后把它写成.jpg文件——这个文件根本不是合法的JPEG,只是原始Y通道的字节流。
  • Firebase ML Kit输入格式不匹配:你读回这个文件的字节流,告诉Firebase这是IMAGE_FORMAT_NV21格式的原始图像数据,但NV21格式需要的字节数是宽×高×3/2,而你传入的字节数只有宽×高(Y通道大小),大小完全不匹配,自然抛出Invalid image data size错误。

快速解决方法:直接用Firebase加载本地图片文件

最简单的修复方式是跳过手动处理字节数组和metadata的步骤,直接让Firebase从你保存的图片Uri加载图像——Firebase会自动处理编码、旋转、尺寸适配等问题,代码会简洁很多:

在第二个Activity中,替换你的字节数组处理代码为:

// 直接从Uri创建FirebaseVisionImage,无需手动处理字节和metadata
FirebaseVisionImage image;
try {
    image = FirebaseVisionImage.fromFilePath(getApplicationContext(), uri);
} catch (IOException e) {
    Log.e(TAG, "加载图片失败: " + e.getMessage());
    return;
}

// 剩下的检测代码保持不变
FirebaseVisionBarcodeDetectorOptions options = new FirebaseVisionBarcodeDetectorOptions.Builder()
        .setBarcodeFormats(FirebaseVisionBarcode.FORMAT_QR_CODE, FirebaseVisionBarcode.FORMAT_DATA_MATRIX)
        .build();
FirebaseVisionBarcodeDetector detector = FirebaseVision.getInstance().getVisionBarcodeDetector(options);

Task<List<FirebaseVisionBarcode>> result = detector.detectInImage(image);
// 处理检测结果...

同时,你需要修正第一个Activity中保存图片的代码——之前保存的不是合法JPEG,应该正确将Camera2的YUV图像转成JPEG再保存,或者直接让ImageReader输出JPEG格式:

修正Camera2的ImageReader配置

创建ImageReader时,指定格式为ImageFormat.JPEG,这样获取的Image就是已经编码好的JPEG数据,直接保存即可:

// 创建ImageReader时设置格式为JPEG,尺寸可以根据需求调整(比如1920×1080)
ImageReader imageReader = ImageReader.newInstance(1920, 1080, ImageFormat.JPEG, 1);
imageReader.setOnImageAvailableListener(onImageAvailableListener, backgroundHandler);

然后修正onImageAvailableListener中的保存逻辑:

private final ImageReader.OnImageAvailableListener onImageAvailableListener = new ImageReader.OnImageAvailableListener() {
    @Override
    public void onImageAvailable(ImageReader imageReader) {
        try {
            storeData.acquire();
            Image resultImg = imageReader.acquireNextImage();
            if (resultImg == null) {
                storeData.release();
                return;
            }

            // JPEG格式的Image直接取planes[0]的buffer就是完整的JPEG字节流
            ByteBuffer buffer = resultImg.getPlanes()[0].getBuffer();
            byte[] data = new byte[buffer.remaining()];
            buffer.get(data);

            String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
            File media = new File(mediaFile.getPath() + File.separator + "IMG_" + timeStamp + ".jpg");

            try (FileOutputStream fos = new FileOutputStream(media)) {
                fos.write(data);
                uri = Uri.fromFile(media);
            } catch (IOException e) {
                Log.e(TAG, "保存图片失败: " + e.getMessage());
            } finally {
                resultImg.close();
            }
        } catch (InterruptedException e) {
            Log.e(TAG, e.getMessage());
        } finally {
            storeData.release();
        }
    }
};

可选方案:处理原始YUV数据(如果需要)

如果你必须使用原始YUV数据传递给Firebase,需要将Camera2的YUV_420_888格式正确转换为NV21格式,再传递字节数组和对应的metadata:

YUV_420_888转NV21的工具方法

private byte[] yuv420ToNv21(Image image) {
    Image.Plane yPlane = image.getPlanes()[0];
    Image.Plane uPlane = image.getPlanes()[1];
    Image.Plane vPlane = image.getPlanes()[2];

    byte[] yBuffer = new byte[yPlane.getBuffer().remaining()];
    byte[] uBuffer = new byte[uPlane.getBuffer().remaining()];
    byte[] vBuffer = new byte[vPlane.getBuffer().remaining()];
    yPlane.getBuffer().get(yBuffer);
    uPlane.getBuffer().get(uBuffer);
    vPlane.getBuffer().get(vBuffer);

    // NV21格式是Y通道 + VU交织通道
    byte[] nv21 = new byte[yBuffer.length + uBuffer.length + vBuffer.length];
    System.arraycopy(yBuffer, 0, nv21, 0, yBuffer.length);

    // 因为YUV_420_888的U和V通道是平面的,需要交织成VU
    int uvIndex = yBuffer.length;
    for (int i = 0; i < uBuffer.length; i++) {
        nv21[uvIndex++] = vBuffer[i];
        nv21[uvIndex++] = uBuffer[i];
    }
    return nv21;
}

然后在第一个Activity中,传递转换后的NV21字节数组(或者保存为原始文件),并确保metadata中的格式和尺寸对应,这样Firebase就能正确处理了。

关于图片尺寸的补充

Firebase ML Kit对图片尺寸没有严格的上限,但过大的图片会增加检测时间和内存占用。如果你想捕获更小的图片,只需要在创建ImageReader时指定更小的尺寸即可(比如1280×720,甚至640×480),这样获取的图像数据量更小,检测速度也更快。

内容的提问来源于stack exchange,提问作者Michael

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:10:00