android surfaceViewを使用してcameraプレビューインタフェース画像データを取得
27554 ワード
android
では、プレビューインタフェースをカメラで取得する必要が変態しているようで、使用シーンもあまりないようです.しかし、プレビューインタフェースの画像を取得するシーンがあります.スキャンコードです.例えば、微信、支付宝のスキャンです.プレビューインタフェースの画像データを取得する必要があります.論理を実現するのは簡単ですが、システムカメラを開くよりも面倒になるに違いありません.
実装手順を簡単に説明します.
SurfaceView
を例示する.surfaceCreated()
コールバックでCamera
オブジェクトをインスタンス化し、オートフォーカスを除去する.onAutoFocus()
コールバックでcamera.takePicture(null,null,callback);
を呼び出す.3
のcallback
でプレビュー画像データ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コードはすべてのコードが長いので、私は貼らないで、パスを話します.
何を考えているのか分からないが、
camera2
の中にはcamera
よりも多く、複雑さもずいぶん向上している.必要なものがあれば検討してもいいです.手の難易度はcamera
より大きい.(今のところ私はまだ霧の水で、camera2
に対して).これは私は実行検証をダウンロードしていませんが、ブログを見るとたくさん書いてあります.