目录

相机扫码场景

业务流程

Bitmap Mode相机扫码提供decode和decodeWithBitmap两种扫码接口。decode接口可以支持自定义相机输出的NV21图像数据,同时支持多码。decodeWithBitmap接口需要将相机图像转为Bitmap格式。2.11.0.300及以上版本推荐使用decode扫码接口,可以减少图像转换时间,提高相机扫码整体速度。

使用Bitmap相机扫码的主要业务流程如下:

  1. 用户打开App发起扫码请求。
  2. 校验是否有相机权限和文件读取权限。
  3. 权限验证通过后,调用华为统一扫码SDK的decode或decodeWithBitmap扫码接口。
  4. 返回扫码结果。
  5. 判断扫码结果是否有效,结果有效则处理扫码结果。如果接收到的“zoomValue”大于1.0,代表当前扫描的码过小,需要按照这个值调整焦距后重新扫码。
  6. App封装扫码结果返回给用户。

decode接口开发步骤

2.11.0.300及以上版本推荐使用。

  1. 获取相机一帧图像。

    “Java”
    // 将相机的data数组转化成ByteArrayOutputStream流。data为byte数组的实例,camera为android.hardware.Camera的实例
    YuvImage yuv = new YuvImage(data, ImageFormat.NV21, camera.getParameters().getPreviewSize().width,
            camera.getParameters().getPreviewSize().height, null);
    “Kotlin”
    // 将相机的data数组转化成ByteArrayOutputStream流。data为byte数组的实例,camera为android.hardware.Camera的实例
    val yuv = YuvImage(data, ImageFormat.NV21, camera.getParameters().getPreviewSize().width,
            camera.getParameters().getPreviewSize().height, null)

  2. 将获取到的YUV流转化为HmsScanFrame。

    “Java”
    HmsScanFrame frame= new HmsScanFrame(yuv);
    “Kotlin”
    val frame = HmsScanFrame(yuv)

  3. 初始化对应接口的选项。decode接口初始化HmsScanFrameOptions,设置支持识别的码制式;设置相机扫码;设置扫描单码或者多码;设置是否调用码值解析功能。

    • setHmsScanTypes(int type):设置码制式,默认识别Scan Kit支持的码制式,指定特定码制式,可以提高扫码速度。
    • setPhotoMode(boolean photoMode):设置Bitmap模式,默认值为fasle(相机扫码)。
    • setMultiMode(boolean multiMode):设置扫描单码或者多码,默认值为false(单码)。
    • setParseResult(boolean parseResul):设置是否调用码值解析功能,若只需要原始码值结果,需设置为false,可提高扫码速度,且识别结果条码格式getScanType()类型将返回纯文本。默认值为true(解析码值结果)。
    “Java”
    // “QRCODE_SCAN_TYPE”和“PDF417_SCAN_TYPE”表示只扫描QR和PDF417的码
    HmsScanFrameOptions option = new HmsScanFrameOptions.Creator().setHmsScanTypes(HmsScan.QRCODE_SCAN_TYPE| HmsScan.PDF417_SCAN_TYPE).setMultiMode(false).setParseResult(true).setPhotoMode(true).create();
    “Kotlin”
    // “QRCODE_SCAN_TYPE”和“PDF417_SCAN_TYPE”表示只扫描QR和PDF417的码
    val option = HmsScanFrameOptions.Creator().setHmsScanTypes(HmsScan.QRCODE_SCAN_TYPE| HmsScan.PDF417_SCAN_TYPE).setMultiMode(false).setParseResult(true).setPhotoMode(true).create()

  4. 调用ScanUtil的静态方法decode发起扫码请求并获取扫码结果对象HmsScanResult,其中包含的信息请参见码值解析。

    • 如果您不需要指定只检测特定的码制式,此处的“options”可以置为“null”。
    • 如果扫描的码过小,Scan Kit会返回调整相机焦距的指令给App,需要App调整相机以便于获取到清晰的码图。
    “Java”
    HmsScanResult result = ScanUtil.decode(BitmapActivity.this, frame, option);
    HmsScan[] hmsScans = result.getHmsScans();
    // 扫码成功时处理解码结果
    if (hmsScans != null && hmsScans.length > 0 && !TextUtils.isEmpty(hmsScans[0].getOriginalValue())) {
        // 展示扫码结果
        ...
    }
    // zoomValue大于1.0时,根据getZoomValue()调整焦距重新扫码
    if (hmsScans != null && hmsScans.length > 0 && TextUtils.isEmpty(hmsScans[0].getOriginalValue()) && hmsScans[0].getZoomValue() != 1.0) {
        // 设置相机焦距,相机重新生成Bitmap继续扫码(convertZoomInt()将放大倍数转化为相机接收的焦距参数)
        Camera.Parameters parameters= camera.getParameters();
        parameters.setZoom(convertZoomInt(hmsScans[0].getZoomValue()));
        camera.setParameters(parameters);
    }
    “Kotlin”
    val hmsScansResult= ScanUtil.decode(this@BitmapActivity, frame, options)
    val hmsScans = hmsScansResult.hmsScans
    // 扫码成功时处理解码结果
    if (hmsScans != null && hmsScans.size > 0 && !TextUtils.isEmpty(hmsScans[0].getOriginalValue())) {
        // 展示扫码结果
        ...
    }
    // zoomValue大于1.0时,根据getZoomValue()调整焦距重新扫码
    if (hmsScans != null && hmsScans.size > 0 && TextUtils.isEmpty(hmsScans[0].getOriginalValue()) && hmsScans[0].getZoomValue() != 1.0) {
        // 设置相机焦距,相机重新生成Bitmap继续扫码(convertZoomInt()将放大倍数转化为相机接收的焦距参数)
        var parameters= camera.getParameters()
        parameters.setZoom(convertZoomInt(hmsScans[0].getZoomValue()))
        camera.setParameters(parameters)
    }

decodeWithBitmap接口开发步骤

  1. 获取相机一帧图像。

    “Java”
    // 将相机的data数组转化成ByteArrayOutputStream流。data为byte数组的实例,camera为android.hardware.Camera的实例
    YuvImage yuv = new YuvImage(data, ImageFormat.NV21, camera.getParameters().getPreviewSize().width,
            camera.getParameters().getPreviewSize().height, null);
    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    yuv.compressToJpeg(new Rect(0, 0, camera.getParameters().getPreviewSize().width,
            camera.getParameters().getPreviewSize().height), 100, stream);
    “Kotlin”
    // 将相机的data数组转化成ByteArrayOutputStream流。data为byte数组的实例,camera为android.hardware.Camera的实例
    val yuv = YuvImage(data, ImageFormat.NV21, camera.getParameters().getPreviewSize().width,
            camera.getParameters().getPreviewSize().height, null)
    val stream = ByteArrayOutputStream()
    yuv.compressToJpeg(Rect(0, 0, camera.getParameters().getPreviewSize().width,
            camera.getParameters().getPreviewSize().height), 100, stream)

  2. 将获取到的ByteArrayOutputStream流转化为Bitmap。

    “Java”
    Bitmap bitmap = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.toByteArray().length);
    “Kotlin”
    val bitmap = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.toByteArray().size)

  3. 初始化HmsScanAnalyzerOptions,设置支持识别的码制式,设置Bitmap模式为相机扫码。

    您可以通过如下方式设置可选参数。

    “Java”
    // “QRCODE_SCAN_TYPE”和“DATAMATRIX_SCAN_TYPE”表示只扫描QR和DataMatrix的码
    HmsScanAnalyzerOptions options = new HmsScanAnalyzerOptions.Creator().setHmsScanTypes(HmsScan.QRCODE_SCAN_TYPE, HmsScan.DATAMATRIX_SCAN_TYPE).setPhotoMode(false).create();
    “Kotlin”
    // “QRCODE_SCAN_TYPE”和“DATAMATRIX_SCAN_TYPE”表示只扫描QR和DataMatrix的码
    val options = HmsScanAnalyzerOptions.Creator().setHmsScanTypes(HmsScan.QRCODE_SCAN_TYPE, HmsScan.DATAMATRIX_SCAN_TYPE).setPhotoMode(false).create()

  4. 调用ScanUtil的静态方法decodeWithBitmap发起扫码请求并获取扫码结果对象HmsScan,其中包含的信息请参见码值解析。

    • 如果您不需要指定只检测特定的码制式,此处的“options”可以置为“null”。
    • 如果扫描的码过小,Scan Kit会返回调整相机焦距的指令给App,需要App调整相机以便于获取到清晰的码图。
    “Java”
    HmsScan[] hmsScans = ScanUtil.decodeWithBitmap(BitmapActivity.this, bitmap, options);
    // 扫码成功时处理解码结果
    if (hmsScans != null && hmsScans.length > 0 && !TextUtils.isEmpty(hmsScans[0].getOriginalValue())) {
        // 展示扫码结果
        ...
    }
    // zoomValue大于1.0时,根据getZoomValue()调整焦距重新扫码
    if (hmsScans != null && hmsScans.length > 0 && TextUtils.isEmpty(hmsScans[0].getOriginalValue()) && hmsScans[0].getZoomValue() != 1.0) {
        // 设置相机焦距,相机重新生成Bitmap继续扫码(convertZoomInt()将放大倍数转化为相机接收的焦距参数)
        Camera.Parameters parameters= camera.getParameters();
        parameters.setZoom(convertZoomInt(hmsScans[0].getZoomValue()));
        camera.setParameters(parameters);
    }
    “Kotlin”
    val hmsScans = ScanUtil.decodeWithBitmap(this@BitmapActivity, bitmap, options)
    // 扫码成功时处理解码结果
    if (hmsScans != null && hmsScans.size > 0 && !TextUtils.isEmpty(hmsScans[0].getOriginalValue())) {
        // 展示扫码结果
        ...
    }
    // zoomValue大于1.0时,根据getZoomValue()调整焦距重新扫码
    if (hmsScans != null && hmsScans.size > 0 && TextUtils.isEmpty(hmsScans[0].getOriginalValue()) && hmsScans[0].getZoomValue() != 1.0) {
        // 设置相机焦距,相机重新生成Bitmap继续扫码(convertZoomInt()将放大倍数转化为相机接收的焦距参数)
        var parameters= camera.getParameters()
        parameters.setZoom(convertZoomInt(hmsScans[0].getZoomValue()))
        camera.setParameters(parameters)
    }
    “convertZoomInt()”方法实现示例代码:
    “Java”
    public int convertZoomInt(double zoomValue) {
        // 计算相机预览缩放值,parameters为相机参数
        List<Integer> allZoomRatios = parameters.getZoomRatios();
        float maxZoom = Math.round(allZoomRatios.get(allZoomRatios.size() - 1) / 100f);
        if (zoomValue >= maxZoom) {
            return allZoomRatios.size() - 1;
        }
        for (int i = 1; i  < allZoomRatios.size(); i++) {
            if (allZoomRatios.get(i) >= (zoomValue * 100) && allZoomRatios.get(i - 1) <= (zoomValue * 100)) {
                return i;
            }
        }
        return -1;
    }
    “Kotlin”
    public fun convertZoomInt(zoomValue:Double):Int {    
        // 计算相机预览缩放值,parameters为相机参数
        val allZoomRatios = parameters.getZoomRatios()
        val maxZoom = Math.round(allZoomRatios.get(allZoomRatios.size() - 1) / 100f)
        if (zoomValue >= maxZoom) {
            return allZoomRatios.size() - 1
        }
        for (i in 1 until allZoomRatios.size) {
            if (allZoomRatios.get(i) >= (zoomValue * 100) && allZoomRatios.get(i - 1) <= (zoomValue * 100)) {
                return i
            }
        }
        return -1
    }