写一份完整的使用camera2使用预览扫描多张二维码并且每次扫描后打开闪光灯的代码
时间: 2024-03-12 13:49:57 浏览: 15
好的,我可以帮你写一份基于camera2的多张二维码扫描代码,如下所示:
```java
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.util.Size;
import android.view.Surface;
import android.view.TextureView;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.DecodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.Result;
import com.google.zxing.ResultPoint;
import com.google.zxing.ResultPointCallback;
import com.google.zxing.common.HybridBinarizer;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MultiQRCodeScanner";
private static final int REQUEST_CAMERA_PERMISSIONS = 1;
private TextureView mTextureView;
private CameraManager mCameraManager;
private CameraDevice mCameraDevice;
private CaptureRequest.Builder mPreviewBuilder;
private CameraCaptureSession mCameraCaptureSession;
private ImageReader mImageReader;
private HandlerThread mBackgroundThread;
private Handler mBackgroundHandler;
private MultiFormatReader mMultiFormatReader;
private boolean mIsFlashOn = false;
private final CameraDevice.StateCallback mCameraDeviceCallback =
new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice cameraDevice) {
mCameraDevice = cameraDevice;
createCameraPreviewSession();
}
@Override
public void onDisconnected(@NonNull CameraDevice cameraDevice) {
cameraDevice.close();
mCameraDevice = null;
}
@Override
public void onError(@NonNull CameraDevice cameraDevice, int error) {
cameraDevice.close();
mCameraDevice = null;
finish();
}
};
private final ImageReader.OnImageAvailableListener mOnImageAvailableListener =
new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Image image = reader.acquireNextImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
int width = image.getWidth();
int height = image.getHeight();
int format = image.getFormat();
// Rotate and crop the image to get the QR code area
Matrix matrix = new Matrix();
matrix.postRotate(90);
Rect sourceRect = new Rect(0, 0, width, height);
Rect targetRect = new Rect(0, 0, reader.getHeight(), reader.getWidth());
matrix.mapRect(targetRect);
Rect rotatedRect = new Rect();
targetRect.offset(-targetRect.left, -targetRect.top);
sourceRect.offset(-sourceRect.left, -sourceRect.top);
float scale = Math.min(
(float) targetRect.width() / sourceRect.width(),
(float) targetRect.height() / sourceRect.height());
sourceRect.offset(
(int) ((sourceRect.width() * scale - sourceRect.width()) / 2),
(int) ((sourceRect.height() * scale - sourceRect.height()) / 2));
matrix.setScale(scale, scale);
matrix.mapRect(rotatedRect, sourceRect);
// Decode the QR code from the cropped image
Map<DecodeHintType, Object> hints = new EnumMap<>(DecodeHintType.class);
List<BarcodeFormat> formats = new ArrayList<>();
formats.add(BarcodeFormat.QR_CODE);
hints.put(DecodeHintType.POSSIBLE_FORMATS, formats);
hints.put(DecodeHintType.NEED_RESULT_POINT_CALLBACK,
new ResultPointCallback() {
@Override
public void foundPossibleResultPoint(ResultPoint point) {
Log.d(TAG, "Found possible result point: " + point);
}
});
Result result = null;
try {
mMultiFormatReader.setHints(hints);
result = mMultiFormatReader.decodeWithState(
new com.google.zxing.BinaryBitmap(
new HybridBinarizer(
new PlanarYUVLuminanceSource(
bytes,
width,
height,
rotatedRect.left,
rotatedRect.top,
rotatedRect.width(),
rotatedRect.height(),
false))));
} catch (Exception e) {
Log.e(TAG, "Failed to decode QR code", e);
} finally {
mMultiFormatReader.reset();
}
if (result != null) {
Log.d(TAG, "Found QR code: " + result.getText());
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(
MainActivity.this,
"Found QR code: " + result.getText(),
Toast.LENGTH_SHORT).show();
}
});
}
image.close();
}
};
private final TextureView.SurfaceTextureListener mSurfaceTextureListener =
new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(
SurfaceTexture surfaceTexture, int width, int height) {
setUpCamera();
openCamera();
}
@Override
public void onSurfaceTextureSizeChanged(
SurfaceTexture surfaceTexture, int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
return true;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextureView = findViewById(R.id.texture_view);
mMultiFormatReader = new MultiFormatReader();
if (ActivityCompat.checkSelfPermission(
this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
this,
new String[]{Manifest.permission.CAMERA},
REQUEST_CAMERA_PERMISSIONS);
}
}
@Override
protected void onResume() {
super.onResume();
startBackgroundThread();
if (mTextureView.isAvailable()) {
setUpCamera();
openCamera();
} else {
mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
}
}
@Override
protected void onPause() {
closeCamera();
stopBackgroundThread();
super.onPause();
}
@Override
public void onRequestPermissionsResult(
int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CAMERA_PERMISSIONS) {
if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(
this,
"You cannot use the app without granting camera permission",
Toast.LENGTH_SHORT).show();
finish();
}
}
}
private void setUpCamera() {
mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
String[] cameraIds = mCameraManager.getCameraIdList();
for (String cameraId : cameraIds) {
CameraCharacteristics cameraCharacteristics =
mCameraManager.getCameraCharacteristics(cameraId);
if (cameraCharacteristics.get(CameraCharacteristics.LENS_FACING)
== CameraCharacteristics.LENS_FACING_BACK) {
StreamConfigurationMap streamConfigurationMap =
cameraCharacteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
Size[] outputSizes =
streamConfigurationMap.getOutputSizes(ImageFormat.YUV_420_888);
Point displaySize = new Point();
getWindowManager().getDefaultDisplay().getSize(displaySize);
for (Size outputSize : outputSizes) {
float ratio = (float) outputSize.getWidth() / outputSize.getHeight();
if (ratio == (float) displaySize.x / displaySize.y) {
mImageReader =
ImageReader.newInstance(
outputSize.getWidth(),
outputSize.getHeight(),
ImageFormat.YUV_420_888,
4);
mImageReader.setOnImageAvailableListener(mOnImageAvailableListener,
mBackgroundHandler);
mPreviewBuilder =
mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
surfaceTexture.setDefaultBufferSize(
outputSize.getWidth(), outputSize.getHeight());
Surface previewSurface = new Surface(surfaceTexture);
Surface imageReaderSurface = mImageReader.getSurface();
mPreviewBuilder.addTarget(previewSurface);
mPreviewBuilder.addTarget(imageReaderSurface);
return;
}
}
break;
}
}
} catch (CameraAccessException e) {
Log.e(TAG, "Failed to set up camera", e);
}
}
private void openCamera() {
try {
if (ActivityCompat.checkSelfPermission(
this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
return;
}
mCameraManager.openCamera(
mCameraManager.getCameraIdList()[0], mCameraDeviceCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
Log.e(TAG, "Failed to open camera", e);
}
}
private void createCameraPreviewSession() {
try {
mPreviewBuilder.set(
CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
mCameraDevice.createCaptureSession(
Arrays.asList(mPreviewBuilder.build()),
new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession session) {
if (mCameraDevice == null) {
return;
}
mCameraCaptureSession = session;
try {
mPreviewBuilder.set(
CaptureRequest.CONTROL_AE_MODE,
CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
mCameraCaptureSession.setRepeatingRequest(
mPreviewBuilder.build(),
null,
mBackgroundHandler);
} catch (CameraAccessException e) {
Log.e(TAG, "Failed to set up camera preview", e);
}
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
Toast.makeText(
MainActivity.this,
"Failed to create camera preview session",
Toast.LENGTH_SHORT).show();
}
},
mBackgroundHandler);
} catch (CameraAccessException e) {
Log.e(TAG, "Failed to create camera preview session", e);
}
}
private void closeCamera() {
if (mCameraCaptureSession != null) {
mCameraCaptureSession.close();
mCameraCaptureSession = null;
}
if (mCameraDevice != null) {
mCameraDevice.close();
mCameraDevice = null;
}
if (mImageReader != null) {
mImageReader.close();
mImageReader = null;
}
}
private void startBackgroundThread() {
mBackgroundThread = new HandlerThread("Camera2Background");
mBackgroundThread.start();
mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
}
private void stopBackgroundThread() {
mBackgroundThread.quitSafely();
try {
mBackgroundThread.join();
mBackgroundThread = null;
mBackgroundHandler = null;
} catch (InterruptedException e) {
Log.e(TAG, "Failed to stop background thread", e);
}
}
}
```
这个代码会在打开预览时自动启动扫描,每次扫描到二维码时会弹出一个 Toast 显示二维码内容。在扫描到二维码后可以通过调用 `mPreviewBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);` 打开闪光灯,或者调用 `mPreviewBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);` 自动控制闪光灯。