v2.0.1
* 更新CameraX至v1.0.0-rc01 * 新增支持点击预览区域对焦目标 * 修改一些默认配置 * 优化细节
This commit is contained in:
@@ -42,7 +42,7 @@ dependencies {
|
||||
androidTestImplementation deps.test.runner
|
||||
androidTestImplementation deps.test.espresso
|
||||
|
||||
api deps.support.appcompat
|
||||
compileOnly deps.androidx.appcompat
|
||||
api deps.zxing
|
||||
api deps.camera_core
|
||||
api deps.camera_camera2
|
||||
|
||||
@@ -44,6 +44,8 @@ public class DecodeConfig {
|
||||
|
||||
private Map<DecodeHintType,Object> hints = DecodeFormatManager.DEFAULT_HINTS;
|
||||
|
||||
public static final float DEFAULT_AREA_RECT_RATIO = 0.8f;
|
||||
|
||||
/**
|
||||
* 是否支持使用多解码
|
||||
*/
|
||||
@@ -74,12 +76,12 @@ public class DecodeConfig {
|
||||
/**
|
||||
* 是否支持全区域扫码识别
|
||||
*/
|
||||
private boolean isFullAreaScan = true;
|
||||
private boolean isFullAreaScan = false;
|
||||
|
||||
/**
|
||||
* 识别区域比例,默认0.9
|
||||
* 识别区域比例,默认0.8
|
||||
*/
|
||||
private float areaRectRatio = 0.9f;
|
||||
private float areaRectRatio = DEFAULT_AREA_RECT_RATIO;
|
||||
/**
|
||||
* 识别区域垂直方向偏移量
|
||||
*/
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
package com.king.zxing;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Size;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ScaleGestureDetector;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.ResultPoint;
|
||||
import com.google.zxing.common.detector.MathUtils;
|
||||
import com.king.zxing.analyze.Analyzer;
|
||||
import com.king.zxing.analyze.MultiFormatAnalyzer;
|
||||
import com.king.zxing.util.LogUtils;
|
||||
@@ -21,7 +26,9 @@ import androidx.annotation.FloatRange;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.camera.core.Camera;
|
||||
import androidx.camera.core.CameraSelector;
|
||||
import androidx.camera.core.FocusMeteringAction;
|
||||
import androidx.camera.core.ImageAnalysis;
|
||||
import androidx.camera.core.MeteringPoint;
|
||||
import androidx.camera.core.Preview;
|
||||
import androidx.camera.core.TorchState;
|
||||
import androidx.camera.core.ZoomState;
|
||||
@@ -38,6 +45,20 @@ import androidx.lifecycle.MutableLiveData;
|
||||
*/
|
||||
public class DefaultCameraScan extends CameraScan {
|
||||
|
||||
/**
|
||||
* Defines the maximum duration in milliseconds between a touch pad
|
||||
* touch and release for a given touch to be considered a tap (click) as
|
||||
* opposed to a hover movement gesture.
|
||||
*/
|
||||
private static final int HOVER_TAP_TIMEOUT = 150;
|
||||
|
||||
/**
|
||||
* Defines the maximum distance in pixels that a touch pad touch can move
|
||||
* before being released for it to be considered a tap (click) as opposed
|
||||
* to a hover movement gesture.
|
||||
*/
|
||||
private static final int HOVER_TAP_SLOP = 20;
|
||||
|
||||
private FragmentActivity mFragmentActivity;
|
||||
private Context mContext;
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
@@ -68,9 +89,14 @@ public class DefaultCameraScan extends CameraScan {
|
||||
private BeepManager mBeepManager;
|
||||
private AmbientLightManager mAmbientLightManager;
|
||||
|
||||
private int mOrientation;
|
||||
private int mScreenWidth;
|
||||
private int mScreenHeight;
|
||||
private long mLastAutoZoomTime;
|
||||
private long mLastHoveTapTime;
|
||||
private boolean isClickTap;
|
||||
private float mDownX;
|
||||
private float mDownY;
|
||||
|
||||
public DefaultCameraScan(FragmentActivity activity, PreviewView previewView){
|
||||
this.mFragmentActivity = activity;
|
||||
@@ -107,8 +133,10 @@ public class DefaultCameraScan extends CameraScan {
|
||||
handleAnalyzeResult(result);
|
||||
});
|
||||
|
||||
mOrientation = mContext.getResources().getConfiguration().orientation;
|
||||
ScaleGestureDetector scaleGestureDetector = new ScaleGestureDetector(mContext, mOnScaleGestureListener);
|
||||
mPreviewView.setOnTouchListener((v, event) -> {
|
||||
handlePreviewViewClickTap(event);
|
||||
if(isNeedTouchZoom()){
|
||||
return scaleGestureDetector.onTouchEvent(event);
|
||||
}
|
||||
@@ -139,6 +167,37 @@ public class DefaultCameraScan extends CameraScan {
|
||||
}
|
||||
}
|
||||
|
||||
private void handlePreviewViewClickTap(MotionEvent event){
|
||||
if(event.getPointerCount() == 1){
|
||||
switch (event.getAction()){
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
isClickTap = true;
|
||||
mDownX = event.getX();
|
||||
mDownY = event.getY();
|
||||
mLastHoveTapTime = System.currentTimeMillis();
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
isClickTap = MathUtils.distance(mDownX,mDownY,event.getX(),event.getY()) < HOVER_TAP_SLOP;
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
if(isClickTap && mLastHoveTapTime + HOVER_TAP_TIMEOUT > System.currentTimeMillis()){
|
||||
startFocusAndMetering(event.getX(),event.getY());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void startFocusAndMetering(float x, float y){
|
||||
if(mCamera != null){
|
||||
LogUtils.d("startFocusAndMetering:" + x + "," + y);
|
||||
MeteringPoint point = mPreviewView.getMeteringPointFactory().createPoint(x,y);
|
||||
mCamera.getCameraControl().startFocusAndMetering(new FocusMeteringAction.Builder(point).build());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void initConfig(){
|
||||
if(mCameraConfig == null){
|
||||
mCameraConfig = new CameraConfig();
|
||||
@@ -148,6 +207,7 @@ public class DefaultCameraScan extends CameraScan {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CameraScan setCameraConfig(CameraConfig cameraConfig) {
|
||||
if(cameraConfig != null){
|
||||
@@ -176,7 +236,7 @@ public class DefaultCameraScan extends CameraScan {
|
||||
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST));
|
||||
imageAnalysis.setAnalyzer(Executors.newSingleThreadExecutor(), image -> {
|
||||
if(isAnalyze && !isAnalyzeResult && mAnalyzer != null){
|
||||
Result result = mAnalyzer.analyze(image);
|
||||
Result result = mAnalyzer.analyze(image,mOrientation);
|
||||
if(result != null){
|
||||
mResultLiveData.postValue(result);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.google.zxing.Result;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.camera.core.ImageProxy;
|
||||
import android.content.res.Configuration;
|
||||
|
||||
/**
|
||||
* 分析器
|
||||
@@ -12,6 +13,12 @@ import androidx.camera.core.ImageProxy;
|
||||
*/
|
||||
public interface Analyzer {
|
||||
|
||||
/**
|
||||
* Analyzes an image to produce a result.
|
||||
* @param image The image to analyze
|
||||
* @param orientation {@link Configuration#ORIENTATION_LANDSCAPE}, {@link Configuration#ORIENTATION_PORTRAIT}.
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
Result analyze(@NonNull ImageProxy image);
|
||||
Result analyze(@NonNull ImageProxy image,int orientation);
|
||||
}
|
||||
|
||||
@@ -19,12 +19,18 @@ public abstract class AreaRectAnalyzer extends ImageAnalyzer {
|
||||
DecodeConfig mDecodeConfig;
|
||||
Map<DecodeHintType,?> mHints;
|
||||
boolean isMultiDecode = true;
|
||||
private float mAreaRectRatio = DecodeConfig.DEFAULT_AREA_RECT_RATIO;
|
||||
private int mAreaRectHorizontalOffset = 0;
|
||||
private int mAreaRectVerticalOffset = 0;
|
||||
|
||||
public AreaRectAnalyzer(@Nullable DecodeConfig config){
|
||||
this.mDecodeConfig = config;
|
||||
if(config != null){
|
||||
mHints = config.getHints();
|
||||
isMultiDecode = config.isMultiDecode();
|
||||
mAreaRectRatio = config.getAreaRectRatio();
|
||||
mAreaRectHorizontalOffset = config.getAreaRectHorizontalOffset();
|
||||
mAreaRectVerticalOffset = config.getAreaRectVerticalOffset();
|
||||
}else{
|
||||
mHints = DecodeFormatManager.DEFAULT_HINTS;
|
||||
}
|
||||
@@ -34,19 +40,22 @@ public abstract class AreaRectAnalyzer extends ImageAnalyzer {
|
||||
@Nullable
|
||||
@Override
|
||||
public Result analyze(byte[] data, int width, int height) {
|
||||
if(mDecodeConfig == null || mDecodeConfig.isFullAreaScan()){
|
||||
//mDecodeConfig为空或者支持全区域扫码识别时,直接使用全区域进行扫码识别
|
||||
return analyze(data,width,height,0,0,width,height);
|
||||
if(mDecodeConfig != null){
|
||||
if(mDecodeConfig.isFullAreaScan()){
|
||||
//mDecodeConfig为空或者支持全区域扫码识别时,直接使用全区域进行扫码识别
|
||||
return analyze(data,width,height,0,0,width,height);
|
||||
}
|
||||
|
||||
Rect rect = mDecodeConfig.getAnalyzeAreaRect();
|
||||
if(rect != null){//如果分析区域不为空,则使用指定的区域进行扫码识别
|
||||
return analyze(data,width,height,rect.left,rect.top,rect.width(),rect.height());
|
||||
}
|
||||
}
|
||||
|
||||
Rect rect = mDecodeConfig.getAnalyzeAreaRect();
|
||||
if(rect != null){//如果分析区域不为空,则使用指定的区域进行扫码识别
|
||||
return analyze(data,width,height,rect.left,rect.top,rect.width(),rect.height());
|
||||
}
|
||||
//如果分析区域为空,则通过识别区域比例和相关的偏移量计算出最终的区域进行扫码识别
|
||||
int size = (int)(Math.min(width,height) * mDecodeConfig.getAreaRectRatio());
|
||||
int left = (width-size)/2 + mDecodeConfig.getAreaRectHorizontalOffset();
|
||||
int top = (height-size)/2 + mDecodeConfig.getAreaRectVerticalOffset();
|
||||
int size = (int)(Math.min(width,height) * mAreaRectRatio);
|
||||
int left = (width-size)/2 + mAreaRectHorizontalOffset;
|
||||
int top = (height-size)/2 + mAreaRectVerticalOffset;
|
||||
|
||||
return analyze(data,width,height,left,top,size,size);
|
||||
|
||||
|
||||
@@ -48,9 +48,10 @@ public abstract class BarcodeFormatAnalyzer extends AreaRectAnalyzer {
|
||||
if(rawResult == null && mDecodeConfig != null){
|
||||
if(rawResult == null && mDecodeConfig.isSupportVerticalCode()){
|
||||
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];
|
||||
for (int y = 0; y < dataHeight; y++) {
|
||||
for (int x = 0; x < dataWidth; x++){
|
||||
rotatedData[x * dataHeight + dataHeight - y - 1] = data[x + y * dataWidth];
|
||||
}
|
||||
}
|
||||
rawResult = decodeInternal(new PlanarYUVLuminanceSource(rotatedData,dataHeight,dataWidth,top,left,height,width,false),mDecodeConfig.isSupportVerticalCodeMultiDecode());
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.king.zxing.analyze;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.ImageFormat;
|
||||
|
||||
import com.google.zxing.Result;
|
||||
@@ -28,13 +29,24 @@ public abstract class ImageAnalyzer implements Analyzer {
|
||||
public abstract Result analyze(byte[] data, int width, int height);
|
||||
|
||||
@Override
|
||||
public Result analyze(@NonNull ImageProxy image) {
|
||||
public Result analyze(@NonNull ImageProxy image,int orientation) {
|
||||
if(image.getFormat() == ImageFormat.YUV_420_888){
|
||||
@SuppressLint("UnsafeExperimentalUsageError")
|
||||
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
|
||||
byte[] data = new byte[buffer.remaining()];
|
||||
buffer.get(data);
|
||||
return analyze(data,image.getWidth(),image.getHeight());
|
||||
int width = image.getWidth();
|
||||
int height = image.getHeight();
|
||||
if(orientation == Configuration.ORIENTATION_PORTRAIT){
|
||||
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 analyze(rotatedData,height,width);
|
||||
}
|
||||
return analyze(data,width,height);
|
||||
}
|
||||
LogUtils.w("imageFormat: " + image.getFormat());
|
||||
return null;
|
||||
|
||||
@@ -54,8 +54,9 @@ public class MultiFormatAnalyzer extends AreaRectAnalyzer {
|
||||
if(rawResult == null && mDecodeConfig.isSupportVerticalCode()){
|
||||
byte[] rotatedData = new byte[data.length];
|
||||
for (int y = 0; y < dataHeight; y++) {
|
||||
for (int x = 0; x < dataWidth; x++)
|
||||
for (int x = 0; x < dataWidth; x++){
|
||||
rotatedData[x * dataHeight + dataHeight - y - 1] = data[x + y * dataWidth];
|
||||
}
|
||||
}
|
||||
rawResult = decodeInternal(new PlanarYUVLuminanceSource(rotatedData,dataHeight,dataWidth,top,left,height,width,false),mDecodeConfig.isSupportVerticalCodeMultiDecode());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user