更新CameraX至v1.2.2
This commit is contained in:
13
README.md
13
README.md
@@ -26,7 +26,7 @@ ZXingLite for Android 是ZXing的精简极速版,基于ZXing库优化扫码和
|
|||||||
## ViewfinderView属性说明
|
## ViewfinderView属性说明
|
||||||
|
|
||||||
| 属性 | 属性类型 | 默认值 | 属性说明 |
|
| 属性 | 属性类型 | 默认值 | 属性说明 |
|
||||||
| :------|:----------| :------ | :------ |
|
|:------------------------|:----------| :------ | :------ |
|
||||||
| maskColor | color |<font color=#000000>#60000000</font>| 扫描区外遮罩的颜色 |
|
| maskColor | color |<font color=#000000>#60000000</font>| 扫描区外遮罩的颜色 |
|
||||||
| frameColor | color |<font color=#1FB3E2>#7F1FB3E2</font>| 扫描区边框的颜色 |
|
| frameColor | color |<font color=#1FB3E2>#7F1FB3E2</font>| 扫描区边框的颜色 |
|
||||||
| cornerColor | color |<font color=#1FB3E2>#FF1FB3E2</font>| 扫描区边角的颜色 |
|
| cornerColor | color |<font color=#1FB3E2>#FF1FB3E2</font>| 扫描区边角的颜色 |
|
||||||
@@ -61,6 +61,7 @@ ZXingLite for Android 是ZXing的精简极速版,基于ZXing库优化扫码和
|
|||||||
| pointDrawable | reference | | 结果点自定义图片 |
|
| pointDrawable | reference | | 结果点自定义图片 |
|
||||||
| showPointAnim | boolean | true | 是否显示结果点的动画 |
|
| showPointAnim | boolean | true | 是否显示结果点的动画 |
|
||||||
| laserDrawable | reference | | 扫描激光自定义图片 |
|
| laserDrawable | reference | | 扫描激光自定义图片 |
|
||||||
|
| laserDrawableRatio | float | 0.625f | 激光扫描图片与屏幕占比 |
|
||||||
| viewfinderStyle | enum | classic | 取景框样式;支持:classic:经典样式(带扫码框那种)、popular:流行样式(不带扫码框) |
|
| viewfinderStyle | enum | classic | 取景框样式;支持:classic:经典样式(带扫码框那种)、popular:流行样式(不带扫码框) |
|
||||||
|
|
||||||
|
|
||||||
@@ -83,7 +84,7 @@ allprojects {
|
|||||||
|
|
||||||
```gradle
|
```gradle
|
||||||
// AndroidX 版本
|
// AndroidX 版本
|
||||||
implementation 'com.github.jenly1314:zxing-lite:2.3.1'
|
implementation 'com.github.jenly1314:zxing-lite:2.4.0'
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -175,7 +176,7 @@ implementation 'com.king.zxing:zxing-lite:1.1.9'
|
|||||||
// 获取CameraScan,扫码相关的配置设置。CameraScan里面包含部分支持链式调用的方法,即调用返回是CameraScan本身的一些配置建议在startCamera之前调用。
|
// 获取CameraScan,扫码相关的配置设置。CameraScan里面包含部分支持链式调用的方法,即调用返回是CameraScan本身的一些配置建议在startCamera之前调用。
|
||||||
getCameraScan().setPlayBeep(true)//设置是否播放音效,默认为false
|
getCameraScan().setPlayBeep(true)//设置是否播放音效,默认为false
|
||||||
.setVibrate(true)//设置是否震动,默认为false
|
.setVibrate(true)//设置是否震动,默认为false
|
||||||
.setCameraConfig(new CameraConfig())//设置相机配置信息,CameraConfig可覆写options方法自定义配置
|
.setCameraConfig(new ResolutionCameraConfig(this))//设置相机配置信息,CameraConfig可覆写options方法自定义配置
|
||||||
.setNeedAutoZoom(false)//二维码太小时可自动缩放,默认为false
|
.setNeedAutoZoom(false)//二维码太小时可自动缩放,默认为false
|
||||||
.setNeedTouchZoom(true)//支持多指触摸捏合缩放,默认为true
|
.setNeedTouchZoom(true)//支持多指触摸捏合缩放,默认为true
|
||||||
.setDarkLightLux(45f)//设置光线足够暗的阈值(单位:lux),需要通过{@link #bindFlashlightView(View)}绑定手电筒才有效
|
.setDarkLightLux(45f)//设置光线足够暗的阈值(单位:lux),需要通过{@link #bindFlashlightView(View)}绑定手电筒才有效
|
||||||
@@ -404,6 +405,12 @@ dependencies {
|
|||||||
|
|
||||||
## 版本记录
|
## 版本记录
|
||||||
|
|
||||||
|
#### v2.4.0:2023-4-15
|
||||||
|
* 优化CameraScan的缺省配置(CameraConfig相关配置)
|
||||||
|
* 优化ViewfinderView自定义属性(新增laserDrawableRatio)
|
||||||
|
* 优化ImageAnalyzer中YUV数据的处理
|
||||||
|
* 更新CameraX至v1.2.2
|
||||||
|
|
||||||
#### v2.3.1:2023-3-4
|
#### v2.3.1:2023-3-4
|
||||||
* 更新CameraX至v1.2.1
|
* 更新CameraX至v1.2.1
|
||||||
* 更新Gradle至v7.5
|
* 更新Gradle至v7.5
|
||||||
|
|||||||
@@ -1,18 +1,22 @@
|
|||||||
apply plugin: 'com.android.application'
|
plugins {
|
||||||
//apply plugin: 'kotlin-android'
|
id 'com.android.application'
|
||||||
//apply plugin: 'kotlin-android-extensions'
|
id 'org.jetbrains.kotlin.android'
|
||||||
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion build_versions.compileSdk
|
namespace 'com.king.zxing.app'
|
||||||
buildToolsVersion build_versions.buildTools
|
compileSdk build_versions.compileSdk
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "com.king.zxing.app"
|
applicationId "com.king.zxing.app"
|
||||||
minSdkVersion build_versions.minSdk
|
minSdk build_versions.minSdk
|
||||||
targetSdkVersion build_versions.targetSdk
|
targetSdk build_versions.targetSdk
|
||||||
versionCode app_version.versionCode
|
versionCode app_version.versionCode
|
||||||
versionName app_version.versionName
|
versionName app_version.versionName
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
minifyEnabled false
|
minifyEnabled false
|
||||||
@@ -24,22 +28,16 @@ android {
|
|||||||
abortOnError false
|
abortOnError false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
coreLibraryDesugaringEnabled true
|
coreLibraryDesugaringEnabled true
|
||||||
sourceCompatibility JavaVersion.VERSION_11
|
sourceCompatibility JavaVersion.VERSION_11
|
||||||
targetCompatibility JavaVersion.VERSION_11
|
targetCompatibility JavaVersion.VERSION_11
|
||||||
}
|
}
|
||||||
|
|
||||||
// kotlinOptions {
|
|
||||||
// jvmTarget = '1.8'
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
|
||||||
testImplementation deps.test.junit
|
testImplementation deps.test.junit
|
||||||
androidTestImplementation deps.test.runner
|
androidTestImplementation deps.test.android_ext_junit
|
||||||
androidTestImplementation deps.test.espresso
|
androidTestImplementation deps.test.espresso
|
||||||
|
|
||||||
implementation deps.androidx.design
|
implementation deps.androidx.design
|
||||||
|
|||||||
Binary file not shown.
@@ -11,8 +11,8 @@
|
|||||||
"type": "SINGLE",
|
"type": "SINGLE",
|
||||||
"filters": [],
|
"filters": [],
|
||||||
"attributes": [],
|
"attributes": [],
|
||||||
"versionCode": 36,
|
"versionCode": 37,
|
||||||
"versionName": "2.3.1",
|
"versionName": "2.4.0",
|
||||||
"outputFile": "app-release.apk"
|
"outputFile": "app-release.apk"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ public class CustomCaptureActivity extends CaptureActivity {
|
|||||||
getCameraScan().setPlayBeep(true)//设置是否播放音效,默认为false
|
getCameraScan().setPlayBeep(true)//设置是否播放音效,默认为false
|
||||||
.setVibrate(true)//设置是否震动,默认为false
|
.setVibrate(true)//设置是否震动,默认为false
|
||||||
// .setCameraConfig(new CameraConfig())//设置相机配置信息,CameraConfig可覆写options方法自定义配置
|
// .setCameraConfig(new CameraConfig())//设置相机配置信息,CameraConfig可覆写options方法自定义配置
|
||||||
.setCameraConfig(new ResolutionCameraConfig(this))//设置CameraConfig,可以根据自己的需求去自定义配置
|
// .setCameraConfig(new ResolutionCameraConfig(this))//设置CameraConfig,可以根据自己的需求去自定义配置
|
||||||
.setNeedAutoZoom(false)//二维码太小时可自动缩放,默认为false
|
.setNeedAutoZoom(false)//二维码太小时可自动缩放,默认为false
|
||||||
.setNeedTouchZoom(true)//支持多指触摸捏合缩放,默认为true
|
.setNeedTouchZoom(true)//支持多指触摸捏合缩放,默认为true
|
||||||
.setDarkLightLux(45f)//设置光线足够暗的阈值(单位:lux),需要通过{@link #bindFlashlightView(View)}绑定手电筒才有效
|
.setDarkLightLux(45f)//设置光线足够暗的阈值(单位:lux),需要通过{@link #bindFlashlightView(View)}绑定手电筒才有效
|
||||||
@@ -117,12 +117,10 @@ public class CustomCaptureActivity extends CaptureActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void showToast(String text){
|
private void showToast(String text){
|
||||||
if(toast == null){
|
if(toast != null){
|
||||||
toast = Toast.makeText(this,text,Toast.LENGTH_SHORT);
|
toast.cancel();
|
||||||
}else{
|
|
||||||
toast.setText(text);
|
|
||||||
toast.setDuration(Toast.LENGTH_SHORT);
|
|
||||||
}
|
}
|
||||||
|
toast = Toast.makeText(this,text,Toast.LENGTH_SHORT);
|
||||||
toast.show();
|
toast.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ import com.king.zxing.util.LogUtils;
|
|||||||
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.core.app.ActivityCompat;
|
import androidx.core.app.ActivityCompat;
|
||||||
@@ -72,6 +74,8 @@ public class MainActivity extends AppCompatActivity implements EasyPermissions.P
|
|||||||
|
|
||||||
private Toast toast;
|
private Toast toast;
|
||||||
|
|
||||||
|
private ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@@ -97,12 +101,10 @@ public class MainActivity extends AppCompatActivity implements EasyPermissions.P
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void showToast(String text){
|
private void showToast(String text){
|
||||||
if(toast == null){
|
if(toast != null){
|
||||||
toast = Toast.makeText(this,text,Toast.LENGTH_SHORT);
|
toast.cancel();
|
||||||
}else{
|
|
||||||
toast.setDuration(Toast.LENGTH_SHORT);
|
|
||||||
toast.setText(text);
|
|
||||||
}
|
}
|
||||||
|
toast = Toast.makeText(this,text,Toast.LENGTH_SHORT);
|
||||||
toast.show();
|
toast.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +167,7 @@ public class MainActivity extends AppCompatActivity implements EasyPermissions.P
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void asyncThread(Runnable runnable){
|
private void asyncThread(Runnable runnable){
|
||||||
new Thread(runnable).start();
|
executor.execute(runnable);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
BIN
app/src/main/res/drawable-xxhdpi/ic_laser_line.png
Normal file
BIN
app/src/main/res/drawable-xxhdpi/ic_laser_line.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.5 KiB |
@@ -13,7 +13,10 @@
|
|||||||
android:id="@+id/viewfinderView"
|
android:id="@+id/viewfinderView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
app:viewfinderStyle="popular"/>
|
app:viewfinderStyle="popular"
|
||||||
|
app:laserStyle="image"
|
||||||
|
app:laserDrawableRatio="0.8"
|
||||||
|
app:laserDrawable="@drawable/ic_laser_line"/>
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/ivFlash"
|
android:id="@+id/ivFlash"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|||||||
57
build.gradle
57
build.gradle
@@ -1,53 +1,10 @@
|
|||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
|
|
||||||
apply from: 'versions.gradle'
|
apply from: 'versions.gradle'
|
||||||
|
}// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
repositories {
|
plugins {
|
||||||
google()
|
id 'com.android.application' version '7.4.2' apply false
|
||||||
mavenCentral()
|
id 'com.android.library' version '7.4.2' apply false
|
||||||
}
|
id 'org.jetbrains.kotlin.android' version '1.8.0' apply false
|
||||||
|
// id 'org.jetbrains.dokka' version '1.7.0' apply false
|
||||||
|
id 'com.vanniktech.maven.publish' version '0.22.0' apply false
|
||||||
dependencies {
|
|
||||||
classpath "com.android.tools.build:gradle:$versions.gralde"
|
|
||||||
// classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlin"
|
|
||||||
// classpath "com.novoda:bintray-release:$versions.bintray_release"
|
|
||||||
classpath "com.vanniktech:gradle-maven-publish-plugin:$versions.mavenPublish"
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
|
||||||
// in the individual module build.gradle files
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
allprojects {
|
|
||||||
repositories {
|
|
||||||
google()
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
allprojects {
|
|
||||||
plugins.withId("com.vanniktech.maven.publish") {
|
|
||||||
mavenPublish {
|
|
||||||
sonatypeHost = "S01"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
task clean(type: Delete) {
|
|
||||||
delete rootProject.buildDir
|
|
||||||
}
|
|
||||||
|
|
||||||
allprojects {
|
|
||||||
tasks.withType(Javadoc) {
|
|
||||||
options{
|
|
||||||
encoding "UTF-8"
|
|
||||||
charSet 'UTF-8'
|
|
||||||
links "http://docs.oracle.com/javase/8/docs/api"
|
|
||||||
}
|
|
||||||
|
|
||||||
options.addStringOption('Xdoclint:none', '-quiet')
|
|
||||||
failOnError false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,11 @@
|
|||||||
## 版本记录
|
## 版本记录
|
||||||
|
|
||||||
|
#### v2.4.0:2023-4-15
|
||||||
|
* 优化CameraScan的缺省配置(CameraConfig相关配置)
|
||||||
|
* 优化ViewfinderView自定义属性(新增laserDrawableRatio)
|
||||||
|
* 优化ImageAnalyzer中YUV数据的处理
|
||||||
|
* 更新CameraX至v1.2.2
|
||||||
|
|
||||||
#### v2.3.1:2023-3-4
|
#### v2.3.1:2023-3-4
|
||||||
* 更新CameraX至v1.2.1
|
* 更新CameraX至v1.2.1
|
||||||
* 更新Gradle至v7.5
|
* 更新Gradle至v7.5
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ org.gradle.jvmargs = -Xmx1536m
|
|||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
android.enableJetifier=true
|
android.enableJetifier=true
|
||||||
|
|
||||||
VERSION_NAME=2.3.1
|
VERSION_NAME=2.4.0
|
||||||
VERSION_CODE=36
|
VERSION_CODE=37
|
||||||
GROUP=com.github.jenly1314
|
GROUP=com.github.jenly1314
|
||||||
|
|
||||||
POM_DESCRIPTION=ZXingLite for Android
|
POM_DESCRIPTION=ZXingLite for Android
|
||||||
@@ -35,6 +35,8 @@ POM_DEVELOPER_ID=jenly
|
|||||||
POM_DEVELOPER_NAME=Jenly Yu
|
POM_DEVELOPER_NAME=Jenly Yu
|
||||||
POM_DEVELOPER_URL=https://github.com/jenly1314/
|
POM_DEVELOPER_URL=https://github.com/jenly1314/
|
||||||
|
|
||||||
|
SONATYPE_HOST=S01
|
||||||
|
|
||||||
RELEASE_REPOSITORY_URL=https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/
|
RELEASE_REPOSITORY_URL=https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/
|
||||||
SNAPSHOT_REPOSITORY_URL=https://s01.oss.sonatype.org/content/repositories/snapshots/
|
SNAPSHOT_REPOSITORY_URL=https://s01.oss.sonatype.org/content/repositories/snapshots/
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1,18 @@
|
|||||||
include ':app', ':zxing-lite'
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
gradlePluginPortal()
|
||||||
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dependencyResolutionManagement {
|
||||||
|
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.name = "ZXingLite"
|
||||||
|
include ':app'
|
||||||
|
include ':zxing-lite'
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
//App
|
//App
|
||||||
def app_version = [:]
|
def app_version = [:]
|
||||||
app_version.versionCode = 36
|
app_version.versionCode = 37
|
||||||
app_version.versionName = "2.3.1"
|
app_version.versionName = "2.4.0"
|
||||||
ext.app_version = app_version
|
ext.app_version = app_version
|
||||||
|
|
||||||
//build version
|
//build version
|
||||||
@@ -22,16 +22,17 @@ versions.appcompat = "1.1.0"
|
|||||||
versions.constraintLayout = "2.0.4"
|
versions.constraintLayout = "2.0.4"
|
||||||
|
|
||||||
//test
|
//test
|
||||||
versions.junit = "1.1.0"
|
versions.junit = "4.13.2"
|
||||||
|
versions.androidExtJunit = "1.1.3"
|
||||||
versions.test = "1.2.0"
|
versions.test = "1.2.0"
|
||||||
versions.runner = "1.2.0"
|
versions.runner = "1.2.0"
|
||||||
versions.espresso = "3.2.0"
|
versions.espresso = "3.4.0"
|
||||||
|
|
||||||
versions.bintray_release = "0.9.2"
|
versions.bintray_release = "0.9.2"
|
||||||
versions.mavenPublish = '0.18.0'
|
versions.mavenPublish = '0.22.0'
|
||||||
versions.gralde = "7.4.1"
|
versions.gralde = "7.4.2"
|
||||||
versions.kotlin = "1.6.0"
|
versions.kotlin = "1.8.0"
|
||||||
versions.coreKtx = "1.6.0"
|
versions.coreKtx = "1.7.0"
|
||||||
|
|
||||||
//zxing
|
//zxing
|
||||||
versions.zxing = "3.5.1"
|
versions.zxing = "3.5.1"
|
||||||
@@ -53,7 +54,8 @@ deps.androidx = androidx
|
|||||||
|
|
||||||
//test
|
//test
|
||||||
def test = [:]
|
def test = [:]
|
||||||
test.junit = "androidx.test.ext:junit:$versions.junit"
|
test.junit = "junit:junit:$versions.junit"
|
||||||
|
test.android_ext_junit = "androidx.test.ext:junit:$versions.androidExtJunit"
|
||||||
test.test = "androidx.test:core:$versions.test"
|
test.test = "androidx.test:core:$versions.test"
|
||||||
test.runner = "androidx.test:runner:$versions.runner"
|
test.runner = "androidx.test:runner:$versions.runner"
|
||||||
test.espresso = "androidx.test.espresso:espresso-core:$versions.espresso"
|
test.espresso = "androidx.test.espresso:espresso-core:$versions.espresso"
|
||||||
|
|||||||
@@ -1,52 +1,46 @@
|
|||||||
apply plugin: 'com.android.library'
|
plugins {
|
||||||
//apply from: 'bintray.gradle'
|
id 'com.android.library'
|
||||||
apply plugin: "com.vanniktech.maven.publish"
|
id 'com.vanniktech.maven.publish'
|
||||||
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion build_versions.compileSdk
|
namespace 'com.king.zxing'
|
||||||
buildToolsVersion build_versions.buildTools
|
compileSdk build_versions.compileSdk
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion build_versions.minSdk
|
minSdk build_versions.minSdk
|
||||||
targetSdkVersion build_versions.targetSdk
|
targetSdk build_versions.targetSdk
|
||||||
versionCode app_version.versionCode
|
|
||||||
versionName app_version.versionName
|
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
consumerProguardFiles "consumer-rules.pro"
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
minifyEnabled false
|
minifyEnabled false
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lintOptions {
|
|
||||||
abortOnError false
|
|
||||||
warning 'InvalidPackage'
|
|
||||||
}
|
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
coreLibraryDesugaringEnabled true
|
coreLibraryDesugaringEnabled true
|
||||||
sourceCompatibility JavaVersion.VERSION_11
|
sourceCompatibility JavaVersion.VERSION_11
|
||||||
targetCompatibility JavaVersion.VERSION_11
|
targetCompatibility JavaVersion.VERSION_11
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lintOptions {
|
||||||
|
abortOnError false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//task javadoc(type: Javadoc) {
|
|
||||||
// source = android.sourceSets.main.java.srcDirs
|
|
||||||
// classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
|
|
||||||
//}
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
|
||||||
testImplementation deps.test.junit
|
testImplementation deps.test.junit
|
||||||
androidTestImplementation deps.test.runner
|
androidTestImplementation deps.test.android_ext_junit
|
||||||
androidTestImplementation deps.test.espresso
|
androidTestImplementation deps.test.espresso
|
||||||
|
|
||||||
coreLibraryDesugaring deps.desugar_jdk
|
coreLibraryDesugaring deps.desugar_jdk
|
||||||
|
|
||||||
compileOnly deps.androidx.appcompat
|
implementation deps.androidx.appcompat
|
||||||
api deps.zxing
|
api deps.zxing
|
||||||
api deps.camera_core
|
api deps.camera_core
|
||||||
api deps.camera_camera2
|
api deps.camera_camera2
|
||||||
|
|||||||
0
zxing-lite/consumer-rules.pro
Normal file
0
zxing-lite/consumer-rules.pro
Normal file
@@ -46,6 +46,15 @@ public abstract class CameraScan implements ICamera, ICameraControl {
|
|||||||
*/
|
*/
|
||||||
public static int LENS_FACING_BACK = CameraSelector.LENS_FACING_BACK;
|
public static int LENS_FACING_BACK = CameraSelector.LENS_FACING_BACK;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 纵横比:4:3
|
||||||
|
*/
|
||||||
|
public static final float ASPECT_RATIO_4_3 = 4.0F / 3.0F;
|
||||||
|
/**
|
||||||
|
* 纵横比:16:9
|
||||||
|
*/
|
||||||
|
public static final float ASPECT_RATIO_16_9 = 16.0F / 9.0F;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否需要支持自动缩放
|
* 是否需要支持自动缩放
|
||||||
*/
|
*/
|
||||||
@@ -59,7 +68,7 @@ public abstract class CameraScan implements ICamera, ICameraControl {
|
|||||||
/**
|
/**
|
||||||
* 是否需要支持触摸缩放
|
* 是否需要支持触摸缩放
|
||||||
*
|
*
|
||||||
* @return
|
* @return 返回是否需要支持触摸缩放
|
||||||
*/
|
*/
|
||||||
protected boolean isNeedTouchZoom() {
|
protected boolean isNeedTouchZoom() {
|
||||||
return isNeedTouchZoom;
|
return isNeedTouchZoom;
|
||||||
@@ -68,8 +77,8 @@ public abstract class CameraScan implements ICamera, ICameraControl {
|
|||||||
/**
|
/**
|
||||||
* 设置是否需要支持触摸缩放
|
* 设置是否需要支持触摸缩放
|
||||||
*
|
*
|
||||||
* @param needTouchZoom
|
* @param needTouchZoom 是否需要支持触摸缩放
|
||||||
* @return
|
* @return {@link CameraScan}
|
||||||
*/
|
*/
|
||||||
public CameraScan setNeedTouchZoom(boolean needTouchZoom) {
|
public CameraScan setNeedTouchZoom(boolean needTouchZoom) {
|
||||||
isNeedTouchZoom = needTouchZoom;
|
isNeedTouchZoom = needTouchZoom;
|
||||||
@@ -79,7 +88,7 @@ public abstract class CameraScan implements ICamera, ICameraControl {
|
|||||||
/**
|
/**
|
||||||
* 是否需要支持自动缩放
|
* 是否需要支持自动缩放
|
||||||
*
|
*
|
||||||
* @return
|
* @return 是否需要支持自动缩放
|
||||||
*/
|
*/
|
||||||
protected boolean isNeedAutoZoom() {
|
protected boolean isNeedAutoZoom() {
|
||||||
return isNeedAutoZoom;
|
return isNeedAutoZoom;
|
||||||
@@ -88,8 +97,8 @@ public abstract class CameraScan implements ICamera, ICameraControl {
|
|||||||
/**
|
/**
|
||||||
* 设置是否需要支持自动缩放
|
* 设置是否需要支持自动缩放
|
||||||
*
|
*
|
||||||
* @param needAutoZoom
|
* @param needAutoZoom 是否需要支持自动缩放
|
||||||
* @return
|
* @return {@link CameraScan}
|
||||||
*/
|
*/
|
||||||
public CameraScan setNeedAutoZoom(boolean needAutoZoom) {
|
public CameraScan setNeedAutoZoom(boolean needAutoZoom) {
|
||||||
isNeedAutoZoom = needAutoZoom;
|
isNeedAutoZoom = needAutoZoom;
|
||||||
@@ -99,7 +108,8 @@ public abstract class CameraScan implements ICamera, ICameraControl {
|
|||||||
/**
|
/**
|
||||||
* 设置相机配置,请在{@link #startCamera()}之前调用
|
* 设置相机配置,请在{@link #startCamera()}之前调用
|
||||||
*
|
*
|
||||||
* @param cameraConfig
|
* @param cameraConfig 相机配置
|
||||||
|
* @return {@link CameraScan}
|
||||||
*/
|
*/
|
||||||
public abstract CameraScan setCameraConfig(CameraConfig cameraConfig);
|
public abstract CameraScan setCameraConfig(CameraConfig cameraConfig);
|
||||||
|
|
||||||
@@ -113,7 +123,8 @@ public abstract class CameraScan implements ICamera, ICameraControl {
|
|||||||
* 2. 如果只是想拦截扫码结果回调自己处理逻辑,但并不想继续分析图像(即不想连扫),可通过
|
* 2. 如果只是想拦截扫码结果回调自己处理逻辑,但并不想继续分析图像(即不想连扫),可通过
|
||||||
* 调用getCameraScan().setAnalyzeImage(false)来停止分析图像。
|
* 调用getCameraScan().setAnalyzeImage(false)来停止分析图像。
|
||||||
*
|
*
|
||||||
* @param analyze
|
* @param analyze 是否分析图像
|
||||||
|
* @return {@link CameraScan}
|
||||||
*/
|
*/
|
||||||
public abstract CameraScan setAnalyzeImage(boolean analyze);
|
public abstract CameraScan setAnalyzeImage(boolean analyze);
|
||||||
|
|
||||||
@@ -123,7 +134,8 @@ public abstract class CameraScan implements ICamera, ICameraControl {
|
|||||||
* <p>
|
* <p>
|
||||||
* 内置了一些{@link Analyzer}的实现类如下:
|
* 内置了一些{@link Analyzer}的实现类如下:
|
||||||
*
|
*
|
||||||
* @param analyzer
|
* @param analyzer 分析器
|
||||||
|
* @return {@link CameraScan}
|
||||||
* @see {@link MultiFormatAnalyzer}
|
* @see {@link MultiFormatAnalyzer}
|
||||||
* @see {@link AreaRectAnalyzer}
|
* @see {@link AreaRectAnalyzer}
|
||||||
* @see {@link ImageAnalyzer}
|
* @see {@link ImageAnalyzer}
|
||||||
@@ -133,47 +145,56 @@ public abstract class CameraScan implements ICamera, ICameraControl {
|
|||||||
public abstract CameraScan setAnalyzer(Analyzer analyzer);
|
public abstract CameraScan setAnalyzer(Analyzer analyzer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置是否震动
|
* 设置是否振动
|
||||||
*
|
*
|
||||||
* @param vibrate
|
* @param vibrate 是否振动
|
||||||
|
* @return {@link CameraScan}
|
||||||
*/
|
*/
|
||||||
public abstract CameraScan setVibrate(boolean vibrate);
|
public abstract CameraScan setVibrate(boolean vibrate);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置是否播放提示音
|
* 设置是否播放提示音
|
||||||
*
|
*
|
||||||
* @param playBeep
|
* @param playBeep 是否播放蜂鸣提示音
|
||||||
|
* @return {@link CameraScan}
|
||||||
*/
|
*/
|
||||||
public abstract CameraScan setPlayBeep(boolean playBeep);
|
public abstract CameraScan setPlayBeep(boolean playBeep);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置扫码结果回调
|
* 设置扫码结果回调
|
||||||
*
|
*
|
||||||
* @param callback
|
* @param callback 扫码结果回调
|
||||||
|
* @return {@link CameraScan}
|
||||||
*/
|
*/
|
||||||
public abstract CameraScan setOnScanResultCallback(OnScanResultCallback callback);
|
public abstract CameraScan setOnScanResultCallback(OnScanResultCallback callback);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 绑定手电筒,绑定后可根据光线传感器,动态显示或隐藏手电筒
|
* 绑定手电筒,绑定后可根据光线传感器,动态显示或隐藏手电筒
|
||||||
*
|
*
|
||||||
* @param v
|
* @param v 手电筒视图
|
||||||
|
* @return {@link CameraScan}
|
||||||
*/
|
*/
|
||||||
public abstract CameraScan bindFlashlightView(@Nullable View v);
|
public abstract CameraScan bindFlashlightView(@Nullable View v);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置光线足够暗的阈值(单位:lux),需要通过{@link #bindFlashlightView(View)}绑定手电筒才有效
|
* 设置光线足够暗的阈值(单位:lux),需要通过{@link #bindFlashlightView(View)}绑定手电筒才有效
|
||||||
*
|
*
|
||||||
* @param lightLux
|
* @param lightLux 光线亮度阈值
|
||||||
|
* @return {@link CameraScan}
|
||||||
*/
|
*/
|
||||||
public abstract CameraScan setDarkLightLux(float lightLux);
|
public abstract CameraScan setDarkLightLux(float lightLux);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置光线足够明亮的阈值(单位:lux),需要通过{@link #bindFlashlightView(View)}绑定手电筒才有效
|
* 设置光线足够明亮的阈值(单位:lux),需要通过{@link #bindFlashlightView(View)}绑定手电筒才有效
|
||||||
*
|
*
|
||||||
* @param lightLux
|
* @param lightLux 光线亮度阈值
|
||||||
|
* @return {@link CameraScan}
|
||||||
*/
|
*/
|
||||||
public abstract CameraScan setBrightLightLux(float lightLux);
|
public abstract CameraScan setBrightLightLux(float lightLux);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 扫描结果回调
|
||||||
|
*/
|
||||||
public interface OnScanResultCallback {
|
public interface OnScanResultCallback {
|
||||||
/**
|
/**
|
||||||
* 扫码结果回调
|
* 扫码结果回调
|
||||||
@@ -193,14 +214,13 @@ public abstract class CameraScan implements ICamera, ICameraControl {
|
|||||||
default void onScanResultFailure() {
|
default void onScanResultFailure() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析扫码结果
|
* 解析扫描结果
|
||||||
*
|
*
|
||||||
* @param data
|
* @param data 需解析的意图数据
|
||||||
* @return
|
* @return 返回解析结果
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public static String parseScanResult(Intent data) {
|
public static String parseScanResult(Intent data) {
|
||||||
|
|||||||
@@ -45,12 +45,25 @@ import androidx.camera.view.PreviewView;
|
|||||||
*/
|
*/
|
||||||
public class CaptureActivity extends AppCompatActivity implements CameraScan.OnScanResultCallback {
|
public class CaptureActivity extends AppCompatActivity implements CameraScan.OnScanResultCallback {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 相机权限请求代码
|
||||||
|
*/
|
||||||
private static final int CAMERA_PERMISSION_REQUEST_CODE = 0X86;
|
private static final int CAMERA_PERMISSION_REQUEST_CODE = 0X86;
|
||||||
|
/**
|
||||||
|
* 预览视图
|
||||||
|
*/
|
||||||
protected PreviewView previewView;
|
protected PreviewView previewView;
|
||||||
|
/**
|
||||||
|
* 取景视图
|
||||||
|
*/
|
||||||
protected ViewfinderView viewfinderView;
|
protected ViewfinderView viewfinderView;
|
||||||
|
/**
|
||||||
|
* 手电筒视图
|
||||||
|
*/
|
||||||
protected View ivFlashlight;
|
protected View ivFlashlight;
|
||||||
|
/**
|
||||||
|
* CameraScan
|
||||||
|
*/
|
||||||
private CameraScan mCameraScan;
|
private CameraScan mCameraScan;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -68,11 +81,11 @@ public class CaptureActivity extends AppCompatActivity implements CameraScan.OnS
|
|||||||
public void initUI() {
|
public void initUI() {
|
||||||
previewView = findViewById(getPreviewViewId());
|
previewView = findViewById(getPreviewViewId());
|
||||||
int viewfinderViewId = getViewfinderViewId();
|
int viewfinderViewId = getViewfinderViewId();
|
||||||
if (viewfinderViewId != 0) {
|
if (viewfinderViewId != 0 && viewfinderViewId != View.NO_ID) {
|
||||||
viewfinderView = findViewById(viewfinderViewId);
|
viewfinderView = findViewById(viewfinderViewId);
|
||||||
}
|
}
|
||||||
int ivFlashlightId = getFlashlightId();
|
int ivFlashlightId = getFlashlightId();
|
||||||
if (ivFlashlightId != 0) {
|
if (ivFlashlightId != 0 && ivFlashlightId != View.NO_ID) {
|
||||||
ivFlashlight = findViewById(ivFlashlightId);
|
ivFlashlight = findViewById(ivFlashlightId);
|
||||||
if (ivFlashlight != null) {
|
if (ivFlashlight != null) {
|
||||||
ivFlashlight.setOnClickListener(v -> onClickFlashlight());
|
ivFlashlight.setOnClickListener(v -> onClickFlashlight());
|
||||||
@@ -144,8 +157,8 @@ public class CaptureActivity extends AppCompatActivity implements CameraScan.OnS
|
|||||||
/**
|
/**
|
||||||
* 请求Camera权限回调结果
|
* 请求Camera权限回调结果
|
||||||
*
|
*
|
||||||
* @param permissions
|
* @param permissions 权限
|
||||||
* @param grantResults
|
* @param grantResults 授权结果
|
||||||
*/
|
*/
|
||||||
public void requestCameraPermissionResult(@NonNull String[] permissions, @NonNull int[] grantResults) {
|
public void requestCameraPermissionResult(@NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||||
if (PermissionUtils.requestPermissionsResult(Manifest.permission.CAMERA, permissions, grantResults)) {
|
if (PermissionUtils.requestPermissionsResult(Manifest.permission.CAMERA, permissions, grantResults)) {
|
||||||
@@ -173,7 +186,7 @@ public class CaptureActivity extends AppCompatActivity implements CameraScan.OnS
|
|||||||
/**
|
/**
|
||||||
* 布局ID;通过覆写此方法可以自定义布局
|
* 布局ID;通过覆写此方法可以自定义布局
|
||||||
*
|
*
|
||||||
* @return
|
* @return 布局ID
|
||||||
*/
|
*/
|
||||||
public int getLayoutId() {
|
public int getLayoutId() {
|
||||||
return R.layout.zxl_capture;
|
return R.layout.zxl_capture;
|
||||||
@@ -188,11 +201,10 @@ public class CaptureActivity extends AppCompatActivity implements CameraScan.OnS
|
|||||||
return R.id.viewfinderView;
|
return R.id.viewfinderView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 预览界面{@link #previewView} 的ID
|
* 预览界面{@link #previewView} 的ID;可通过覆写此方法自定义ID
|
||||||
*
|
*
|
||||||
* @return
|
* @return 默认返回{@code R.id.previewView}
|
||||||
*/
|
*/
|
||||||
public int getPreviewViewId() {
|
public int getPreviewViewId() {
|
||||||
return R.id.previewView;
|
return R.id.previewView;
|
||||||
@@ -208,7 +220,7 @@ public class CaptureActivity extends AppCompatActivity implements CameraScan.OnS
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get {@link CameraScan}
|
* 获取 {@link CameraScan}
|
||||||
*
|
*
|
||||||
* @return {@link #mCameraScan}
|
* @return {@link #mCameraScan}
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import com.king.zxing.util.LogUtils;
|
|||||||
import com.king.zxing.util.PermissionUtils;
|
import com.king.zxing.util.PermissionUtils;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.camera.view.PreviewView;
|
import androidx.camera.view.PreviewView;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
@@ -46,14 +47,29 @@ import androidx.fragment.app.Fragment;
|
|||||||
*/
|
*/
|
||||||
public class CaptureFragment extends Fragment implements CameraScan.OnScanResultCallback {
|
public class CaptureFragment extends Fragment implements CameraScan.OnScanResultCallback {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 相机权限请求代码
|
||||||
|
*/
|
||||||
private static final int CAMERA_PERMISSION_REQUEST_CODE = 0X86;
|
private static final int CAMERA_PERMISSION_REQUEST_CODE = 0X86;
|
||||||
|
/**
|
||||||
|
* 根视图
|
||||||
|
*/
|
||||||
private View mRootView;
|
private View mRootView;
|
||||||
|
/**
|
||||||
|
* 预览视图
|
||||||
|
*/
|
||||||
protected PreviewView previewView;
|
protected PreviewView previewView;
|
||||||
|
/**
|
||||||
|
* 取景视图
|
||||||
|
*/
|
||||||
protected ViewfinderView viewfinderView;
|
protected ViewfinderView viewfinderView;
|
||||||
|
/**
|
||||||
|
* 手电筒视图
|
||||||
|
*/
|
||||||
protected View ivFlashlight;
|
protected View ivFlashlight;
|
||||||
|
/**
|
||||||
|
* CameraScan
|
||||||
|
*/
|
||||||
private CameraScan mCameraScan;
|
private CameraScan mCameraScan;
|
||||||
|
|
||||||
public static CaptureFragment newInstance() {
|
public static CaptureFragment newInstance() {
|
||||||
@@ -70,21 +86,26 @@ public class CaptureFragment extends Fragment implements CameraScan.OnScanResult
|
|||||||
if (isContentView()) {
|
if (isContentView()) {
|
||||||
mRootView = createRootView(inflater, container);
|
mRootView = createRootView(inflater, container);
|
||||||
}
|
}
|
||||||
initUI();
|
|
||||||
return mRootView;
|
return mRootView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
initUI();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化
|
* 初始化
|
||||||
*/
|
*/
|
||||||
public void initUI() {
|
public void initUI() {
|
||||||
previewView = mRootView.findViewById(getPreviewViewId());
|
previewView = mRootView.findViewById(getPreviewViewId());
|
||||||
int viewfinderViewId = getViewfinderViewId();
|
int viewfinderViewId = getViewfinderViewId();
|
||||||
if (viewfinderViewId != 0) {
|
if (viewfinderViewId != 0 && viewfinderViewId != View.NO_ID) {
|
||||||
viewfinderView = mRootView.findViewById(viewfinderViewId);
|
viewfinderView = mRootView.findViewById(viewfinderViewId);
|
||||||
}
|
}
|
||||||
int ivFlashlightId = getFlashlightId();
|
int ivFlashlightId = getFlashlightId();
|
||||||
if (ivFlashlightId != 0) {
|
if (ivFlashlightId != 0 && ivFlashlightId != View.NO_ID) {
|
||||||
ivFlashlight = mRootView.findViewById(ivFlashlightId);
|
ivFlashlight = mRootView.findViewById(ivFlashlightId);
|
||||||
if (ivFlashlight != null) {
|
if (ivFlashlight != null) {
|
||||||
ivFlashlight.setOnClickListener(v -> onClickFlashlight());
|
ivFlashlight.setOnClickListener(v -> onClickFlashlight());
|
||||||
@@ -156,8 +177,8 @@ public class CaptureFragment extends Fragment implements CameraScan.OnScanResult
|
|||||||
/**
|
/**
|
||||||
* 请求Camera权限回调结果
|
* 请求Camera权限回调结果
|
||||||
*
|
*
|
||||||
* @param permissions
|
* @param permissions 权限
|
||||||
* @param grantResults
|
* @param grantResults 授权结果
|
||||||
*/
|
*/
|
||||||
public void requestCameraPermissionResult(@NonNull String[] permissions, @NonNull int[] grantResults) {
|
public void requestCameraPermissionResult(@NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||||
if (PermissionUtils.requestPermissionsResult(Manifest.permission.CAMERA, permissions, grantResults)) {
|
if (PermissionUtils.requestPermissionsResult(Manifest.permission.CAMERA, permissions, grantResults)) {
|
||||||
@@ -168,9 +189,9 @@ public class CaptureFragment extends Fragment implements CameraScan.OnScanResult
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroyView() {
|
||||||
releaseCamera();
|
releaseCamera();
|
||||||
super.onDestroy();
|
super.onDestroyView();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -197,7 +218,7 @@ public class CaptureFragment extends Fragment implements CameraScan.OnScanResult
|
|||||||
/**
|
/**
|
||||||
* 布局ID;通过覆写此方法可以自定义布局
|
* 布局ID;通过覆写此方法可以自定义布局
|
||||||
*
|
*
|
||||||
* @return
|
* @return 布局ID
|
||||||
*/
|
*/
|
||||||
public int getLayoutId() {
|
public int getLayoutId() {
|
||||||
return R.layout.zxl_capture;
|
return R.layout.zxl_capture;
|
||||||
@@ -213,9 +234,9 @@ public class CaptureFragment extends Fragment implements CameraScan.OnScanResult
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 预览界面{@link #previewView} 的ID
|
* 预览界面{@link #previewView} 的ID;可通过覆写此方法自定义ID
|
||||||
*
|
*
|
||||||
* @return
|
* @return 默认返回{@code R.id.previewView}
|
||||||
*/
|
*/
|
||||||
public int getPreviewViewId() {
|
public int getPreviewViewId() {
|
||||||
return R.id.previewView;
|
return R.id.previewView;
|
||||||
@@ -231,7 +252,7 @@ public class CaptureFragment extends Fragment implements CameraScan.OnScanResult
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get {@link CameraScan}
|
* 获取 {@link CameraScan}
|
||||||
*
|
*
|
||||||
* @return {@link #mCameraScan}
|
* @return {@link #mCameraScan}
|
||||||
*/
|
*/
|
||||||
@@ -252,6 +273,11 @@ public class CaptureFragment extends Fragment implements CameraScan.OnScanResult
|
|||||||
|
|
||||||
//--------------------------------------------
|
//--------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取根视图
|
||||||
|
*
|
||||||
|
* @return {@link #mRootView}
|
||||||
|
*/
|
||||||
public View getRootView() {
|
public View getRootView() {
|
||||||
return mRootView;
|
return mRootView;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,6 +95,12 @@ public class DecodeConfig {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取配置的解码支持类型 {@link DecodeHintType}
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* @see {@link DecodeFormatManager}
|
||||||
|
*/
|
||||||
public Map<DecodeHintType, Object> getHints() {
|
public Map<DecodeHintType, Object> getHints() {
|
||||||
return hints;
|
return hints;
|
||||||
}
|
}
|
||||||
@@ -105,7 +111,7 @@ public class DecodeConfig {
|
|||||||
* @param hints {@link DecodeFormatManager}
|
* @param hints {@link DecodeFormatManager}
|
||||||
* <p>
|
* <p>
|
||||||
* 内置的一些解码可参见如下:
|
* 内置的一些解码可参见如下:
|
||||||
* @return
|
* @return {@link DecodeConfig}
|
||||||
* @see {@link DecodeFormatManager#DEFAULT_HINTS}
|
* @see {@link DecodeFormatManager#DEFAULT_HINTS}
|
||||||
* @see {@link DecodeFormatManager#ALL_HINTS}
|
* @see {@link DecodeFormatManager#ALL_HINTS}
|
||||||
* @see {@link DecodeFormatManager#CODE_128_HINTS}
|
* @see {@link DecodeFormatManager#CODE_128_HINTS}
|
||||||
@@ -124,7 +130,7 @@ public class DecodeConfig {
|
|||||||
/**
|
/**
|
||||||
* 是否支持识别反色码,黑白颜色反转
|
* 是否支持识别反色码,黑白颜色反转
|
||||||
*
|
*
|
||||||
* @return
|
* @return 是否支持识别反色码
|
||||||
*/
|
*/
|
||||||
public boolean isSupportLuminanceInvert() {
|
public boolean isSupportLuminanceInvert() {
|
||||||
return isSupportLuminanceInvert;
|
return isSupportLuminanceInvert;
|
||||||
@@ -134,7 +140,7 @@ public class DecodeConfig {
|
|||||||
* 设置是否支持识别反色码,黑白颜色反转
|
* 设置是否支持识别反色码,黑白颜色反转
|
||||||
*
|
*
|
||||||
* @param supportLuminanceInvert 默认为{@code false},想要增强支持扫码识别反色码时可使用,相应的也会增加性能消耗。
|
* @param supportLuminanceInvert 默认为{@code false},想要增强支持扫码识别反色码时可使用,相应的也会增加性能消耗。
|
||||||
* @return
|
* @return {@link DecodeConfig}
|
||||||
*/
|
*/
|
||||||
public DecodeConfig setSupportLuminanceInvert(boolean supportLuminanceInvert) {
|
public DecodeConfig setSupportLuminanceInvert(boolean supportLuminanceInvert) {
|
||||||
isSupportLuminanceInvert = supportLuminanceInvert;
|
isSupportLuminanceInvert = supportLuminanceInvert;
|
||||||
@@ -144,7 +150,7 @@ public class DecodeConfig {
|
|||||||
/**
|
/**
|
||||||
* 是否支持扫垂直的条码
|
* 是否支持扫垂直的条码
|
||||||
*
|
*
|
||||||
* @return
|
* @return 是否支持扫垂直的条码
|
||||||
*/
|
*/
|
||||||
public boolean isSupportVerticalCode() {
|
public boolean isSupportVerticalCode() {
|
||||||
return isSupportVerticalCode;
|
return isSupportVerticalCode;
|
||||||
@@ -154,7 +160,7 @@ public class DecodeConfig {
|
|||||||
* 设置是否支持扫垂直的条码
|
* 设置是否支持扫垂直的条码
|
||||||
*
|
*
|
||||||
* @param supportVerticalCode 默认为{@code false},想要增强支持扫码识别垂直的条码时可使用,相应的也会增加性能消耗。
|
* @param supportVerticalCode 默认为{@code false},想要增强支持扫码识别垂直的条码时可使用,相应的也会增加性能消耗。
|
||||||
* @return
|
* @return {@link DecodeConfig}
|
||||||
*/
|
*/
|
||||||
public DecodeConfig setSupportVerticalCode(boolean supportVerticalCode) {
|
public DecodeConfig setSupportVerticalCode(boolean supportVerticalCode) {
|
||||||
isSupportVerticalCode = supportVerticalCode;
|
isSupportVerticalCode = supportVerticalCode;
|
||||||
@@ -164,7 +170,7 @@ public class DecodeConfig {
|
|||||||
/**
|
/**
|
||||||
* 是否支持使用多解码
|
* 是否支持使用多解码
|
||||||
*
|
*
|
||||||
* @return
|
* @return 是否支持使用多解码
|
||||||
*/
|
*/
|
||||||
public boolean isMultiDecode() {
|
public boolean isMultiDecode() {
|
||||||
return isMultiDecode;
|
return isMultiDecode;
|
||||||
@@ -185,7 +191,7 @@ public class DecodeConfig {
|
|||||||
/**
|
/**
|
||||||
* 是否支持识别反色码(条码黑白颜色反转的码)使用多解码
|
* 是否支持识别反色码(条码黑白颜色反转的码)使用多解码
|
||||||
*
|
*
|
||||||
* @return
|
* @return 是否支持识别反色码
|
||||||
*/
|
*/
|
||||||
public boolean isSupportLuminanceInvertMultiDecode() {
|
public boolean isSupportLuminanceInvertMultiDecode() {
|
||||||
return isSupportLuminanceInvertMultiDecode;
|
return isSupportLuminanceInvertMultiDecode;
|
||||||
@@ -195,7 +201,7 @@ public class DecodeConfig {
|
|||||||
* 设置是否支持识别反色码(条码黑白颜色反转的码)使用多解码
|
* 设置是否支持识别反色码(条码黑白颜色反转的码)使用多解码
|
||||||
*
|
*
|
||||||
* @param supportLuminanceInvertMultiDecode 默认为{@code false},想要增强支持扫码识别反色码时可使用,相应的也会增加性能消耗。
|
* @param supportLuminanceInvertMultiDecode 默认为{@code false},想要增强支持扫码识别反色码时可使用,相应的也会增加性能消耗。
|
||||||
* @return
|
* @return {@link DecodeConfig}
|
||||||
* @see {@link HybridBinarizer} , {@link GlobalHistogramBinarizer}
|
* @see {@link HybridBinarizer} , {@link GlobalHistogramBinarizer}
|
||||||
*/
|
*/
|
||||||
public DecodeConfig setSupportLuminanceInvertMultiDecode(boolean supportLuminanceInvertMultiDecode) {
|
public DecodeConfig setSupportLuminanceInvertMultiDecode(boolean supportLuminanceInvertMultiDecode) {
|
||||||
@@ -206,7 +212,7 @@ public class DecodeConfig {
|
|||||||
/**
|
/**
|
||||||
* 是否支持垂直的条码,使用多解码
|
* 是否支持垂直的条码,使用多解码
|
||||||
*
|
*
|
||||||
* @return
|
* @return 是否支持垂直的条码,使用多解码
|
||||||
*/
|
*/
|
||||||
public boolean isSupportVerticalCodeMultiDecode() {
|
public boolean isSupportVerticalCodeMultiDecode() {
|
||||||
return isSupportVerticalCodeMultiDecode;
|
return isSupportVerticalCodeMultiDecode;
|
||||||
@@ -216,7 +222,7 @@ public class DecodeConfig {
|
|||||||
* 设置是否支持垂直的条码,使用多解码;解码时,对应的二值化的实现: {@link HybridBinarizer} , {@link GlobalHistogramBinarizer}
|
* 设置是否支持垂直的条码,使用多解码;解码时,对应的二值化的实现: {@link HybridBinarizer} , {@link GlobalHistogramBinarizer}
|
||||||
*
|
*
|
||||||
* @param supportVerticalCodeMultiDecode 默认为{@code false},想要增强支持扫码识别垂直的条码时可使用,相应的也会增加性能消耗。
|
* @param supportVerticalCodeMultiDecode 默认为{@code false},想要增强支持扫码识别垂直的条码时可使用,相应的也会增加性能消耗。
|
||||||
* @return
|
* @return {@link DecodeConfig}
|
||||||
*/
|
*/
|
||||||
public DecodeConfig setSupportVerticalCodeMultiDecode(boolean supportVerticalCodeMultiDecode) {
|
public DecodeConfig setSupportVerticalCodeMultiDecode(boolean supportVerticalCodeMultiDecode) {
|
||||||
isSupportVerticalCodeMultiDecode = supportVerticalCodeMultiDecode;
|
isSupportVerticalCodeMultiDecode = supportVerticalCodeMultiDecode;
|
||||||
@@ -226,7 +232,7 @@ public class DecodeConfig {
|
|||||||
/**
|
/**
|
||||||
* 需要分析识别区域
|
* 需要分析识别区域
|
||||||
*
|
*
|
||||||
* @return
|
* @return 分析识别区域
|
||||||
*/
|
*/
|
||||||
public Rect getAnalyzeAreaRect() {
|
public Rect getAnalyzeAreaRect() {
|
||||||
return analyzeAreaRect;
|
return analyzeAreaRect;
|
||||||
@@ -244,7 +250,7 @@ public class DecodeConfig {
|
|||||||
* 您还可以通过{@link CameraScan#setCameraConfig(CameraConfig)}去自定义配置{@link CameraConfig}的配置信息控制预览相关配置信息
|
* 您还可以通过{@link CameraScan#setCameraConfig(CameraConfig)}去自定义配置{@link CameraConfig}的配置信息控制预览相关配置信息
|
||||||
* <p>
|
* <p>
|
||||||
* 即判定区域分析的优先级顺序为:{@link #setFullAreaScan(boolean)} -> {@link #setAnalyzeAreaRect(Rect)} -> {@link #setAreaRectRatio(float)}
|
* 即判定区域分析的优先级顺序为:{@link #setFullAreaScan(boolean)} -> {@link #setAnalyzeAreaRect(Rect)} -> {@link #setAreaRectRatio(float)}
|
||||||
* @return
|
* @return {@link DecodeConfig}
|
||||||
*/
|
*/
|
||||||
public DecodeConfig setAnalyzeAreaRect(Rect analyzeAreaRect) {
|
public DecodeConfig setAnalyzeAreaRect(Rect analyzeAreaRect) {
|
||||||
this.analyzeAreaRect = analyzeAreaRect;
|
this.analyzeAreaRect = analyzeAreaRect;
|
||||||
@@ -254,7 +260,7 @@ public class DecodeConfig {
|
|||||||
/**
|
/**
|
||||||
* 是否支持全区域扫码识别
|
* 是否支持全区域扫码识别
|
||||||
*
|
*
|
||||||
* @return
|
* @return 是否支持全区域扫码识别
|
||||||
*/
|
*/
|
||||||
public boolean isFullAreaScan() {
|
public boolean isFullAreaScan() {
|
||||||
return isFullAreaScan;
|
return isFullAreaScan;
|
||||||
@@ -274,7 +280,7 @@ public class DecodeConfig {
|
|||||||
* 您还可以通过{@link CameraScan#setCameraConfig(CameraConfig)}去自定义配置{@link CameraConfig}的配置信息控制预览相关配置信息
|
* 您还可以通过{@link CameraScan#setCameraConfig(CameraConfig)}去自定义配置{@link CameraConfig}的配置信息控制预览相关配置信息
|
||||||
* <p>
|
* <p>
|
||||||
* 即判定区域分析的优先级顺序为:{@link #setFullAreaScan(boolean)} -> {@link #setAnalyzeAreaRect(Rect)} -> {@link #setAreaRectRatio(float)}
|
* 即判定区域分析的优先级顺序为:{@link #setFullAreaScan(boolean)} -> {@link #setAnalyzeAreaRect(Rect)} -> {@link #setAreaRectRatio(float)}
|
||||||
* @return
|
* @return {@link DecodeConfig}
|
||||||
*/
|
*/
|
||||||
public DecodeConfig setFullAreaScan(boolean fullAreaScan) {
|
public DecodeConfig setFullAreaScan(boolean fullAreaScan) {
|
||||||
isFullAreaScan = fullAreaScan;
|
isFullAreaScan = fullAreaScan;
|
||||||
@@ -284,7 +290,7 @@ public class DecodeConfig {
|
|||||||
/**
|
/**
|
||||||
* 识别区域比例,默认{@link #DEFAULT_AREA_RECT_RATIO},设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别
|
* 识别区域比例,默认{@link #DEFAULT_AREA_RECT_RATIO},设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别
|
||||||
*
|
*
|
||||||
* @return
|
* @return 识别区域比例,默认{@link #DEFAULT_AREA_RECT_RATIO}
|
||||||
*/
|
*/
|
||||||
public float getAreaRectRatio() {
|
public float getAreaRectRatio() {
|
||||||
return areaRectRatio;
|
return areaRectRatio;
|
||||||
@@ -302,7 +308,7 @@ public class DecodeConfig {
|
|||||||
* 您还可以通过{@link CameraScan#setCameraConfig(CameraConfig)}去自定义配置{@link CameraConfig}的配置信息控制预览相关配置信息
|
* 您还可以通过{@link CameraScan#setCameraConfig(CameraConfig)}去自定义配置{@link CameraConfig}的配置信息控制预览相关配置信息
|
||||||
* <p>
|
* <p>
|
||||||
* 即判定区域分析的优先级顺序为:{@link #setFullAreaScan(boolean)} -> {@link #setAnalyzeAreaRect(Rect)} -> {@link #setAreaRectRatio(float)}
|
* 即判定区域分析的优先级顺序为:{@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) {
|
public DecodeConfig setAreaRectRatio(@FloatRange(from = 0.5, to = 1.0) float areaRectRatio) {
|
||||||
this.areaRectRatio = areaRectRatio;
|
this.areaRectRatio = areaRectRatio;
|
||||||
@@ -312,7 +318,7 @@ public class DecodeConfig {
|
|||||||
/**
|
/**
|
||||||
* 识别区域垂直方向偏移量,支持负数,大于0时,居中心向下偏移,小于0时,居中心向上偏移
|
* 识别区域垂直方向偏移量,支持负数,大于0时,居中心向下偏移,小于0时,居中心向上偏移
|
||||||
*
|
*
|
||||||
* @return
|
* @return 识别区域垂直方向偏移量
|
||||||
*/
|
*/
|
||||||
public int getAreaRectVerticalOffset() {
|
public int getAreaRectVerticalOffset() {
|
||||||
return areaRectVerticalOffset;
|
return areaRectVerticalOffset;
|
||||||
@@ -322,7 +328,7 @@ public class DecodeConfig {
|
|||||||
* 设置识别区域垂直方向偏移量,支持负数,大于0时,居中心向下偏移,小于0时,居中心向上偏移
|
* 设置识别区域垂直方向偏移量,支持负数,大于0时,居中心向下偏移,小于0时,居中心向上偏移
|
||||||
*
|
*
|
||||||
* @param areaRectVerticalOffset
|
* @param areaRectVerticalOffset
|
||||||
* @return
|
* @return {@link DecodeConfig}
|
||||||
*/
|
*/
|
||||||
public DecodeConfig setAreaRectVerticalOffset(int areaRectVerticalOffset) {
|
public DecodeConfig setAreaRectVerticalOffset(int areaRectVerticalOffset) {
|
||||||
this.areaRectVerticalOffset = areaRectVerticalOffset;
|
this.areaRectVerticalOffset = areaRectVerticalOffset;
|
||||||
@@ -332,7 +338,7 @@ public class DecodeConfig {
|
|||||||
/**
|
/**
|
||||||
* 识别区域水平方向偏移量,支持负数,大于0时,居中心向右偏移,小于0时,居中心向左偏移
|
* 识别区域水平方向偏移量,支持负数,大于0时,居中心向右偏移,小于0时,居中心向左偏移
|
||||||
*
|
*
|
||||||
* @return
|
* @return 识别区域水平方向偏移量
|
||||||
*/
|
*/
|
||||||
public int getAreaRectHorizontalOffset() {
|
public int getAreaRectHorizontalOffset() {
|
||||||
return areaRectHorizontalOffset;
|
return areaRectHorizontalOffset;
|
||||||
@@ -342,7 +348,7 @@ public class DecodeConfig {
|
|||||||
* 设置识别区域水平方向偏移量,支持负数,大于0时,居中心向右偏移,小于0时,居中心向左偏移
|
* 设置识别区域水平方向偏移量,支持负数,大于0时,居中心向右偏移,小于0时,居中心向左偏移
|
||||||
*
|
*
|
||||||
* @param areaRectHorizontalOffset
|
* @param areaRectHorizontalOffset
|
||||||
* @return
|
* @return {@link DecodeConfig}
|
||||||
*/
|
*/
|
||||||
public DecodeConfig setAreaRectHorizontalOffset(int areaRectHorizontalOffset) {
|
public DecodeConfig setAreaRectHorizontalOffset(int areaRectHorizontalOffset) {
|
||||||
this.areaRectHorizontalOffset = areaRectHorizontalOffset;
|
this.areaRectHorizontalOffset = areaRectHorizontalOffset;
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ public final class DecodeFormatManager {
|
|||||||
* 二维码
|
* 二维码
|
||||||
*/
|
*/
|
||||||
public static final Map<DecodeHintType, Object> TWO_DIMENSIONAL_HINTS = new EnumMap<>(DecodeHintType.class);
|
public static final Map<DecodeHintType, Object> TWO_DIMENSIONAL_HINTS = new EnumMap<>(DecodeHintType.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 默认
|
* 默认
|
||||||
*/
|
*/
|
||||||
@@ -86,7 +85,7 @@ public final class DecodeFormatManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 二维码
|
* 一维码
|
||||||
* 包括如下几种格式:
|
* 包括如下几种格式:
|
||||||
* {@link BarcodeFormat#CODABAR}
|
* {@link BarcodeFormat#CODABAR}
|
||||||
* {@link BarcodeFormat#CODE_39}
|
* {@link BarcodeFormat#CODE_39}
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ import com.google.zxing.ResultPoint;
|
|||||||
import com.google.zxing.common.detector.MathUtils;
|
import com.google.zxing.common.detector.MathUtils;
|
||||||
import com.king.zxing.analyze.Analyzer;
|
import com.king.zxing.analyze.Analyzer;
|
||||||
import com.king.zxing.analyze.MultiFormatAnalyzer;
|
import com.king.zxing.analyze.MultiFormatAnalyzer;
|
||||||
|
import com.king.zxing.config.AspectRatioCameraConfig;
|
||||||
import com.king.zxing.config.CameraConfig;
|
import com.king.zxing.config.CameraConfig;
|
||||||
|
import com.king.zxing.config.ResolutionCameraConfig;
|
||||||
import com.king.zxing.manager.AmbientLightManager;
|
import com.king.zxing.manager.AmbientLightManager;
|
||||||
import com.king.zxing.manager.BeepManager;
|
import com.king.zxing.manager.BeepManager;
|
||||||
import com.king.zxing.util.LogUtils;
|
import com.king.zxing.util.LogUtils;
|
||||||
@@ -67,14 +69,12 @@ public class DefaultCameraScan extends CameraScan {
|
|||||||
* opposed to a hover movement gesture.
|
* opposed to a hover movement gesture.
|
||||||
*/
|
*/
|
||||||
private static final int HOVER_TAP_TIMEOUT = 150;
|
private static final int HOVER_TAP_TIMEOUT = 150;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the maximum distance in pixels that a touch pad touch can move
|
* 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
|
* before being released for it to be considered a tap (click) as opposed
|
||||||
* to a hover movement gesture.
|
* to a hover movement gesture.
|
||||||
*/
|
*/
|
||||||
private static final int HOVER_TAP_SLOP = 20;
|
private static final int HOVER_TAP_SLOP = 20;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 每次缩放改变的步长
|
* 每次缩放改变的步长
|
||||||
*/
|
*/
|
||||||
@@ -83,40 +83,73 @@ public class DefaultCameraScan extends CameraScan {
|
|||||||
private FragmentActivity mFragmentActivity;
|
private FragmentActivity mFragmentActivity;
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
private LifecycleOwner mLifecycleOwner;
|
private LifecycleOwner mLifecycleOwner;
|
||||||
|
/**
|
||||||
|
* 预览视图
|
||||||
|
*/
|
||||||
private PreviewView mPreviewView;
|
private PreviewView mPreviewView;
|
||||||
|
|
||||||
private ListenableFuture<ProcessCameraProvider> mCameraProviderFuture;
|
private ListenableFuture<ProcessCameraProvider> mCameraProviderFuture;
|
||||||
|
/**
|
||||||
|
* 相机
|
||||||
|
*/
|
||||||
private Camera mCamera;
|
private Camera mCamera;
|
||||||
|
/**
|
||||||
|
* 相机配置
|
||||||
|
*/
|
||||||
private CameraConfig mCameraConfig;
|
private CameraConfig mCameraConfig;
|
||||||
|
/**
|
||||||
|
* 分析器
|
||||||
|
*/
|
||||||
private Analyzer mAnalyzer;
|
private Analyzer mAnalyzer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否分析
|
* 是否分析
|
||||||
*/
|
*/
|
||||||
private volatile boolean isAnalyze = true;
|
private volatile boolean isAnalyze = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否已经分析出结果
|
* 是否已经分析出结果
|
||||||
*/
|
*/
|
||||||
private volatile boolean isAnalyzeResult;
|
private volatile boolean isAnalyzeResult;
|
||||||
|
/**
|
||||||
|
* 闪光灯(手电筒)视图
|
||||||
|
*/
|
||||||
private View flashlightView;
|
private View flashlightView;
|
||||||
|
|
||||||
private MutableLiveData<Result> mResultLiveData;
|
private MutableLiveData<Result> mResultLiveData;
|
||||||
|
/**
|
||||||
|
* 扫描结果回调
|
||||||
|
*/
|
||||||
private OnScanResultCallback mOnScanResultCallback;
|
private OnScanResultCallback mOnScanResultCallback;
|
||||||
|
/**
|
||||||
|
* 蜂鸣音效管理器:主要用于播放蜂鸣提示音和振动效果
|
||||||
|
*/
|
||||||
private BeepManager mBeepManager;
|
private BeepManager mBeepManager;
|
||||||
|
/**
|
||||||
|
* 环境光线管理器:主要通过传感器来监听光线的亮度变化
|
||||||
|
*/
|
||||||
private AmbientLightManager mAmbientLightManager;
|
private AmbientLightManager mAmbientLightManager;
|
||||||
|
|
||||||
private int mOrientation;
|
private int mOrientation;
|
||||||
private int mImageWidth;
|
private int mImageWidth;
|
||||||
private int mImageHeight;
|
private int mImageHeight;
|
||||||
|
/**
|
||||||
|
* 最后自动缩放时间
|
||||||
|
*/
|
||||||
private long mLastAutoZoomTime;
|
private long mLastAutoZoomTime;
|
||||||
|
/**
|
||||||
|
* 最后点击时间,根据两次点击时间间隔用于区分单机和触摸缩放事件
|
||||||
|
*/
|
||||||
private long mLastHoveTapTime;
|
private long mLastHoveTapTime;
|
||||||
|
/**
|
||||||
|
* 是否是点击事件
|
||||||
|
*/
|
||||||
private boolean isClickTap;
|
private boolean isClickTap;
|
||||||
|
/**
|
||||||
|
* 按下时X坐标
|
||||||
|
*/
|
||||||
private float mDownX;
|
private float mDownX;
|
||||||
|
/**
|
||||||
|
* 按下时Y坐标
|
||||||
|
*/
|
||||||
private float mDownY;
|
private float mDownY;
|
||||||
|
|
||||||
public DefaultCameraScan(@NonNull FragmentActivity activity, @NonNull PreviewView previewView) {
|
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) {
|
private void handlePreviewViewClickTap(MotionEvent event) {
|
||||||
if (event.getPointerCount() == 1) {
|
if (event.getPointerCount() == 1) {
|
||||||
@@ -226,8 +259,8 @@ public class DefaultCameraScan extends CameraScan {
|
|||||||
/**
|
/**
|
||||||
* 开始对焦和测光
|
* 开始对焦和测光
|
||||||
*
|
*
|
||||||
* @param x
|
* @param x X轴坐标
|
||||||
* @param y
|
* @param y Y轴坐标
|
||||||
*/
|
*/
|
||||||
private void startFocusAndMetering(float x, float y) {
|
private void startFocusAndMetering(float x, float y) {
|
||||||
if (mCamera != null) {
|
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
|
@Override
|
||||||
public CameraScan setCameraConfig(CameraConfig cameraConfig) {
|
public CameraScan setCameraConfig(CameraConfig cameraConfig) {
|
||||||
if (cameraConfig != null) {
|
if (cameraConfig != null) {
|
||||||
@@ -261,12 +281,35 @@ public class DefaultCameraScan extends CameraScan {
|
|||||||
return this;
|
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
|
@Override
|
||||||
public void startCamera() {
|
public void startCamera() {
|
||||||
initConfig();
|
initCameraConfig(mContext);
|
||||||
|
if (mAnalyzer == null) {
|
||||||
|
mAnalyzer = new MultiFormatAnalyzer();
|
||||||
|
}
|
||||||
mCameraProviderFuture = ProcessCameraProvider.getInstance(mContext);
|
mCameraProviderFuture = ProcessCameraProvider.getInstance(mContext);
|
||||||
mCameraProviderFuture.addListener(() -> {
|
mCameraProviderFuture.addListener(() -> {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Preview preview = mCameraConfig.options(new Preview.Builder());
|
Preview preview = mCameraConfig.options(new Preview.Builder());
|
||||||
|
|
||||||
@@ -336,6 +379,7 @@ public class DefaultCameraScan extends CameraScan {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理自动缩放
|
* 处理自动缩放
|
||||||
|
*
|
||||||
* @param distance
|
* @param distance
|
||||||
* @param result
|
* @param result
|
||||||
* @return
|
* @return
|
||||||
@@ -353,7 +397,8 @@ public class DefaultCameraScan extends CameraScan {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 扫描结果回调
|
* 扫描结果回调
|
||||||
* @param result
|
*
|
||||||
|
* @param result 扫描结果
|
||||||
*/
|
*/
|
||||||
private void scanResultCallback(Result result) {
|
private void scanResultCallback(Result result) {
|
||||||
if (mOnScanResultCallback != null && mOnScanResultCallback.onScanResultCallback(result)) {
|
if (mOnScanResultCallback != null && mOnScanResultCallback.onScanResultCallback(result)) {
|
||||||
@@ -473,11 +518,6 @@ public class DefaultCameraScan extends CameraScan {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否支持闪光灯
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasFlashUnit() {
|
public boolean hasFlashUnit() {
|
||||||
if (mCamera != null) {
|
if (mCamera != null) {
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ public interface ICamera {
|
|||||||
void stopCamera();
|
void stopCamera();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取{@link Camera}
|
* 获取 {@link Camera}
|
||||||
*
|
*
|
||||||
* @return
|
* @return {@link Camera}
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
Camera getCamera();
|
Camera getCamera();
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ public interface ICameraControl {
|
|||||||
/**
|
/**
|
||||||
* 缩放到指定比例
|
* 缩放到指定比例
|
||||||
*
|
*
|
||||||
* @param ratio
|
* @param ratio 缩放比例
|
||||||
*/
|
*/
|
||||||
void zoomTo(float 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);
|
void lineZoomTo(@FloatRange(from = 0.0, to = 1.0) float linearZoom);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置闪光灯(手电筒)是否开启
|
* 设置闪光灯(手电筒)是否开启
|
||||||
*
|
*
|
||||||
* @param torch
|
* @param torch 是否开启闪光灯(手电筒)
|
||||||
*/
|
*/
|
||||||
void enableTorch(boolean torch);
|
void enableTorch(boolean torch);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 闪光灯(手电筒)是否开启
|
* 闪光灯(手电筒)是否开启
|
||||||
*
|
*
|
||||||
* @return
|
* @return 闪光灯(手电筒)是否开启
|
||||||
*/
|
*/
|
||||||
boolean isTorchEnabled();
|
boolean isTorchEnabled();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否支持闪光灯
|
* 是否支持闪光灯
|
||||||
*
|
*
|
||||||
* @return
|
* @return 是否支持闪光灯
|
||||||
*/
|
*/
|
||||||
boolean hasFlashUnit();
|
boolean hasFlashUnit();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import android.graphics.BitmapFactory;
|
|||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.LinearGradient;
|
import android.graphics.LinearGradient;
|
||||||
|
import android.graphics.Matrix;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.PixelFormat;
|
import android.graphics.PixelFormat;
|
||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
@@ -26,8 +27,6 @@ import android.view.GestureDetector;
|
|||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import com.king.zxing.util.LogUtils;
|
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -216,6 +215,10 @@ public class ViewfinderView extends View {
|
|||||||
|
|
||||||
private Bitmap laserBitmap;
|
private Bitmap laserBitmap;
|
||||||
|
|
||||||
|
private float laserBitmapRatio;
|
||||||
|
|
||||||
|
private float laserBitmapWidth;
|
||||||
|
|
||||||
private int viewfinderStyle = ViewfinderStyle.CLASSIC;
|
private int viewfinderStyle = ViewfinderStyle.CLASSIC;
|
||||||
|
|
||||||
private List<Point> pointList;
|
private List<Point> pointList;
|
||||||
@@ -248,7 +251,7 @@ public class ViewfinderView extends View {
|
|||||||
*/
|
*/
|
||||||
public enum LaserStyle {
|
public enum LaserStyle {
|
||||||
NONE(0), LINE(1), GRID(2), IMAGE(3);
|
NONE(0), LINE(1), GRID(2), IMAGE(3);
|
||||||
private int mValue;
|
private final int mValue;
|
||||||
|
|
||||||
LaserStyle(int value) {
|
LaserStyle(int value) {
|
||||||
mValue = value;
|
mValue = value;
|
||||||
@@ -270,7 +273,7 @@ public class ViewfinderView extends View {
|
|||||||
public enum TextLocation {
|
public enum TextLocation {
|
||||||
TOP(0), BOTTOM(1);
|
TOP(0), BOTTOM(1);
|
||||||
|
|
||||||
private int mValue;
|
private final int mValue;
|
||||||
|
|
||||||
TextLocation(int value) {
|
TextLocation(int value) {
|
||||||
mValue = value;
|
mValue = value;
|
||||||
@@ -292,7 +295,7 @@ public class ViewfinderView extends View {
|
|||||||
public enum FrameGravity {
|
public enum FrameGravity {
|
||||||
CENTER(0), LEFT(1), TOP(2), RIGHT(3), BOTTOM(4);
|
CENTER(0), LEFT(1), TOP(2), RIGHT(3), BOTTOM(4);
|
||||||
|
|
||||||
private int mValue;
|
private final int mValue;
|
||||||
|
|
||||||
FrameGravity(int value) {
|
FrameGravity(int value) {
|
||||||
mValue = value;
|
mValue = value;
|
||||||
@@ -369,6 +372,7 @@ public class ViewfinderView extends View {
|
|||||||
isShowPointAnim = array.getBoolean(R.styleable.ViewfinderView_showPointAnim, true);
|
isShowPointAnim = array.getBoolean(R.styleable.ViewfinderView_showPointAnim, true);
|
||||||
Drawable pointDrawable = array.getDrawable(R.styleable.ViewfinderView_pointDrawable);
|
Drawable pointDrawable = array.getDrawable(R.styleable.ViewfinderView_pointDrawable);
|
||||||
Drawable laserDrawable = array.getDrawable(R.styleable.ViewfinderView_laserDrawable);
|
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);
|
viewfinderStyle = array.getInt(R.styleable.ViewfinderView_viewfinderStyle, ViewfinderStyle.CLASSIC);
|
||||||
|
|
||||||
array.recycle();
|
array.recycle();
|
||||||
@@ -433,6 +437,24 @@ public class ViewfinderView extends View {
|
|||||||
this.laserStyle = laserStyle;
|
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) {
|
public void setPointImageResource(@DrawableRes int drawable) {
|
||||||
setPointBitmap(BitmapFactory.decodeResource(getResources(), drawable));
|
setPointBitmap(BitmapFactory.decodeResource(getResources(), drawable));
|
||||||
}
|
}
|
||||||
@@ -448,10 +470,26 @@ public class ViewfinderView extends View {
|
|||||||
initFrame(getWidth(),getHeight());
|
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) {
|
private void initFrame(int width, int height) {
|
||||||
|
|
||||||
int size = (int) (Math.min(width, height) * frameRatio);
|
int size = (int) (Math.min(width, height) * frameRatio);
|
||||||
|
|
||||||
|
if (laserBitmapWidth <= 0) {
|
||||||
|
laserBitmapWidth = Math.min(width, height) * laserBitmapRatio;
|
||||||
|
scaleLaserBitmap();
|
||||||
|
}
|
||||||
|
|
||||||
if (frameWidth <= 0 || frameWidth > width) {
|
if (frameWidth <= 0 || frameWidth > width) {
|
||||||
frameWidth = size;
|
frameWidth = size;
|
||||||
}
|
}
|
||||||
@@ -582,7 +620,7 @@ public class ViewfinderView extends View {
|
|||||||
private void drawImageScanner(Canvas canvas, Rect frame) {
|
private void drawImageScanner(Canvas canvas, Rect frame) {
|
||||||
if (laserBitmap != null) {
|
if (laserBitmap != null) {
|
||||||
paint.setColor(Color.WHITE);
|
paint.setColor(Color.WHITE);
|
||||||
canvas.drawBitmap(laserBitmap, frame.left, scannerStart, paint);
|
canvas.drawBitmap(laserBitmap, (getWidth() - laserBitmap.getWidth()) / 2, scannerStart, paint);
|
||||||
if (scannerStart < scannerEnd) {
|
if (scannerStart < scannerEnd) {
|
||||||
scannerStart += scannerLineMoveDistance;
|
scannerStart += scannerLineMoveDistance;
|
||||||
} else {
|
} else {
|
||||||
@@ -591,7 +629,6 @@ public class ViewfinderView extends View {
|
|||||||
} else {
|
} else {
|
||||||
drawLineScanner(canvas, frame);
|
drawLineScanner(canvas, frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -16,13 +16,15 @@ import java.util.Map;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 条码分析器
|
||||||
|
*
|
||||||
* @author <a href="mailto:jenly1314@gmail.com">Jenly</a>
|
* @author <a href="mailto:jenly1314@gmail.com">Jenly</a>
|
||||||
*/
|
*/
|
||||||
public abstract class BarcodeFormatAnalyzer extends AreaRectAnalyzer {
|
public abstract class BarcodeFormatAnalyzer extends AreaRectAnalyzer {
|
||||||
|
|
||||||
private Reader mReader;
|
private Reader mReader;
|
||||||
|
|
||||||
public BarcodeFormatAnalyzer(@Nullable Map<DecodeHintType,Object> hints){
|
public BarcodeFormatAnalyzer(@Nullable Map<DecodeHintType, Object> hints) {
|
||||||
this(new DecodeConfig().setHints(hints));
|
this(new DecodeConfig().setHints(hints));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,62 +33,62 @@ public abstract class BarcodeFormatAnalyzer extends AreaRectAnalyzer {
|
|||||||
initReader();
|
initReader();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initReader(){
|
private void initReader() {
|
||||||
mReader = createReader();
|
mReader = createReader();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@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;
|
Result rawResult = null;
|
||||||
if(mReader != null){
|
if (mReader != null) {
|
||||||
try {
|
try {
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(data,dataWidth,dataHeight,left,top,width,height,false);
|
PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(data, dataWidth, dataHeight, left, top, width, height, false);
|
||||||
rawResult = decodeInternal(source,isMultiDecode);
|
rawResult = decodeInternal(source, isMultiDecode);
|
||||||
|
|
||||||
if(rawResult == null && mDecodeConfig != null){
|
if (rawResult == null && mDecodeConfig != null) {
|
||||||
if(rawResult == null && mDecodeConfig.isSupportVerticalCode()){
|
if (rawResult == null && mDecodeConfig.isSupportVerticalCode()) {
|
||||||
byte[] rotatedData = new byte[data.length];
|
byte[] rotatedData = new byte[data.length];
|
||||||
for (int y = 0; y < dataHeight; y++) {
|
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];
|
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()){
|
if (mDecodeConfig.isSupportLuminanceInvert()) {
|
||||||
rawResult = decodeInternal(source.invert(),mDecodeConfig.isSupportLuminanceInvertMultiDecode());
|
rawResult = decodeInternal(source.invert(), mDecodeConfig.isSupportLuminanceInvertMultiDecode());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(rawResult != null){
|
if (rawResult != null) {
|
||||||
long end = System.currentTimeMillis();
|
long end = System.currentTimeMillis();
|
||||||
LogUtils.d("Found barcode in " + (end - start) + " ms");
|
LogUtils.d("Found barcode in " + (end - start) + " ms");
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
||||||
}finally {
|
} finally {
|
||||||
mReader.reset();
|
mReader.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rawResult;
|
return rawResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Result decodeInternal(LuminanceSource source,boolean isMultiDecode){
|
private Result decodeInternal(LuminanceSource source, boolean isMultiDecode) {
|
||||||
Result result = null;
|
Result result = null;
|
||||||
try{
|
try {
|
||||||
try{
|
try {
|
||||||
//采用HybridBinarizer解析
|
//采用HybridBinarizer解析
|
||||||
result = mReader.decode(new BinaryBitmap(new HybridBinarizer(source)),mHints);
|
result = mReader.decode(new BinaryBitmap(new HybridBinarizer(source)), mHints);
|
||||||
}catch (Exception e){
|
} catch (Exception e) {
|
||||||
|
|
||||||
}
|
}
|
||||||
if(isMultiDecode && result == null){
|
if (isMultiDecode && result == null) {
|
||||||
//如果没有解析成功,再采用GlobalHistogramBinarizer解析一次
|
//如果没有解析成功,再采用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;
|
return result;
|
||||||
|
|||||||
@@ -5,22 +5,23 @@ import android.content.res.Configuration;
|
|||||||
import android.graphics.ImageFormat;
|
import android.graphics.ImageFormat;
|
||||||
|
|
||||||
import com.google.zxing.Result;
|
import com.google.zxing.Result;
|
||||||
|
import com.king.zxing.util.BitmapUtils;
|
||||||
import com.king.zxing.util.LogUtils;
|
import com.king.zxing.util.LogUtils;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.camera.core.ImageProxy;
|
import androidx.camera.core.ImageProxy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 图像分析器
|
* 图像分析器
|
||||||
|
*
|
||||||
* @author <a href="mailto:jenly1314@gmail.com">Jenly</a>
|
* @author <a href="mailto:jenly1314@gmail.com">Jenly</a>
|
||||||
*/
|
*/
|
||||||
public abstract class ImageAnalyzer implements Analyzer {
|
public abstract class ImageAnalyzer implements Analyzer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分析图像数据
|
* 分析图像数据
|
||||||
|
*
|
||||||
* @param data
|
* @param data
|
||||||
* @param width
|
* @param width
|
||||||
* @param height
|
* @param height
|
||||||
@@ -29,25 +30,23 @@ public abstract class ImageAnalyzer implements Analyzer {
|
|||||||
public abstract Result analyze(byte[] data, int width, int height);
|
public abstract Result analyze(byte[] data, int width, int height);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result analyze(@NonNull ImageProxy image,int orientation) {
|
public Result analyze(@NonNull ImageProxy image, int orientation) {
|
||||||
if(image.getFormat() == ImageFormat.YUV_420_888){
|
if (image.getFormat() == ImageFormat.YUV_420_888) {
|
||||||
@SuppressLint("UnsafeExperimentalUsageError")
|
|
||||||
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
|
|
||||||
byte[] data = new byte[buffer.remaining()];
|
|
||||||
buffer.get(data);
|
|
||||||
int width = image.getWidth();
|
int width = image.getWidth();
|
||||||
int height = image.getHeight();
|
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];
|
byte[] rotatedData = new byte[data.length];
|
||||||
for (int y = 0; y < height; y++) {
|
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];
|
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);
|
return analyze(data, width, height);
|
||||||
}else{
|
} else {
|
||||||
LogUtils.w("imageFormat: " + image.getFormat());
|
LogUtils.w("imageFormat: " + image.getFormat());
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -11,15 +11,17 @@ import androidx.annotation.Nullable;
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 二维码分析器
|
||||||
|
*
|
||||||
* @author <a href="mailto:jenly1314@gmail.com">Jenly</a>
|
* @author <a href="mailto:jenly1314@gmail.com">Jenly</a>
|
||||||
*/
|
*/
|
||||||
public class QRCodeAnalyzer extends BarcodeFormatAnalyzer {
|
public class QRCodeAnalyzer extends BarcodeFormatAnalyzer {
|
||||||
|
|
||||||
public QRCodeAnalyzer() {
|
public QRCodeAnalyzer() {
|
||||||
this((DecodeConfig)null);
|
this((DecodeConfig) null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public QRCodeAnalyzer(@Nullable Map<DecodeHintType,Object> hints){
|
public QRCodeAnalyzer(@Nullable Map<DecodeHintType, Object> hints) {
|
||||||
this(new DecodeConfig().setHints(hints));
|
this(new DecodeConfig().setHints(hints));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,11 @@ package com.king.zxing.config;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
|
|
||||||
|
import com.king.zxing.CameraScan;
|
||||||
import com.king.zxing.util.LogUtils;
|
import com.king.zxing.util.LogUtils;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.camera.core.AspectRatio;
|
import androidx.camera.core.AspectRatio;
|
||||||
import androidx.camera.core.CameraSelector;
|
import androidx.camera.core.CameraSelector;
|
||||||
@@ -18,6 +21,9 @@ import androidx.camera.core.Preview;
|
|||||||
*/
|
*/
|
||||||
public final class AspectRatioCameraConfig extends CameraConfig {
|
public final class AspectRatioCameraConfig extends CameraConfig {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 纵横比
|
||||||
|
*/
|
||||||
private int mAspectRatio;
|
private int mAspectRatio;
|
||||||
|
|
||||||
public AspectRatioCameraConfig(Context context) {
|
public AspectRatioCameraConfig(Context context) {
|
||||||
@@ -34,14 +40,15 @@ public final class AspectRatioCameraConfig extends CameraConfig {
|
|||||||
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
|
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
|
||||||
int width = displayMetrics.widthPixels;
|
int width = displayMetrics.widthPixels;
|
||||||
int height = displayMetrics.heightPixels;
|
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);
|
float ratio = Math.max(width, height) / (float) Math.min(width, height);
|
||||||
if (Math.abs(ratio - 4.0F / 3.0F) < Math.abs(ratio - 16.0F / 9.0F)) {
|
if (Math.abs(ratio - CameraScan.ASPECT_RATIO_4_3) < Math.abs(ratio - CameraScan.ASPECT_RATIO_16_9)) {
|
||||||
mAspectRatio = AspectRatio.RATIO_4_3;
|
mAspectRatio = AspectRatio.RATIO_4_3;
|
||||||
} else {
|
} else {
|
||||||
mAspectRatio = AspectRatio.RATIO_16_9;
|
mAspectRatio = AspectRatio.RATIO_16_9;
|
||||||
}
|
}
|
||||||
LogUtils.d("aspectRatio:" + mAspectRatio);
|
LogUtils.d("aspectRatio: " + mAspectRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.content.Context;
|
|||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
import android.util.Size;
|
import android.util.Size;
|
||||||
|
|
||||||
|
import com.king.zxing.CameraScan;
|
||||||
import com.king.zxing.util.LogUtils;
|
import com.king.zxing.util.LogUtils;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@@ -29,7 +30,9 @@ public class ResolutionCameraConfig extends CameraConfig {
|
|||||||
*/
|
*/
|
||||||
public static final int IMAGE_QUALITY_720P = 720;
|
public static final int IMAGE_QUALITY_720P = 720;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 目标尺寸
|
||||||
|
*/
|
||||||
private Size mTargetSize;
|
private Size mTargetSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -62,29 +65,27 @@ public class ResolutionCameraConfig extends CameraConfig {
|
|||||||
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
|
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
|
||||||
int width = displayMetrics.widthPixels;
|
int width = displayMetrics.widthPixels;
|
||||||
int height = displayMetrics.heightPixels;
|
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),在此前提下尽可能的找到屏幕接近的分辨率
|
// 因为为了保持流畅性和性能,尽可能的限制在imageQuality(默认:1080p),在此前提下尽可能的找到屏幕接近的分辨率
|
||||||
if (width < height) {
|
if (width < height) {
|
||||||
|
float ratio = height / (float) width;
|
||||||
int size = Math.min(width, imageQuality);
|
int size = Math.min(width, imageQuality);
|
||||||
float ratio = width / (float) height;
|
if (Math.abs(ratio - CameraScan.ASPECT_RATIO_4_3) < Math.abs(ratio - CameraScan.ASPECT_RATIO_16_9)) {
|
||||||
if (ratio > 0.7F) {
|
mTargetSize = new Size(size, Math.round(size * CameraScan.ASPECT_RATIO_4_3));
|
||||||
// 一般应用于平板
|
|
||||||
mTargetSize = new Size(size, (int) (size / 3.0F * 4.0F));
|
|
||||||
} else {
|
} else {
|
||||||
mTargetSize = new Size(size, (int) (size / 9.0F * 16.0F));
|
mTargetSize = new Size(size, Math.round(size * CameraScan.ASPECT_RATIO_16_9));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int size = Math.min(height, imageQuality);
|
int size = Math.min(height, imageQuality);
|
||||||
float ratio = height / (float) width;
|
float ratio = width / (float) height;
|
||||||
if (ratio > 0.7F) {
|
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);
|
||||||
mTargetSize = new Size((int) (size / 3.0F * 4.0F), size);
|
|
||||||
} else {
|
} 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
|
@NonNull
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import android.hardware.SensorEventListener;
|
|||||||
import android.hardware.SensorManager;
|
import android.hardware.SensorManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 环境光线管理器:主要通过传感器来监听光线的亮度变化
|
||||||
|
*
|
||||||
* @author <a href="mailto:jenly1314@gmail.com">Jenly</a>
|
* @author <a href="mailto:jenly1314@gmail.com">Jenly</a>
|
||||||
*/
|
*/
|
||||||
public class AmbientLightManager implements SensorEventListener {
|
public class AmbientLightManager implements SensorEventListener {
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import com.king.zxing.util.LogUtils;
|
|||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 蜂鸣音效管理器:主要用于播放蜂鸣提示音和振动效果
|
||||||
|
*
|
||||||
* @author <a href="mailto:jenly1314@gmail.com">Jenly</a>
|
* @author <a href="mailto:jenly1314@gmail.com">Jenly</a>
|
||||||
*/
|
*/
|
||||||
public final class BeepManager implements MediaPlayer.OnErrorListener, Closeable {
|
public final class BeepManager implements MediaPlayer.OnErrorListener, Closeable {
|
||||||
|
|||||||
273
zxing-lite/src/main/java/com/king/zxing/util/BitmapUtils.java
Normal file
273
zxing-lite/src/main/java/com/king/zxing/util/BitmapUtils.java
Normal file
@@ -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 <a href="https://github.com/googlesamples/mlkit/blob/master/android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/BitmapUtils.java">BitmapUtils</a>
|
||||||
|
*/
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* <p>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
|
||||||
|
*
|
||||||
|
* <p>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.
|
||||||
|
*
|
||||||
|
* <p>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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -48,6 +48,7 @@
|
|||||||
<attr name="pointDrawable" format="reference"/>
|
<attr name="pointDrawable" format="reference"/>
|
||||||
<attr name="showPointAnim" format="boolean"/>
|
<attr name="showPointAnim" format="boolean"/>
|
||||||
<attr name="laserDrawable" format="reference"/>
|
<attr name="laserDrawable" format="reference"/>
|
||||||
|
<attr name="laserDrawableRatio" format="float"/>
|
||||||
<attr name="viewfinderStyle" format="enum">
|
<attr name="viewfinderStyle" format="enum">
|
||||||
<enum name="classic" value="0"/>
|
<enum name="classic" value="0"/>
|
||||||
<enum name="popular" value="1"/>
|
<enum name="popular" value="1"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user