mirror of
https://github.com/status-im/react-native-camera.git
synced 2025-02-24 17:58:20 +00:00
Apply barcode scanner on preview frames.
This commit is contained in:
parent
ce11617743
commit
918c00f003
@ -8,8 +8,17 @@ import android.content.Context;
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.hardware.Camera;
|
||||
import android.view.TextureView;
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.EnumMap;
|
||||
import java.util.EnumSet;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.BinaryBitmap;
|
||||
import com.google.zxing.DecodeHintType;
|
||||
@ -18,17 +27,24 @@ import com.google.zxing.PlanarYUVLuminanceSource;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.common.HybridBinarizer;
|
||||
|
||||
class RCTCameraViewFinder extends TextureView implements TextureView.SurfaceTextureListener {
|
||||
class RCTCameraViewFinder extends TextureView implements TextureView.SurfaceTextureListener, Camera.PreviewCallback {
|
||||
private int _cameraType;
|
||||
private SurfaceTexture _surfaceTexture;
|
||||
private boolean _isStarting;
|
||||
private boolean _isStopping;
|
||||
private Camera _camera;
|
||||
|
||||
// concurrency lock for barcode scanner to avoid flooding the runtime
|
||||
public static volatile boolean barcodeScannerTaskLock = false;
|
||||
|
||||
// reader instance for the barcode scanner
|
||||
private final MultiFormatReader _multiFormatReader = new MultiFormatReader();
|
||||
|
||||
public RCTCameraViewFinder(Context context, int type) {
|
||||
super(context);
|
||||
this.setSurfaceTextureListener(this);
|
||||
this._cameraType = type;
|
||||
this.initBarcodeReader();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -119,6 +135,8 @@ class RCTCameraViewFinder extends TextureView implements TextureView.SurfaceText
|
||||
_camera.setParameters(parameters);
|
||||
_camera.setPreviewTexture(_surfaceTexture);
|
||||
_camera.startPreview();
|
||||
// send previews to `onPreviewFrame`
|
||||
_camera.setPreviewCallback(this);
|
||||
} catch (NullPointerException e) {
|
||||
e.printStackTrace();
|
||||
} catch (Exception e) {
|
||||
@ -136,6 +154,7 @@ class RCTCameraViewFinder extends TextureView implements TextureView.SurfaceText
|
||||
try {
|
||||
if (_camera != null) {
|
||||
_camera.stopPreview();
|
||||
// stop sending previews to `onPreviewFrame`
|
||||
_camera.setPreviewCallback(null);
|
||||
RCTCamera.getInstance().releaseCameraInstance(_cameraType);
|
||||
_camera = null;
|
||||
@ -148,4 +167,85 @@ class RCTCameraViewFinder extends TextureView implements TextureView.SurfaceText
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the barcode decoder.
|
||||
*
|
||||
* TODO add hints for the `barCodeTypes` prop instead of the hardcoded `EAN_13`
|
||||
*/
|
||||
private void initBarcodeReader() {
|
||||
EnumMap<DecodeHintType, Object> hints = new EnumMap<>(DecodeHintType.class);
|
||||
EnumSet<BarcodeFormat> decodeFormats = EnumSet.noneOf(BarcodeFormat.class);
|
||||
decodeFormats.add(BarcodeFormat.EAN_13);
|
||||
hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats);
|
||||
_multiFormatReader.setHints(hints);
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawn a barcode reader task if
|
||||
* - the barcode scanner is enabled (has a onBarCodeRead function)
|
||||
* - one isn't already running
|
||||
*
|
||||
* See {Camera.PreviewCallback}
|
||||
*/
|
||||
public void onPreviewFrame(byte[] data, Camera camera) {
|
||||
if (RCTCamera.getInstance().isBarcodeScannerEnabled() && !RCTCameraViewFinder.barcodeScannerTaskLock) {
|
||||
RCTCameraViewFinder.barcodeScannerTaskLock = true;
|
||||
new ReaderAsyncTask(camera, data).execute();
|
||||
}
|
||||
}
|
||||
|
||||
private class ReaderAsyncTask extends AsyncTask<Void, Void, Void> {
|
||||
private byte[] imageData;
|
||||
private final Camera camera;
|
||||
|
||||
ReaderAsyncTask(Camera camera, byte[] imageData) {
|
||||
this.camera = camera;
|
||||
this.imageData = imageData;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... ignored) {
|
||||
if (isCancelled()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Camera.Size size = camera.getParameters().getPreviewSize();
|
||||
|
||||
int width = size.width;
|
||||
int height = size.height;
|
||||
|
||||
// rotate for zxing if orientation is portrait
|
||||
if (RCTCamera.getInstance().getActualDeviceOrientation() == 0) {
|
||||
byte[] rotated = new byte[imageData.length];
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
rotated[x * height + height - y - 1] = imageData[x + y * width];
|
||||
}
|
||||
}
|
||||
width = size.height;
|
||||
height = size.width;
|
||||
imageData = rotated;
|
||||
}
|
||||
|
||||
try {
|
||||
PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(imageData, width, height, 0, 0, width, height, false);
|
||||
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
|
||||
Result result = _multiFormatReader.decodeWithState(bitmap);
|
||||
|
||||
ReactContext reactContext = RCTCameraModule.getReactContextSingleton();
|
||||
WritableMap event = Arguments.createMap();
|
||||
event.putString("data", result.getText());
|
||||
event.putString("type", result.getBarcodeFormat().toString());
|
||||
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("CameraBarCodeReadAndroid", event);
|
||||
|
||||
} catch (Throwable t) {
|
||||
// meh
|
||||
} finally {
|
||||
_multiFormatReader.reset();
|
||||
RCTCameraViewFinder.barcodeScannerTaskLock = false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user