v2.0.1
* 更新CameraX至v1.0.0-rc01 * 新增支持点击预览区域对焦目标 * 修改一些默认配置 * 优化细节
This commit is contained in:
10
README.md
10
README.md
@@ -194,8 +194,8 @@ CameraScan配置示例(只需识别二维码的配置示例)
|
||||
//初始化解码配置
|
||||
DecodeConfig decodeConfig = new DecodeConfig();
|
||||
decodeConfig.setHints(DecodeFormatManager.QR_CODE_HINTS)//如果只有识别二维码的需求,这样设置效率会更高
|
||||
.setFullAreaScan(false)//设置是否全区域识别,默认true
|
||||
.setAreaRectRatio(0.9f)//设置识别区域比例,默认0.9,设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别
|
||||
.setFullAreaScan(false)//设置是否全区域识别,默认false
|
||||
.setAreaRectRatio(0.8f)//设置识别区域比例,默认0.8,设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别
|
||||
.setAreaRectVerticalOffset(0)//设置识别区域垂直方向偏移量,默认为0,为0表示居中,可以为负数
|
||||
.setAreaRectHorizontalOffset(0);//设置识别区域水平方向偏移量,默认为0,为0表示居中,可以为负数
|
||||
|
||||
@@ -239,6 +239,12 @@ compileOptions {
|
||||
|
||||
## 版本记录
|
||||
|
||||
#### v2.0.1:2020-12-30
|
||||
* 更新CameraX至v1.0.0-rc01
|
||||
* 新增支持点击预览区域对焦目标
|
||||
* 修改一些默认配置
|
||||
* 优化细节
|
||||
|
||||
#### v2.0.0:2020-12-24
|
||||
* 基于CameraX进行重构
|
||||
* 抽象整体流程,可扩展性更高
|
||||
|
||||
@@ -41,9 +41,9 @@ dependencies {
|
||||
androidTestImplementation deps.test.runner
|
||||
androidTestImplementation deps.test.espresso
|
||||
|
||||
implementation deps.support.design
|
||||
implementation deps.support.appcompat
|
||||
implementation deps.support.constraintlayout
|
||||
implementation deps.androidx.design
|
||||
implementation deps.androidx.appcompat
|
||||
implementation deps.androidx.constraintlayout
|
||||
|
||||
implementation deps.kotlin
|
||||
implementation deps.corektx
|
||||
|
||||
Binary file not shown.
@@ -1 +1 @@
|
||||
[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":27,"versionName":"2.0.0","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release","dirName":""},"path":"app-release.apk","properties":{}}]
|
||||
[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":28,"versionName":"2.0.1","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release","dirName":""},"path":"app-release.apk","properties":{}}]
|
||||
@@ -67,10 +67,10 @@ public class CustomCaptureActivity extends CaptureActivity {
|
||||
decodeConfig.setHints(DecodeFormatManager.ALL_HINTS)////设置解码
|
||||
.setSupportVerticalCode(true)//设置是否支持扫垂直的条码 (增强识别率,相应的也会增加性能消耗)
|
||||
.setSupportLuminanceInvert(true)//设置是否支持识别反色码,黑白颜色反转(增强识别率,相应的也会增加性能消耗)
|
||||
// .setAreaRectRatio(0.9f)//设置识别区域比例,默认0.9,设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别
|
||||
.setAreaRectRatio(0.8f)//设置识别区域比例,默认0.8,设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别
|
||||
// .setAreaRectVerticalOffset(0)//设置识别区域垂直方向偏移量,默认为0,为0表示居中,可以为负数
|
||||
// .setAreaRectHorizontalOffset(0)//设置识别区域水平方向偏移量,默认为0,为0表示居中,可以为负数
|
||||
.setFullAreaScan(true);//设置是否全区域识别,默认true
|
||||
.setFullAreaScan(false);//设置是否全区域识别,默认false
|
||||
|
||||
//获取CameraScan,里面有扫码相关的配置设置。CameraScan里面包含部分支持链式调用的方法,即调用返回是CameraScan本身的一些配置建议在startCamera之前调用。
|
||||
getCameraScan().setPlayBeep(true)//设置是否播放音效,默认为false
|
||||
|
||||
@@ -41,8 +41,8 @@ public class QRCodeActivity extends CaptureActivity {
|
||||
//初始化解码配置
|
||||
DecodeConfig decodeConfig = new DecodeConfig();
|
||||
decodeConfig.setHints(DecodeFormatManager.QR_CODE_HINTS)//如果只有识别二维码的需求,这样设置效率会更高
|
||||
.setFullAreaScan(false)//设置是否全区域识别,默认true
|
||||
.setAreaRectRatio(0.9f)//设置识别区域比例,默认0.9,设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别
|
||||
.setFullAreaScan(false)//设置是否全区域识别,默认false
|
||||
.setAreaRectRatio(0.8f)//设置识别区域比例,默认0.8,设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别
|
||||
.setAreaRectVerticalOffset(0)//设置识别区域垂直方向偏移量,默认为0,为0表示居中,可以为负数
|
||||
.setAreaRectHorizontalOffset(0);//设置识别区域水平方向偏移量,默认为0,为0表示居中,可以为负数
|
||||
|
||||
|
||||
@@ -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,7 +40,8 @@ public abstract class AreaRectAnalyzer extends ImageAnalyzer {
|
||||
@Nullable
|
||||
@Override
|
||||
public Result analyze(byte[] data, int width, int height) {
|
||||
if(mDecodeConfig == null || mDecodeConfig.isFullAreaScan()){
|
||||
if(mDecodeConfig != null){
|
||||
if(mDecodeConfig.isFullAreaScan()){
|
||||
//mDecodeConfig为空或者支持全区域扫码识别时,直接使用全区域进行扫码识别
|
||||
return analyze(data,width,height,0,0,width,height);
|
||||
}
|
||||
@@ -43,10 +50,12 @@ public abstract class AreaRectAnalyzer extends ImageAnalyzer {
|
||||
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,9 +54,10 @@ 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());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//App
|
||||
def app_version = [:]
|
||||
app_version.versionCode = 27
|
||||
app_version.versionName = "2.0.0"
|
||||
app_version.versionCode = 28
|
||||
app_version.versionName = "2.0.1"
|
||||
ext.app_version = app_version
|
||||
|
||||
//build version
|
||||
@@ -35,18 +35,18 @@ versions.coreKtx = "1.3.2"
|
||||
//zxing
|
||||
versions.zxing = "3.3.0"
|
||||
|
||||
versions.camerax = "1.0.0-beta12"
|
||||
versions.camerax = "1.0.0-rc01"
|
||||
|
||||
versions.easypermissions = "3.0.0"
|
||||
|
||||
ext.versions = versions
|
||||
|
||||
//support
|
||||
def support = [:]
|
||||
support.design = "com.google.android.material:material:$versions.material"
|
||||
support.appcompat = "androidx.appcompat:appcompat:$versions.appcompat"
|
||||
support.constraintlayout = "androidx.constraintlayout:constraintlayout:$versions.constraintLayout"
|
||||
deps.support = support
|
||||
//androidx
|
||||
def androidx = [:]
|
||||
androidx.design = "com.google.android.material:material:$versions.material"
|
||||
androidx.appcompat = "androidx.appcompat:appcompat:$versions.appcompat"
|
||||
androidx.constraintlayout = "androidx.constraintlayout:constraintlayout:$versions.constraintLayout"
|
||||
deps.androidx = androidx
|
||||
|
||||
//test
|
||||
def test = [:]
|
||||
|
||||
Reference in New Issue
Block a user