Merge pull request #141 from wix/barcode_key

Support diff orientations and barcode alignment
This commit is contained in:
Ran Greenberg 2018-03-22 13:40:06 +02:00 committed by GitHub
commit 7bfd606673
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 422 additions and 216 deletions

View File

@ -2,7 +2,7 @@ apply plugin: 'com.android.library'
android {
compileSdkVersion 25
buildToolsVersion "25.0.1"
buildToolsVersion "26.0.3"
defaultConfig {
minSdkVersion 16
@ -14,7 +14,7 @@ android {
}
}
lintOptions {
warning 'InvalidPackage'
warning 'InvalidPackage'
}
}
@ -22,6 +22,5 @@ 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'
}

View File

@ -216,4 +216,9 @@ public class Utils {
public static int convertDeviceHeightToSupportedAspectRatio(float actualWidth, float actualHeight) {
return (int) (actualHeight / actualWidth > MAX_SCREEN_RATIO ? actualWidth * MAX_SCREEN_RATIO : actualHeight);
}
public static void runOnWorkerThread(Runnable runnable) {
new Thread(runnable).start();
}
}

View File

@ -1,6 +1,5 @@
package com.wix.RNCameraKit.camera;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Rect;
import android.hardware.Camera;
@ -12,26 +11,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 com.wix.RNCameraKit.camera.barcode.BarcodeFrame;
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;
private Rect frameRect;
private BarcodeFrame barcodeFrame;
@ColorInt private int frameColor = Color.GREEN;
@ColorInt private int laserColor = Color.RED;
public CameraView(ThemedReactContext context) {
super(context);
this.context = context;
surface = new SurfaceView(context);
setBackgroundColor(Color.BLACK);
addView(surface, MATCH_PARENT, MATCH_PARENT);
@ -44,9 +37,10 @@ public class CameraView extends FrameLayout implements SurfaceHolder.Callback {
CameraViewManager.getCamera().autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
}
});
} catch (Exception e) {
} catch (Exception ignored) {
}
}
@ -60,8 +54,8 @@ 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);
if (barcodeFrame != null) {
((View) barcodeFrame).layout(0, 0, actualPreviewWidth, height);
}
}
@ -102,66 +96,48 @@ public class CameraView extends FrameLayout implements SurfaceHolder.Callback {
}
public void showFrame() {
viewFinder = createViewFinderView(getContext());
addView((View) viewFinder);
barcodeFrame = new BarcodeFrame(getContext());
barcodeFrame.setFrameColor(frameColor);
barcodeFrame.setLaserColor(laserColor);
addView(barcodeFrame);
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;
if (frameRect == null) {
if (barcodeFrame != null) {
Rect framingRect = new Rect(barcodeFrame.getFrameRect());
int frameWidth = barcodeFrame.getWidth();
int frameHeight = barcodeFrame.getHeight();
if (previewWidth < frameWidth) {
framingRect.left = framingRect.left * previewWidth / frameWidth;
framingRect.right = framingRect.right * previewWidth / frameWidth;
}
if (previewHeight < frameHeight) {
framingRect.top = framingRect.top * previewHeight / frameHeight;
framingRect.bottom = framingRect.bottom * previewHeight / frameHeight;
}
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;
frameRect = framingRect;
} else {
viewFrameRect = new Rect(0, 0, previewWidth, previewHeight);
frameRect = new Rect(0, 0, previewWidth, previewHeight);
}
}
return viewFrameRect;
return frameRect;
}
public void setFrameColor(@ColorInt int color) {
this.frameColor = color;
if (viewFinder != null) {
viewFinder.setBorderColor(frameColor);
if (barcodeFrame != null) {
barcodeFrame.setFrameColor(color);
}
}
public void setLaserColor(@ColorInt int color) {
this.laserColor = color;
if (viewFinder != null) {
viewFinder.setLaserColor(laserColor);
if (barcodeFrame != null) {
barcodeFrame.setLaserColor(laserColor);
}
}
}

View File

@ -51,10 +51,15 @@ public class CameraViewManager extends SimpleViewManager<CameraView> {
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 void onPreviewFrame(final byte[] data, final Camera camera) {
Utils.runOnWorkerThread(new Runnable() {
@Override
public void run() {
if (scanner != null) {
scanner.onPreviewFrame(data, camera);
}
}
});
}
};
@ -137,6 +142,7 @@ public class CameraViewManager extends SimpleViewManager<CameraView> {
}
private static void releaseCamera() {
camera.setOneShotPreviewCallback(null);
cameraReleased.set(true);
camera.release();
}
@ -161,10 +167,10 @@ public class CameraViewManager extends SimpleViewManager<CameraView> {
try {
camera.stopPreview();
camera.setPreviewDisplay(cameraViews.peek().getHolder());
camera.startPreview();
if (shouldScan) {
camera.setOneShotPreviewCallback(previewCallback);
}
camera.startPreview();
} catch (IOException | RuntimeException e) {
e.printStackTrace();
}
@ -274,13 +280,13 @@ public class CameraViewManager extends SimpleViewManager<CameraView> {
}
public static void setBarcodeScanner() {
scanner = new BarcodeScanner(reactContext, previewCallback);
scanner.setResultHandler(new BarcodeScanner.ResultHandler() {
scanner = new BarcodeScanner(previewCallback, new BarcodeScanner.ResultHandler() {
@Override
public void handleResult(Result rawResult) {
public void handleResult(Result result) {
WritableMap event = Arguments.createMap();
event.putString("codeStringValue", rawResult.getText());
reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(cameraViews.peek().getId(), "onReadCode", event);
event.putString("codeStringValue", result.getText());
if (!cameraViews.empty())
reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(cameraViews.peek().getId(), "onReadCode", event);
}
});
}

View File

@ -0,0 +1,110 @@
package com.wix.RNCameraKit.camera.barcode;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.support.annotation.ColorInt;
import android.view.View;
import com.wix.RNCameraKit.R;
public class BarcodeFrame extends View {
private static final int STROKE_WIDTH = 5;
private static final int ANIMATION_SPEED = 8;
private static final int WIDTH_SCALE = 7;
private static final double HEIGHT_SCALE = 2.75;
private Paint dimPaint;
private Paint framePaint;
private Paint borderPaint;
private Paint laserPaint;
private Rect frameRect;
private int width;
private int height;
private int borderMargin;
private long previousFrameTime = System.currentTimeMillis();
private int laserY;
public BarcodeFrame(Context context) {
super(context);
init(context);
}
private void init(Context context) {
framePaint = new Paint();
framePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
dimPaint = new Paint();
dimPaint.setStyle(Paint.Style.FILL);
dimPaint.setColor(context.getResources().getColor(R.color.bg_dark));
borderPaint = new Paint();
borderPaint.setStyle(Paint.Style.STROKE);
borderPaint.setStrokeWidth(STROKE_WIDTH);
laserPaint = new Paint();
laserPaint.setStyle(Paint.Style.STROKE);
laserPaint.setStrokeWidth(STROKE_WIDTH);
frameRect = new Rect();
borderMargin = context.getResources().getDimensionPixelSize(R.dimen.border_length);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = getMeasuredWidth();
height = getMeasuredHeight();
int marginWidth = width / WIDTH_SCALE;
int marginHeight = (int) (height / HEIGHT_SCALE);
frameRect.left = marginWidth;
frameRect.right = width - marginWidth;
frameRect.top = marginHeight;
frameRect.bottom = height - marginHeight;
}
@Override
protected void onDraw(Canvas canvas) {
long timeElapsed = (System.currentTimeMillis() - previousFrameTime);
super.onDraw(canvas);
canvas.drawRect(0, 0, width, height, dimPaint);
canvas.drawRect(frameRect, framePaint);
drawBorder(canvas);
drawLaser(canvas, timeElapsed);
previousFrameTime = System.currentTimeMillis();
this.invalidate(frameRect);
}
private void drawBorder(Canvas canvas) {
canvas.drawLine(frameRect.left, frameRect.top, frameRect.left, frameRect.top + borderMargin, borderPaint);
canvas.drawLine(frameRect.left, frameRect.top, frameRect.left + borderMargin, frameRect.top, borderPaint);
canvas.drawLine(frameRect.left, frameRect.bottom, frameRect.left, frameRect.bottom - borderMargin, borderPaint);
canvas.drawLine(frameRect.left, frameRect.bottom, frameRect.left + borderMargin, frameRect.bottom, borderPaint);
canvas.drawLine(frameRect.right, frameRect.top, frameRect.right - borderMargin, frameRect.top, borderPaint);
canvas.drawLine(frameRect.right, frameRect.top, frameRect.right, frameRect.top + borderMargin, borderPaint);
canvas.drawLine(frameRect.right, frameRect.bottom, frameRect.right, frameRect.bottom - borderMargin, borderPaint);
canvas.drawLine(frameRect.right, frameRect.bottom, frameRect.right - borderMargin, frameRect.bottom, borderPaint);
}
private void drawLaser(Canvas canvas, long timeElapsed) {
if (laserY > frameRect.bottom || laserY < frameRect.top) laserY = frameRect.top;
canvas.drawLine(frameRect.left + STROKE_WIDTH, laserY, frameRect.right - STROKE_WIDTH, laserY, laserPaint);
laserY += (timeElapsed) / ANIMATION_SPEED;
}
public Rect getFrameRect() {
return frameRect;
}
public void setFrameColor(@ColorInt int borderColor) {
borderPaint.setColor(borderColor);
}
public void setLaserColor(@ColorInt int laserColor) {
laserPaint.setColor(laserColor);
}
}

View File

@ -1,13 +1,12 @@
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.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import com.google.zxing.BarcodeFormat;
@ -15,33 +14,26 @@ 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);
void handleResult(Result result);
}
private MultiFormatReader mMultiFormatReader;
public static final List<BarcodeFormat> ALL_FORMATS = new ArrayList<>();
private List<BarcodeFormat> mFormats;
private ResultHandler mResultHandler;
private static final List<BarcodeFormat> ALL_FORMATS = new ArrayList<>();
private ResultHandler resultHandler;
private Context context;
private Camera.PreviewCallback previewCallback;
static {
@ -64,154 +56,90 @@ public class BarcodeScanner {
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());
public BarcodeScanner(@NonNull Camera.PreviewCallback previewCallback, @NonNull ResultHandler resultHandler) {
Map<DecodeHintType, Object> hints = new EnumMap<>(DecodeHintType.class);
hints.put(DecodeHintType.POSSIBLE_FORMATS, ALL_FORMATS);
mMultiFormatReader = new MultiFormatReader();
mMultiFormatReader.setHints(hints);
this.previewCallback = previewCallback;
this.resultHandler = resultHandler;
}
public void onPreviewFrame(byte[] data, Camera camera) {
if(mResultHandler == null) {
return;
}
public void onPreviewFrame(byte[] data, final Camera camera) {
try {
Camera.Parameters parameters = camera.getParameters();
Camera.Size size = parameters.getPreviewSize();
Camera.Size size = camera.getParameters().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);
}
int tmp = width;
width = height;
height = tmp;
data = getRotatedData(data, camera);
Result rawResult = null;
PlanarYUVLuminanceSource source = buildLuminanceSource(data, width, height);
final Result result = decodeResult(getLuminanceSource(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() {
if (result != null) {
new Handler(Looper.getMainLooper()).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);
}
resultHandler.handleResult(result);
}
});
} else {
camera.setOneShotPreviewCallback(previewCallback);
}
} catch(RuntimeException e) {
// TODO: Terrible hack. It is possible that this method is invoked after camera is released.
camera.setOneShotPreviewCallback(previewCallback);
} catch (RuntimeException e) {
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;
@Nullable
private Result decodeResult(LuminanceSource source) {
Result rawResult = null;
if (source != null) {
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
try {
rawResult = mMultiFormatReader.decodeWithState(bitmap);
} catch (ReaderException ignored) {
} finally {
mMultiFormatReader.reset();
}
try {
source = new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top,
rect.width(), rect.height(), false);
} catch(Exception e) {
e.printStackTrace();
}
if (rawResult == null && source.isRotateSupported()) {
LuminanceSource rotatedSource = source.rotateCounterClockwise();
bitmap = new BinaryBitmap(new HybridBinarizer(rotatedSource));
try {
rawResult = mMultiFormatReader.decodeWithState(bitmap);
} catch (ReaderException ignored) {
} finally {
mMultiFormatReader.reset();
}
}
}
return rawResult;
}
return source;
}
private LuminanceSource getLuminanceSource(byte[] data, int width, int height) {
Rect rect = CameraViewManager.getFramingRectInPreview(width, height);
try {
return new RotateLuminanceSource(data, width, height, rect.left, rect.top,
rect.width(), rect.height(), false);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
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;
private byte[] getRotatedData(byte[] data, Camera camera) {
Camera.Size size = camera.getParameters().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;
}
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];
}
return rotatedData;
}
}

View File

@ -0,0 +1,164 @@
package com.wix.RNCameraKit.camera.barcode;
import com.google.zxing.LuminanceSource;
/**
* This class is mostly copy of {@link com.google.zxing.PlanarYUVLuminanceSource} class.
* The only difference is adding {@code rotateCounterClockwise()} method
* It was copied due to PlanarYUVLuminanceSource being final, so it can not be extended
* Zxing license - {https://github.com/zxing/zxing/blob/master/LICENSE}
*/
public class RotateLuminanceSource extends LuminanceSource {
private static final int THUMBNAIL_SCALE_FACTOR = 2;
private final byte[] yuvData;
private final int dataWidth;
private final int dataHeight;
private final int left;
private final int top;
RotateLuminanceSource(byte[] yuvData,
int dataWidth,
int dataHeight,
int left,
int top,
int width,
int height,
boolean reverseHorizontal) {
super(width, height);
if (left + width > dataWidth || top + height > dataHeight) {
throw new IllegalArgumentException("Crop rectangle does not fit within image data.");
}
this.yuvData = yuvData;
this.dataWidth = dataWidth;
this.dataHeight = dataHeight;
this.left = left;
this.top = top;
if (reverseHorizontal) {
reverseHorizontal(width, height);
}
}
@Override
public byte[] getRow(int y, byte[] row) {
if (y < 0 || y >= getHeight()) {
throw new IllegalArgumentException("Requested row is outside the image: " + y);
}
int width = getWidth();
if (row == null || row.length < width) {
row = new byte[width];
}
int offset = (y + top) * dataWidth + left;
System.arraycopy(yuvData, offset, row, 0, width);
return row;
}
@Override
public byte[] getMatrix() {
int width = getWidth();
int height = getHeight();
// If the caller asks for the entire underlying image, save the copy and give them the
// original data. The docs specifically warn that result.length must be ignored.
if (width == dataWidth && height == dataHeight) {
return yuvData;
}
int area = width * height;
byte[] matrix = new byte[area];
int inputOffset = top * dataWidth + left;
// If the width matches the full width of the underlying data, perform a single copy.
if (width == dataWidth) {
System.arraycopy(yuvData, inputOffset, matrix, 0, area);
return matrix;
}
// Otherwise copy one cropped row at a time.
for (int y = 0; y < height; y++) {
int outputOffset = y * width;
System.arraycopy(yuvData, inputOffset, matrix, outputOffset, width);
inputOffset += dataWidth;
}
return matrix;
}
@Override
public boolean isCropSupported() {
return true;
}
@Override
public LuminanceSource crop(int left, int top, int width, int height) {
return new RotateLuminanceSource(yuvData,
dataWidth,
dataHeight,
this.left + left,
this.top + top,
width,
height,
false);
}
public int[] renderThumbnail() {
int width = getWidth() / THUMBNAIL_SCALE_FACTOR;
int height = getHeight() / THUMBNAIL_SCALE_FACTOR;
int[] pixels = new int[width * height];
byte[] yuv = yuvData;
int inputOffset = top * dataWidth + left;
for (int y = 0; y < height; y++) {
int outputOffset = y * width;
for (int x = 0; x < width; x++) {
int grey = yuv[inputOffset + x * THUMBNAIL_SCALE_FACTOR] & 0xff;
pixels[outputOffset + x] = 0xFF000000 | (grey * 0x00010101);
}
inputOffset += dataWidth * THUMBNAIL_SCALE_FACTOR;
}
return pixels;
}
/**
* @return width of image from {@link #renderThumbnail()}
*/
public int getThumbnailWidth() {
return getWidth() / THUMBNAIL_SCALE_FACTOR;
}
/**
* @return height of image from {@link #renderThumbnail()}
*/
public int getThumbnailHeight() {
return getHeight() / THUMBNAIL_SCALE_FACTOR;
}
private void reverseHorizontal(int width, int height) {
byte[] yuvData = this.yuvData;
for (int y = 0, rowStart = top * dataWidth + left; y < height; y++, rowStart += dataWidth) {
int middle = rowStart + width / 2;
for (int x1 = rowStart, x2 = rowStart + width - 1; x1 < middle; x1++, x2--) {
byte temp = yuvData[x1];
yuvData[x1] = yuvData[x2];
yuvData[x2] = temp;
}
}
}
@Override
public boolean isRotateSupported() {
return true;
}
@Override
public LuminanceSource rotateCounterClockwise() {
byte[] rotatedData = new byte[yuvData.length];
for (int y = 0; y < dataHeight; y++) {
for (int x = 0; x < dataWidth; x++)
rotatedData[x * dataHeight + dataHeight - y - 1] = yuvData[x + y * dataWidth];
}
return new RotateLuminanceSource(rotatedData, dataHeight, dataWidth, top, (dataWidth - left - getWidth()), getHeight(), getWidth(), false);
}
}

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="bg_dark">#BF000000</color>
</resources>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="border_length">30dp</dimen>
</resources>

View File

@ -25,18 +25,19 @@ def enableSeparateBuildPerCPUArchitecture = false
def enableProguardInReleaseBuilds = false
android {
compileSdkVersion 23
buildToolsVersion '26.0.2'
compileSdkVersion 25
buildToolsVersion '26.0.3'
defaultConfig {
applicationId "com.camerakit"
minSdkVersion 16
targetSdkVersion 22
targetSdkVersion 25
versionCode 1
versionName "1.0"
ndk {
abiFilters "armeabi-v7a", "x86"
}
multiDexEnabled true
}
splits {
abi {
@ -70,7 +71,8 @@ android {
dependencies {
compile fileTree(dir: "libs", include: ["*.jar"])
compile project(":rncamerakit")
compile "com.android.support:appcompat-v7:23.0.1"
compile "com.android.support:appcompat-v7:25.0.1"
compile 'com.android.support:multidex:1.0.3'
compile "com.facebook.react:react-native:+" // From node_modules
}

View File

@ -1,6 +1,8 @@
package com.camerakit;
import android.app.Application;
import android.content.Context;
import android.support.multidex.MultiDex;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
@ -35,6 +37,12 @@ public class MainApplication extends Application implements ReactApplication {
}
};
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;

View File

@ -3,6 +3,7 @@
buildscript {
repositories {
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
@ -20,5 +21,6 @@ allprojects {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}
google()
}
}

View File

@ -45,8 +45,6 @@ export default class CameraScreen extends Component {
scanBarcode={true}
laserColor={"blue"}
frameColor={"yellow"}
//onReadCode={((event) => Alert.alert(`Qr code found ${event.nativeEvent.codeStringValue} `))}
onReadCode = {((event) => this.setState({ example: CheckingScreen}))}
hideControls={true}
// offsetForScannerFrame = {10}

View File

@ -1,4 +1,4 @@
// This index is the example app index,
// if you look for react-naitve-camera-kit index,
// please jump src/index 😅
require('./ExampleCode/app');
require('./example-js-code/app');

View File

@ -51,7 +51,7 @@ export default class CameraScreen extends Component {
hideControls={true}
// offsetForScannerFrame = {10}
// heightForScannerFrame = {300}
colorForScannerFrame = {'blue'}
colorForScannerFrame={'blue'}
/>
);
}