commit
b1041eb81f
@ -21,5 +21,7 @@ android {
|
||||
dependencies {
|
||||
compile 'com.facebook.react:react-native:+'
|
||||
compile 'com.android.support:recyclerview-v7:25.0.1'
|
||||
compile 'com.google.zxing:core:3.3.0'
|
||||
compile 'me.dm7.barcodescanner:core:1.9.8'
|
||||
compile group: 'com.drewnoakes', name: 'metadata-extractor', version: '2.9.1'
|
||||
}
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
package com.wix.RNCameraKit.camera;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.Camera;
|
||||
import android.support.annotation.ColorInt;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.View;
|
||||
@ -10,12 +13,20 @@ import android.widget.FrameLayout;
|
||||
import com.facebook.react.uimanager.ThemedReactContext;
|
||||
import com.wix.RNCameraKit.Utils;
|
||||
|
||||
import me.dm7.barcodescanner.core.IViewFinder;
|
||||
import me.dm7.barcodescanner.core.ViewFinderView;
|
||||
|
||||
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
|
||||
public class CameraView extends FrameLayout implements SurfaceHolder.Callback {
|
||||
private ThemedReactContext context;
|
||||
private SurfaceView surface;
|
||||
|
||||
private Rect viewFrameRect;
|
||||
private IViewFinder viewFinder;
|
||||
@ColorInt private int frameColor = Color.GREEN;
|
||||
@ColorInt private int laserColor = Color.RED;
|
||||
|
||||
public CameraView(ThemedReactContext context) {
|
||||
super(context);
|
||||
this.context = context;
|
||||
@ -49,6 +60,9 @@ public class CameraView extends FrameLayout implements SurfaceHolder.Callback {
|
||||
int actualPreviewHeight = getResources().getDisplayMetrics().heightPixels;
|
||||
int height = Utils.convertDeviceHeightToSupportedAspectRatio(actualPreviewWidth, actualPreviewHeight);
|
||||
surface.layout(0, 0, actualPreviewWidth, height);
|
||||
if (viewFinder != null) {
|
||||
((View) viewFinder).layout(0, 0, actualPreviewWidth, height);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -70,4 +84,84 @@ public class CameraView extends FrameLayout implements SurfaceHolder.Callback {
|
||||
public SurfaceHolder getHolder() {
|
||||
return surface.getHolder();
|
||||
}
|
||||
|
||||
private final Runnable measureAndLayout = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
measure(
|
||||
MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY),
|
||||
MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.EXACTLY));
|
||||
layout(getLeft(), getTop(), getRight(), getBottom());
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void requestLayout() {
|
||||
super.requestLayout();
|
||||
post(measureAndLayout);
|
||||
}
|
||||
|
||||
public void showFrame() {
|
||||
viewFinder = createViewFinderView(getContext());
|
||||
addView((View) viewFinder);
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
private IViewFinder createViewFinderView(Context context) {
|
||||
ViewFinderView viewFinderView = new ViewFinderView(context);
|
||||
viewFinderView.setBorderColor(frameColor);
|
||||
viewFinderView.setLaserColor(laserColor);
|
||||
viewFinderView.setLaserEnabled(true);
|
||||
viewFinderView.setBorderStrokeWidth(5);
|
||||
viewFinderView.setBorderLineLength(60);
|
||||
viewFinderView.setMaskColor(Color.argb(60, 0, 0, 0));
|
||||
|
||||
viewFinderView.setSquareViewFinder(true);
|
||||
viewFinderView.setViewFinderOffset(11);
|
||||
return viewFinderView;
|
||||
}
|
||||
|
||||
public Rect getFramingRectInPreview(int previewWidth, int previewHeight) {
|
||||
if (viewFrameRect == null) {
|
||||
if (viewFinder != null) {
|
||||
Rect framingRect = viewFinder.getFramingRect();
|
||||
int viewFinderViewWidth = viewFinder.getWidth();
|
||||
int viewFinderViewHeight = viewFinder.getHeight();
|
||||
if (framingRect == null || viewFinderViewWidth == 0 || viewFinderViewHeight == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Rect rect = new Rect(framingRect);
|
||||
|
||||
if (previewWidth < viewFinderViewWidth) {
|
||||
rect.left = rect.left * previewWidth / viewFinderViewWidth;
|
||||
rect.right = rect.right * previewWidth / viewFinderViewWidth;
|
||||
}
|
||||
|
||||
if (previewHeight < viewFinderViewHeight) {
|
||||
rect.top = rect.top * previewHeight / viewFinderViewHeight;
|
||||
rect.bottom = rect.bottom * previewHeight / viewFinderViewHeight;
|
||||
}
|
||||
|
||||
viewFrameRect = rect;
|
||||
} else {
|
||||
viewFrameRect = new Rect(0, 0, previewWidth, previewHeight);
|
||||
}
|
||||
}
|
||||
return viewFrameRect;
|
||||
}
|
||||
|
||||
public void setFrameColor(@ColorInt int color) {
|
||||
this.frameColor = color;
|
||||
if (viewFinder != null) {
|
||||
viewFinder.setBorderColor(frameColor);
|
||||
}
|
||||
}
|
||||
|
||||
public void setLaserColor(@ColorInt int color) {
|
||||
this.laserColor = color;
|
||||
if (viewFinder != null) {
|
||||
viewFinder.setLaserColor(laserColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,27 +1,41 @@
|
||||
package com.wix.RNCameraKit.camera;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.Camera;
|
||||
import android.hardware.SensorManager;
|
||||
import android.support.annotation.ColorInt;
|
||||
import android.support.annotation.IntRange;
|
||||
import android.view.Display;
|
||||
import android.view.OrientationEventListener;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.common.MapBuilder;
|
||||
import com.facebook.react.uimanager.SimpleViewManager;
|
||||
import com.facebook.react.uimanager.ThemedReactContext;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import com.facebook.react.uimanager.events.RCTEventEmitter;
|
||||
import com.google.zxing.Result;
|
||||
import com.wix.RNCameraKit.Utils;
|
||||
import com.wix.RNCameraKit.camera.barcode.BarcodeScanner;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static com.wix.RNCameraKit.camera.Orientation.getSupportedRotation;
|
||||
|
||||
@SuppressWarnings("MagicNumber deprecation") // We're still using Camera API 1, everything is deprecated
|
||||
@SuppressWarnings("MagicNumber deprecation")
|
||||
// We're still using Camera API 1, everything is deprecated
|
||||
public class CameraViewManager extends SimpleViewManager<CameraView> {
|
||||
|
||||
private static Camera camera = null;
|
||||
@ -33,6 +47,17 @@ public class CameraViewManager extends SimpleViewManager<CameraView> {
|
||||
private static int currentRotation = 0;
|
||||
private static AtomicBoolean cameraReleased = new AtomicBoolean(false);
|
||||
|
||||
private static boolean shouldScan = false;
|
||||
private static BarcodeScanner scanner;
|
||||
private static Camera.PreviewCallback previewCallback = new Camera.PreviewCallback() {
|
||||
@Override
|
||||
public void onPreviewFrame(byte[] data, Camera camera) {
|
||||
if (scanner != null) {
|
||||
scanner.onPreviewFrame(data, camera);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public static Camera getCamera() {
|
||||
return camera;
|
||||
}
|
||||
@ -49,7 +74,7 @@ public class CameraViewManager extends SimpleViewManager<CameraView> {
|
||||
}
|
||||
|
||||
static void setCameraView(CameraView cameraView) {
|
||||
if(!cameraViews.isEmpty() && cameraViews.peek() == cameraView) return;
|
||||
if (!cameraViews.isEmpty() && cameraViews.peek() == cameraView) return;
|
||||
CameraViewManager.cameraViews.push(cameraView);
|
||||
connectHolder();
|
||||
createOrientationListener();
|
||||
@ -58,13 +83,13 @@ public class CameraViewManager extends SimpleViewManager<CameraView> {
|
||||
private static void createOrientationListener() {
|
||||
if (orientationListener != null) return;
|
||||
orientationListener = new OrientationEventListener(reactContext, SensorManager.SENSOR_DELAY_NORMAL) {
|
||||
@Override
|
||||
public void onOrientationChanged(@IntRange(from = -1, to = 359) int angle) {
|
||||
if (angle == OrientationEventListener.ORIENTATION_UNKNOWN) return;
|
||||
setCameraRotation(359 - angle, false);
|
||||
}
|
||||
};
|
||||
orientationListener.enable();
|
||||
@Override
|
||||
public void onOrientationChanged(@IntRange(from = -1, to = 359) int angle) {
|
||||
if (angle == OrientationEventListener.ORIENTATION_UNKNOWN) return;
|
||||
setCameraRotation(359 - angle, false);
|
||||
}
|
||||
};
|
||||
orientationListener.enable();
|
||||
}
|
||||
|
||||
static boolean setFlashMode(String mode) {
|
||||
@ -108,6 +133,7 @@ public class CameraViewManager extends SimpleViewManager<CameraView> {
|
||||
} catch (RuntimeException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
setBarcodeScanner();
|
||||
}
|
||||
|
||||
private static void releaseCamera() {
|
||||
@ -116,16 +142,16 @@ public class CameraViewManager extends SimpleViewManager<CameraView> {
|
||||
}
|
||||
|
||||
private static void connectHolder() {
|
||||
if (cameraViews.isEmpty() || cameraViews.peek().getHolder() == null) return;
|
||||
if (cameraViews.isEmpty() || cameraViews.peek().getHolder() == null) return;
|
||||
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if(camera == null) {
|
||||
if (camera == null) {
|
||||
initCamera();
|
||||
}
|
||||
|
||||
if(cameraViews.isEmpty()) {
|
||||
if (cameraViews.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -135,6 +161,9 @@ public class CameraViewManager extends SimpleViewManager<CameraView> {
|
||||
try {
|
||||
camera.stopPreview();
|
||||
camera.setPreviewDisplay(cameraViews.peek().getHolder());
|
||||
if (shouldScan) {
|
||||
camera.setOneShotPreviewCallback(previewCallback);
|
||||
}
|
||||
camera.startPreview();
|
||||
} catch (IOException | RuntimeException e) {
|
||||
e.printStackTrace();
|
||||
@ -146,12 +175,12 @@ public class CameraViewManager extends SimpleViewManager<CameraView> {
|
||||
}
|
||||
|
||||
static void removeCameraView() {
|
||||
if(!cameraViews.isEmpty()) {
|
||||
if (!cameraViews.isEmpty()) {
|
||||
cameraViews.pop();
|
||||
}
|
||||
if(!cameraViews.isEmpty()) {
|
||||
if (!cameraViews.isEmpty()) {
|
||||
connectHolder();
|
||||
} else if(camera != null){
|
||||
} else if (camera != null) {
|
||||
releaseCamera();
|
||||
camera = null;
|
||||
}
|
||||
@ -188,8 +217,8 @@ public class CameraViewManager extends SimpleViewManager<CameraView> {
|
||||
}
|
||||
|
||||
private static Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
|
||||
final double ASPECT_TOLERANCE = 0.1;
|
||||
double targetRatio=(double)h / w;
|
||||
final double ASPECT_TOLERANCE = 0.15;
|
||||
double targetRatio = (double) h / w;
|
||||
if (sizes == null) return null;
|
||||
Camera.Size optimalSize = null;
|
||||
double minDiff = Double.MAX_VALUE;
|
||||
@ -232,10 +261,65 @@ public class CameraViewManager extends SimpleViewManager<CameraView> {
|
||||
parameters.setPictureSize(optimalPictureSize.width, optimalPictureSize.height);
|
||||
parameters.setFlashMode(flashMode);
|
||||
camera.setParameters(parameters);
|
||||
} catch (RuntimeException ignored) {}
|
||||
} catch (RuntimeException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
public static void reconnect() {
|
||||
connectHolder();
|
||||
}
|
||||
|
||||
public static int getRotationCount() {
|
||||
return currentRotation / 90;
|
||||
}
|
||||
|
||||
public static void setBarcodeScanner() {
|
||||
scanner = new BarcodeScanner(reactContext, previewCallback);
|
||||
scanner.setResultHandler(new BarcodeScanner.ResultHandler() {
|
||||
@Override
|
||||
public void handleResult(Result rawResult) {
|
||||
WritableMap event = Arguments.createMap();
|
||||
event.putString("qrcodeStringValue", rawResult.getText());
|
||||
reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(cameraViews.peek().getId(), "onReadCode", event);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
|
||||
return MapBuilder.<String, Object>builder()
|
||||
.put("onReadCode",
|
||||
MapBuilder.of("registrationName", "onReadCode"))
|
||||
.build();
|
||||
}
|
||||
|
||||
@ReactProp(name = "scanBarcode")
|
||||
public void setShouldScan(CameraView view, boolean scanBarcode) {
|
||||
shouldScan = scanBarcode;
|
||||
if (shouldScan && camera != null) {
|
||||
camera.setOneShotPreviewCallback(previewCallback);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactProp(name = "showFrame")
|
||||
public void setFrame(CameraView view, boolean show) {
|
||||
if (show) {
|
||||
view.showFrame();
|
||||
}
|
||||
}
|
||||
|
||||
@ReactProp(name = "frameColor", defaultInt = Color.GREEN)
|
||||
public void setFrameColor(CameraView view, @ColorInt int color) {
|
||||
view.setFrameColor(color);
|
||||
}
|
||||
|
||||
@ReactProp(name = "laserColor", defaultInt = Color.RED)
|
||||
public void setLaserColor(CameraView view, @ColorInt int color) {
|
||||
view.setLaserColor(color);
|
||||
}
|
||||
|
||||
public static synchronized Rect getFramingRectInPreview(int previewWidth, int previewHeight) {
|
||||
return cameraViews.peek().getFramingRectInPreview(previewWidth, previewHeight);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,217 @@
|
||||
package com.wix.RNCameraKit.camera.barcode;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.Camera;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.BinaryBitmap;
|
||||
import com.google.zxing.DecodeHintType;
|
||||
import com.google.zxing.LuminanceSource;
|
||||
import com.google.zxing.MultiFormatReader;
|
||||
import com.google.zxing.NotFoundException;
|
||||
import com.google.zxing.PlanarYUVLuminanceSource;
|
||||
import com.google.zxing.ReaderException;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.common.HybridBinarizer;
|
||||
import com.wix.RNCameraKit.camera.CameraViewManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import me.dm7.barcodescanner.core.DisplayUtils;
|
||||
|
||||
public class BarcodeScanner {
|
||||
|
||||
public interface ResultHandler {
|
||||
void handleResult(Result rawResult);
|
||||
}
|
||||
|
||||
private MultiFormatReader mMultiFormatReader;
|
||||
public static final List<BarcodeFormat> ALL_FORMATS = new ArrayList<>();
|
||||
private List<BarcodeFormat> mFormats;
|
||||
private ResultHandler mResultHandler;
|
||||
|
||||
private Context context;
|
||||
private Camera.PreviewCallback previewCallback;
|
||||
|
||||
static {
|
||||
ALL_FORMATS.add(BarcodeFormat.AZTEC);
|
||||
ALL_FORMATS.add(BarcodeFormat.CODABAR);
|
||||
ALL_FORMATS.add(BarcodeFormat.CODE_39);
|
||||
ALL_FORMATS.add(BarcodeFormat.CODE_93);
|
||||
ALL_FORMATS.add(BarcodeFormat.CODE_128);
|
||||
ALL_FORMATS.add(BarcodeFormat.DATA_MATRIX);
|
||||
ALL_FORMATS.add(BarcodeFormat.EAN_8);
|
||||
ALL_FORMATS.add(BarcodeFormat.EAN_13);
|
||||
ALL_FORMATS.add(BarcodeFormat.ITF);
|
||||
ALL_FORMATS.add(BarcodeFormat.MAXICODE);
|
||||
ALL_FORMATS.add(BarcodeFormat.PDF_417);
|
||||
ALL_FORMATS.add(BarcodeFormat.QR_CODE);
|
||||
ALL_FORMATS.add(BarcodeFormat.RSS_14);
|
||||
ALL_FORMATS.add(BarcodeFormat.RSS_EXPANDED);
|
||||
ALL_FORMATS.add(BarcodeFormat.UPC_A);
|
||||
ALL_FORMATS.add(BarcodeFormat.UPC_E);
|
||||
ALL_FORMATS.add(BarcodeFormat.UPC_EAN_EXTENSION);
|
||||
}
|
||||
|
||||
public BarcodeScanner(Context context, Camera.PreviewCallback previewCallback) {
|
||||
this.context = context;
|
||||
this.previewCallback = previewCallback;
|
||||
initMultiFormatReader();
|
||||
}
|
||||
|
||||
public void setFormats(List<BarcodeFormat> formats) {
|
||||
mFormats = formats;
|
||||
initMultiFormatReader();
|
||||
}
|
||||
|
||||
public void setResultHandler(ResultHandler resultHandler) {
|
||||
mResultHandler = resultHandler;
|
||||
}
|
||||
|
||||
public Collection<BarcodeFormat> getFormats() {
|
||||
if(mFormats == null) {
|
||||
return ALL_FORMATS;
|
||||
}
|
||||
return mFormats;
|
||||
}
|
||||
|
||||
private void initMultiFormatReader() {
|
||||
Map<DecodeHintType,Object> hints = new EnumMap<>(DecodeHintType.class);
|
||||
hints.put(DecodeHintType.POSSIBLE_FORMATS, getFormats());
|
||||
mMultiFormatReader = new MultiFormatReader();
|
||||
mMultiFormatReader.setHints(hints);
|
||||
}
|
||||
|
||||
public void onPreviewFrame(byte[] data, Camera camera) {
|
||||
if(mResultHandler == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Camera.Parameters parameters = camera.getParameters();
|
||||
Camera.Size size = parameters.getPreviewSize();
|
||||
int width = size.width;
|
||||
int height = size.height;
|
||||
|
||||
if (DisplayUtils.getScreenOrientation(context) == Configuration.ORIENTATION_PORTRAIT) {
|
||||
int rotationCount = CameraViewManager.getRotationCount();
|
||||
if (rotationCount == 1 || rotationCount == 3) {
|
||||
int tmp = width;
|
||||
width = height;
|
||||
height = tmp;
|
||||
}
|
||||
data = getRotatedData(data, camera);
|
||||
}
|
||||
|
||||
Result rawResult = null;
|
||||
PlanarYUVLuminanceSource source = buildLuminanceSource(data, width, height);
|
||||
|
||||
if (source != null) {
|
||||
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
|
||||
try {
|
||||
rawResult = mMultiFormatReader.decodeWithState(bitmap);
|
||||
} catch (ReaderException re) {
|
||||
// continue
|
||||
} catch (NullPointerException npe) {
|
||||
// This is terrible
|
||||
} catch (ArrayIndexOutOfBoundsException ignored) {
|
||||
|
||||
} finally {
|
||||
mMultiFormatReader.reset();
|
||||
}
|
||||
|
||||
if (rawResult == null) {
|
||||
LuminanceSource invertedSource = source.invert();
|
||||
bitmap = new BinaryBitmap(new HybridBinarizer(invertedSource));
|
||||
try {
|
||||
rawResult = mMultiFormatReader.decodeWithState(bitmap);
|
||||
} catch (NotFoundException e) {
|
||||
// continue
|
||||
} finally {
|
||||
mMultiFormatReader.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final Result finalRawResult = rawResult;
|
||||
|
||||
if (finalRawResult != null) {
|
||||
Handler handler = new Handler(Looper.getMainLooper());
|
||||
handler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Stopping the preview can take a little long.
|
||||
// So we want to set result handler to null to discard subsequent calls to
|
||||
// onPreviewFrame.
|
||||
ResultHandler tmpResultHandler = mResultHandler;
|
||||
mResultHandler = null;
|
||||
|
||||
//TODO:decide if I need to do this
|
||||
//stopCameraPreview();
|
||||
if (tmpResultHandler != null) {
|
||||
tmpResultHandler.handleResult(finalRawResult);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
camera.setOneShotPreviewCallback(previewCallback);
|
||||
}
|
||||
} catch(RuntimeException e) {
|
||||
// TODO: Terrible hack. It is possible that this method is invoked after camera is released.
|
||||
Log.w("CameraKit", e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int width, int height) {
|
||||
Rect rect = CameraViewManager.getFramingRectInPreview(width, height);
|
||||
if (rect == null) {
|
||||
return null;
|
||||
}
|
||||
// Go ahead and assume it's YUV rather than die.
|
||||
PlanarYUVLuminanceSource source = null;
|
||||
|
||||
try {
|
||||
source = new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top,
|
||||
rect.width(), rect.height(), false);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
private static byte[] getRotatedData(byte[] data, Camera camera) {
|
||||
Camera.Parameters parameters = camera.getParameters();
|
||||
Camera.Size size = parameters.getPreviewSize();
|
||||
int width = size.width;
|
||||
int height = size.height;
|
||||
|
||||
int rotationCount = CameraViewManager.getRotationCount();
|
||||
|
||||
if (rotationCount == 1 || rotationCount == 3) {
|
||||
for (int i = 0; i < rotationCount; i++) {
|
||||
byte[] rotatedData = new byte[data.length];
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++)
|
||||
rotatedData[x * height + height - y - 1] = data[x + y * width];
|
||||
}
|
||||
data = rotatedData;
|
||||
int tmp = width;
|
||||
width = height;
|
||||
height = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
import React, {Component} from 'react';
|
||||
import React, { Component } from 'react';
|
||||
import {
|
||||
AppRegistry,
|
||||
StyleSheet,
|
||||
@ -14,8 +14,9 @@ import {
|
||||
} from 'react-native-camera-kit';
|
||||
|
||||
import CameraScreen from './src/CameraScreen';
|
||||
import AlbumsScreen from './src/AlbumsScreen';
|
||||
import GalleryScreen from './src/GalleryScreen';
|
||||
import AlbumsScreen from './src/AlbumsScreen';
|
||||
import GalleryScreen from './src/GalleryScreen';
|
||||
import BarcodeScreen from './src/BarcodeScreen';
|
||||
|
||||
class example extends Component {
|
||||
|
||||
@ -32,29 +33,35 @@ class example extends Component {
|
||||
return <Example />;
|
||||
}
|
||||
return (
|
||||
<View style={{flex: 1}}>
|
||||
<View style={{ flex: 1 }}>
|
||||
<View style={styles.headerContainer}>
|
||||
<Text style={styles.headerText}>
|
||||
Welcome to Camera Kit
|
||||
</Text>
|
||||
<Text style={{fontSize: 40}}>📷</Text>
|
||||
<Text style={{ fontSize: 40 }}>📷</Text>
|
||||
</View>
|
||||
|
||||
|
||||
<View style={styles.container}>
|
||||
<TouchableOpacity onPress={() => this.setState({example: CameraScreen})}>
|
||||
<TouchableOpacity onPress={() => this.setState({ example: BarcodeScreen })}>
|
||||
<Text style={styles.buttonText}>
|
||||
Barcode scanner Screen
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity onPress={() => this.setState({ example: CameraScreen })}>
|
||||
<Text style={styles.buttonText}>
|
||||
Camera Screen
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity onPress={() => this.setState({example: AlbumsScreen})}>
|
||||
<TouchableOpacity onPress={() => this.setState({ example: AlbumsScreen })}>
|
||||
<Text style={styles.buttonText}>
|
||||
Albums Screen
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity onPress={() => this.setState({example: GalleryScreen})}>
|
||||
<TouchableOpacity onPress={() => this.setState({ example: GalleryScreen })}>
|
||||
<Text style={styles.buttonText}>
|
||||
Gallery Screen
|
||||
</Text>
|
||||
|
||||
44
example/src/BarcodeScreen.js
Normal file
44
example/src/BarcodeScreen.js
Normal file
@ -0,0 +1,44 @@
|
||||
import React, { Component } from 'react';
|
||||
import {
|
||||
Alert
|
||||
} from 'react-native';
|
||||
import { CameraKitCameraScreen } from 'react-native-camera-kit';
|
||||
|
||||
|
||||
export default class CameraScreen extends Component {
|
||||
|
||||
|
||||
onBottomButtonPressed(event) {
|
||||
const captureImages = JSON.stringify(event.captureImages);
|
||||
Alert.alert(
|
||||
`${event.type} button pressed`,
|
||||
`${captureImages}`,
|
||||
[
|
||||
{ text: 'OK', onPress: () => console.log('OK Pressed') },
|
||||
],
|
||||
{ cancelable: false }
|
||||
)
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<CameraKitCameraScreen
|
||||
actions={{ rightButtonText: 'Done', leftButtonText: 'Cancel' }}
|
||||
onBottomButtonPressed={(event) => this.onBottomButtonPressed(event)}
|
||||
flashImages={{
|
||||
on: require('./../images/flashOn.png'),
|
||||
off: require('./../images/flashOff.png'),
|
||||
auto: require('./../images/flashAuto.png')
|
||||
}}
|
||||
showFrame={true}
|
||||
scanBarcode={true}
|
||||
laserColor={"blue"}
|
||||
frameColor={"yellow"}
|
||||
onReadCode={((event) => console.log('QRCODE', event.nativeEvent.qrcodeStringValue))}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
2
index.js
2
index.js
@ -7,7 +7,7 @@ export {
|
||||
CameraKitGallery,
|
||||
CameraKitCamera,
|
||||
CameraKitGalleryView,
|
||||
CameraKitCameraScreen
|
||||
CameraKitCameraScreen,
|
||||
};
|
||||
|
||||
|
||||
|
||||
7129
package-lock.json
generated
Normal file
7129
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,9 @@
|
||||
import React, {Component} from 'react';
|
||||
import * as _ from 'lodash';
|
||||
import React, { Component } from 'react';
|
||||
import {
|
||||
requireNativeComponent,
|
||||
NativeModules
|
||||
NativeModules,
|
||||
processColor
|
||||
} from 'react-native';
|
||||
|
||||
const NativeCamera = requireNativeComponent('CameraView', null);
|
||||
@ -9,39 +11,44 @@ const NativeCameraModule = NativeModules.CameraModule;
|
||||
|
||||
export default class CameraKitCamera extends React.Component {
|
||||
|
||||
render() {
|
||||
return <NativeCamera {...this.props}/>
|
||||
}
|
||||
render() {
|
||||
const transformedProps = _.cloneDeep(this.props);
|
||||
_.update(transformedProps, 'cameraOptions.ratioOverlayColor', (c) => processColor(c));
|
||||
_.update(transformedProps, 'frameColor', (c) => processColor(c));
|
||||
_.update(transformedProps, 'laserColor', (c) => processColor(c));
|
||||
|
||||
async logData() {
|
||||
console.log('front Camera?', await NativeCameraModule.hasFrontCamera());
|
||||
console.log('hasFlash?', await NativeCameraModule.hasFlashForCurrentCamera());
|
||||
console.log('flashMode?', await NativeCameraModule.getFlashMode());
|
||||
}
|
||||
return <NativeCamera {...transformedProps}/>
|
||||
}
|
||||
|
||||
static async requestDeviceCameraAuthorization() {
|
||||
async logData() {
|
||||
console.log('front Camera?', await NativeCameraModule.hasFrontCamera());
|
||||
console.log('hasFlash?', await NativeCameraModule.hasFlashForCurrentCamera());
|
||||
console.log('flashMode?', await NativeCameraModule.getFlashMode());
|
||||
}
|
||||
|
||||
static async requestDeviceCameraAuthorization() {
|
||||
const usersAuthorizationAnswer = await NativeCameraModule.requestDeviceCameraAuthorization();
|
||||
return usersAuthorizationAnswer;
|
||||
}
|
||||
}
|
||||
|
||||
async capture(saveToCameraRoll = true) {
|
||||
const imageTmpPath = await NativeCameraModule.capture(saveToCameraRoll);
|
||||
return imageTmpPath;
|
||||
}
|
||||
async capture(saveToCameraRoll = true) {
|
||||
const imageTmpPath = await NativeCameraModule.capture(saveToCameraRoll);
|
||||
return imageTmpPath;
|
||||
}
|
||||
|
||||
async changeCamera() {
|
||||
const success = await NativeCameraModule.changeCamera();
|
||||
return success;
|
||||
}
|
||||
async changeCamera() {
|
||||
const success = await NativeCameraModule.changeCamera();
|
||||
return success;
|
||||
}
|
||||
|
||||
async setFlashMode(flashMode = 'auto') {
|
||||
const success = await NativeCameraModule.setFlashMode(flashMode);
|
||||
return success;
|
||||
}
|
||||
async setFlashMode(flashMode = 'auto') {
|
||||
const success = await NativeCameraModule.setFlashMode(flashMode);
|
||||
return success;
|
||||
}
|
||||
|
||||
static async checkDeviceCameraAuthorizationStatus() {
|
||||
return await NativeCameraModule.checkDeviceCameraAuthorizationStatus();
|
||||
}
|
||||
static async checkDeviceCameraAuthorizationStatus() {
|
||||
return await NativeCameraModule.checkDeviceCameraAuthorizationStatus();
|
||||
}
|
||||
|
||||
static async hasCameraPermission() {
|
||||
const success = await NativeCameraModule.hasCameraPermission();
|
||||
|
||||
@ -26,7 +26,6 @@ export default class CameraKitCamera extends React.Component {
|
||||
static async requestDeviceCameraAuthorization() {
|
||||
const usersAuthorizationAnswer = await NativeCameraAction.requestDeviceCameraAuthorization();
|
||||
return usersAuthorizationAnswer;
|
||||
|
||||
}
|
||||
|
||||
async capture(saveToCameraRoll = true) {
|
||||
|
||||
@ -37,14 +37,14 @@ export default class CameraScreenBase extends Component {
|
||||
mode: FLASH_MODE_AUTO,
|
||||
image: _.get(this.props, 'flashImages.auto')
|
||||
},
|
||||
{
|
||||
mode: FLASH_MODE_ON,
|
||||
image: _.get(this.props, 'flashImages.on')
|
||||
},
|
||||
{
|
||||
mode: FLASH_MODE_OFF,
|
||||
image: _.get(this.props, 'flashImages.off')
|
||||
}
|
||||
{
|
||||
mode: FLASH_MODE_ON,
|
||||
image: _.get(this.props, 'flashImages.on')
|
||||
},
|
||||
{
|
||||
mode: FLASH_MODE_OFF,
|
||||
image: _.get(this.props, 'flashImages.off')
|
||||
}
|
||||
];
|
||||
this.state = {
|
||||
captureImages: [],
|
||||
@ -130,15 +130,20 @@ export default class CameraScreenBase extends Component {
|
||||
<View style={styles.cameraContainer}>
|
||||
{
|
||||
this.isCaptureRetakeMode() ?
|
||||
<Image
|
||||
style={{flex: 1, justifyContent: 'flex-end'}}
|
||||
source={{uri: this.state.imageCaptured.uri}}
|
||||
/> :
|
||||
<CameraKitCamera
|
||||
ref={(cam) => this.camera = cam}
|
||||
style={{flex: 1, justifyContent: 'flex-end'}}
|
||||
cameraOptions={this.state.cameraOptions}
|
||||
/>
|
||||
<Image
|
||||
style={{ flex: 1, justifyContent: 'flex-end' }}
|
||||
source={{ uri: this.state.imageCaptured.uri }}
|
||||
/> :
|
||||
<CameraKitCamera
|
||||
ref={(cam) => this.camera = cam}
|
||||
style={{ flex: 1, justifyContent: 'flex-end' }}
|
||||
cameraOptions={this.state.cameraOptions}
|
||||
showFrame={this.props.showFrame}
|
||||
scanBarcode={this.props.scanBarcode}
|
||||
laserColor={this.props.laserColor}
|
||||
frameColor={this.props.frameColor}
|
||||
onReadCode={this.props.onReadCode}
|
||||
/>
|
||||
}
|
||||
</View>
|
||||
);
|
||||
@ -195,7 +200,7 @@ export default class CameraScreenBase extends Component {
|
||||
}
|
||||
|
||||
sendBottomButtonPressedAction(type, captureRetakeMode, image) {
|
||||
if(this.props.onBottomButtonPressed) {
|
||||
if (this.props.onBottomButtonPressed) {
|
||||
this.props.onBottomButtonPressed({ type, captureImages: this.state.captureImages, captureRetakeMode, image })
|
||||
}
|
||||
}
|
||||
@ -203,14 +208,14 @@ export default class CameraScreenBase extends Component {
|
||||
async onButtonPressed(type) {
|
||||
const captureRetakeMode = this.isCaptureRetakeMode();
|
||||
if (captureRetakeMode) {
|
||||
if(type === 'left') {
|
||||
if (type === 'left') {
|
||||
GalleryManager.deleteTempImage(this.state.imageCaptured.uri);
|
||||
this.setState({imageCaptured: undefined});
|
||||
this.setState({ imageCaptured: undefined });
|
||||
}
|
||||
else if(type === 'right') {
|
||||
else if (type === 'right') {
|
||||
const result = await GalleryManager.saveImageURLToCameraRoll(this.state.imageCaptured.uri);
|
||||
const savedImage = {...this.state.imageCaptured, ...result}; // Note: Can't just return 'result' as on iOS not all data is returned by the native call (just the ID).
|
||||
this.setState({imageCaptured: undefined, captureImages: _.concat(this.state.captureImages, savedImage)}, () => {
|
||||
const savedImage = { ...this.state.imageCaptured, ...result }; // Note: Can't just return 'result' as on iOS not all data is returned by the native call (just the ID).
|
||||
this.setState({ imageCaptured: undefined, captureImages: _.concat(this.state.captureImages, savedImage) }, () => {
|
||||
this.sendBottomButtonPressedAction(type, captureRetakeMode);
|
||||
});
|
||||
}
|
||||
@ -244,7 +249,7 @@ export default class CameraScreenBase extends Component {
|
||||
|
||||
renderBottomButtons() {
|
||||
return (
|
||||
<View style={[styles.bottomButtons, {backgroundColor: '#ffffff00'}]}>
|
||||
<View style={[styles.bottomButtons, { backgroundColor: '#ffffff00' }]}>
|
||||
{this.renderBottomButton('left')}
|
||||
{this.renderCaptureButton()}
|
||||
{this.renderBottomButton('right')}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user