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);
        }
    }
}
相关推荐
雨白2 小时前
Jetpack系列(二):Lifecycle与LiveData结合,打造响应式UI
android·android jetpack
kk爱闹3 小时前
【挑战14天学完python和pytorch】- day01
android·pytorch·python
每次的天空5 小时前
Android-自定义View的实战学习总结
android·学习·kotlin·音视频
恋猫de小郭5 小时前
Flutter Widget Preview 功能已合并到 master,提前在体验毛坯的预览支持
android·flutter·ios
断剑重铸之日6 小时前
Android自定义相机开发(类似OCR扫描相机)
android
随心最为安6 小时前
Android Library Maven 发布完整流程指南
android
岁月玲珑6 小时前
【使用Android Studio调试手机app时候手机老掉线问题】
android·ide·android studio
还鮟11 小时前
CTF Web的数组巧用
android
小蜜蜂嗡嗡12 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi0012 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体