android surfaceViewを使用してcameraプレビューインタフェース画像データを取得

27554 ワード

androidでは、プレビューインタフェースをカメラで取得する必要が変態しているようで、使用シーンもあまりないようです.しかし、プレビューインタフェースの画像を取得するシーンがあります.スキャンコードです.例えば、微信、支付宝のスキャンです.プレビューインタフェースの画像データを取得する必要があります.
論理を実現するのは簡単ですが、システムカメラを開くよりも面倒になるに違いありません.
実装手順を簡単に説明します.
  • は、SurfaceViewを例示する.
  • surfaceCreated()コールバックでCameraオブジェクトをインスタンス化し、オートフォーカスを除去する.
  • は、onAutoFocus()コールバックでcamera.takePicture(null,null,callback);を呼び出す.
  • は、ステップ3callbackでプレビュー画像データint data[]を取得する.
  • (オプション)取得したデータをファイルに変換します.
  • (オプション)ファイルオブジェクトをbitmapオブジェクトにロードします.
  • は、使用しないでカメラリソースを解放する.

  • コードの詳細:
  • インベントリファイル:
  •     <uses-feature android:name="android.hardware.camera" />
        <uses-feature android:name="android.hardware.camera.autofocus" />
    
        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.CAMERA" />
        <uses-permission android:name="android.permission.RECORD_AUDIO" />
  • javaコード:
  • package com.python.cat.testgradle;
    
    import android.Manifest;
    import android.app.Activity;
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.hardware.Camera;
    import android.os.Bundle;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;
    import android.view.View;
    import android.widget.Button;
    import android.widget.FrameLayout;
    import android.widget.Toast;
    
    import com.apkfuns.logutils.LogUtils;
    import com.google.zxing.BinaryBitmap;
    import com.google.zxing.ChecksumException;
    import com.google.zxing.FormatException;
    import com.google.zxing.NotFoundException;
    import com.google.zxing.RGBLuminanceSource;
    import com.google.zxing.Result;
    import com.google.zxing.common.GlobalHistogramBinarizer;
    import com.google.zxing.qrcode.QRCodeReader;
    import com.yanzhenjie.permission.Action;
    import com.yanzhenjie.permission.AndPermission;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.Arrays;
    import java.util.List;
    
    public class UseCameraActivity extends Activity {
    
    
        private Activity get() {
            return this;
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_asome);
            setTitle(getClass().getSimpleName());
            final FrameLayout frameLayout = findViewById(R.id.prev_content_layout);
            Button btn = findViewById(R.id.start_camera_preview);
    
            btn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    AndPermission.with(get())
                            .permission(Manifest.permission.CAMERA,
                                    Manifest.permission.WRITE_EXTERNAL_STORAGE
                            )
                            .onDenied(new Action() {
                                @Override
                                public void onAction(List permissions) {
                                    LogUtils.e("error....." + permissions);
                                }
                            })
                            .onGranted(new Action() {
                                @Override
                                public void onAction(List permissions) {
                                    LogUtils.w("you can do..");
                                    ScanView scanView = new ScanView(get());
                                    frameLayout.removeAllViews();
                                    frameLayout.addView(scanView);
                                }
                            }).start();
                }
            });
        }
    
    
        static class ScanView extends SurfaceView implements SurfaceHolder.Callback,
                Camera.AutoFocusCallback {
            private Camera mCamera;
            private final File fileImg;
    
            private ScanView self;
    
            public ScanView(Context context) {
                super(context);
                fileImg = new File(context.getCacheDir(), "prev_view.jpg");
                SurfaceHolder mHolder = getHolder();
                self = this;
                mHolder.addCallback(this);
                // deprecated setting, but required on Android versions prior to 3.0
                mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
            }
    
            @Override
            public void onAutoFocus(boolean success, Camera camera) {
                LogUtils.w("auto focus..." + success);
                if (mCamera != null) {
                    mCamera.takePicture(null, null, null, new Camera.PictureCallback() {
                        @Override
                        public void onPictureTaken(byte[] data, Camera camera) {
    
                            mCamera.cancelAutoFocus();
                            mCamera.stopPreview(); //        !!!
                            LogUtils.w("========data========");
                            LogUtils.w("----------data-----------------");
    //                        camera.startPreview();
                            File pictureFile = fileImg;
                            if (pictureFile == null) {
                                LogUtils.e("Error creating media file, check storage permissions: " +
                                        null);
                                return;
                            }
    
                            if (data == null) {
                                return;
                            }
                            try {
                                LogUtils.d(data);
                                FileOutputStream fos = new FileOutputStream(pictureFile);
                                fos.write(data);
                                fos.close();
                                LogUtils.e("save preview complete###!!!");
                                LogUtils.e("save preview complete###!!!" + pictureFile);
                                BitmapFactory.Options options = new BitmapFactory.Options();
                                options.inJustDecodeBounds = true;
                                BitmapFactory.decodeFile(pictureFile.getAbsolutePath(), options);
                                options.inJustDecodeBounds = false;
                                int outWidth = options.outWidth;
                                int outHeight = options.outHeight;
                                if (outWidth >= getWidth() * 2) {
                                    options.inSampleSize = outWidth / getWidth();
                                }
                                if (outHeight >= getHeight() * 2) {
                                    options.inSampleSize = outHeight / getHeight();
                                }
                                Bitmap bmp = BitmapFactory.decodeFile(pictureFile.getAbsolutePath(), options);
                                Result result = parseInfoFromBitmap(bmp);
                                if (result != null) {
                                    Toast.makeText(getContext(), "INFO:" + result.getText(), Toast.LENGTH_SHORT).show();
                                    LogUtils.w("    :" + result);
                                } else {
                                    LogUtils.e("     ....");
                                    mCamera.startPreview();
                                    mCamera.autoFocus(self);
                                    // todo:               ...
                                }
                            } catch (Exception e) {
                                LogUtils.e("Error accessing file: " + e.getMessage());
                            }
                        }
                    });
                }
            }
    
            public Result parseInfoFromBitmap(Bitmap bitmap) {
                int[] pixels = new int[bitmap.getWidth() * bitmap.getHeight()];
                bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
                LogUtils.w("### pixels dest==" + Arrays.toString(pixels));
    
                RGBLuminanceSource source = new RGBLuminanceSource(bitmap.getWidth(),
                        bitmap.getHeight(), pixels);
                GlobalHistogramBinarizer binarizer = new GlobalHistogramBinarizer(source);
                BinaryBitmap image = new BinaryBitmap(binarizer);
                Result result = null;
                try {
                    result = new QRCodeReader().decode(image);
                    return result;
                } catch (NotFoundException e) {
                    e.printStackTrace();
                    Toast.makeText(getContext(), "      ,    ", Toast.LENGTH_SHORT).show();
                } catch (ChecksumException e) {
                    e.printStackTrace();
                } catch (FormatException e) {
                    e.printStackTrace();
                }
    
                return null;
    
            }
    
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                LogUtils.e("x surfaceCreated.. #####");
                try {
                    mCamera = Camera.open();
                    mCamera.setPreviewDisplay(holder);
                    mCamera.setDisplayOrientation(90);
                    Camera.Parameters parameters = mCamera.getParameters();
    //                parameters.setPictureSize(1600, 1200);
    //                parameters.setPreviewSize(640, 480);
                    mCamera.setParameters(parameters);
                    mCamera.startPreview();
                    mCamera.autoFocus(this);
                    LogUtils.e("surfaceCreated.. #####");
    
                } catch (IOException e) {
                    LogUtils.e("Error setting camera preview: " + e.getMessage());
                }
            }
    
            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    
                LogUtils.w("--change-");
            }
    
            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                LogUtils.w("destroy--");
                if (mCamera != null) {
                    mCamera.cancelAutoFocus();
                    mCamera.stopPreview();
                    mCamera.release();
                }
            }
        }
    }
    
  • レイアウトファイル:
  • <RelativeLayout 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=".UseCameraActivity">
    
    
        <Button
            android:id="@+id/start_camera_preview"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:text="@string/start_camera_preview" />
    
        <FrameLayout
            android:id="@+id/prev_content_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_above="@id/start_camera_preview">FrameLayout>
    RelativeLayout>
  • gradle構成(オプション):
  • implementation 'com.yanzhenjie:permission:2.0.0-rc4' //         
    implementation 'com.google.zxing:core:3.3.1' // zxing        

    うーん、以上がカメラプレビュー画像データを取得するコードです.ただし、ここで使用するCameraインタフェースは時代遅れで、使用することはお勧めしません.ただし、実行できます.私の現在のcompileSdkVersion=26です.
    味噌にします.完全なappコードはあるかもしれません.
    =======
    update:Camera2について、私は諦めることを選んだ....
    公式の言い方は:
    The android.hardware.camera2 package provides an interface to individual camera devices connected to an Android device. It replaces the deprecated Camera class. This package models a camera device as a pipeline, which takes in input requests for capturing a single frame, captures the single image per the request, and then outputs one capture result metadata packet, plus a set of output image buffers for the request. The requests are processed in-order, and multiple requests can be in flight at once. Since the camera device is a pipeline with multiple stages, having multiple requests in flight is required to maintain full framerate on most Android devices.
    いずれにしても、Cameraの代わりに一言読んだ.
    でも、本当に面倒くさい.私は中国語が見つからず、直接実行できるケースを見つけて、2人の外国人が書いたブログを見つけて、中には完全なコードが入っています.ただし、直接アクセスはできないと思います.私はプロジェクトにコピーしました.直接実行できます.
    完全なappコードはすべてのコードが長いので、私は貼らないで、パスを話します.
  • com.python.cat.testgradle.MainActivity.JAva[この元のコードに動的権限申請がないため、手動で追加しました...]
  • com.python.cat.testgradle.AndroidCameraApi.JAva私がくれたのは私のコードのパスと元のリンクです.

  • 何を考えているのか分からないが、camera2の中にはcameraよりも多く、複雑さもずいぶん向上している.必要なものがあれば検討してもいいです.手の難易度はcameraより大きい.(今のところ私はまだ霧の水で、camera2に対して).
    これは私は実行検証をダウンロードしていませんが、ブログを見るとたくさん書いてあります.