getHints() {
return hints;
}
@@ -105,7 +111,7 @@ public class DecodeConfig {
* @param hints {@link DecodeFormatManager}
*
* 内置的一些解码可参见如下:
- * @return
+ * @return {@link DecodeConfig}
* @see {@link DecodeFormatManager#DEFAULT_HINTS}
* @see {@link DecodeFormatManager#ALL_HINTS}
* @see {@link DecodeFormatManager#CODE_128_HINTS}
@@ -124,7 +130,7 @@ public class DecodeConfig {
/**
* 是否支持识别反色码,黑白颜色反转
*
- * @return
+ * @return 是否支持识别反色码
*/
public boolean isSupportLuminanceInvert() {
return isSupportLuminanceInvert;
@@ -134,7 +140,7 @@ public class DecodeConfig {
* 设置是否支持识别反色码,黑白颜色反转
*
* @param supportLuminanceInvert 默认为{@code false},想要增强支持扫码识别反色码时可使用,相应的也会增加性能消耗。
- * @return
+ * @return {@link DecodeConfig}
*/
public DecodeConfig setSupportLuminanceInvert(boolean supportLuminanceInvert) {
isSupportLuminanceInvert = supportLuminanceInvert;
@@ -144,7 +150,7 @@ public class DecodeConfig {
/**
* 是否支持扫垂直的条码
*
- * @return
+ * @return 是否支持扫垂直的条码
*/
public boolean isSupportVerticalCode() {
return isSupportVerticalCode;
@@ -154,7 +160,7 @@ public class DecodeConfig {
* 设置是否支持扫垂直的条码
*
* @param supportVerticalCode 默认为{@code false},想要增强支持扫码识别垂直的条码时可使用,相应的也会增加性能消耗。
- * @return
+ * @return {@link DecodeConfig}
*/
public DecodeConfig setSupportVerticalCode(boolean supportVerticalCode) {
isSupportVerticalCode = supportVerticalCode;
@@ -164,7 +170,7 @@ public class DecodeConfig {
/**
* 是否支持使用多解码
*
- * @return
+ * @return 是否支持使用多解码
*/
public boolean isMultiDecode() {
return isMultiDecode;
@@ -185,7 +191,7 @@ public class DecodeConfig {
/**
* 是否支持识别反色码(条码黑白颜色反转的码)使用多解码
*
- * @return
+ * @return 是否支持识别反色码
*/
public boolean isSupportLuminanceInvertMultiDecode() {
return isSupportLuminanceInvertMultiDecode;
@@ -195,7 +201,7 @@ public class DecodeConfig {
* 设置是否支持识别反色码(条码黑白颜色反转的码)使用多解码
*
* @param supportLuminanceInvertMultiDecode 默认为{@code false},想要增强支持扫码识别反色码时可使用,相应的也会增加性能消耗。
- * @return
+ * @return {@link DecodeConfig}
* @see {@link HybridBinarizer} , {@link GlobalHistogramBinarizer}
*/
public DecodeConfig setSupportLuminanceInvertMultiDecode(boolean supportLuminanceInvertMultiDecode) {
@@ -206,7 +212,7 @@ public class DecodeConfig {
/**
* 是否支持垂直的条码,使用多解码
*
- * @return
+ * @return 是否支持垂直的条码,使用多解码
*/
public boolean isSupportVerticalCodeMultiDecode() {
return isSupportVerticalCodeMultiDecode;
@@ -216,7 +222,7 @@ public class DecodeConfig {
* 设置是否支持垂直的条码,使用多解码;解码时,对应的二值化的实现: {@link HybridBinarizer} , {@link GlobalHistogramBinarizer}
*
* @param supportVerticalCodeMultiDecode 默认为{@code false},想要增强支持扫码识别垂直的条码时可使用,相应的也会增加性能消耗。
- * @return
+ * @return {@link DecodeConfig}
*/
public DecodeConfig setSupportVerticalCodeMultiDecode(boolean supportVerticalCodeMultiDecode) {
isSupportVerticalCodeMultiDecode = supportVerticalCodeMultiDecode;
@@ -226,7 +232,7 @@ public class DecodeConfig {
/**
* 需要分析识别区域
*
- * @return
+ * @return 分析识别区域
*/
public Rect getAnalyzeAreaRect() {
return analyzeAreaRect;
@@ -244,7 +250,7 @@ public class DecodeConfig {
* 您还可以通过{@link CameraScan#setCameraConfig(CameraConfig)}去自定义配置{@link CameraConfig}的配置信息控制预览相关配置信息
*
* 即判定区域分析的优先级顺序为:{@link #setFullAreaScan(boolean)} -> {@link #setAnalyzeAreaRect(Rect)} -> {@link #setAreaRectRatio(float)}
- * @return
+ * @return {@link DecodeConfig}
*/
public DecodeConfig setAnalyzeAreaRect(Rect analyzeAreaRect) {
this.analyzeAreaRect = analyzeAreaRect;
@@ -254,7 +260,7 @@ public class DecodeConfig {
/**
* 是否支持全区域扫码识别
*
- * @return
+ * @return 是否支持全区域扫码识别
*/
public boolean isFullAreaScan() {
return isFullAreaScan;
@@ -274,7 +280,7 @@ public class DecodeConfig {
* 您还可以通过{@link CameraScan#setCameraConfig(CameraConfig)}去自定义配置{@link CameraConfig}的配置信息控制预览相关配置信息
*
* 即判定区域分析的优先级顺序为:{@link #setFullAreaScan(boolean)} -> {@link #setAnalyzeAreaRect(Rect)} -> {@link #setAreaRectRatio(float)}
- * @return
+ * @return {@link DecodeConfig}
*/
public DecodeConfig setFullAreaScan(boolean fullAreaScan) {
isFullAreaScan = fullAreaScan;
@@ -284,7 +290,7 @@ public class DecodeConfig {
/**
* 识别区域比例,默认{@link #DEFAULT_AREA_RECT_RATIO},设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别
*
- * @return
+ * @return 识别区域比例,默认{@link #DEFAULT_AREA_RECT_RATIO}
*/
public float getAreaRectRatio() {
return areaRectRatio;
@@ -302,7 +308,7 @@ public class DecodeConfig {
* 您还可以通过{@link CameraScan#setCameraConfig(CameraConfig)}去自定义配置{@link CameraConfig}的配置信息控制预览相关配置信息
*
* 即判定区域分析的优先级顺序为:{@link #setFullAreaScan(boolean)} -> {@link #setAnalyzeAreaRect(Rect)} -> {@link #setAreaRectRatio(float)}
- * @return
+ * @return {@link DecodeConfig}
*/
public DecodeConfig setAreaRectRatio(@FloatRange(from = 0.5, to = 1.0) float areaRectRatio) {
this.areaRectRatio = areaRectRatio;
@@ -312,7 +318,7 @@ public class DecodeConfig {
/**
* 识别区域垂直方向偏移量,支持负数,大于0时,居中心向下偏移,小于0时,居中心向上偏移
*
- * @return
+ * @return 识别区域垂直方向偏移量
*/
public int getAreaRectVerticalOffset() {
return areaRectVerticalOffset;
@@ -322,7 +328,7 @@ public class DecodeConfig {
* 设置识别区域垂直方向偏移量,支持负数,大于0时,居中心向下偏移,小于0时,居中心向上偏移
*
* @param areaRectVerticalOffset
- * @return
+ * @return {@link DecodeConfig}
*/
public DecodeConfig setAreaRectVerticalOffset(int areaRectVerticalOffset) {
this.areaRectVerticalOffset = areaRectVerticalOffset;
@@ -332,7 +338,7 @@ public class DecodeConfig {
/**
* 识别区域水平方向偏移量,支持负数,大于0时,居中心向右偏移,小于0时,居中心向左偏移
*
- * @return
+ * @return 识别区域水平方向偏移量
*/
public int getAreaRectHorizontalOffset() {
return areaRectHorizontalOffset;
@@ -342,7 +348,7 @@ public class DecodeConfig {
* 设置识别区域水平方向偏移量,支持负数,大于0时,居中心向右偏移,小于0时,居中心向左偏移
*
* @param areaRectHorizontalOffset
- * @return
+ * @return {@link DecodeConfig}
*/
public DecodeConfig setAreaRectHorizontalOffset(int areaRectHorizontalOffset) {
this.areaRectHorizontalOffset = areaRectHorizontalOffset;
diff --git a/zxing-lite/src/main/java/com/king/zxing/DecodeFormatManager.java b/zxing-lite/src/main/java/com/king/zxing/DecodeFormatManager.java
index 0a08c42..10d6e91 100644
--- a/zxing-lite/src/main/java/com/king/zxing/DecodeFormatManager.java
+++ b/zxing-lite/src/main/java/com/king/zxing/DecodeFormatManager.java
@@ -41,7 +41,6 @@ public final class DecodeFormatManager {
* 二维码
*/
public static final Map TWO_DIMENSIONAL_HINTS = new EnumMap<>(DecodeHintType.class);
-
/**
* 默认
*/
@@ -86,7 +85,7 @@ public final class DecodeFormatManager {
}
/**
- * 二维码
+ * 一维码
* 包括如下几种格式:
* {@link BarcodeFormat#CODABAR}
* {@link BarcodeFormat#CODE_39}
diff --git a/zxing-lite/src/main/java/com/king/zxing/DefaultCameraScan.java b/zxing-lite/src/main/java/com/king/zxing/DefaultCameraScan.java
index a62777e..c2d6971 100644
--- a/zxing-lite/src/main/java/com/king/zxing/DefaultCameraScan.java
+++ b/zxing-lite/src/main/java/com/king/zxing/DefaultCameraScan.java
@@ -17,7 +17,9 @@ 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.config.AspectRatioCameraConfig;
import com.king.zxing.config.CameraConfig;
+import com.king.zxing.config.ResolutionCameraConfig;
import com.king.zxing.manager.AmbientLightManager;
import com.king.zxing.manager.BeepManager;
import com.king.zxing.util.LogUtils;
@@ -67,14 +69,12 @@ public class DefaultCameraScan extends CameraScan {
* 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;
-
/**
* 每次缩放改变的步长
*/
@@ -83,40 +83,73 @@ public class DefaultCameraScan extends CameraScan {
private FragmentActivity mFragmentActivity;
private Context mContext;
private LifecycleOwner mLifecycleOwner;
+ /**
+ * 预览视图
+ */
private PreviewView mPreviewView;
private ListenableFuture mCameraProviderFuture;
+ /**
+ * 相机
+ */
private Camera mCamera;
-
+ /**
+ * 相机配置
+ */
private CameraConfig mCameraConfig;
+ /**
+ * 分析器
+ */
private Analyzer mAnalyzer;
-
/**
* 是否分析
*/
private volatile boolean isAnalyze = true;
-
/**
* 是否已经分析出结果
*/
private volatile boolean isAnalyzeResult;
-
+ /**
+ * 闪光灯(手电筒)视图
+ */
private View flashlightView;
private MutableLiveData mResultLiveData;
-
+ /**
+ * 扫描结果回调
+ */
private OnScanResultCallback mOnScanResultCallback;
-
+ /**
+ * 蜂鸣音效管理器:主要用于播放蜂鸣提示音和振动效果
+ */
private BeepManager mBeepManager;
+ /**
+ * 环境光线管理器:主要通过传感器来监听光线的亮度变化
+ */
private AmbientLightManager mAmbientLightManager;
private int mOrientation;
private int mImageWidth;
private int mImageHeight;
+ /**
+ * 最后自动缩放时间
+ */
private long mLastAutoZoomTime;
+ /**
+ * 最后点击时间,根据两次点击时间间隔用于区分单机和触摸缩放事件
+ */
private long mLastHoveTapTime;
+ /**
+ * 是否是点击事件
+ */
private boolean isClickTap;
+ /**
+ * 按下时X坐标
+ */
private float mDownX;
+ /**
+ * 按下时Y坐标
+ */
private float mDownY;
public DefaultCameraScan(@NonNull FragmentActivity activity, @NonNull PreviewView previewView) {
@@ -199,7 +232,7 @@ public class DefaultCameraScan extends CameraScan {
/**
* 处理预览视图点击事件;如果触发的点击事件被判定对焦操作,则开始自动对焦
*
- * @param event
+ * @param event 事件
*/
private void handlePreviewViewClickTap(MotionEvent event) {
if (event.getPointerCount() == 1) {
@@ -226,8 +259,8 @@ public class DefaultCameraScan extends CameraScan {
/**
* 开始对焦和测光
*
- * @param x
- * @param y
+ * @param x X轴坐标
+ * @param y Y轴坐标
*/
private void startFocusAndMetering(float x, float y) {
if (mCamera != null) {
@@ -240,19 +273,6 @@ public class DefaultCameraScan extends CameraScan {
}
}
- /**
- * 初始化配置
- */
- private void initConfig() {
- if (mCameraConfig == null) {
- mCameraConfig = new CameraConfig();
- }
- if (mAnalyzer == null) {
- mAnalyzer = new MultiFormatAnalyzer();
- }
- }
-
-
@Override
public CameraScan setCameraConfig(CameraConfig cameraConfig) {
if (cameraConfig != null) {
@@ -261,12 +281,35 @@ public class DefaultCameraScan extends CameraScan {
return this;
}
+ /**
+ * 初始化相机配置
+ */
+ /**
+ * 初始化相机配置
+ */
+ private void initCameraConfig(Context context) {
+ if (mCameraConfig == null) {
+ DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+ int size = Math.min(displayMetrics.widthPixels, displayMetrics.heightPixels);
+ // 根据分辨率初始化缺省配置CameraConfig;在此前提下尽可能的找到比屏幕分辨率小一级的配置;在适配、性能与体验之间得有所取舍,找到平衡点。
+ if (size > ResolutionCameraConfig.IMAGE_QUALITY_1080P) {
+ mCameraConfig = new ResolutionCameraConfig(context);
+ } else if (size > ResolutionCameraConfig.IMAGE_QUALITY_720P) {
+ mCameraConfig = new ResolutionCameraConfig(context, ResolutionCameraConfig.IMAGE_QUALITY_720P);
+ } else {
+ mCameraConfig = new AspectRatioCameraConfig(context);
+ }
+ }
+ }
+
@Override
public void startCamera() {
- initConfig();
+ initCameraConfig(mContext);
+ if (mAnalyzer == null) {
+ mAnalyzer = new MultiFormatAnalyzer();
+ }
mCameraProviderFuture = ProcessCameraProvider.getInstance(mContext);
mCameraProviderFuture.addListener(() -> {
-
try {
Preview preview = mCameraConfig.options(new Preview.Builder());
@@ -336,6 +379,7 @@ public class DefaultCameraScan extends CameraScan {
/**
* 处理自动缩放
+ *
* @param distance
* @param result
* @return
@@ -353,7 +397,8 @@ public class DefaultCameraScan extends CameraScan {
/**
* 扫描结果回调
- * @param result
+ *
+ * @param result 扫描结果
*/
private void scanResultCallback(Result result) {
if (mOnScanResultCallback != null && mOnScanResultCallback.onScanResultCallback(result)) {
@@ -473,11 +518,6 @@ public class DefaultCameraScan extends CameraScan {
return false;
}
- /**
- * 是否支持闪光灯
- *
- * @return
- */
@Override
public boolean hasFlashUnit() {
if (mCamera != null) {
diff --git a/zxing-lite/src/main/java/com/king/zxing/ICamera.java b/zxing-lite/src/main/java/com/king/zxing/ICamera.java
index b8543c2..e12e043 100644
--- a/zxing-lite/src/main/java/com/king/zxing/ICamera.java
+++ b/zxing-lite/src/main/java/com/king/zxing/ICamera.java
@@ -21,9 +21,9 @@ public interface ICamera {
void stopCamera();
/**
- * 获取{@link Camera}
+ * 获取 {@link Camera}
*
- * @return
+ * @return {@link Camera}
*/
@Nullable
Camera getCamera();
diff --git a/zxing-lite/src/main/java/com/king/zxing/ICameraControl.java b/zxing-lite/src/main/java/com/king/zxing/ICameraControl.java
index 2dfa9c8..8f736bb 100644
--- a/zxing-lite/src/main/java/com/king/zxing/ICameraControl.java
+++ b/zxing-lite/src/main/java/com/king/zxing/ICameraControl.java
@@ -22,7 +22,7 @@ public interface ICameraControl {
/**
* 缩放到指定比例
*
- * @param ratio
+ * @param ratio 缩放比例
*/
void zoomTo(float ratio);
@@ -39,28 +39,28 @@ public interface ICameraControl {
/**
* 线性缩放到指定比例
*
- * @param linearZoom
+ * @param linearZoom 线性缩放比例;范围在:0.0 ~ 1.0之间
*/
void lineZoomTo(@FloatRange(from = 0.0, to = 1.0) float linearZoom);
/**
* 设置闪光灯(手电筒)是否开启
*
- * @param torch
+ * @param torch 是否开启闪光灯(手电筒)
*/
void enableTorch(boolean torch);
/**
* 闪光灯(手电筒)是否开启
*
- * @return
+ * @return 闪光灯(手电筒)是否开启
*/
boolean isTorchEnabled();
/**
* 是否支持闪光灯
*
- * @return
+ * @return 是否支持闪光灯
*/
boolean hasFlashUnit();
}
diff --git a/zxing-lite/src/main/java/com/king/zxing/ViewfinderView.java b/zxing-lite/src/main/java/com/king/zxing/ViewfinderView.java
index 4e3af5b..d8f0259 100644
--- a/zxing-lite/src/main/java/com/king/zxing/ViewfinderView.java
+++ b/zxing-lite/src/main/java/com/king/zxing/ViewfinderView.java
@@ -8,6 +8,7 @@ import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
+import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Point;
@@ -26,8 +27,6 @@ import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
-import com.king.zxing.util.LogUtils;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
@@ -216,6 +215,10 @@ public class ViewfinderView extends View {
private Bitmap laserBitmap;
+ private float laserBitmapRatio;
+
+ private float laserBitmapWidth;
+
private int viewfinderStyle = ViewfinderStyle.CLASSIC;
private List pointList;
@@ -248,7 +251,7 @@ public class ViewfinderView extends View {
*/
public enum LaserStyle {
NONE(0), LINE(1), GRID(2), IMAGE(3);
- private int mValue;
+ private final int mValue;
LaserStyle(int value) {
mValue = value;
@@ -270,7 +273,7 @@ public class ViewfinderView extends View {
public enum TextLocation {
TOP(0), BOTTOM(1);
- private int mValue;
+ private final int mValue;
TextLocation(int value) {
mValue = value;
@@ -292,7 +295,7 @@ public class ViewfinderView extends View {
public enum FrameGravity {
CENTER(0), LEFT(1), TOP(2), RIGHT(3), BOTTOM(4);
- private int mValue;
+ private final int mValue;
FrameGravity(int value) {
mValue = value;
@@ -369,6 +372,7 @@ public class ViewfinderView extends View {
isShowPointAnim = array.getBoolean(R.styleable.ViewfinderView_showPointAnim, true);
Drawable pointDrawable = array.getDrawable(R.styleable.ViewfinderView_pointDrawable);
Drawable laserDrawable = array.getDrawable(R.styleable.ViewfinderView_laserDrawable);
+ laserBitmapRatio = array.getFloat(R.styleable.ViewfinderView_laserDrawableRatio, 0.625f);
viewfinderStyle = array.getInt(R.styleable.ViewfinderView_viewfinderStyle, ViewfinderStyle.CLASSIC);
array.recycle();
@@ -433,6 +437,24 @@ public class ViewfinderView extends View {
this.laserStyle = laserStyle;
}
+ /**
+ * 设置激光扫描自定义图片
+ *
+ * @param drawableResId
+ */
+ public void setLaserDrawable(@DrawableRes int drawableResId) {
+ setLaserBitmap(BitmapFactory.decodeResource(getResources(), drawableResId));
+ }
+
+ /**
+ * 设置激光扫描自定义图片
+ *
+ * @param laserBitmap
+ */
+ public void setLaserBitmap(Bitmap laserBitmap) {
+ this.laserBitmap = laserBitmap;
+ scaleLaserBitmap();
+ }
public void setPointImageResource(@DrawableRes int drawable) {
setPointBitmap(BitmapFactory.decodeResource(getResources(), drawable));
}
@@ -448,10 +470,26 @@ public class ViewfinderView extends View {
initFrame(getWidth(),getHeight());
}
+ private void scaleLaserBitmap() {
+ if (laserBitmap != null && laserBitmapWidth > 0) {
+ float ratio = laserBitmapWidth / laserBitmap.getWidth();
+ Matrix matrix = new Matrix();
+ matrix.postScale(ratio, ratio);
+ int w = laserBitmap.getWidth();
+ int h = laserBitmap.getHeight();
+ laserBitmap = Bitmap.createBitmap(laserBitmap, 0, 0, w, h, matrix, true);
+ }
+ }
+
private void initFrame(int width, int height) {
int size = (int) (Math.min(width, height) * frameRatio);
+ if (laserBitmapWidth <= 0) {
+ laserBitmapWidth = Math.min(width, height) * laserBitmapRatio;
+ scaleLaserBitmap();
+ }
+
if (frameWidth <= 0 || frameWidth > width) {
frameWidth = size;
}
@@ -582,7 +620,7 @@ public class ViewfinderView extends View {
private void drawImageScanner(Canvas canvas, Rect frame) {
if (laserBitmap != null) {
paint.setColor(Color.WHITE);
- canvas.drawBitmap(laserBitmap, frame.left, scannerStart, paint);
+ canvas.drawBitmap(laserBitmap, (getWidth() - laserBitmap.getWidth()) / 2, scannerStart, paint);
if (scannerStart < scannerEnd) {
scannerStart += scannerLineMoveDistance;
} else {
@@ -591,7 +629,6 @@ public class ViewfinderView extends View {
} else {
drawLineScanner(canvas, frame);
}
-
}
/**
diff --git a/zxing-lite/src/main/java/com/king/zxing/analyze/BarcodeFormatAnalyzer.java b/zxing-lite/src/main/java/com/king/zxing/analyze/BarcodeFormatAnalyzer.java
index 4d9c521..09de404 100644
--- a/zxing-lite/src/main/java/com/king/zxing/analyze/BarcodeFormatAnalyzer.java
+++ b/zxing-lite/src/main/java/com/king/zxing/analyze/BarcodeFormatAnalyzer.java
@@ -16,13 +16,15 @@ import java.util.Map;
import androidx.annotation.Nullable;
/**
+ * 条码分析器
+ *
* @author Jenly
*/
public abstract class BarcodeFormatAnalyzer extends AreaRectAnalyzer {
private Reader mReader;
- public BarcodeFormatAnalyzer(@Nullable Map hints){
+ public BarcodeFormatAnalyzer(@Nullable Map hints) {
this(new DecodeConfig().setHints(hints));
}
@@ -31,62 +33,62 @@ public abstract class BarcodeFormatAnalyzer extends AreaRectAnalyzer {
initReader();
}
- private void initReader(){
+ private void initReader() {
mReader = createReader();
}
@Nullable
@Override
- public Result analyze(byte[] data, int dataWidth, int dataHeight,int left,int top,int width,int height) {
+ public Result analyze(byte[] data, int dataWidth, int dataHeight, int left, int top, int width, int height) {
Result rawResult = null;
- if(mReader != null){
+ if (mReader != null) {
try {
long start = System.currentTimeMillis();
- PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(data,dataWidth,dataHeight,left,top,width,height,false);
- rawResult = decodeInternal(source,isMultiDecode);
+ PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(data, dataWidth, dataHeight, left, top, width, height, false);
+ rawResult = decodeInternal(source, isMultiDecode);
- if(rawResult == null && mDecodeConfig != null){
- if(rawResult == null && mDecodeConfig.isSupportVerticalCode()){
+ if (rawResult == null && mDecodeConfig != null) {
+ 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());
+ rawResult = decodeInternal(new PlanarYUVLuminanceSource(rotatedData, dataHeight, dataWidth, top, left, height, width, false), mDecodeConfig.isSupportVerticalCodeMultiDecode());
}
- if(mDecodeConfig.isSupportLuminanceInvert()){
- rawResult = decodeInternal(source.invert(),mDecodeConfig.isSupportLuminanceInvertMultiDecode());
+ if (mDecodeConfig.isSupportLuminanceInvert()) {
+ rawResult = decodeInternal(source.invert(), mDecodeConfig.isSupportLuminanceInvertMultiDecode());
}
}
- if(rawResult != null){
+ if (rawResult != null) {
long end = System.currentTimeMillis();
LogUtils.d("Found barcode in " + (end - start) + " ms");
}
} catch (Exception e) {
- }finally {
+ } finally {
mReader.reset();
}
}
return rawResult;
}
- private Result decodeInternal(LuminanceSource source,boolean isMultiDecode){
+ private Result decodeInternal(LuminanceSource source, boolean isMultiDecode) {
Result result = null;
- try{
- try{
+ try {
+ try {
//采用HybridBinarizer解析
- result = mReader.decode(new BinaryBitmap(new HybridBinarizer(source)),mHints);
- }catch (Exception e){
+ result = mReader.decode(new BinaryBitmap(new HybridBinarizer(source)), mHints);
+ } catch (Exception e) {
}
- if(isMultiDecode && result == null){
+ if (isMultiDecode && result == null) {
//如果没有解析成功,再采用GlobalHistogramBinarizer解析一次
- result = mReader.decode(new BinaryBitmap(new GlobalHistogramBinarizer(source)),mHints);
+ result = mReader.decode(new BinaryBitmap(new GlobalHistogramBinarizer(source)), mHints);
}
- }catch (Exception e){
+ } catch (Exception e) {
}
return result;
diff --git a/zxing-lite/src/main/java/com/king/zxing/analyze/ImageAnalyzer.java b/zxing-lite/src/main/java/com/king/zxing/analyze/ImageAnalyzer.java
index 44cc45b..ce6bf27 100644
--- a/zxing-lite/src/main/java/com/king/zxing/analyze/ImageAnalyzer.java
+++ b/zxing-lite/src/main/java/com/king/zxing/analyze/ImageAnalyzer.java
@@ -5,22 +5,23 @@ import android.content.res.Configuration;
import android.graphics.ImageFormat;
import com.google.zxing.Result;
+import com.king.zxing.util.BitmapUtils;
import com.king.zxing.util.LogUtils;
-import java.nio.ByteBuffer;
-
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.camera.core.ImageProxy;
/**
* 图像分析器
+ *
* @author Jenly
*/
public abstract class ImageAnalyzer implements Analyzer {
/**
* 分析图像数据
+ *
* @param data
* @param width
* @param height
@@ -29,25 +30,23 @@ public abstract class ImageAnalyzer implements Analyzer {
public abstract Result analyze(byte[] data, int width, int height);
@Override
- 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);
+ public Result analyze(@NonNull ImageProxy image, int orientation) {
+ if (image.getFormat() == ImageFormat.YUV_420_888) {
int width = image.getWidth();
int height = image.getHeight();
- if(orientation == Configuration.ORIENTATION_PORTRAIT){
+ @SuppressLint("UnsafeOptInUsageError")
+ byte[] data = BitmapUtils.yuv420ThreePlanesToNV21(image.getImage().getPlanes(), width, height).array();
+ 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++){
+ for (int x = 0; x < width; x++) {
rotatedData[x * height + height - y - 1] = data[x + y * width];
}
}
- return analyze(rotatedData,height,width);
+ return analyze(rotatedData, height, width);
}
- return analyze(data,width,height);
- }else{
+ return analyze(data, width, height);
+ } else {
LogUtils.w("imageFormat: " + image.getFormat());
}
return null;
diff --git a/zxing-lite/src/main/java/com/king/zxing/analyze/QRCodeAnalyzer.java b/zxing-lite/src/main/java/com/king/zxing/analyze/QRCodeAnalyzer.java
index fb8d70e..a6c9af5 100644
--- a/zxing-lite/src/main/java/com/king/zxing/analyze/QRCodeAnalyzer.java
+++ b/zxing-lite/src/main/java/com/king/zxing/analyze/QRCodeAnalyzer.java
@@ -11,15 +11,17 @@ import androidx.annotation.Nullable;
/**
+ * 二维码分析器
+ *
* @author Jenly
*/
public class QRCodeAnalyzer extends BarcodeFormatAnalyzer {
public QRCodeAnalyzer() {
- this((DecodeConfig)null);
+ this((DecodeConfig) null);
}
- public QRCodeAnalyzer(@Nullable Map hints){
+ public QRCodeAnalyzer(@Nullable Map hints) {
this(new DecodeConfig().setHints(hints));
}
diff --git a/zxing-lite/src/main/java/com/king/zxing/config/AspectRatioCameraConfig.java b/zxing-lite/src/main/java/com/king/zxing/config/AspectRatioCameraConfig.java
index a12030d..3e5b039 100644
--- a/zxing-lite/src/main/java/com/king/zxing/config/AspectRatioCameraConfig.java
+++ b/zxing-lite/src/main/java/com/king/zxing/config/AspectRatioCameraConfig.java
@@ -3,8 +3,11 @@ package com.king.zxing.config;
import android.content.Context;
import android.util.DisplayMetrics;
+import com.king.zxing.CameraScan;
import com.king.zxing.util.LogUtils;
+import java.util.Locale;
+
import androidx.annotation.NonNull;
import androidx.camera.core.AspectRatio;
import androidx.camera.core.CameraSelector;
@@ -18,6 +21,9 @@ import androidx.camera.core.Preview;
*/
public final class AspectRatioCameraConfig extends CameraConfig {
+ /**
+ * 纵横比
+ */
private int mAspectRatio;
public AspectRatioCameraConfig(Context context) {
@@ -34,14 +40,15 @@ public final class AspectRatioCameraConfig extends CameraConfig {
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
int width = displayMetrics.widthPixels;
int height = displayMetrics.heightPixels;
+ LogUtils.d(String.format(Locale.getDefault(), "displayMetrics: %dx%d", width, height));
- float ratio = Math.max(width, height) / Math.min(width, height);
- if (Math.abs(ratio - 4.0F / 3.0F) < Math.abs(ratio - 16.0F / 9.0F)) {
+ float ratio = Math.max(width, height) / (float) Math.min(width, height);
+ if (Math.abs(ratio - CameraScan.ASPECT_RATIO_4_3) < Math.abs(ratio - CameraScan.ASPECT_RATIO_16_9)) {
mAspectRatio = AspectRatio.RATIO_4_3;
} else {
mAspectRatio = AspectRatio.RATIO_16_9;
}
- LogUtils.d("aspectRatio:" + mAspectRatio);
+ LogUtils.d("aspectRatio: " + mAspectRatio);
}
@NonNull
diff --git a/zxing-lite/src/main/java/com/king/zxing/config/ResolutionCameraConfig.java b/zxing-lite/src/main/java/com/king/zxing/config/ResolutionCameraConfig.java
index 5239679..e8b5376 100644
--- a/zxing-lite/src/main/java/com/king/zxing/config/ResolutionCameraConfig.java
+++ b/zxing-lite/src/main/java/com/king/zxing/config/ResolutionCameraConfig.java
@@ -4,6 +4,7 @@ import android.content.Context;
import android.util.DisplayMetrics;
import android.util.Size;
+import com.king.zxing.CameraScan;
import com.king.zxing.util.LogUtils;
import java.util.Locale;
@@ -29,7 +30,9 @@ public class ResolutionCameraConfig extends CameraConfig {
*/
public static final int IMAGE_QUALITY_720P = 720;
-
+ /**
+ * 目标尺寸
+ */
private Size mTargetSize;
/**
@@ -62,29 +65,27 @@ public class ResolutionCameraConfig extends CameraConfig {
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
int width = displayMetrics.widthPixels;
int height = displayMetrics.heightPixels;
+ LogUtils.d(String.format(Locale.getDefault(), "displayMetrics: %dx%d", width, height));
- LogUtils.d(String.format(Locale.getDefault(), "displayMetrics:%d x %d", width, height));
// 因为为了保持流畅性和性能,尽可能的限制在imageQuality(默认:1080p),在此前提下尽可能的找到屏幕接近的分辨率
if (width < height) {
+ float ratio = height / (float) width;
int size = Math.min(width, imageQuality);
- float ratio = width / (float) height;
- if (ratio > 0.7F) {
- // 一般应用于平板
- mTargetSize = new Size(size, (int) (size / 3.0F * 4.0F));
+ if (Math.abs(ratio - CameraScan.ASPECT_RATIO_4_3) < Math.abs(ratio - CameraScan.ASPECT_RATIO_16_9)) {
+ mTargetSize = new Size(size, Math.round(size * CameraScan.ASPECT_RATIO_4_3));
} else {
- mTargetSize = new Size(size, (int) (size / 9.0F * 16.0F));
+ mTargetSize = new Size(size, Math.round(size * CameraScan.ASPECT_RATIO_16_9));
}
} else {
int size = Math.min(height, imageQuality);
- float ratio = height / (float) width;
- if (ratio > 0.7F) {
- // 一般应用于平板
- mTargetSize = new Size((int) (size / 3.0F * 4.0F), size);
+ float ratio = width / (float) height;
+ if (Math.abs(ratio - CameraScan.ASPECT_RATIO_4_3) < Math.abs(ratio - CameraScan.ASPECT_RATIO_16_9)) {
+ mTargetSize = new Size(Math.round(size * CameraScan.ASPECT_RATIO_4_3), size);
} else {
- mTargetSize = new Size((int) (size / 9.0F * 16.0F), size);
+ mTargetSize = new Size(Math.round(size * CameraScan.ASPECT_RATIO_16_9), size);
}
}
- LogUtils.d("targetSize:" + mTargetSize);
+ LogUtils.d("targetSize: " + mTargetSize);
}
@NonNull
diff --git a/zxing-lite/src/main/java/com/king/zxing/manager/AmbientLightManager.java b/zxing-lite/src/main/java/com/king/zxing/manager/AmbientLightManager.java
index 8db276c..c3d94b3 100644
--- a/zxing-lite/src/main/java/com/king/zxing/manager/AmbientLightManager.java
+++ b/zxing-lite/src/main/java/com/king/zxing/manager/AmbientLightManager.java
@@ -7,6 +7,8 @@ import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
/**
+ * 环境光线管理器:主要通过传感器来监听光线的亮度变化
+ *
* @author Jenly
*/
public class AmbientLightManager implements SensorEventListener {
diff --git a/zxing-lite/src/main/java/com/king/zxing/manager/BeepManager.java b/zxing-lite/src/main/java/com/king/zxing/manager/BeepManager.java
index b9dd88c..e36dbe2 100644
--- a/zxing-lite/src/main/java/com/king/zxing/manager/BeepManager.java
+++ b/zxing-lite/src/main/java/com/king/zxing/manager/BeepManager.java
@@ -13,6 +13,8 @@ import com.king.zxing.util.LogUtils;
import java.io.Closeable;
/**
+ * 蜂鸣音效管理器:主要用于播放蜂鸣提示音和振动效果
+ *
* @author Jenly
*/
public final class BeepManager implements MediaPlayer.OnErrorListener, Closeable {
diff --git a/zxing-lite/src/main/java/com/king/zxing/util/BitmapUtils.java b/zxing-lite/src/main/java/com/king/zxing/util/BitmapUtils.java
new file mode 100644
index 0000000..19f7c77
--- /dev/null
+++ b/zxing-lite/src/main/java/com/king/zxing/util/BitmapUtils.java
@@ -0,0 +1,273 @@
+package com.king.zxing.util;
+
+import android.annotation.SuppressLint;
+import android.content.ContentResolver;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.ImageFormat;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.YuvImage;
+import android.media.ExifInterface;
+import android.media.Image;
+import android.net.Uri;
+import android.os.Build;
+import android.provider.MediaStore;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.camera.core.ImageProxy;
+
+/**
+ * Utils functions for bitmap conversions.
+ *
+ * @see BitmapUtils
+ */
+public class BitmapUtils {
+
+ private BitmapUtils() {
+ throw new AssertionError();
+ }
+
+ /**
+ * Converts NV21 format byte buffer to bitmap.
+ */
+ @Nullable
+ public static Bitmap getBitmap(ByteBuffer data, int width, int height, int rotationDegrees) {
+ data.rewind();
+ byte[] imageInBuffer = new byte[data.limit()];
+ data.get(imageInBuffer, 0, imageInBuffer.length);
+ try {
+ YuvImage image = new YuvImage(
+ imageInBuffer, ImageFormat.NV21, width, height, null);
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ image.compressToJpeg(new Rect(0, 0, width, height), 80, stream);
+
+ Bitmap bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());
+
+ stream.close();
+ return rotateBitmap(bmp, rotationDegrees, false, false);
+ } catch (Exception e) {
+ LogUtils.e("Error: " + e.getMessage());
+ }
+ return null;
+ }
+
+ /**
+ * Converts a YUV_420_888 image from CameraX API to a bitmap.
+ */
+ @Nullable
+ public static Bitmap getBitmap(ImageProxy image) {
+
+ @SuppressLint("UnsafeOptInUsageError")
+ ByteBuffer nv21Buffer = yuv420ThreePlanesToNV21(image.getImage().getPlanes(), image.getWidth(), image.getHeight());
+ return getBitmap(nv21Buffer, image.getWidth(), image.getHeight(), image.getImageInfo().getRotationDegrees());
+ }
+
+ /**
+ * Rotates a bitmap if it is converted from a bytebuffer.
+ */
+ private static Bitmap rotateBitmap(
+ Bitmap bitmap, int rotationDegrees, boolean flipX, boolean flipY) {
+ Matrix matrix = new Matrix();
+
+ // Rotate the image back to straight.
+ matrix.postRotate(rotationDegrees);
+
+ // Mirror the image along the X or Y axis.
+ matrix.postScale(flipX ? -1.0f : 1.0f, flipY ? -1.0f : 1.0f);
+ Bitmap rotatedBitmap =
+ Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
+
+ // Recycle the old bitmap if it has changed.
+ if (rotatedBitmap != bitmap) {
+ bitmap.recycle();
+ }
+ return rotatedBitmap;
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.N)
+ @Nullable
+ public static Bitmap getBitmapFromContentUri(ContentResolver contentResolver, Uri imageUri)
+ throws IOException {
+ Bitmap decodedBitmap = MediaStore.Images.Media.getBitmap(contentResolver, imageUri);
+ if (decodedBitmap == null) {
+ return null;
+ }
+ int orientation = getExifOrientationTag(contentResolver, imageUri);
+
+ int rotationDegrees = 0;
+ boolean flipX = false;
+ boolean flipY = false;
+ // See e.g. https://magnushoff.com/articles/jpeg-orientation/ for a detailed explanation on each
+ // orientation.
+ switch (orientation) {
+ case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
+ flipX = true;
+ break;
+ case ExifInterface.ORIENTATION_ROTATE_90:
+ rotationDegrees = 90;
+ break;
+ case ExifInterface.ORIENTATION_TRANSPOSE:
+ rotationDegrees = 90;
+ flipX = true;
+ break;
+ case ExifInterface.ORIENTATION_ROTATE_180:
+ rotationDegrees = 180;
+ break;
+ case ExifInterface.ORIENTATION_FLIP_VERTICAL:
+ flipY = true;
+ break;
+ case ExifInterface.ORIENTATION_ROTATE_270:
+ rotationDegrees = -90;
+ break;
+ case ExifInterface.ORIENTATION_TRANSVERSE:
+ rotationDegrees = -90;
+ flipX = true;
+ break;
+ case ExifInterface.ORIENTATION_UNDEFINED:
+ case ExifInterface.ORIENTATION_NORMAL:
+ default:
+ // No transformations necessary in this case.
+ }
+
+ return rotateBitmap(decodedBitmap, rotationDegrees, flipX, flipY);
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.N)
+ private static int getExifOrientationTag(ContentResolver resolver, Uri imageUri) {
+ // We only support parsing EXIF orientation tag from local file on the device.
+ // See also:
+ // https://android-developers.googleblog.com/2016/12/introducing-the-exifinterface-support-library.html
+ if (!ContentResolver.SCHEME_CONTENT.equals(imageUri.getScheme())
+ && !ContentResolver.SCHEME_FILE.equals(imageUri.getScheme())) {
+ return 0;
+ }
+
+ ExifInterface exif;
+ try (InputStream inputStream = resolver.openInputStream(imageUri)) {
+ if (inputStream == null) {
+ return 0;
+ }
+
+ exif = new ExifInterface(inputStream);
+ } catch (IOException e) {
+ LogUtils.e("failed to open file to read rotation meta data: " + imageUri, e);
+ return 0;
+ }
+
+ return exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
+ }
+
+ /**
+ * Converts YUV_420_888 to NV21 bytebuffer.
+ *
+ * The NV21 format consists of a single byte array containing the Y, U and V values. For an
+ * image of size S, the first S positions of the array contain all the Y values. The remaining
+ * positions contain interleaved V and U values. U and V are subsampled by a factor of 2 in both
+ * dimensions, so there are S/4 U values and S/4 V values. In summary, the NV21 array will contain
+ * S Y values followed by S/4 VU values: YYYYYYYYYYYYYY(...)YVUVUVUVU(...)VU
+ *
+ *
YUV_420_888 is a generic format that can describe any YUV image where U and V are subsampled
+ * by a factor of 2 in both dimensions. {@link Image#getPlanes} returns an array with the Y, U and
+ * V planes. The Y plane is guaranteed not to be interleaved, so we can just copy its values into
+ * the first part of the NV21 array. The U and V planes may already have the representation in the
+ * NV21 format. This happens if the planes share the same buffer, the V buffer is one position
+ * before the U buffer and the planes have a pixelStride of 2. If this is case, we can just copy
+ * them to the NV21 array.
+ */
+ public static ByteBuffer yuv420ThreePlanesToNV21(Image.Plane[] yuv420888planes, int width, int height) {
+ int imageSize = width * height;
+ byte[] out = new byte[imageSize + 2 * (imageSize / 4)];
+
+ if (areUVPlanesNV21(yuv420888planes, width, height)) {
+ // Copy the Y values.
+ yuv420888planes[0].getBuffer().get(out, 0, imageSize);
+
+ ByteBuffer uBuffer = yuv420888planes[1].getBuffer();
+ ByteBuffer vBuffer = yuv420888planes[2].getBuffer();
+ // Get the first V value from the V buffer, since the U buffer does not contain it.
+ vBuffer.get(out, imageSize, 1);
+ // Copy the first U value and the remaining VU values from the U buffer.
+ uBuffer.get(out, imageSize + 1, 2 * imageSize / 4 - 1);
+ } else {
+ // Fallback to copying the UV values one by one, which is slower but also works.
+ // Unpack Y.
+ unpackPlane(yuv420888planes[0], width, height, out, 0, 1);
+ // Unpack U.
+ unpackPlane(yuv420888planes[1], width, height, out, imageSize + 1, 2);
+ // Unpack V.
+ unpackPlane(yuv420888planes[2], width, height, out, imageSize, 2);
+ }
+
+ return ByteBuffer.wrap(out);
+ }
+
+ /**
+ * Checks if the UV plane buffers of a YUV_420_888 image are in the NV21 format.
+ */
+ private static boolean areUVPlanesNV21(Image.Plane[] planes, int width, int height) {
+ int imageSize = width * height;
+
+ ByteBuffer uBuffer = planes[1].getBuffer();
+ ByteBuffer vBuffer = planes[2].getBuffer();
+
+ // Backup buffer properties.
+ int vBufferPosition = vBuffer.position();
+ int uBufferLimit = uBuffer.limit();
+
+ // Advance the V buffer by 1 byte, since the U buffer will not contain the first V value.
+ vBuffer.position(vBufferPosition + 1);
+ // Chop off the last byte of the U buffer, since the V buffer will not contain the last U value.
+ uBuffer.limit(uBufferLimit - 1);
+
+ // Check that the buffers are equal and have the expected number of elements.
+ boolean areNV21 =
+ (vBuffer.remaining() == (2 * imageSize / 4 - 2)) && (vBuffer.compareTo(uBuffer) == 0);
+
+ // Restore buffers to their initial state.
+ vBuffer.position(vBufferPosition);
+ uBuffer.limit(uBufferLimit);
+
+ return areNV21;
+ }
+
+ /**
+ * Unpack an image plane into a byte array.
+ *
+ *
The input plane data will be copied in 'out', starting at 'offset' and every pixel will be
+ * spaced by 'pixelStride'. Note that there is no row padding on the output.
+ */
+ private static void unpackPlane(
+ Image.Plane plane, int width, int height, byte[] out, int offset, int pixelStride) {
+ ByteBuffer buffer = plane.getBuffer();
+ buffer.rewind();
+
+ // Compute the size of the current plane.
+ // We assume that it has the aspect ratio as the original image.
+ int numRow = (buffer.limit() + plane.getRowStride() - 1) / plane.getRowStride();
+ if (numRow == 0) {
+ return;
+ }
+ int scaleFactor = height / numRow;
+ int numCol = width / scaleFactor;
+
+ // Extract the data in the output buffer.
+ int outputPos = offset;
+ int rowStart = 0;
+ for (int row = 0; row < numRow; row++) {
+ int inputPos = rowStart;
+ for (int col = 0; col < numCol; col++) {
+ out[outputPos] = buffer.get(inputPos);
+ outputPos += pixelStride;
+ inputPos += plane.getPixelStride();
+ }
+ rowStart += plane.getRowStride();
+ }
+ }
+}
diff --git a/zxing-lite/src/main/res/values/attrs.xml b/zxing-lite/src/main/res/values/attrs.xml
index 3aedfdb..ad0125c 100644
--- a/zxing-lite/src/main/res/values/attrs.xml
+++ b/zxing-lite/src/main/res/values/attrs.xml
@@ -48,6 +48,7 @@
+