Android 二维码相关(三)

Android 二维码相关(三)

本篇文章主要讲下二维码扫描相关.

1: 权限相关

由于文中需要使用Camera以及surfaceview,所以我们需要提前申请相机权限:

java 复制代码
<uses-permission android:name="android.permission.CAMERA" />

2: 添加SurfaceView预览

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ScanActivity">
    <SurfaceView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:id="@+id/surface"
        />
</androidx.constraintlayout.widget.ConstraintLayout>

3: 初始化相机

通过SurfaceView我们获取SurfaceHolder:

java 复制代码
surfaceView = findViewById(R.id.surface);
SurfaceHolder holder = surfaceView.getHolder();
holder.addCallback(new SurfaceHolder.Callback() {
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {

    }
});
  1. surfaceCreated中我们初始化相机配置
  2. surfaceDestroyed 中我们重置参数
3.1 startCamera()
java 复制代码
private void startCamera() {
    Camera open = Camera.open();
    Camera.Parameters parameters = open.getParameters();
    parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
    open.setParameters(parameters);
    open.setDisplayOrientation(90);
    open.setPreviewCallback(new Camera.PreviewCallback() {
            @Override
            public void onPreviewFrame(byte[] data, Camera camera) {
                
            }
    });
    try {
        open.setPreviewDisplay(surfaceView.getHolder());
        open.startPreview();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
3.2 stopCamera()
java 复制代码
private void stopCamera() {
    if (open != null) {
        open.stopPreview();
        open.setPreviewCallback(null);
        open.release();
        open = null;
    }
}
3.3 Camera.PreviewCallback

具体的解析方法,以及数据来源根据Camera.PreviewCallback 的回调来实现:

  1. 获取数据的宽高

    java 复制代码
    Camera.Size previewSize = camera.getParameters().getPreviewSize();
    int width = previewSize.width;
    int height = previewSize.height;
  2. 将预览数据转换为二进制位图

    java 复制代码
     PlanarYUVLuminanceSource planarYUVLuminanceSource = new PlanarYUVLuminanceSource(data, width, height, 0, 0, width, height, false);
     BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(planarYUVLuminanceSource));
  3. 设置解码参数

    java 复制代码
    EnumMap<DecodeHintType, Object> decodeHintTypeObjectEnumMap = new EnumMap<>(DecodeHintType.class);
    Collection<BarcodeFormat> list = new ArrayList<>();
    list.addAll(EnumSet.of(BarcodeFormat.QR_CODE));
    decodeHintTypeObjectEnumMap.put(DecodeHintType.POSSIBLE_FORMATS, list);
  4. 解码

    创建MultiFormatReader对象,用于解码.并通过setHints方法设置解码格式

    java 复制代码
    MultiFormatReader multiFormatReader = new MultiFormatReader();
    multiFormatReader.setHints(decodeHintTypeObjectEnumMap);
    try {
        Result decode = multiFormatReader.decode(binaryBitmap);
        String text = decode.getText();
        Log.i("xxxxx", "onPreviewFrame: " + text);
    } catch (Throwable e) {
        Log.e("xxxxx", "onPreviewFrame: ", e);
    }

注: onPreviewFrame是Android相机预览帧回调函数,它会在每一帧预览数据可用时被调用.

完整的代码如下:

java 复制代码
public class ScanActivity extends AppCompatActivity implements SurfaceHolder.Callback, Camera.PreviewCallback {
    private SurfaceView surfaceView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scan);
        surfaceView = findViewById(R.id.surface);
        SurfaceHolder holder = surfaceView.getHolder();
        holder.addCallback(this);
    }

    Camera open;

    private void startCamera() {
        Camera open = Camera.open();
        Camera.Parameters parameters = open.getParameters();
        parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
        open.setParameters(parameters);
        open.setDisplayOrientation(90);
        open.setPreviewCallback(this);
        try {
            open.setPreviewDisplay(surfaceView.getHolder());
            open.startPreview();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    private void stopCamera() {
        if (open != null) {
            open.stopPreview();
            open.setPreviewCallback(null);
            open.release();
            open = null;
        }
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        startCamera();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        stopCamera();
    }

    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
        if (camera == null || camera.getParameters() == null) return;
        Camera.Size previewSize = camera.getParameters().getPreviewSize();
        int width = previewSize.width;
        int height = previewSize.height;
        //预览数据转二进制位图
        PlanarYUVLuminanceSource planarYUVLuminanceSource = new PlanarYUVLuminanceSource(data, width, height, 0, 0, width, height, false);
        BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(planarYUVLuminanceSource));
        // 设置解码参数
        EnumMap<DecodeHintType, Object> decodeHintTypeObjectEnumMap = new EnumMap<>(DecodeHintType.class);
        Collection<BarcodeFormat> list = new ArrayList<>();
        list.addAll(EnumSet.of(BarcodeFormat.QR_CODE));
        decodeHintTypeObjectEnumMap.put(DecodeHintType.POSSIBLE_FORMATS, list);

        MultiFormatReader multiFormatReader = new MultiFormatReader();
        multiFormatReader.setHints(decodeHintTypeObjectEnumMap);
        try {
            Result decode = multiFormatReader.decode(binaryBitmap);
            String text = decode.getText();
            Log.i("xxxxx", "onPreviewFrame: " + text);
        } catch (Throwable e) {
            Log.e("xxxxx", "onPreviewFrame: ", e);
        }
    }
}
相关推荐
2501_9159214313 分钟前
常用iOS性能测试工具大全及使用指南
android·测试工具·ios·小程序·uni-app·cocoa·iphone
晨尘光14 分钟前
【Android下载gradle超时解决方法】
android
zhen_hong19 分钟前
ReactAgent原理
android·java·javascript
皮皮宋吖27 分钟前
皮皮宋渗透日记 11|文件包含漏洞全解析:LFI/RFI/ 伪协议 / 绕过 / 防御
android·安全
阿拉斯攀登32 分钟前
【无人售货柜・RK+YOLO】篇 6:安卓端落地!RK3576 + 安卓系统,YOLO RKNN 模型实时推理保姆级教程
android·人工智能·yolo·目标跟踪·瑞芯微·嵌入式驱动
只能是遇见1 小时前
ERROR 1524 (HY000) Plugin ‘mysql_native_password‘ is not loaded
android·数据库·mysql
helloworddm1 小时前
第一篇:设计模式在 Android 视频播放器中的实战应用
android·设计模式·音视频
恋猫de小郭1 小时前
Android 禁止侧载将正式实施,需要等待 24 小时冷静期
android·flutter·harmonyos
idealzouhu2 小时前
【Kotlin】 数据流完全指南:冷流、热流与 Android 实战
android·开发语言·kotlin
有位神秘人2 小时前
Android中Mvvm+Retrofit的常用网络架构记录
android·网络·retrofit