diff --git a/README.md b/README.md
index d9a675a..fd9e30a 100644
--- a/README.md
+++ b/README.md
@@ -55,9 +55,9 @@ OpenCV二维码识别:封装好的API,通过 **OpenCVQRCodeDetector** 你可
### [opencv-qrcode-scanning](opencv-qrcode-scanning)
-OpenCV二维码扫码:有了上面的OpenCV二维码识别功能,基本的扫码相关界面还是需要有个的,扫码加识别完美搭配,依赖[MLKit](https://github.com/jenly1314/MLKit)中的 **mlkit-camera-core**;
+OpenCV二维码扫码:有了上面的OpenCV二维码识别功能,基本的扫码相关界面还是需要有个的,扫码加识别完美搭配;
-**opencv-qrcode-scanning** 相当于[MLKit](https://github.com/jenly1314/MLKit)中的 **mlkit-camera-core**的衍生库。
+**opencv-qrcode-scanning** 相当于[CameraScan](https://github.com/jenly1314/CameraScan)的衍生库。
### [wechat-qrcode](wechat-qrcode)
@@ -65,25 +65,23 @@ OpenCV二维码扫码:有了上面的OpenCV二维码识别功能,基本的
### [wechat-qrcode-scanning](wechat-qrcode-scanning)
-微信二维码扫码:有了上面的微信二维码识别功能,基本的扫码相关界面还是需要有个的,扫码加识别完美搭配,依赖[MLKit](https://github.com/jenly1314/MLKit)中的 **mlkit-camera-core**;
+微信二维码扫码:有了上面的微信二维码识别功能,基本的扫码相关界面还是需要有个的,扫码加识别完美搭配;
-**wechat-qrcode-scanning** 相当于[MLKit](https://github.com/jenly1314/MLKit)中的 **mlkit-camera-core**的衍生库。
-
-### [Java版本(点击查看java分支)](https://github.com/jenly1314/WeChatQrCode/tree/java)
+**wechat-qrcode-scanning** 相当于[CameraScan](https://github.com/jenly1314/CameraScan)的衍生库。
+### [Java版本(点击查看java分支)](https://github.com/jenly1314/WeChatQrCode/tree/java)
## 引入
### Gradle:
-1. 在Project的 **build.gradle** 里面添加远程仓库
-
+1. 在Project的 **build.gradle** 或 **setting.gradle** 中添加远程仓库
+
```gradle
-allprojects {
- repositories {
- //...
- mavenCentral()
- }
+repositories {
+ //...
+ mavenCentral()
+ maven { url 'https://jitpack.io' }
}
```
@@ -91,41 +89,23 @@ allprojects {
```gradle
// OpenCV基础库(*必须)
-implementation 'com.github.jenly1314.WeChatQRCode:opencv:1.3.0'
-implementation 'com.github.jenly1314.WeChatQRCode:opencv-armv7a:1.3.0'
-
-// OpenCV二维码识别功能(可选)
-implementation 'com.github.jenly1314.WeChatQRCode:opencv-qrcode:1.3.0'
-// OpenCV二维码扫码功能(可选)
-implementation 'com.github.jenly1314.WeChatQRCode:opencv-qrcode-scanning:1.3.0'
-
-// 微信二维码识别功能(可选)
-implementation 'com.github.jenly1314.WeChatQRCode:wechat-qrcode:1.3.0'
-// 微信二维码扫码功能(可选)
-implementation 'com.github.jenly1314.WeChatQRCode:wechat-qrcode-scanning:1.3.0'
+implementation 'com.github.jenly1314.WeChatQRCode:opencv:2.0.0'
+implementation 'com.github.jenly1314.WeChatQRCode:opencv-armv7a:2.0.0'
-```
-
-根据需要选择支持的 SO 库架构
-```gradle
-// OpenCV基础库(*必须)
-implementation 'com.github.jenly1314.WeChatQRCode:opencv:1.3.0'
-implementation 'com.github.jenly1314.WeChatQRCode:opencv-armv7a:1.3.0'
-
-// OpenCV的其他ABI(可选),根据你的需求选择想要的so支持
-implementation 'com.github.jenly1314.WeChatQRCode:opencv-armv64:1.3.0'
-implementation 'com.github.jenly1314.WeChatQRCode:opencv-x86:1.3.0'
-implementation 'com.github.jenly1314.WeChatQRCode:opencv-x86_64:1.3.0'
+// OpenCV的其他ABI(可选),根据你的需要选择想要支持的SO库架构
+implementation 'com.github.jenly1314.WeChatQRCode:opencv-armv64:2.0.0'
+implementation 'com.github.jenly1314.WeChatQRCode:opencv-x86:2.0.0'
+implementation 'com.github.jenly1314.WeChatQRCode:opencv-x86_64:2.0.0'
// OpenCV二维码识别功能(可选)
-implementation 'com.github.jenly1314.WeChatQRCode:opencv-qrcode:1.3.0'
+implementation 'com.github.jenly1314.WeChatQRCode:opencv-qrcode:2.0.0'
// OpenCV二维码扫码功能(可选)
-implementation 'com.github.jenly1314.WeChatQRCode:opencv-qrcode-scanning:1.3.0'
+implementation 'com.github.jenly1314.WeChatQRCode:opencv-qrcode-scanning:2.0.0'
// 微信二维码识别功能(可选)
-implementation 'com.github.jenly1314.WeChatQRCode:wechat-qrcode:1.3.0'
+implementation 'com.github.jenly1314.WeChatQRCode:wechat-qrcode:2.0.0'
// 微信二维码扫码功能(可选)
-implementation 'com.github.jenly1314.WeChatQRCode:wechat-qrcode-scanning:1.3.0'
+implementation 'com.github.jenly1314.WeChatQRCode:wechat-qrcode-scanning:2.0.0'
```
@@ -135,7 +115,8 @@ implementation 'com.github.jenly1314.WeChatQRCode:wechat-qrcode-scanning:1.3.0'
> 使用 v1.3.x 以上版本时,要求 compileSdkVersion >= 33
-> 如果 compileSdkVersion < 33 请使用 v1.3.x 以前的版本(如:v1.2.1)
+> 如果 **compileSdkVersion < 33** 请使用 [**v1.x版本**](https://github.com/jenly1314/WeChatQRCode/tree/1.x/)
+
#### ABI过滤
@@ -232,7 +213,7 @@ class WeChatQRCodeActivity : WeChatCameraScanActivity() {
if (result is WeChatScanningAnalyzer.QRCodeAnalyzeResult) { // 如果需要处理结果二维码的位置信息
val buffer = StringBuilder()
- val bitmap = result.bitmap.drawRect { canvas, paint ->
+ val bitmap = result.bitmap?.drawRect { canvas, paint ->
// 扫码结果可能有多个
for ((index, data) in result.result.withIndex()) {
buffer.append("[$index] ").append(data).append("\n")
@@ -308,63 +289,43 @@ class WeChatQRCodeActivity : WeChatCameraScanActivity() {
**wechat-qrcode-scanning**
扫描识别二维码实现示例:通过直接继承 OpenCVCameraScanActivity 实现的示例 [OpenCVQRCodeActivity](app/src/main/java/com/king/wechat/qrcode/app/OpenCVQRCodeActivity.kt)
-
-
+
### 特别说明
-因为 **wechat-qrcode-scanning** 依赖了 [MLKit](https://github.com/jenly1314/MLKit) 中的 **mlkit-camera-core**,
-所以关于 **CameraScan** 的和界面布局在使用上完全遵循 **mlkit-camera-core** 的使用方式。
+因为 **wechat-qrcode-scanning** 和 **opencv-qrcode-scanning** 都是以[CameraScan](https://github.com/jenly1314/CameraScan)作为基础库去实现具体的分析检测功能,所以关于 **CameraScan** 的使用和自定义扫码界面布局都完全遵循[CameraScan](https://github.com/jenly1314/CameraScan) 的使用方式。
-这里贴出一部分主要的使用示例:
+> 关于**CameraScan**的使用,你可以直接去看[CameraScan](https://github.com/jenly1314/CameraScan)的使用说明;
-#### CameraScan配置示例
+> 关于扫描框动画,你可以查看[ViewfinderView](https://github.com/jenly1314/ViewfinderView)的使用说明;
-**CameraScan** 里面包含部分支持链式调用的方法,即调用返回是 **CameraScan** 本身的一些配置建议在调用 **startCamera()** 方法之前调用。
+### 2.x版本的变化
-> 如果是通过继承 **BaseCameraScanActivity** 或者 **BaseCameraScanFragment** 或其子类实现的相机扫描,可以在
-**initCameraScan()** 方法中获取 **CameraScan** ,然后根据需要修改相关配置。
+从 **1.x** 到 **2.x** 主要变化如下:
+* 1.x版本中 **wechat-qrcode-scanning** 和 **opencv-qrcode-scanning** 默认依赖的 **mlkit-camera-core** 被移除了;
+> 从2.0.0版本开始 **wechat-qrcode-scanning** 和 **opencv-qrcode-scanning** 都改为依赖[CameraScan](https://github.com/jenly1314/CameraScan);([CameraScan](https://github.com/jenly1314/CameraScan)是一个独立的库,单独进行维护)
-```java
-// 获取CameraScan,根据需要修改相关配置
-getCameraScan().setPlayBeep(true)//设置是否播放音效,默认为false
- .setVibrate(true)//设置是否震动,默认为false
- .setCameraConfig(new ResolutionCameraConfig(this))//设置相机配置信息,CameraConfig可覆写options方法自定义配置
- .setNeedTouchZoom(true)//支持多指触摸捏合缩放,默认为true
- .setDarkLightLux(45f)//设置光线足够暗的阈值(单位:lux),需要通过{@link #bindFlashlightView(View)}绑定手电筒才有效
- .setBrightLightLux(100f)//设置光线足够明亮的阈值(单位:lux),需要通过{@link #bindFlashlightView(View)}绑定手电筒才有效
- .bindFlashlightView(ivFlashlight)//绑定手电筒,绑定后可根据光线传感器,动态显示或隐藏手电筒按钮
- .setOnScanResultCallback(this)//设置扫码结果回调,需要自己处理或者需要连扫时,可设置回调,自己去处理相关逻辑
- .setAnalyzer(new BarcodeScanningAnalyzer())//设置分析器,如这里使用条码分析器,BarcodeScanningAnalyzer是mlkit-barcode-scanning中的
- .setAnalyzeImage(true)//设置是否分析图片,默认为true。如果设置为false,相当于关闭了扫码识别功能
+> 从2.0.0版本开始 **wechat-qrcode-scanning** 和 **opencv-qrcode-scanning** 都已默认依赖 **ViewfinderView**[ViewfinderView](https://github.com/jenly1314/ViewfinderView)
- // 启动预览(如果是通过直接或间接继承BaseCameraScanActivity或BaseCameraScanFragment实现的则无需调用startCamera)
- getCameraScan().startCamera();
+> 从2.0.0版本开始默认布局包含了扫描动画 **ViewfinderView** 和手电筒按钮,集成步骤更简单。
+基于以上两点主要差异:2.x的主要使用方式和1.x基本类似,部分细节有所变更。
- // 设置闪光灯(手电筒)是否开启,需在startCamera之后调用才有效
- getCameraScan().enableTorch(torch);
-```
+> 如果你是从 **1.x** 版本升级至 **2.x** 版本,那么你需要知道上面所说的差异;特别是独立出去单独维护的库,其包名都有所变化,这一点需要注意一下,大部分变动只需变更导入的包名即可完成升级。
-#### 布局示例
+> 如果你使用的是1.x版本的话请直接[查看v1.x分支版本](https://github.com/jenly1314/WeChatQRCode/tree/1.x/)
-**PreviewView** 用来预览,布局内至少要保证有 **PreviewView**;如果是继承 **BaseCameraScanActivity** 或
-**BaseCameraScanFragment** 或其子类实现的相机扫描;快速实现扫描功能;
+### 2.x版本的使用
-需自定义布局时,通过覆写getLayoutId方法即可;更多代码用法可直接查看 **BaseCameraScanActivity** 源码或参见下面的使用示例。
+2.x版本的实现主要是以[CameraScan](https://github.com/jenly1314/CameraScan)作为基础库去实现具体的分析检测功能,所以你可以直接去看[CameraScan](https://github.com/jenly1314/CameraScan)的使用说明,只要知道了[CameraScan](https://github.com/jenly1314/CameraScan)的基本使用方式,自然就会使用 **wechat-qrcode-scanning** 和 **opencv-qrcode-scanning**了。
-```Xml
-
-
-
-
-```
+### 二维码扫码识别
+
+下面就列一下OpenCVQRCode和WeChatQRCode实现扫二维码功能的核心类;主要包括实现扫描二维码的**Analyzer** 和便于快速实现扫描检测的 **BaseCameraScanActivity** 或 **BaseCameraScanFragment** 的子类。
-> 关于扫描框动画:你暂时可以参考[app](app)中的源码示例,直接使用[ViewfinderView](https://github.com/jenly1314/ViewfinderView);(后续发布新版本时,计划自动依赖 **ViewfinderView**)
+| 功能 | 所属子模块 | 对应的Analyzer实现 | 对应的BaseCameraScanActivity子类 |
+|:--------|:-----------------------|:-----------------------|:--------------------------------------------------|
+| 二维码扫码识别 | opencv-qrcode-scanning | OpenCVScanningAnalyzer | OpenCVCameraScanActivity/OpenCVCameraScanFragment |
+| 二维码扫码识别 | wechat-qrcode-scanning | WeChatScanningAnalyzer | WeChatCameraScanActivity/WeChatCameraScanFragment |
更多使用详情,请查看[app](app)中的源码使用示例或直接查看 [API帮助文档](https://jitpack.io/com/github/jenly1314/WeChatQRCode/latest/javadoc/)
@@ -389,11 +350,17 @@ getCameraScan().setPlayBeep(true)//设置是否播放音效,默认为false
## 相关推荐
#### [MLKit](https://github.com/jenly1314/MLKit) 一个强大易用的工具包。通过ML Kit您可以很轻松的实现文字识别、条码识别、图像标记、人脸检测、对象检测等功能。
-#### [ZXingLite](https://github.com/jenly1314/ZXingLite) 基于ZXing库优化扫码和生成二维码/条形码功能,扫码界面完全支持自定义。
-
+#### [ZXingLite](https://github.com/jenly1314/ZXingLite) 基于zxing实现的扫码库,优化扫码和生成二维码/条形码功能。
+#### [CameraScan](https://github.com/jenly1314/CameraScan) 一个简化扫描识别流程的通用基础库。
+#### [ViewfinderView](https://github.com/jenly1314/ViewfinderView) ViewfinderView一个取景视图:主要用于渲染扫描相关的动画效果。
## 版本记录
+#### v2.0.0:2023-8-14
+* **wechat-qrcode-scanning** 和 **opencv-qrcode-scanning** 中移除原依赖(**mlkit-camera-core**),现改为依赖[CameraScan](https://github.com/jenly1314/CameraScan)
+* **wechat-qrcode-scanning** 和 **opencv-qrcode-scanning** 添加默认依赖[ViewfinderView](https://github.com/jenly1314/ViewfinderView)
+* 优化扫描分析过程的性能体验(优化帧数据分析过程)
+
#### v1.3.0:2023-4-16
* 新增OpenCV二维码扫码识别库(opencv-qrcode和opencv-qrcode-scanning)
* 更新mlkit-camera-core至v1.4.0
diff --git a/app/build.gradle b/app/build.gradle
index 94d87b5..902302d 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -36,13 +36,15 @@ android {
kotlinOptions {
jvmTarget = JavaVersion.VERSION_11.toString()
}
-
- lintOptions {
- abortOnError false
+ packagingOptions {
+ resources {
+ excludes += ['META-INF/*.kotlin_module']
+ }
}
- packagingOptions {
- exclude 'META-INF/*.kotlin_module'
+
+ lint {
+ abortOnError false
}
}
@@ -59,11 +61,8 @@ dependencies {
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$versions.lifecycleKtx"
- implementation "com.github.jenly1314:viewfinderview:$versions.viewfinderview"
-
implementation "com.github.jenly1314.AppUpdater:app-dialog:$versions.appDialog"
-
implementation project(path: ':opencv')
implementation project(path: ':opencv-armv7a')
// implementation project(path: ':opencv-armv64')
diff --git a/app/release/app-release.apk b/app/release/app-release.apk
index 60cf507..31ac50f 100644
Binary files a/app/release/app-release.apk and b/app/release/app-release.apk differ
diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json
index 8c2cb44..7a796f2 100644
--- a/app/release/output-metadata.json
+++ b/app/release/output-metadata.json
@@ -11,8 +11,8 @@
"type": "SINGLE",
"filters": [],
"attributes": [],
- "versionCode": 7,
- "versionName": "1.3.0",
+ "versionCode": 8,
+ "versionName": "2.0.0",
"outputFile": "app-release.apk"
}
],
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 77dd3fb..7664904 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,6 +1,5 @@
-
+
diff --git a/app/src/main/java/com/king/wechat/qrcode/app/Function.kt b/app/src/main/java/com/king/wechat/qrcode/app/Function.kt
index 0860dd5..fee5683 100644
--- a/app/src/main/java/com/king/wechat/qrcode/app/Function.kt
+++ b/app/src/main/java/com/king/wechat/qrcode/app/Function.kt
@@ -4,7 +4,7 @@ import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
-import com.king.mlkit.vision.camera.util.LogUtils
+import com.king.camera.scan.util.LogUtils
/**
* @author Jenly
diff --git a/app/src/main/java/com/king/wechat/qrcode/app/MainActivity.kt b/app/src/main/java/com/king/wechat/qrcode/app/MainActivity.kt
index aae70c8..2ba88c2 100644
--- a/app/src/main/java/com/king/wechat/qrcode/app/MainActivity.kt
+++ b/app/src/main/java/com/king/wechat/qrcode/app/MainActivity.kt
@@ -10,9 +10,9 @@ import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityOptionsCompat
import androidx.lifecycle.lifecycleScope
-import com.king.mlkit.vision.camera.CameraScan
-import com.king.mlkit.vision.camera.util.LogUtils
-import com.king.mlkit.vision.camera.util.PermissionUtils
+import com.king.camera.scan.CameraScan
+import com.king.camera.scan.util.LogUtils
+import com.king.camera.scan.util.PermissionUtils
import com.king.opencv.qrcode.OpenCVQRCodeDetector
import com.king.wechat.qrcode.WeChatQRCodeDetector
import kotlinx.coroutines.Dispatchers
diff --git a/app/src/main/java/com/king/wechat/qrcode/app/OpenCVQRCodeActivity.kt b/app/src/main/java/com/king/wechat/qrcode/app/OpenCVQRCodeActivity.kt
index 560bc26..8755c25 100644
--- a/app/src/main/java/com/king/wechat/qrcode/app/OpenCVQRCodeActivity.kt
+++ b/app/src/main/java/com/king/wechat/qrcode/app/OpenCVQRCodeActivity.kt
@@ -7,9 +7,9 @@ import android.view.View
import android.widget.ImageView
import com.king.app.dialog.AppDialog
import com.king.app.dialog.AppDialogConfig
-import com.king.mlkit.vision.camera.AnalyzeResult
-import com.king.mlkit.vision.camera.CameraScan
-import com.king.mlkit.vision.camera.analyze.Analyzer
+import com.king.camera.scan.AnalyzeResult
+import com.king.camera.scan.CameraScan
+import com.king.camera.scan.analyze.Analyzer
import com.king.opencv.qrcode.scanning.OpenCVCameraScanActivity
import com.king.opencv.qrcode.scanning.analyze.OpenCVScanningAnalyzer
@@ -83,10 +83,6 @@ class OpenCVQRCodeActivity : OpenCVCameraScanActivity() {
return OpenCVScanningAnalyzer(true)
}
- override fun getLayoutId(): Int {
- return R.layout.activity_opencv_qrcode
- }
-
companion object {
const val TAG = "OpenCVQRCodeActivity"
}
diff --git a/app/src/main/java/com/king/wechat/qrcode/app/WeChatMultiQRCodeActivity.kt b/app/src/main/java/com/king/wechat/qrcode/app/WeChatMultiQRCodeActivity.kt
index e8fbd92..7380d5d 100644
--- a/app/src/main/java/com/king/wechat/qrcode/app/WeChatMultiQRCodeActivity.kt
+++ b/app/src/main/java/com/king/wechat/qrcode/app/WeChatMultiQRCodeActivity.kt
@@ -1,5 +1,6 @@
package com.king.wechat.qrcode.app
+import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.Path
import android.util.Log
@@ -7,9 +8,9 @@ import android.view.View
import android.widget.ImageView
import com.king.app.dialog.AppDialog
import com.king.app.dialog.AppDialogConfig
-import com.king.mlkit.vision.camera.AnalyzeResult
-import com.king.mlkit.vision.camera.CameraScan
-import com.king.mlkit.vision.camera.analyze.Analyzer
+import com.king.camera.scan.AnalyzeResult
+import com.king.camera.scan.CameraScan
+import com.king.camera.scan.analyze.Analyzer
import com.king.wechat.qrcode.scanning.WeChatCameraScanActivity
import com.king.wechat.qrcode.scanning.analyze.WeChatScanningAnalyzer
@@ -20,6 +21,7 @@ import com.king.wechat.qrcode.scanning.analyze.WeChatScanningAnalyzer
*/
class WeChatMultiQRCodeActivity : WeChatCameraScanActivity() {
+ @SuppressLint("LongLogTag")
override fun onScanResultCallback(result: AnalyzeResult>) {
// 停止分析
cameraScan.setAnalyzeImage(false)
@@ -28,7 +30,7 @@ class WeChatMultiQRCodeActivity : WeChatCameraScanActivity() {
if (result is WeChatScanningAnalyzer.QRCodeAnalyzeResult) { // 如果需要处理结果二维码的位置信息
val buffer = StringBuilder()
- val bitmap = result.bitmap.drawRect { canvas, paint ->
+ val bitmap = result.bitmap?.drawRect { canvas, paint ->
// 扫码结果可能有多个
result.result.forEachIndexed { index, data ->
buffer.append("[$index] ").append(data).append("\n")
@@ -86,10 +88,6 @@ class WeChatMultiQRCodeActivity : WeChatCameraScanActivity() {
return WeChatScanningAnalyzer(true)
}
- override fun getLayoutId(): Int {
- return R.layout.activity_wechat_multi_qrcode
- }
-
companion object {
const val TAG = "WeChatMultiQRCodeActivity"
}
diff --git a/app/src/main/java/com/king/wechat/qrcode/app/WeChatQRCodeActivity.kt b/app/src/main/java/com/king/wechat/qrcode/app/WeChatQRCodeActivity.kt
index 2025320..92dbaa0 100644
--- a/app/src/main/java/com/king/wechat/qrcode/app/WeChatQRCodeActivity.kt
+++ b/app/src/main/java/com/king/wechat/qrcode/app/WeChatQRCodeActivity.kt
@@ -4,10 +4,10 @@ import android.content.Intent
import android.graphics.Point
import android.util.Log
import android.widget.ImageView
-import com.king.mlkit.vision.camera.AnalyzeResult
-import com.king.mlkit.vision.camera.CameraScan
-import com.king.mlkit.vision.camera.analyze.Analyzer
-import com.king.mlkit.vision.camera.util.PointUtils
+import com.king.camera.scan.AnalyzeResult
+import com.king.camera.scan.CameraScan
+import com.king.camera.scan.analyze.Analyzer
+import com.king.camera.scan.util.PointUtils
import com.king.view.viewfinderview.ViewfinderView
import com.king.wechat.qrcode.scanning.WeChatCameraScanActivity
import com.king.wechat.qrcode.scanning.analyze.WeChatScanningAnalyzer
@@ -20,19 +20,23 @@ import com.king.wechat.qrcode.scanning.analyze.WeChatScanningAnalyzer
class WeChatQRCodeActivity : WeChatCameraScanActivity() {
private lateinit var ivResult: ImageView
- private lateinit var viewfinderView: ViewfinderView
override fun initUI() {
super.initUI()
ivResult = findViewById(R.id.ivResult)
- viewfinderView = findViewById(R.id.viewfinderView)
}
override fun onScanResultCallback(result: AnalyzeResult>) {
// 停止分析
cameraScan.setAnalyzeImage(false)
Log.d(TAG, result.result.toString())
-
+ val frameMetadata = result.frameMetadata
+ var width = frameMetadata.width
+ var height = frameMetadata.height
+ if(frameMetadata.rotation == 90 || frameMetadata.rotation == 270) {
+ width = frameMetadata.height
+ height = frameMetadata.width
+ }
// 当初始化 WeChatScanningAnalyzer 时,如果是需要二维码的位置信息,则会返回 WeChatScanningAnalyzer.QRCodeAnalyzeResult
if (result is WeChatScanningAnalyzer.QRCodeAnalyzeResult) { // 如果需要处理结果二维码的位置信息
//取预览当前帧图片并显示,为结果点提供参照
@@ -57,8 +61,8 @@ class WeChatQRCodeActivity : WeChatCameraScanActivity() {
val point = PointUtils.transform(
centerX,
centerY,
- result.bitmap.width,
- result.bitmap.height,
+ width,
+ height,
viewfinderView.width,
viewfinderView.height
)
diff --git a/app/src/main/res/layout/activity_opencv_qrcode.xml b/app/src/main/res/layout/activity_opencv_qrcode.xml
deleted file mode 100644
index 369a093..0000000
--- a/app/src/main/res/layout/activity_opencv_qrcode.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_wechat_multi_qrcode.xml b/app/src/main/res/layout/activity_wechat_multi_qrcode.xml
deleted file mode 100644
index 369a093..0000000
--- a/app/src/main/res/layout/activity_wechat_multi_qrcode.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_wechat_qrcode.xml b/app/src/main/res/layout/activity_wechat_qrcode.xml
index 516611d..927c8e5 100644
--- a/app/src/main/res/layout/activity_wechat_qrcode.xml
+++ b/app/src/main/res/layout/activity_wechat_qrcode.xml
@@ -19,4 +19,12 @@
app:vvLaserStyle="image"
app:vvLaserDrawableRatio="0.8"
app:vvLaserDrawable="@drawable/ic_laser_line"/>
+
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index 5397f3b..b911c69 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -18,8 +18,8 @@ android.useAndroidX = true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style = official
-VERSION_NAME=1.3.0
-VERSION_CODE=7
+VERSION_NAME=2.0.0
+VERSION_CODE=8
GROUP=com.github.jenly1314.WeChatQRCode
POM_DESCRIPTION=Wechat QRCode
@@ -44,6 +44,4 @@ SONATYPE_HOST=S01
RELEASE_REPOSITORY_URL=https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/
SNAPSHOT_REPOSITORY_URL=https://s01.oss.sonatype.org/content/repositories/snapshots/
-RELEASE_SIGNING_ENABLED=false
-
-
+RELEASE_SIGNING_ENABLED=false
\ No newline at end of file
diff --git a/opencv-armv64/build.gradle b/opencv-armv64/build.gradle
index 6110355..93d3c81 100644
--- a/opencv-armv64/build.gradle
+++ b/opencv-armv64/build.gradle
@@ -10,15 +10,14 @@ android {
defaultConfig {
minSdk build_versions.minSdk
targetSdk build_versions.targetSdk
- versionCode opencv_version.versionCode
- versionName opencv_version.versionName
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles "consumer-rules.pro"
}
-
buildTypes {
release {
minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
@@ -26,10 +25,10 @@ android {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
-
- lintOptions {
+ lint {
abortOnError false
}
+
}
dependencies {
diff --git a/opencv-armv64/src/main/AndroidManifest.xml b/opencv-armv64/src/main/AndroidManifest.xml
index 509d6d2..9a40236 100644
--- a/opencv-armv64/src/main/AndroidManifest.xml
+++ b/opencv-armv64/src/main/AndroidManifest.xml
@@ -1,4 +1,3 @@
-
+
diff --git a/opencv-armv7a/build.gradle b/opencv-armv7a/build.gradle
index 94c6a2c..3efaa58 100644
--- a/opencv-armv7a/build.gradle
+++ b/opencv-armv7a/build.gradle
@@ -10,15 +10,14 @@ android {
defaultConfig {
minSdk build_versions.minSdk
targetSdk build_versions.targetSdk
- versionCode opencv_version.versionCode
- versionName opencv_version.versionName
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles "consumer-rules.pro"
}
-
buildTypes {
release {
minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
@@ -26,10 +25,10 @@ android {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
-
- lintOptions {
+ lint {
abortOnError false
}
+
}
dependencies {
diff --git a/opencv-armv7a/src/main/AndroidManifest.xml b/opencv-armv7a/src/main/AndroidManifest.xml
index f3e54fc..9a40236 100644
--- a/opencv-armv7a/src/main/AndroidManifest.xml
+++ b/opencv-armv7a/src/main/AndroidManifest.xml
@@ -1,4 +1,3 @@
-
+
diff --git a/opencv-qrcode-scanning/build.gradle b/opencv-qrcode-scanning/build.gradle
index 78d75b6..24412aa 100644
--- a/opencv-qrcode-scanning/build.gradle
+++ b/opencv-qrcode-scanning/build.gradle
@@ -10,17 +10,14 @@ android {
defaultConfig {
minSdk build_versions.minSdk
targetSdk build_versions.targetSdk
- versionCode app_version.versionCode
- versionName app_version.versionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
}
-
buildTypes {
release {
minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
@@ -28,10 +25,10 @@ android {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
-
- lintOptions {
+ lint {
abortOnError false
}
+
}
dependencies {
@@ -42,7 +39,8 @@ dependencies {
androidTestImplementation "androidx.test.ext:junit:$versions.androidExtJunit"
androidTestImplementation "androidx.test.espresso:espresso-core:$versions.espressoCore"
- api "com.github.jenly1314.MLKit:mlkit-camera-core:$versions.mlkit"
+ api "com.github.jenly1314:CameraScan:$versions.cameraScan"
+ api "com.github.jenly1314:viewfinderview:$versions.viewfinderview"
compileOnly project(path: ':opencv')
compileOnly project(path: ':opencv-qrcode')
diff --git a/opencv-qrcode-scanning/src/main/java/com/king/opencv/qrcode/scanning/OpenCVCameraScanActivity.java b/opencv-qrcode-scanning/src/main/java/com/king/opencv/qrcode/scanning/OpenCVCameraScanActivity.java
index ee024da..5a78e3d 100644
--- a/opencv-qrcode-scanning/src/main/java/com/king/opencv/qrcode/scanning/OpenCVCameraScanActivity.java
+++ b/opencv-qrcode-scanning/src/main/java/com/king/opencv/qrcode/scanning/OpenCVCameraScanActivity.java
@@ -1,8 +1,11 @@
package com.king.opencv.qrcode.scanning;
-import com.king.mlkit.vision.camera.BaseCameraScanActivity;
-import com.king.mlkit.vision.camera.analyze.Analyzer;
+import android.view.View;
+
+import com.king.camera.scan.BaseCameraScanActivity;
+import com.king.camera.scan.analyze.Analyzer;
import com.king.opencv.qrcode.scanning.analyze.OpenCVScanningAnalyzer;
+import com.king.view.viewfinderview.ViewfinderView;
import java.util.List;
@@ -16,9 +19,41 @@
* @author Jenly
*/
public abstract class OpenCVCameraScanActivity extends BaseCameraScanActivity> {
+
+ protected ViewfinderView viewfinderView;
+
+ @Override
+ public void initUI() {
+ int viewfinderViewId = getViewfinderViewId();
+ if (viewfinderViewId != View.NO_ID && viewfinderViewId != 0) {
+ viewfinderView = findViewById(viewfinderViewId);
+ }
+ super.initUI();
+ }
+
@Nullable
@Override
public Analyzer> createAnalyzer() {
return new OpenCVScanningAnalyzer();
}
+
+ /**
+ * 布局ID;通过覆写此方法可以自定义布局
+ *
+ * @return 布局ID
+ */
+ @Override
+ public int getLayoutId() {
+ return R.layout.opencv_camera_scan;
+ }
+
+ /**
+ * {@link #viewfinderView} 的 ID
+ *
+ * @return 默认返回{@code R.id.viewfinderView}, 如果不需要扫码框可以返回{@link View#NO_ID}
+ */
+
+ public int getViewfinderViewId() {
+ return R.id.viewfinderView;
+ }
}
diff --git a/opencv-qrcode-scanning/src/main/java/com/king/opencv/qrcode/scanning/OpenCVCameraScanFragment.java b/opencv-qrcode-scanning/src/main/java/com/king/opencv/qrcode/scanning/OpenCVCameraScanFragment.java
index 5063266..e571721 100644
--- a/opencv-qrcode-scanning/src/main/java/com/king/opencv/qrcode/scanning/OpenCVCameraScanFragment.java
+++ b/opencv-qrcode-scanning/src/main/java/com/king/opencv/qrcode/scanning/OpenCVCameraScanFragment.java
@@ -1,8 +1,11 @@
package com.king.opencv.qrcode.scanning;
-import com.king.mlkit.vision.camera.BaseCameraScanFragment;
-import com.king.mlkit.vision.camera.analyze.Analyzer;
+import android.view.View;
+
+import com.king.camera.scan.BaseCameraScanFragment;
+import com.king.camera.scan.analyze.Analyzer;
import com.king.opencv.qrcode.scanning.analyze.OpenCVScanningAnalyzer;
+import com.king.view.viewfinderview.ViewfinderView;
import java.util.List;
@@ -16,9 +19,41 @@
* @author Jenly
*/
public abstract class OpenCVCameraScanFragment extends BaseCameraScanFragment> {
+
+ protected ViewfinderView viewfinderView;
+
+ @Override
+ public void initUI() {
+ int viewfinderViewId = getViewfinderViewId();
+ if (viewfinderViewId != View.NO_ID && viewfinderViewId != 0) {
+ viewfinderView = getRootView().findViewById(viewfinderViewId);
+ }
+ super.initUI();
+ }
+
@Nullable
@Override
public Analyzer> createAnalyzer() {
return new OpenCVScanningAnalyzer();
}
+
+ /**
+ * 布局ID;通过覆写此方法可以自定义布局
+ *
+ * @return 布局ID
+ */
+ @Override
+ public int getLayoutId() {
+ return R.layout.opencv_camera_scan;
+ }
+
+ /**
+ * {@link #viewfinderView} 的 ID
+ *
+ * @return 默认返回{@code R.id.viewfinderView}, 如果不需要扫码框可以返回{@link View#NO_ID}
+ */
+
+ public int getViewfinderViewId() {
+ return R.id.viewfinderView;
+ }
}
diff --git a/opencv-qrcode-scanning/src/main/java/com/king/opencv/qrcode/scanning/analyze/OpenCVScanningAnalyzer.java b/opencv-qrcode-scanning/src/main/java/com/king/opencv/qrcode/scanning/analyze/OpenCVScanningAnalyzer.java
index 5973768..a676265 100644
--- a/opencv-qrcode-scanning/src/main/java/com/king/opencv/qrcode/scanning/analyze/OpenCVScanningAnalyzer.java
+++ b/opencv-qrcode-scanning/src/main/java/com/king/opencv/qrcode/scanning/analyze/OpenCVScanningAnalyzer.java
@@ -1,17 +1,24 @@
package com.king.opencv.qrcode.scanning.analyze;
-import android.graphics.Bitmap;
+import android.graphics.ImageFormat;
-import com.king.mlkit.vision.camera.AnalyzeResult;
-import com.king.mlkit.vision.camera.analyze.Analyzer;
-import com.king.mlkit.vision.camera.util.BitmapUtils;
-import com.king.mlkit.vision.camera.util.LogUtils;
+import com.king.camera.scan.AnalyzeResult;
+import com.king.camera.scan.FrameMetadata;
+import com.king.camera.scan.analyze.Analyzer;
+import com.king.camera.scan.util.LogUtils;
import com.king.opencv.qrcode.OpenCVQRCodeDetector;
+import org.opencv.core.Core;
+import org.opencv.core.CvType;
import org.opencv.core.Mat;
+import org.opencv.imgproc.Imgproc;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.atomic.AtomicBoolean;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -24,11 +31,19 @@
*/
public class OpenCVScanningAnalyzer implements Analyzer> {
- private OpenCVQRCodeDetector mDetector = new OpenCVQRCodeDetector();
+ private static final int ROTATION_90 = 90;
+ private static final int ROTATION_180 = 180;
+ private static final int ROTATION_270 = 270;
+
+ private final Queue queue = new ConcurrentLinkedQueue<>();
+
+ private final AtomicBoolean joinQueue = new AtomicBoolean(false);
+
+ private final OpenCVQRCodeDetector mDetector = new OpenCVQRCodeDetector();
/**
* 是否需要输出二维码的各个顶点
*/
- private boolean isOutputVertices;
+ private final boolean isOutputVertices;
public OpenCVScanningAnalyzer() {
this(false);
@@ -44,17 +59,33 @@ public OpenCVScanningAnalyzer(boolean isOutputVertices) {
}
@Override
- public void analyze(@NonNull ImageProxy imageProxy, @NonNull OnAnalyzeListener>> listener) {
+ public void analyze(@NonNull ImageProxy imageProxy, @NonNull Analyzer.OnAnalyzeListener>> listener) {
+ if (!joinQueue.get()) {
+ int imageSize = imageProxy.getWidth() * imageProxy.getHeight();
+ byte[] bytes = new byte[imageSize + 2 * (imageSize / 4)];
+ queue.add(bytes);
+ joinQueue.set(true);
+ }
+ if (queue.isEmpty()) {
+ return;
+ }
+ final byte[] nv21Data = queue.poll();
AnalyzeResult> result = null;
try {
- final Bitmap bitmap = BitmapUtils.getBitmap(imageProxy);
- result = detectAndDecode(bitmap, isOutputVertices);
+ yuv_420_888toNv21(imageProxy, nv21Data);
+ FrameMetadata frameMetadata = new FrameMetadata(
+ imageProxy.getWidth(),
+ imageProxy.getHeight(),
+ imageProxy.getImageInfo().getRotationDegrees());
+ result = detectAndDecode(nv21Data, frameMetadata, isOutputVertices);
} catch (Exception e) {
LogUtils.w(e);
}
- if (result != null && !result.getResult().isEmpty()) {
+ if (result != null) {
+ joinQueue.set(false);
listener.onSuccess(result);
} else {
+ queue.add(nv21Data);
listener.onFailure(null);
}
}
@@ -62,33 +93,120 @@ public void analyze(@NonNull ImageProxy imageProxy, @NonNull OnAnalyzeListener> detectAndDecode(Bitmap bitmap, boolean isOutputVertices) {
+ private AnalyzeResult> detectAndDecode(byte[] nv21, FrameMetadata frameMetadata, boolean isOutputVertices) {
+ Mat mat = new Mat(frameMetadata.getHeight() + frameMetadata.getHeight() / 2, frameMetadata.getWidth(), CvType.CV_8UC1);
+ mat.put(0,0, nv21);
+ Mat bgrMat = new Mat();
+ Imgproc.cvtColor(mat, bgrMat, Imgproc.COLOR_YUV2BGR_NV21);
+ mat.release();
+ rotation(bgrMat, frameMetadata.getRotation());
if (isOutputVertices) {
// 如果需要返回二维码的各个顶点
final Mat points = new Mat();
- String result = mDetector.detectAndDecode(bitmap, points);
+ String result = mDetector.detectAndDecode(bgrMat, points);
+ bgrMat.release();
if (result != null && !result.isEmpty()) {
List list = new ArrayList();
list.add(result);
- return new QRCodeAnalyzeResult<>(bitmap, list, points);
+ return new QRCodeAnalyzeResult<>(nv21, ImageFormat.NV21, frameMetadata, list, points);
}
} else {
// 反之则需识别结果即可
- String result = mDetector.detectAndDecode(bitmap);
+ String result = mDetector.detectAndDecode(bgrMat);
+ bgrMat.release();
if (result != null && !result.isEmpty()) {
List list = new ArrayList();
list.add(result);
- return new QRCodeAnalyzeResult(bitmap, list);
+ return new QRCodeAnalyzeResult<>(nv21, ImageFormat.NV21, frameMetadata, list);
}
}
return null;
}
+ /**
+ * YUV420_888转NV21
+ *
+ * @param image
+ * @param nv21
+ */
+ private void yuv_420_888toNv21(@NonNull ImageProxy image, byte[] nv21) {
+ ImageProxy.PlaneProxy yPlane = image.getPlanes()[0];
+ ImageProxy.PlaneProxy uPlane = image.getPlanes()[1];
+ ImageProxy.PlaneProxy vPlane = image.getPlanes()[2];
+
+ ByteBuffer yBuffer = yPlane.getBuffer();
+ ByteBuffer uBuffer = uPlane.getBuffer();
+ ByteBuffer vBuffer = vPlane.getBuffer();
+ yBuffer.rewind();
+ uBuffer.rewind();
+ vBuffer.rewind();
+
+ int ySize = yBuffer.remaining();
+
+ int position = 0;
+
+ // Add the full y buffer to the array. If rowStride > 1, some padding may be skipped.
+ for (int row = 0; row < image.getHeight(); row++) {
+ yBuffer.get(nv21, position, image.getWidth());
+ position += image.getWidth();
+ yBuffer.position(Math.min(ySize, yBuffer.position() - image.getWidth() + yPlane.getRowStride()));
+ }
+
+ int chromaHeight = image.getHeight() / 2;
+ int chromaWidth = image.getWidth() / 2;
+ int vRowStride = vPlane.getRowStride();
+ int uRowStride = uPlane.getRowStride();
+ int vPixelStride = vPlane.getPixelStride();
+ int uPixelStride = uPlane.getPixelStride();
+
+ // Interleave the u and v frames, filling up the rest of the buffer. Use two line buffers to
+ // perform faster bulk gets from the byte buffers.
+ byte[] vLineBuffer = new byte[vRowStride];
+ byte[] uLineBuffer = new byte[uRowStride];
+ for (int row = 0; row < chromaHeight; row++) {
+ vBuffer.get(vLineBuffer, 0, Math.min(vRowStride, vBuffer.remaining()));
+ uBuffer.get(uLineBuffer, 0, Math.min(uRowStride, uBuffer.remaining()));
+ int vLineBufferPosition = 0;
+ int uLineBufferPosition = 0;
+ for (int col = 0; col < chromaWidth; col++) {
+ nv21[position++] = vLineBuffer[vLineBufferPosition];
+ nv21[position++] = uLineBuffer[uLineBufferPosition];
+ vLineBufferPosition += vPixelStride;
+ uLineBufferPosition += uPixelStride;
+ }
+ }
+ }
+
+ /**
+ * 旋转指定角度
+ * @param mat
+ * @param rotation
+ */
+ private void rotation(Mat mat, int rotation) {
+ // 旋转90°
+ if (rotation == ROTATION_90) {
+ // 将图像逆时针旋转90°,然后再关于x轴对称
+ Core.transpose(mat, mat);
+ // 然后再绕Y轴旋转180° (顺时针)
+ Core.flip(mat, mat, 1);
+ } else if (rotation == ROTATION_180) {
+ //将图片绕X轴旋转180°(顺时针)
+ Core.flip(mat, mat, 0);
+ //将图片绕Y轴旋转180°(顺时针)
+ Core.flip(mat, mat, 1);
+ } else if (rotation == ROTATION_270) {
+ // 将图像逆时针旋转90°,然后再关于x轴对称
+ Core.transpose(mat, mat);
+ // 将图片绕X轴旋转180°(顺时针)
+ Core.flip(mat, mat, 0);
+ }
+ }
+
/**
* 二维码分析结果
*
@@ -101,12 +219,12 @@ public static class QRCodeAnalyzeResult extends AnalyzeResult {
*/
private Mat points;
- public QRCodeAnalyzeResult(Bitmap bitmap, T result) {
- super(bitmap, result);
+ public QRCodeAnalyzeResult(@NonNull byte[] imageData, int imageFormat, @NonNull FrameMetadata frameMetadata, @NonNull T result) {
+ super(imageData, imageFormat, frameMetadata, result);
}
- public QRCodeAnalyzeResult(Bitmap bitmap, T result, Mat points) {
- super(bitmap, result);
+ public QRCodeAnalyzeResult(@NonNull byte[] imageData, int imageFormat, @NonNull FrameMetadata frameMetadata, @NonNull T result, @Nullable Mat points) {
+ super(imageData, imageFormat, frameMetadata, result);
this.points = points;
}
@@ -119,9 +237,5 @@ public Mat getPoints() {
return points;
}
- @Deprecated
- public void setPoints(Mat points) {
- this.points = points;
- }
}
}
diff --git a/opencv-qrcode-scanning/src/main/res/layout/opencv_camera_scan.xml b/opencv-qrcode-scanning/src/main/res/layout/opencv_camera_scan.xml
new file mode 100644
index 0000000..399bef4
--- /dev/null
+++ b/opencv-qrcode-scanning/src/main/res/layout/opencv_camera_scan.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/opencv-qrcode/build.gradle b/opencv-qrcode/build.gradle
index 0150d4b..60335ad 100644
--- a/opencv-qrcode/build.gradle
+++ b/opencv-qrcode/build.gradle
@@ -10,17 +10,14 @@ android {
defaultConfig {
minSdk build_versions.minSdk
targetSdk build_versions.targetSdk
- versionCode app_version.versionCode
- versionName app_version.versionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
}
-
buildTypes {
release {
minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
@@ -28,10 +25,10 @@ android {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
-
- lintOptions {
+ lint {
abortOnError false
}
+
}
dependencies {
diff --git a/opencv-x86/build.gradle b/opencv-x86/build.gradle
index 53c0de2..5fea5b1 100644
--- a/opencv-x86/build.gradle
+++ b/opencv-x86/build.gradle
@@ -10,15 +10,14 @@ android {
defaultConfig {
minSdk build_versions.minSdk
targetSdk build_versions.targetSdk
- versionCode opencv_version.versionCode
- versionName opencv_version.versionName
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles "consumer-rules.pro"
}
-
buildTypes {
release {
minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
@@ -26,10 +25,10 @@ android {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
-
- lintOptions {
+ lint {
abortOnError false
}
+
}
dependencies {
diff --git a/opencv-x86/src/main/AndroidManifest.xml b/opencv-x86/src/main/AndroidManifest.xml
index 0130f42..9a40236 100644
--- a/opencv-x86/src/main/AndroidManifest.xml
+++ b/opencv-x86/src/main/AndroidManifest.xml
@@ -1,4 +1,3 @@
-
+
diff --git a/opencv-x86_64/build.gradle b/opencv-x86_64/build.gradle
index d40dd0c..ab7cb5e 100644
--- a/opencv-x86_64/build.gradle
+++ b/opencv-x86_64/build.gradle
@@ -10,15 +10,14 @@ android {
defaultConfig {
minSdk build_versions.minSdk
targetSdk build_versions.targetSdk
- versionCode opencv_version.versionCode
- versionName opencv_version.versionName
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles "consumer-rules.pro"
}
-
buildTypes {
release {
minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
@@ -26,10 +25,10 @@ android {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
-
- lintOptions {
+ lint {
abortOnError false
}
+
}
dependencies {
diff --git a/opencv-x86_64/src/main/AndroidManifest.xml b/opencv-x86_64/src/main/AndroidManifest.xml
index 71ee8fe..9a40236 100644
--- a/opencv-x86_64/src/main/AndroidManifest.xml
+++ b/opencv-x86_64/src/main/AndroidManifest.xml
@@ -1,4 +1,3 @@
-
+
diff --git a/opencv/build.gradle b/opencv/build.gradle
index c1efce0..1c0666a 100644
--- a/opencv/build.gradle
+++ b/opencv/build.gradle
@@ -101,8 +101,6 @@ android {
defaultConfig {
minSdk build_versions.minSdk
targetSdk build_versions.targetSdk
- versionCode opencv_version.versionCode
- versionName opencv_version.versionName
externalNativeBuild {
cmake {
@@ -135,7 +133,6 @@ android {
lintOptions {
abortOnError false
- warning 'InvalidPackage'
}
sourceSets {
@@ -155,6 +152,10 @@ android {
}
ndkVersion '22.1.7171670'
+ lint {
+ abortOnError false
+ warning 'InvalidPackage'
+ }
}
dependencies {
diff --git a/settings.gradle b/settings.gradle
index 23a6012..72f30de 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -10,6 +10,7 @@ dependencyResolutionManagement {
repositories {
google()
mavenCentral()
+ maven { url 'https://jitpack.io' }
}
}
diff --git a/versions.gradle b/versions.gradle
index 517e533..84d2a65 100644
--- a/versions.gradle
+++ b/versions.gradle
@@ -1,7 +1,7 @@
//App
def app_version = [:]
-app_version.versionCode = 7
-app_version.versionName = "1.3.0"
+app_version.versionCode = 8
+app_version.versionName = "2.0.0"
ext.app_version = app_version
def opencv_version = [:]
@@ -36,8 +36,8 @@ versions.androidExtJunit = "1.1.3"
versions.espressoCore = "3.4.0"
versions.lifecycleKtx="2.3.1"
-versions.mlkit="1.4.0"
versions.viewfinderview="1.0.0"
+versions.cameraScan="1.0.0"
versions.appDialog="1.1.4"
diff --git a/wechat-qrcode-scanning/build.gradle b/wechat-qrcode-scanning/build.gradle
index 3516239..ab0f370 100644
--- a/wechat-qrcode-scanning/build.gradle
+++ b/wechat-qrcode-scanning/build.gradle
@@ -10,17 +10,14 @@ android {
defaultConfig {
minSdk build_versions.minSdk
targetSdk build_versions.targetSdk
- versionCode app_version.versionCode
- versionName app_version.versionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
}
-
buildTypes {
release {
minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
@@ -28,10 +25,10 @@ android {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
-
- lintOptions {
+ lint {
abortOnError false
}
+
}
dependencies {
@@ -42,7 +39,8 @@ dependencies {
androidTestImplementation "androidx.test.ext:junit:$versions.androidExtJunit"
androidTestImplementation "androidx.test.espresso:espresso-core:$versions.espressoCore"
- api "com.github.jenly1314.MLKit:mlkit-camera-core:$versions.mlkit"
+ api "com.github.jenly1314:CameraScan:$versions.cameraScan"
+ api "com.github.jenly1314:viewfinderview:$versions.viewfinderview"
compileOnly project(path: ':opencv')
compileOnly project(path: ':wechat-qrcode')
diff --git a/wechat-qrcode-scanning/src/main/AndroidManifest.xml b/wechat-qrcode-scanning/src/main/AndroidManifest.xml
index 2ffb9d0..a5918e6 100644
--- a/wechat-qrcode-scanning/src/main/AndroidManifest.xml
+++ b/wechat-qrcode-scanning/src/main/AndroidManifest.xml
@@ -1,5 +1,4 @@
-
+
\ No newline at end of file
diff --git a/wechat-qrcode-scanning/src/main/java/com/king/wechat/qrcode/scanning/WeChatCameraScanActivity.java b/wechat-qrcode-scanning/src/main/java/com/king/wechat/qrcode/scanning/WeChatCameraScanActivity.java
index 273305c..8ff9652 100644
--- a/wechat-qrcode-scanning/src/main/java/com/king/wechat/qrcode/scanning/WeChatCameraScanActivity.java
+++ b/wechat-qrcode-scanning/src/main/java/com/king/wechat/qrcode/scanning/WeChatCameraScanActivity.java
@@ -1,7 +1,10 @@
package com.king.wechat.qrcode.scanning;
-import com.king.mlkit.vision.camera.BaseCameraScanActivity;
-import com.king.mlkit.vision.camera.analyze.Analyzer;
+import android.view.View;
+
+import com.king.camera.scan.BaseCameraScanActivity;
+import com.king.camera.scan.analyze.Analyzer;
+import com.king.view.viewfinderview.ViewfinderView;
import com.king.wechat.qrcode.scanning.analyze.WeChatScanningAnalyzer;
import java.util.List;
@@ -16,9 +19,41 @@
* @author Jenly
*/
public abstract class WeChatCameraScanActivity extends BaseCameraScanActivity> {
+
+ protected ViewfinderView viewfinderView;
+
+ @Override
+ public void initUI() {
+ int viewfinderViewId = getViewfinderViewId();
+ if (viewfinderViewId != View.NO_ID && viewfinderViewId != 0) {
+ viewfinderView = findViewById(viewfinderViewId);
+ }
+ super.initUI();
+ }
+
@Nullable
@Override
public Analyzer> createAnalyzer() {
return new WeChatScanningAnalyzer();
}
+
+ /**
+ * 布局ID;通过覆写此方法可以自定义布局
+ *
+ * @return 布局ID
+ */
+ @Override
+ public int getLayoutId() {
+ return R.layout.wechat_camera_scan;
+ }
+
+ /**
+ * {@link #viewfinderView} 的 ID
+ *
+ * @return 默认返回{@code R.id.viewfinderView}, 如果不需要扫码框可以返回{@link View#NO_ID}
+ */
+
+ public int getViewfinderViewId() {
+ return R.id.viewfinderView;
+ }
}
\ No newline at end of file
diff --git a/wechat-qrcode-scanning/src/main/java/com/king/wechat/qrcode/scanning/WeChatCameraScanFragment.java b/wechat-qrcode-scanning/src/main/java/com/king/wechat/qrcode/scanning/WeChatCameraScanFragment.java
index 00f707f..aa24c2f 100644
--- a/wechat-qrcode-scanning/src/main/java/com/king/wechat/qrcode/scanning/WeChatCameraScanFragment.java
+++ b/wechat-qrcode-scanning/src/main/java/com/king/wechat/qrcode/scanning/WeChatCameraScanFragment.java
@@ -1,7 +1,10 @@
package com.king.wechat.qrcode.scanning;
-import com.king.mlkit.vision.camera.BaseCameraScanFragment;
-import com.king.mlkit.vision.camera.analyze.Analyzer;
+import android.view.View;
+
+import com.king.camera.scan.BaseCameraScanFragment;
+import com.king.camera.scan.analyze.Analyzer;
+import com.king.view.viewfinderview.ViewfinderView;
import com.king.wechat.qrcode.scanning.analyze.WeChatScanningAnalyzer;
import java.util.List;
@@ -16,9 +19,40 @@
* @author Jenly
*/
public abstract class WeChatCameraScanFragment extends BaseCameraScanFragment> {
+ protected ViewfinderView viewfinderView;
+
+ @Override
+ public void initUI() {
+ int viewfinderViewId = getViewfinderViewId();
+ if (viewfinderViewId != View.NO_ID && viewfinderViewId != 0) {
+ viewfinderView = getRootView().findViewById(viewfinderViewId);
+ }
+ super.initUI();
+ }
+
@Nullable
@Override
public Analyzer> createAnalyzer() {
return new WeChatScanningAnalyzer();
}
+
+ /**
+ * 布局ID;通过覆写此方法可以自定义布局
+ *
+ * @return 布局ID
+ */
+ @Override
+ public int getLayoutId() {
+ return R.layout.wechat_camera_scan;
+ }
+
+ /**
+ * {@link #viewfinderView} 的 ID
+ *
+ * @return 默认返回{@code R.id.viewfinderView}, 如果不需要扫码框可以返回{@link View#NO_ID}
+ */
+
+ public int getViewfinderViewId() {
+ return R.id.viewfinderView;
+ }
}
diff --git a/wechat-qrcode-scanning/src/main/java/com/king/wechat/qrcode/scanning/analyze/WeChatScanningAnalyzer.java b/wechat-qrcode-scanning/src/main/java/com/king/wechat/qrcode/scanning/analyze/WeChatScanningAnalyzer.java
index b633cde..acf5d2b 100644
--- a/wechat-qrcode-scanning/src/main/java/com/king/wechat/qrcode/scanning/analyze/WeChatScanningAnalyzer.java
+++ b/wechat-qrcode-scanning/src/main/java/com/king/wechat/qrcode/scanning/analyze/WeChatScanningAnalyzer.java
@@ -1,17 +1,24 @@
package com.king.wechat.qrcode.scanning.analyze;
-import android.graphics.Bitmap;
+import android.graphics.ImageFormat;
-import com.king.mlkit.vision.camera.AnalyzeResult;
-import com.king.mlkit.vision.camera.analyze.Analyzer;
-import com.king.mlkit.vision.camera.util.BitmapUtils;
-import com.king.mlkit.vision.camera.util.LogUtils;
+import com.king.camera.scan.AnalyzeResult;
+import com.king.camera.scan.FrameMetadata;
+import com.king.camera.scan.analyze.Analyzer;
+import com.king.camera.scan.util.LogUtils;
import com.king.wechat.qrcode.WeChatQRCodeDetector;
+import org.opencv.core.Core;
+import org.opencv.core.CvType;
import org.opencv.core.Mat;
+import org.opencv.imgproc.Imgproc;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.atomic.AtomicBoolean;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -24,10 +31,17 @@
*/
public class WeChatScanningAnalyzer implements Analyzer> {
+ private static final int ROTATION_90 = 90;
+ private static final int ROTATION_180 = 180;
+ private static final int ROTATION_270 = 270;
+ private final Queue queue = new ConcurrentLinkedQueue<>();
+
+ private final AtomicBoolean joinQueue = new AtomicBoolean(false);
+
/**
* 是否需要输出二维码的各个顶点
*/
- private boolean isOutputVertices;
+ private final boolean isOutputVertices;
public WeChatScanningAnalyzer() {
this(false);
@@ -44,16 +58,32 @@ public WeChatScanningAnalyzer(boolean isOutputVertices) {
@Override
public void analyze(@NonNull ImageProxy imageProxy, @NonNull Analyzer.OnAnalyzeListener>> listener) {
+ if (!joinQueue.get()) {
+ int imageSize = imageProxy.getWidth() * imageProxy.getHeight();
+ byte[] bytes = new byte[imageSize + 2 * (imageSize / 4)];
+ queue.add(bytes);
+ joinQueue.set(true);
+ }
+ if (queue.isEmpty()) {
+ return;
+ }
+ final byte[] nv21Data = queue.poll();
AnalyzeResult> result = null;
try {
- final Bitmap bitmap = BitmapUtils.getBitmap(imageProxy);
- result = detectAndDecode(bitmap, isOutputVertices);
+ yuv_420_888toNv21(imageProxy, nv21Data);
+ FrameMetadata frameMetadata = new FrameMetadata(
+ imageProxy.getWidth(),
+ imageProxy.getHeight(),
+ imageProxy.getImageInfo().getRotationDegrees());
+ result = detectAndDecode(nv21Data, frameMetadata, isOutputVertices);
} catch (Exception e) {
LogUtils.w(e);
}
- if (result != null && !result.getResult().isEmpty()) {
+ if (result != null) {
+ joinQueue.set(false);
listener.onSuccess(result);
} else {
+ queue.add(nv21Data);
listener.onFailure(null);
}
}
@@ -61,30 +91,117 @@ public void analyze(@NonNull ImageProxy imageProxy, @NonNull Analyzer.OnAnalyzeL
/**
* 检测并识别二维码
*
- * @param bitmap
+ * @param nv21
* @param isOutputVertices
* @return
*/
@Nullable
- private AnalyzeResult> detectAndDecode(Bitmap bitmap, boolean isOutputVertices) {
+ private AnalyzeResult> detectAndDecode(byte[] nv21, FrameMetadata frameMetadata, boolean isOutputVertices) {
+ Mat mat = new Mat(frameMetadata.getHeight() + frameMetadata.getHeight() / 2, frameMetadata.getWidth(), CvType.CV_8UC1);
+ mat.put(0,0, nv21);
+ Mat bgrMat = new Mat();
+ Imgproc.cvtColor(mat, bgrMat, Imgproc.COLOR_YUV2BGR_NV21);
+ mat.release();
+ rotation(bgrMat, frameMetadata.getRotation());
if (isOutputVertices) {
// 如果需要返回二维码的各个顶点
final List points = new ArrayList<>();
- List result = WeChatQRCodeDetector.detectAndDecode(bitmap, points);
+ List result = WeChatQRCodeDetector.detectAndDecode(bgrMat, points);
+ bgrMat.release();
if (result != null && !result.isEmpty()) {
- return new QRCodeAnalyzeResult<>(bitmap, result, points);
+ return new QRCodeAnalyzeResult<>(nv21, ImageFormat.NV21, frameMetadata, result, points);
}
} else {
// 反之则需识别结果即可
- List result = WeChatQRCodeDetector.detectAndDecode(bitmap);
+ List result = WeChatQRCodeDetector.detectAndDecode(bgrMat);
+ bgrMat.release();
if (result != null && !result.isEmpty()) {
- return new QRCodeAnalyzeResult<>(bitmap, result);
+ return new QRCodeAnalyzeResult<>(nv21, ImageFormat.NV21, frameMetadata, result);
}
}
return null;
}
+ /**
+ * 旋转指定角度
+ * @param mat
+ * @param rotation
+ */
+ private void rotation(Mat mat, int rotation) {
+ // 旋转90°
+ if (rotation == ROTATION_90) {
+ // 将图像逆时针旋转90°,然后再关于x轴对称
+ Core.transpose(mat, mat);
+ // 然后再绕Y轴旋转180° (顺时针)
+ Core.flip(mat, mat, 1);
+ } else if (rotation == ROTATION_180) {
+ //将图片绕X轴旋转180°(顺时针)
+ Core.flip(mat, mat, 0);
+ //将图片绕Y轴旋转180°(顺时针)
+ Core.flip(mat, mat, 1);
+ } else if (rotation == ROTATION_270) {
+ // 将图像逆时针旋转90°,然后再关于x轴对称
+ Core.transpose(mat, mat);
+ // 将图片绕X轴旋转180°(顺时针)
+ Core.flip(mat, mat, 0);
+ }
+ }
+
+ /**
+ * YUV420_888转NV21
+ *
+ * @param image
+ * @param nv21
+ */
+ private void yuv_420_888toNv21(@NonNull ImageProxy image, byte[] nv21) {
+ ImageProxy.PlaneProxy yPlane = image.getPlanes()[0];
+ ImageProxy.PlaneProxy uPlane = image.getPlanes()[1];
+ ImageProxy.PlaneProxy vPlane = image.getPlanes()[2];
+
+ ByteBuffer yBuffer = yPlane.getBuffer();
+ ByteBuffer uBuffer = uPlane.getBuffer();
+ ByteBuffer vBuffer = vPlane.getBuffer();
+ yBuffer.rewind();
+ uBuffer.rewind();
+ vBuffer.rewind();
+
+ int ySize = yBuffer.remaining();
+
+ int position = 0;
+
+ // Add the full y buffer to the array. If rowStride > 1, some padding may be skipped.
+ for (int row = 0; row < image.getHeight(); row++) {
+ yBuffer.get(nv21, position, image.getWidth());
+ position += image.getWidth();
+ yBuffer.position(Math.min(ySize, yBuffer.position() - image.getWidth() + yPlane.getRowStride()));
+ }
+
+ int chromaHeight = image.getHeight() / 2;
+ int chromaWidth = image.getWidth() / 2;
+ int vRowStride = vPlane.getRowStride();
+ int uRowStride = uPlane.getRowStride();
+ int vPixelStride = vPlane.getPixelStride();
+ int uPixelStride = uPlane.getPixelStride();
+
+ // Interleave the u and v frames, filling up the rest of the buffer. Use two line buffers to
+ // perform faster bulk gets from the byte buffers.
+ byte[] vLineBuffer = new byte[vRowStride];
+ byte[] uLineBuffer = new byte[uRowStride];
+ for (int row = 0; row < chromaHeight; row++) {
+ vBuffer.get(vLineBuffer, 0, Math.min(vRowStride, vBuffer.remaining()));
+ uBuffer.get(uLineBuffer, 0, Math.min(uRowStride, uBuffer.remaining()));
+ int vLineBufferPosition = 0;
+ int uLineBufferPosition = 0;
+ for (int col = 0; col < chromaWidth; col++) {
+ nv21[position++] = vLineBuffer[vLineBufferPosition];
+ nv21[position++] = uLineBuffer[uLineBufferPosition];
+ vLineBufferPosition += vPixelStride;
+ uLineBufferPosition += uPixelStride;
+ }
+ }
+ }
+
/**
* 二维码分析结果
*
@@ -97,12 +214,12 @@ public static class QRCodeAnalyzeResult extends AnalyzeResult {
*/
private List points;
- public QRCodeAnalyzeResult(Bitmap bitmap, T result) {
- super(bitmap, result);
+ public QRCodeAnalyzeResult(@NonNull byte[] imageData, int imageFormat, @NonNull FrameMetadata frameMetadata, @NonNull T result) {
+ super(imageData, imageFormat, frameMetadata, result);
}
- public QRCodeAnalyzeResult(Bitmap bitmap, T result, List points) {
- super(bitmap, result);
+ public QRCodeAnalyzeResult(@NonNull byte[] imageData, int imageFormat, @NonNull FrameMetadata frameMetadata, @NonNull T result, @Nullable List points) {
+ super(imageData, imageFormat, frameMetadata, result);
this.points = points;
}
@@ -111,13 +228,10 @@ public QRCodeAnalyzeResult(Bitmap bitmap, T result, List points) {
*
* @return
*/
+ @Nullable
public List getPoints() {
return points;
}
- @Deprecated
- public void setPoints(List points) {
- this.points = points;
- }
}
}
diff --git a/wechat-qrcode-scanning/src/main/res/layout/wechat_camera_scan.xml b/wechat-qrcode-scanning/src/main/res/layout/wechat_camera_scan.xml
new file mode 100644
index 0000000..399bef4
--- /dev/null
+++ b/wechat-qrcode-scanning/src/main/res/layout/wechat_camera_scan.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/wechat-qrcode/build.gradle b/wechat-qrcode/build.gradle
index dd90665..201b847 100644
--- a/wechat-qrcode/build.gradle
+++ b/wechat-qrcode/build.gradle
@@ -10,23 +10,14 @@ android {
defaultConfig {
minSdk build_versions.minSdk
targetSdk build_versions.targetSdk
- versionCode app_version.versionCode
- versionName app_version.versionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
-
- externalNativeBuild {
- cmake {
- arguments "-DANDROID_STL=c++_shared"
- }
- }
}
-
buildTypes {
release {
minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
@@ -34,10 +25,10 @@ android {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
-
- lintOptions {
+ lint {
abortOnError false
}
+
}
dependencies {
diff --git a/wechat-qrcode/src/main/AndroidManifest.xml b/wechat-qrcode/src/main/AndroidManifest.xml
index d08ab3c..a5918e6 100644
--- a/wechat-qrcode/src/main/AndroidManifest.xml
+++ b/wechat-qrcode/src/main/AndroidManifest.xml
@@ -1,5 +1,4 @@
-
+
\ No newline at end of file
diff --git a/wechat-qrcode/src/main/java/com/king/wechat/qrcode/WeChatQRCodeDetector.java b/wechat-qrcode/src/main/java/com/king/wechat/qrcode/WeChatQRCodeDetector.java
index a0e64e9..651ea63 100644
--- a/wechat-qrcode/src/main/java/com/king/wechat/qrcode/WeChatQRCodeDetector.java
+++ b/wechat-qrcode/src/main/java/com/king/wechat/qrcode/WeChatQRCodeDetector.java
@@ -106,8 +106,11 @@ private static String getExternalFilesDir(Context context, String path) {
if (files != null && files.length > 0) {
return files[0].getAbsolutePath();
}
- return context.getExternalFilesDir(path).getAbsolutePath();
-
+ File file = context.getExternalFilesDir(path);
+ if(file == null) {
+ file = new File(context.getFilesDir(), path);
+ }
+ return file.getAbsolutePath();
}
/**