diff --git a/app/build.gradle b/app/build.gradle index 24f9be7..77aa3ff 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -50,5 +50,5 @@ dependencies { implementation deps.easypermissions - implementation project(':lib') + implementation project(':zxing-lite') } diff --git a/app/src/main/java/com/king/zxing/app/MainActivity.java b/app/src/main/java/com/king/zxing/app/MainActivity.java index 91f2516..3328982 100644 --- a/app/src/main/java/com/king/zxing/app/MainActivity.java +++ b/app/src/main/java/com/king/zxing/app/MainActivity.java @@ -18,21 +18,20 @@ package com.king.zxing.app; import android.Manifest; import android.content.Context; import android.content.Intent; +import android.graphics.Bitmap; import android.provider.MediaStore; import android.os.Bundle; -import android.text.TextUtils; -import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.Toast; import com.king.zxing.CameraScan; import com.king.zxing.CaptureActivity; -import com.king.zxing.app.util.UriUtils; import com.king.zxing.util.CodeUtils; import com.king.zxing.util.LogUtils; +import java.io.IOException; import java.util.List; import androidx.appcompat.app.AppCompatActivity; @@ -50,9 +49,9 @@ import pub.devrel.easypermissions.EasyPermissions; * * 2、通过继承CaptureActivity或者CaptureFragment并自定义布局。(适用于大多场景,并无需关心扫码相关逻辑,自定义布局时需覆写getLayoutId方法) * - * 3、在你项目的Activity或者Fragment中创建一个CaptureHelper并在相应的生命周期中调用CaptureHelper的周期。(适用于想在扫码界面写交互逻辑,又因为项目架构或其它原因,无法直接或间接继承CaptureActivity或CaptureFragment时使用) + * 3、在你项目的Activity或者Fragment中实例化一个CameraScan即可。(适用于想在扫码界面写交互逻辑,又因为项目架构或其它原因,无法直接或间接继承CaptureActivity或CaptureFragment时使用) * - * 4、参照CaptureHelper写一个自定义的扫码帮助类,其它步骤同方式3。(扩展高级用法,谨慎使用) + * 4、继承CameraScan自己实现一个,可参照默认实现类DefaultCameraScan,其它步骤同方式3。(扩展高级用法,谨慎使用) * */ public class MainActivity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks{ @@ -109,26 +108,28 @@ public class MainActivity extends AppCompatActivity implements EasyPermissions.P } private void parsePhoto(Intent data){ - final String path = UriUtils.getImagePath(this,data); - LogUtils.d("path:" + path); - if(TextUtils.isEmpty(path)){ - return; - } - //异步解析 - asyncThread(new Runnable() { - @Override - public void run() { - final String result = CodeUtils.parseCode(path); - runOnUiThread(new Runnable() { - @Override - public void run() { - Log.d("Jenly","result:" + result); - Toast.makeText(getContext(),result,Toast.LENGTH_SHORT).show(); - } + +// final String path = UriUtils.getImagePath(this,data); +// LogUtils.d("path:" + path); +// if(TextUtils.isEmpty(path)){ +// return; +// } + + try { + Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(),data.getData()); + //异步解析 + asyncThread(() -> { + final String result = CodeUtils.parseCode(bitmap); + runOnUiThread(() -> { + LogUtils.d("result:" + result); + Toast.makeText(getContext(),result,Toast.LENGTH_SHORT).show(); }); - } - }); + }); + + } catch (IOException e) { + e.printStackTrace(); + } } diff --git a/app/src/main/java/com/king/zxing/app/util/UriUtils.java b/app/src/main/java/com/king/zxing/app/util/UriUtils.java index a000452..93a3ea6 100644 --- a/app/src/main/java/com/king/zxing/app/util/UriUtils.java +++ b/app/src/main/java/com/king/zxing/app/util/UriUtils.java @@ -10,6 +10,8 @@ import android.provider.DocumentsContract; import android.provider.MediaStore; import android.util.Log; +import com.king.zxing.util.LogUtils; + /** * @author Jenly Jenly */ @@ -28,7 +30,7 @@ public final class UriUtils { //获取系統版本 int currentapiVersion = Build.VERSION.SDK_INT; if(currentapiVersion> Build.VERSION_CODES.KITKAT){ - Log.d("uri=intent.getData :", "" + uri); + LogUtils.d("uri=intent.getData :" + uri); if (DocumentsContract.isDocumentUri(context, uri)) { String docId = DocumentsContract.getDocumentId(uri); Log.d("getDocumentId(uri) :", "" + docId); diff --git a/settings.gradle b/settings.gradle index 85e82b5..15445da 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':app', ':lib' +include ':app', ':zxing-lite' diff --git a/lib/.gitignore b/zxing-lite/.gitignore similarity index 87% rename from lib/.gitignore rename to zxing-lite/.gitignore index 3543521..796b96d 100644 --- a/lib/.gitignore +++ b/zxing-lite/.gitignore @@ -1 +1 @@ -/build +/build diff --git a/lib/bintray.gradle b/zxing-lite/bintray.gradle similarity index 97% rename from lib/bintray.gradle rename to zxing-lite/bintray.gradle index 779be5e..1719f79 100644 --- a/lib/bintray.gradle +++ b/zxing-lite/bintray.gradle @@ -1,12 +1,12 @@ -apply plugin: 'com.novoda.bintray-release' - -//添加 -publish { - userOrg = 'jenly'//bintray.com用户名 - groupId = 'com.king.zxing'//jcenter上的路径 - artifactId = 'zxing-lite'//项目名称 - publishVersion = app_version.versionName//版本号 - desc = 'ZXingLite for Android'//描述 - website = 'https://github.com/jenly1314/ZXingLite'//网站 - +apply plugin: 'com.novoda.bintray-release' + +//添加 +publish { + userOrg = 'jenly'//bintray.com用户名 + groupId = 'com.king.zxing'//jcenter上的路径 + artifactId = 'zxing-lite'//项目名称 + publishVersion = app_version.versionName//版本号 + desc = 'ZXingLite for Android'//描述 + website = 'https://github.com/jenly1314/ZXingLite'//网站 + } \ No newline at end of file diff --git a/lib/build.gradle b/zxing-lite/build.gradle similarity index 96% rename from lib/build.gradle rename to zxing-lite/build.gradle index 35ff9d9..90ee12c 100644 --- a/lib/build.gradle +++ b/zxing-lite/build.gradle @@ -1,51 +1,51 @@ -apply plugin: 'com.android.library' -apply from: 'bintray.gradle' - -android { - compileSdkVersion build_versions.compileSdk - buildToolsVersion build_versions.buildTools - defaultConfig { - minSdkVersion build_versions.minSdk - targetSdkVersion build_versions.targetSdk - versionCode app_version.versionCode - versionName app_version.versionName - - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - - } - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - } - - lintOptions { - abortOnError false - warning 'InvalidPackage' - } - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } -} - -//task javadoc(type: Javadoc) { -// source = android.sourceSets.main.java.srcDirs -// classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) -//} - -dependencies { - implementation fileTree(include: ['*.jar'], dir: 'libs') - testImplementation deps.test.junit - androidTestImplementation deps.test.runner - androidTestImplementation deps.test.espresso - - compileOnly deps.androidx.appcompat - api deps.zxing - api deps.camera_core - api deps.camera_camera2 - api deps.camera_lifecycle - api deps.camera_view -} +apply plugin: 'com.android.library' +apply from: 'bintray.gradle' + +android { + compileSdkVersion build_versions.compileSdk + buildToolsVersion build_versions.buildTools + defaultConfig { + minSdkVersion build_versions.minSdk + targetSdkVersion build_versions.targetSdk + versionCode app_version.versionCode + versionName app_version.versionName + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + + lintOptions { + abortOnError false + warning 'InvalidPackage' + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +//task javadoc(type: Javadoc) { +// source = android.sourceSets.main.java.srcDirs +// classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) +//} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + testImplementation deps.test.junit + androidTestImplementation deps.test.runner + androidTestImplementation deps.test.espresso + + compileOnly deps.androidx.appcompat + api deps.zxing + api deps.camera_core + api deps.camera_camera2 + api deps.camera_lifecycle + api deps.camera_view +} diff --git a/zxing-lite/gradle.properties b/zxing-lite/gradle.properties new file mode 100644 index 0000000..60e9686 --- /dev/null +++ b/zxing-lite/gradle.properties @@ -0,0 +1,3 @@ +POM_NAME=ZXingLite +POM_ARTIFACT_ID=zxing-lite +POM_PACKAGING=aar \ No newline at end of file diff --git a/lib/proguard-rules.pro b/zxing-lite/proguard-rules.pro similarity index 96% rename from lib/proguard-rules.pro rename to zxing-lite/proguard-rules.pro index e786d4a..b9139f6 100644 --- a/lib/proguard-rules.pro +++ b/zxing-lite/proguard-rules.pro @@ -1,34 +1,34 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile - -#ZXingLite --dontwarn com.king.zxing.** --keep class com.king.zxing.**{ *;} --keepattributes InnerClasses --keepclassmembers enum * { - public static **[] values(); - public static ** valueOf(java.lang.String); -} - -#ZXing --dontwarn com.google.zxing.** +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile + +#ZXingLite +-dontwarn com.king.zxing.** +-keep class com.king.zxing.**{ *;} +-keepattributes InnerClasses +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} + +#ZXing +-dontwarn com.google.zxing.** -keep class com.google.zxing.**{ *;} \ No newline at end of file diff --git a/lib/src/androidTest/java/com/king/zxing/ExampleInstrumentedTest.java b/zxing-lite/src/androidTest/java/com/king/zxing/ExampleInstrumentedTest.java similarity index 96% rename from lib/src/androidTest/java/com/king/zxing/ExampleInstrumentedTest.java rename to zxing-lite/src/androidTest/java/com/king/zxing/ExampleInstrumentedTest.java index cdd5ac9..0f6cc11 100644 --- a/lib/src/androidTest/java/com/king/zxing/ExampleInstrumentedTest.java +++ b/zxing-lite/src/androidTest/java/com/king/zxing/ExampleInstrumentedTest.java @@ -1,27 +1,27 @@ -package com.king.zxing; - -import android.content.Context; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import androidx.test.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; - -import static org.junit.Assert.*; - -/** - * Instrumented test, which will execute on an Android device. - * - * @see Testing documentation - */ -@RunWith(AndroidJUnit4.class) -public class ExampleInstrumentedTest { - @Test - public void useAppContext() { - // Context of the app under test. - Context appContext = InstrumentationRegistry.getTargetContext(); - - assertEquals("com.king.zxing.test", appContext.getPackageName()); - } -} +package com.king.zxing; + +import android.content.Context; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("com.king.zxing.test", appContext.getPackageName()); + } +} diff --git a/lib/src/main/AndroidManifest.xml b/zxing-lite/src/main/AndroidManifest.xml similarity index 97% rename from lib/src/main/AndroidManifest.xml rename to zxing-lite/src/main/AndroidManifest.xml index 1aa341d..fe7a4d3 100644 --- a/lib/src/main/AndroidManifest.xml +++ b/zxing-lite/src/main/AndroidManifest.xml @@ -1,15 +1,15 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/lib/src/main/java/com/king/zxing/CameraConfig.java b/zxing-lite/src/main/java/com/king/zxing/CameraConfig.java similarity index 100% rename from lib/src/main/java/com/king/zxing/CameraConfig.java rename to zxing-lite/src/main/java/com/king/zxing/CameraConfig.java diff --git a/lib/src/main/java/com/king/zxing/CameraScan.java b/zxing-lite/src/main/java/com/king/zxing/CameraScan.java similarity index 100% rename from lib/src/main/java/com/king/zxing/CameraScan.java rename to zxing-lite/src/main/java/com/king/zxing/CameraScan.java diff --git a/lib/src/main/java/com/king/zxing/CaptureActivity.java b/zxing-lite/src/main/java/com/king/zxing/CaptureActivity.java similarity index 96% rename from lib/src/main/java/com/king/zxing/CaptureActivity.java rename to zxing-lite/src/main/java/com/king/zxing/CaptureActivity.java index 5f261ea..9213f61 100644 --- a/lib/src/main/java/com/king/zxing/CaptureActivity.java +++ b/zxing-lite/src/main/java/com/king/zxing/CaptureActivity.java @@ -1,214 +1,214 @@ -/* - * Copyright (C) 2018 Jenly Yu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.king.zxing; - -import android.Manifest; -import android.os.Bundle; -import android.view.View; - -import com.google.zxing.Result; -import com.king.zxing.util.LogUtils; -import com.king.zxing.util.PermissionUtils; - -import androidx.annotation.LayoutRes; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.appcompat.app.AppCompatActivity; -import androidx.camera.view.PreviewView; - -/** - * @author Jenly - */ -public class CaptureActivity extends AppCompatActivity implements CameraScan.OnScanResultCallback{ - - private static final int CAMERA_PERMISSION_REQUEST_CODE = 0X86; - - protected PreviewView previewView; - protected ViewfinderView viewfinderView; - protected View ivFlashlight; - - private CameraScan mCameraScan; - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - int layoutId = getLayoutId(); - if(isContentView(layoutId)){ - setContentView(layoutId); - } - initUI(); - } - - /** - * 初始化 - */ - public void initUI(){ - previewView = findViewById(getPreviewViewId()); - int viewfinderViewId = getViewfinderViewId(); - if(viewfinderViewId != 0){ - viewfinderView = findViewById(viewfinderViewId); - } - int ivFlashlightId = getFlashlightId(); - if(ivFlashlightId != 0){ - ivFlashlight = findViewById(ivFlashlightId); - if(ivFlashlight != null){ - ivFlashlight.setOnClickListener(v -> onClickFlashlight()); - } - } - initCameraScan(); - startCamera(); - } - - /** - * 点击手电筒 - */ - protected void onClickFlashlight(){ - toggleTorchState(); - } - - /** - * 初始化CameraScan - */ - public void initCameraScan(){ - mCameraScan = new DefaultCameraScan(this,previewView); - mCameraScan.setOnScanResultCallback(this); - } - - - /** - * 启动相机预览 - */ - public void startCamera(){ - if(mCameraScan != null){ - if(PermissionUtils.checkPermission(this,Manifest.permission.CAMERA)){ - mCameraScan.startCamera(); - }else{ - LogUtils.d("checkPermissionResult != PERMISSION_GRANTED"); - PermissionUtils.requestPermission(this,Manifest.permission.CAMERA,CAMERA_PERMISSION_REQUEST_CODE); - } - } - } - - - /** - * 释放相机 - */ - private void releaseCamera(){ - if(mCameraScan != null){ - mCameraScan.release(); - } - } - - /** - * 切换闪光灯状态(开启/关闭) - */ - protected void toggleTorchState(){ - if(mCameraScan != null){ - boolean isTorch = mCameraScan.isTorchEnabled(); - mCameraScan.enableTorch(!isTorch); - if(ivFlashlight != null){ - ivFlashlight.setSelected(!isTorch); - } - } - } - - @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - if(requestCode == CAMERA_PERMISSION_REQUEST_CODE){ - requestCameraPermissionResult(permissions,grantResults); - } - } - - /** - * 请求Camera权限回调结果 - * @param permissions - * @param grantResults - */ - public void requestCameraPermissionResult(@NonNull String[] permissions, @NonNull int[] grantResults){ - if(PermissionUtils.requestPermissionsResult(Manifest.permission.CAMERA,permissions,grantResults)){ - startCamera(); - }else{ - finish(); - } - } - - @Override - protected void onDestroy() { - releaseCamera(); - super.onDestroy(); - } - - /** - * 返回true时会自动初始化{@link #setContentView(int)},返回为false是需自己去初始化{@link #setContentView(int)} - * @param layoutId - * @return 默认返回true - */ - public boolean isContentView(@LayoutRes int layoutId){ - return true; - } - - /** - * 布局id - * @return - */ - public int getLayoutId(){ - return R.layout.zxl_capture; - } - - /** - * {@link #viewfinderView} 的 ID - * @return 默认返回{@code R.id.viewfinderView}, 如果不需要扫码框可以返回0 - */ - public int getViewfinderViewId(){ - return R.id.viewfinderView; - } - - - /** - * 预览界面{@link #previewView} 的ID - * @return - */ - public int getPreviewViewId(){ - return R.id.previewView; - } - - /** - * 获取 {@link #ivFlashlight} 的ID - * @return 默认返回{@code R.id.ivFlashlight}, 如果不需要手电筒按钮可以返回0 - */ - public int getFlashlightId(){ - return R.id.ivFlashlight; - } - - /** - * Get {@link CameraScan} - * @return {@link #mCameraScan} - */ - public CameraScan getCameraScan(){ - return mCameraScan; - } - - /** - * 接收扫码结果回调 - * @param result 扫码结果 - * @return 返回true表示拦截,将不自动执行后续逻辑,为false表示不拦截,默认不拦截 - */ - @Override - public boolean onScanResultCallback(Result result) { - return false; - } +/* + * Copyright (C) 2018 Jenly Yu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.king.zxing; + +import android.Manifest; +import android.os.Bundle; +import android.view.View; + +import com.google.zxing.Result; +import com.king.zxing.util.LogUtils; +import com.king.zxing.util.PermissionUtils; + +import androidx.annotation.LayoutRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.camera.view.PreviewView; + +/** + * @author Jenly + */ +public class CaptureActivity extends AppCompatActivity implements CameraScan.OnScanResultCallback{ + + private static final int CAMERA_PERMISSION_REQUEST_CODE = 0X86; + + protected PreviewView previewView; + protected ViewfinderView viewfinderView; + protected View ivFlashlight; + + private CameraScan mCameraScan; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + int layoutId = getLayoutId(); + if(isContentView(layoutId)){ + setContentView(layoutId); + } + initUI(); + } + + /** + * 初始化 + */ + public void initUI(){ + previewView = findViewById(getPreviewViewId()); + int viewfinderViewId = getViewfinderViewId(); + if(viewfinderViewId != 0){ + viewfinderView = findViewById(viewfinderViewId); + } + int ivFlashlightId = getFlashlightId(); + if(ivFlashlightId != 0){ + ivFlashlight = findViewById(ivFlashlightId); + if(ivFlashlight != null){ + ivFlashlight.setOnClickListener(v -> onClickFlashlight()); + } + } + initCameraScan(); + startCamera(); + } + + /** + * 点击手电筒 + */ + protected void onClickFlashlight(){ + toggleTorchState(); + } + + /** + * 初始化CameraScan + */ + public void initCameraScan(){ + mCameraScan = new DefaultCameraScan(this,previewView); + mCameraScan.setOnScanResultCallback(this); + } + + + /** + * 启动相机预览 + */ + public void startCamera(){ + if(mCameraScan != null){ + if(PermissionUtils.checkPermission(this,Manifest.permission.CAMERA)){ + mCameraScan.startCamera(); + }else{ + LogUtils.d("checkPermissionResult != PERMISSION_GRANTED"); + PermissionUtils.requestPermission(this,Manifest.permission.CAMERA,CAMERA_PERMISSION_REQUEST_CODE); + } + } + } + + + /** + * 释放相机 + */ + private void releaseCamera(){ + if(mCameraScan != null){ + mCameraScan.release(); + } + } + + /** + * 切换闪光灯状态(开启/关闭) + */ + protected void toggleTorchState(){ + if(mCameraScan != null){ + boolean isTorch = mCameraScan.isTorchEnabled(); + mCameraScan.enableTorch(!isTorch); + if(ivFlashlight != null){ + ivFlashlight.setSelected(!isTorch); + } + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if(requestCode == CAMERA_PERMISSION_REQUEST_CODE){ + requestCameraPermissionResult(permissions,grantResults); + } + } + + /** + * 请求Camera权限回调结果 + * @param permissions + * @param grantResults + */ + public void requestCameraPermissionResult(@NonNull String[] permissions, @NonNull int[] grantResults){ + if(PermissionUtils.requestPermissionsResult(Manifest.permission.CAMERA,permissions,grantResults)){ + startCamera(); + }else{ + finish(); + } + } + + @Override + protected void onDestroy() { + releaseCamera(); + super.onDestroy(); + } + + /** + * 返回true时会自动初始化{@link #setContentView(int)},返回为false是需自己去初始化{@link #setContentView(int)} + * @param layoutId + * @return 默认返回true + */ + public boolean isContentView(@LayoutRes int layoutId){ + return true; + } + + /** + * 布局id + * @return + */ + public int getLayoutId(){ + return R.layout.zxl_capture; + } + + /** + * {@link #viewfinderView} 的 ID + * @return 默认返回{@code R.id.viewfinderView}, 如果不需要扫码框可以返回0 + */ + public int getViewfinderViewId(){ + return R.id.viewfinderView; + } + + + /** + * 预览界面{@link #previewView} 的ID + * @return + */ + public int getPreviewViewId(){ + return R.id.previewView; + } + + /** + * 获取 {@link #ivFlashlight} 的ID + * @return 默认返回{@code R.id.ivFlashlight}, 如果不需要手电筒按钮可以返回0 + */ + public int getFlashlightId(){ + return R.id.ivFlashlight; + } + + /** + * Get {@link CameraScan} + * @return {@link #mCameraScan} + */ + public CameraScan getCameraScan(){ + return mCameraScan; + } + + /** + * 接收扫码结果回调 + * @param result 扫码结果 + * @return 返回true表示拦截,将不自动执行后续逻辑,为false表示不拦截,默认不拦截 + */ + @Override + public boolean onScanResultCallback(Result result) { + return false; + } } \ No newline at end of file diff --git a/lib/src/main/java/com/king/zxing/CaptureFragment.java b/zxing-lite/src/main/java/com/king/zxing/CaptureFragment.java similarity index 100% rename from lib/src/main/java/com/king/zxing/CaptureFragment.java rename to zxing-lite/src/main/java/com/king/zxing/CaptureFragment.java diff --git a/lib/src/main/java/com/king/zxing/DecodeConfig.java b/zxing-lite/src/main/java/com/king/zxing/DecodeConfig.java similarity index 100% rename from lib/src/main/java/com/king/zxing/DecodeConfig.java rename to zxing-lite/src/main/java/com/king/zxing/DecodeConfig.java diff --git a/lib/src/main/java/com/king/zxing/DecodeFormatManager.java b/zxing-lite/src/main/java/com/king/zxing/DecodeFormatManager.java similarity index 100% rename from lib/src/main/java/com/king/zxing/DecodeFormatManager.java rename to zxing-lite/src/main/java/com/king/zxing/DecodeFormatManager.java diff --git a/lib/src/main/java/com/king/zxing/DefaultCameraScan.java b/zxing-lite/src/main/java/com/king/zxing/DefaultCameraScan.java similarity index 99% rename from lib/src/main/java/com/king/zxing/DefaultCameraScan.java rename to zxing-lite/src/main/java/com/king/zxing/DefaultCameraScan.java index b75d461..37071ba 100644 --- a/lib/src/main/java/com/king/zxing/DefaultCameraScan.java +++ b/zxing-lite/src/main/java/com/king/zxing/DefaultCameraScan.java @@ -16,6 +16,8 @@ import com.google.zxing.ResultPoint; import com.google.zxing.common.detector.MathUtils; import com.king.zxing.analyze.Analyzer; import com.king.zxing.analyze.MultiFormatAnalyzer; +import com.king.zxing.manager.AmbientLightManager; +import com.king.zxing.manager.BeepManager; import com.king.zxing.util.LogUtils; import java.util.concurrent.Executors; diff --git a/lib/src/main/java/com/king/zxing/ICamera.java b/zxing-lite/src/main/java/com/king/zxing/ICamera.java similarity index 100% rename from lib/src/main/java/com/king/zxing/ICamera.java rename to zxing-lite/src/main/java/com/king/zxing/ICamera.java diff --git a/lib/src/main/java/com/king/zxing/ICameraControl.java b/zxing-lite/src/main/java/com/king/zxing/ICameraControl.java similarity index 100% rename from lib/src/main/java/com/king/zxing/ICameraControl.java rename to zxing-lite/src/main/java/com/king/zxing/ICameraControl.java diff --git a/lib/src/main/java/com/king/zxing/ViewfinderView.java b/zxing-lite/src/main/java/com/king/zxing/ViewfinderView.java similarity index 97% rename from lib/src/main/java/com/king/zxing/ViewfinderView.java rename to zxing-lite/src/main/java/com/king/zxing/ViewfinderView.java index db7e943..8dab4dc 100644 --- a/lib/src/main/java/com/king/zxing/ViewfinderView.java +++ b/zxing-lite/src/main/java/com/king/zxing/ViewfinderView.java @@ -1,580 +1,580 @@ -package com.king.zxing; -/* - * Copyright (C) 2008 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.LinearGradient; -import android.graphics.Paint; -import android.graphics.Point; -import android.graphics.Rect; -import android.graphics.RectF; -import android.graphics.Shader; -import android.text.Layout; -import android.text.StaticLayout; -import android.text.TextPaint; -import android.text.TextUtils; -import android.util.AttributeSet; -import android.util.DisplayMetrics; -import android.util.TypedValue; -import android.view.View; - -import androidx.annotation.ColorInt; -import androidx.annotation.ColorRes; -import androidx.annotation.Nullable; -import androidx.core.content.ContextCompat; - -import static com.king.zxing.ViewfinderView.FrameGravity.*; - -/** - * This view is overlaid on top of the camera preview. It adds the viewfinder rectangle and partial - * transparency outside it, as well as the laser scanner animation and result points. - * - * @author dswitkin@google.com (Daniel Switkin) - */ -public class ViewfinderView extends View { - - private static final int CURRENT_POINT_OPACITY = 0xA0; - private static final int MAX_RESULT_POINTS = 20; - private static final int POINT_SIZE = 30; - - /** - * 画笔 - */ - private Paint paint; - - /** - * 文本画笔 - */ - private TextPaint textPaint; - /** - * 扫码框外面遮罩颜色 - */ - private int maskColor; - /** - * 扫描区域边框颜色 - */ - private int frameColor; - /** - * 扫描线颜色 - */ - private int laserColor; - /** - * 扫码框四角颜色 - */ - private int cornerColor; - - /** - * 提示文本与扫码框的边距 - */ - private float labelTextPadding; - /** - * 提示文本的宽度 - */ - private int labelTextWidth; - /** - * 提示文本的位置 - */ - private TextLocation labelTextLocation; - /** - * 扫描区域提示文本 - */ - private String labelText; - /** - * 扫描区域提示文本颜色 - */ - private int labelTextColor; - /** - * 提示文本字体大小 - */ - private float labelTextSize; - - /** - * 扫描线开始位置 - */ - public int scannerStart = 0; - /** - * 扫描线结束位置 - */ - public int scannerEnd = 0; - - /** - * 扫码框宽 - */ - private int frameWidth; - /** - * 扫码框高 - */ - private int frameHeight; - /** - * 扫描激光线风格 - */ - private LaserStyle laserStyle; - - /** - * 网格列数 - */ - private int gridColumn; - /** - * 网格高度 - */ - private int gridHeight; - - /** - * 扫码框 - */ - private Rect frame; - - /** - * 扫描区边角的宽 - */ - private int cornerRectWidth; - /** - * 扫描区边角的高 - */ - private int cornerRectHeight; - /** - * 扫描线每次移动距离 - */ - private int scannerLineMoveDistance; - /** - * 扫描线高度 - */ - private int scannerLineHeight; - - /** - * 边框线宽度 - */ - private int frameLineWidth; - - /** - * 扫描动画延迟间隔时间 默认20毫秒 - */ - private int scannerAnimationDelay; - - /** - * 扫码框占比 - */ - private float frameRatio; - - /** - * 扫码框内间距 - */ - private float framePaddingLeft; - private float framePaddingTop; - private float framePaddingRight; - private float framePaddingBottom; - /** - * 扫码框对齐方式 - */ - private FrameGravity frameGravity; - - - private Point point; - private int pointColor; - private int pointStrokeColor; - - private float pointRadius; - private float pointStrokeRatio = 1.2f; - - - public enum LaserStyle{ - NONE(0),LINE(1),GRID(2); - private int mValue; - LaserStyle(int value){ - mValue = value; - } - - private static LaserStyle getFromInt(int value){ - for(LaserStyle style : LaserStyle.values()){ - if(style.mValue == value){ - return style; - } - } - return LaserStyle.LINE; - } - } - - public enum TextLocation { - TOP(0),BOTTOM(1); - - private int mValue; - - TextLocation(int value){ - mValue = value; - } - - private static TextLocation getFromInt(int value){ - for(TextLocation location : TextLocation.values()){ - if(location.mValue == value){ - return location; - } - } - return TextLocation.TOP; - } - } - - - public enum FrameGravity { - CENTER(0), LEFT(1), TOP(2), RIGHT(3), BOTTOM(4); - - private int mValue; - - FrameGravity(int value) { - mValue = value; - } - - private static FrameGravity getFromInt(int value) { - for (FrameGravity gravity : values()) { - if (gravity.mValue == value) { - return gravity; - } - } - return CENTER; - } - } - - public ViewfinderView(Context context) { - this(context,null); - } - - public ViewfinderView(Context context, @Nullable AttributeSet attrs) { - this(context, attrs,0); - } - - public ViewfinderView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - init(context,attrs); - } - - - private void init(Context context, AttributeSet attrs) { - //初始化自定义属性信息 - TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ViewfinderView); - maskColor = array.getColor(R.styleable.ViewfinderView_maskColor, ContextCompat.getColor(context,R.color.viewfinder_mask)); - frameColor = array.getColor(R.styleable.ViewfinderView_frameColor, ContextCompat.getColor(context,R.color.viewfinder_frame)); - cornerColor = array.getColor(R.styleable.ViewfinderView_cornerColor, ContextCompat.getColor(context,R.color.viewfinder_corner)); - laserColor = array.getColor(R.styleable.ViewfinderView_laserColor, ContextCompat.getColor(context,R.color.viewfinder_laser)); - - labelText = array.getString(R.styleable.ViewfinderView_labelText); - labelTextColor = array.getColor(R.styleable.ViewfinderView_labelTextColor, ContextCompat.getColor(context,R.color.viewfinder_text_color)); - labelTextSize = array.getDimension(R.styleable.ViewfinderView_labelTextSize, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,14f,getResources().getDisplayMetrics())); - labelTextPadding = array.getDimension(R.styleable.ViewfinderView_labelTextPadding,TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,24,getResources().getDisplayMetrics())); - labelTextWidth = array.getDimensionPixelSize(R.styleable.ViewfinderView_labelTextWidth,0); - labelTextLocation = TextLocation.getFromInt(array.getInt(R.styleable.ViewfinderView_labelTextLocation,0)); - - frameWidth = array.getDimensionPixelSize(R.styleable.ViewfinderView_frameWidth,0); - frameHeight = array.getDimensionPixelSize(R.styleable.ViewfinderView_frameHeight,0); - - laserStyle = LaserStyle.getFromInt(array.getInt(R.styleable.ViewfinderView_laserStyle,LaserStyle.LINE.mValue)); - gridColumn = array.getInt(R.styleable.ViewfinderView_gridColumn,20); - gridHeight = (int)array.getDimension(R.styleable.ViewfinderView_gridHeight,TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,40,getResources().getDisplayMetrics())); - - cornerRectWidth = (int)array.getDimension(R.styleable.ViewfinderView_cornerRectWidth,TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,4,getResources().getDisplayMetrics())); - cornerRectHeight = (int)array.getDimension(R.styleable.ViewfinderView_cornerRectHeight,TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,16,getResources().getDisplayMetrics())); - scannerLineMoveDistance = (int)array.getDimension(R.styleable.ViewfinderView_scannerLineMoveDistance,TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,2,getResources().getDisplayMetrics())); - scannerLineHeight = (int)array.getDimension(R.styleable.ViewfinderView_scannerLineHeight,TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,5,getResources().getDisplayMetrics())); - frameLineWidth = (int)array.getDimension(R.styleable.ViewfinderView_frameLineWidth,TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,1,getResources().getDisplayMetrics())); - scannerAnimationDelay = array.getInteger(R.styleable.ViewfinderView_scannerAnimationDelay,20); - frameRatio = array.getFloat(R.styleable.ViewfinderView_frameRatio,0.625f); - framePaddingLeft = array.getDimension(R.styleable.ViewfinderView_framePaddingLeft,0); - framePaddingTop = array.getDimension(R.styleable.ViewfinderView_framePaddingTop,0); - framePaddingRight = array.getDimension(R.styleable.ViewfinderView_framePaddingRight,0); - framePaddingBottom = array.getDimension(R.styleable.ViewfinderView_framePaddingBottom,0); - frameGravity = FrameGravity.getFromInt(array.getInt(R.styleable.ViewfinderView_frameGravity, CENTER.mValue)); - array.recycle(); - - pointColor = laserColor; - pointStrokeColor = Color.WHITE; - - pointRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,10,getResources().getDisplayMetrics()); - paint = new Paint(Paint.ANTI_ALIAS_FLAG); - textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - - } - - private DisplayMetrics getDisplayMetrics(){ - return getResources().getDisplayMetrics(); - } - - public void setLabelText(String labelText) { - this.labelText = labelText; - } - - public void setLabelTextColor(@ColorInt int color) { - this.labelTextColor = color; - } - - public void setLabelTextColorResource(@ColorRes int id){ - this.labelTextColor = ContextCompat.getColor(getContext(),id); - } - - public void setLabelTextSize(float textSize) { - this.labelTextSize = textSize; - } - - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - initFrame(w,h); - } - - private void initFrame(int width,int height){ - - int size = (int)(Math.min(width,height) * frameRatio); - - if(frameWidth <= 0 || frameWidth > width){ - frameWidth = size; - } - - if(frameHeight <= 0 || frameHeight > height){ - frameHeight = size; - } - - if(labelTextWidth <= 0){ - labelTextWidth = width - getPaddingLeft() - getPaddingRight(); - } - - float leftOffsets = (width - frameWidth) / 2 + framePaddingLeft - framePaddingRight; - float topOffsets = (height - frameHeight) / 2 + framePaddingTop - framePaddingBottom; - switch (frameGravity){ - case LEFT: - leftOffsets = framePaddingLeft; - break; - case TOP: - topOffsets = framePaddingTop; - break; - case RIGHT: - leftOffsets = width - frameWidth + framePaddingRight; - break; - case BOTTOM: - topOffsets = height - frameHeight + framePaddingBottom; - break; - } - - frame = new Rect((int)leftOffsets, (int)topOffsets, (int)leftOffsets + frameWidth, (int)topOffsets + frameHeight); - } - - @Override - public void onDraw(Canvas canvas) { - - if (frame == null) { - return; - } - - if(scannerStart == 0 || scannerEnd == 0) { - scannerStart = frame.top; - scannerEnd = frame.bottom - scannerLineHeight; - } - - int width = canvas.getWidth(); - int height = canvas.getHeight(); - - // 绘制模糊区域 - drawExterior(canvas,frame,width,height); - // 绘制扫描动画 - drawLaserScanner(canvas,frame); - // 绘制取景区域框 - drawFrame(canvas, frame); - // 绘制取景区域边角 - drawCorner(canvas, frame); - //绘制提示信息 - drawTextInfo(canvas, frame); - // 间隔更新取景区域 - postInvalidateDelayed(scannerAnimationDelay, frame.left, frame.top, frame.right, frame.bottom); - } - - /** - * 绘制文本 - * @param canvas - * @param frame - */ - private void drawTextInfo(Canvas canvas, Rect frame) { - if(!TextUtils.isEmpty(labelText)){ - textPaint.setColor(labelTextColor); - textPaint.setTextSize(labelTextSize); - textPaint.setTextAlign(Paint.Align.CENTER); - StaticLayout staticLayout = new StaticLayout(labelText,textPaint,labelTextWidth, Layout.Alignment.ALIGN_NORMAL,1.2f,0.0f,true); - if(labelTextLocation == TextLocation.BOTTOM){ - canvas.translate(frame.left + frame.width() / 2,frame.bottom + labelTextPadding); - }else{ - canvas.translate(frame.left + frame.width() / 2,frame.top - labelTextPadding - staticLayout.getHeight()); - } - staticLayout.draw(canvas); - } - - } - - /** - * 绘制边角 - * @param canvas - * @param frame - */ - private void drawCorner(Canvas canvas, Rect frame) { - paint.setColor(cornerColor); - //左上 - canvas.drawRect(frame.left, frame.top, frame.left + cornerRectWidth, frame.top + cornerRectHeight, paint); - canvas.drawRect(frame.left, frame.top, frame.left + cornerRectHeight, frame.top + cornerRectWidth, paint); - //右上 - canvas.drawRect(frame.right - cornerRectWidth, frame.top, frame.right, frame.top + cornerRectHeight, paint); - canvas.drawRect(frame.right - cornerRectHeight, frame.top, frame.right, frame.top + cornerRectWidth, paint); - //左下 - canvas.drawRect(frame.left, frame.bottom - cornerRectWidth, frame.left + cornerRectHeight, frame.bottom, paint); - canvas.drawRect(frame.left, frame.bottom - cornerRectHeight, frame.left + cornerRectWidth, frame.bottom, paint); - //右下 - canvas.drawRect(frame.right - cornerRectWidth, frame.bottom - cornerRectHeight, frame.right, frame.bottom, paint); - canvas.drawRect(frame.right - cornerRectHeight, frame.bottom - cornerRectWidth, frame.right, frame.bottom, paint); - } - - /** - * 绘制激光扫描线 - * @param canvas - * @param frame - */ - private void drawLaserScanner(Canvas canvas, Rect frame) { - if(laserStyle != null){ - paint.setColor(laserColor); - switch (laserStyle){ - case LINE://线 - drawLineScanner(canvas,frame); - break; - case GRID://网格 - drawGridScanner(canvas,frame); - break; - } - paint.setShader(null); - } - } - - /** - * 绘制线性式扫描 - * @param canvas - * @param frame - */ - private void drawLineScanner(Canvas canvas,Rect frame){ - //线性渐变 - LinearGradient linearGradient = new LinearGradient( - frame.left, scannerStart, - frame.left, scannerStart + scannerLineHeight, - shadeColor(laserColor), - laserColor, - Shader.TileMode.MIRROR); - - paint.setShader(linearGradient); - if(scannerStart <= scannerEnd) { - //椭圆 - RectF rectF = new RectF(frame.left + 2 * scannerLineHeight, scannerStart, frame.right - 2 * scannerLineHeight, scannerStart + scannerLineHeight); - canvas.drawOval(rectF, paint); - scannerStart += scannerLineMoveDistance; - } else { - scannerStart = frame.top; - } - } - - /** - * 绘制网格式扫描 - * @param canvas - * @param frame - */ - private void drawGridScanner(Canvas canvas,Rect frame){ - int stroke = 2; - paint.setStrokeWidth(stroke); - //计算Y轴开始位置 - int startY = gridHeight > 0 && scannerStart - frame.top > gridHeight ? scannerStart - gridHeight : frame.top; - - LinearGradient linearGradient = new LinearGradient(frame.left + frame.width()/2, startY, frame.left + frame.width()/2, scannerStart, new int[]{shadeColor(laserColor), laserColor}, new float[]{0,1f}, LinearGradient.TileMode.CLAMP); - //给画笔设置着色器 - paint.setShader(linearGradient); - - float wUnit = frame.width() * 1.0f/ gridColumn; - float hUnit = wUnit; - //遍历绘制网格纵线 - for (int i = 1; i < gridColumn; i++) { - canvas.drawLine(frame.left + i * wUnit, startY,frame.left + i * wUnit, scannerStart,paint); - } - - int height = gridHeight > 0 && scannerStart - frame.top > gridHeight ? gridHeight : scannerStart - frame.top; - - //遍历绘制网格横线 - for (int i = 0; i <= height/hUnit; i++) { - canvas.drawLine(frame.left, scannerStart - i * hUnit,frame.right, scannerStart - i * hUnit,paint); - } - - if(scannerStart width){ + frameWidth = size; + } + + if(frameHeight <= 0 || frameHeight > height){ + frameHeight = size; + } + + if(labelTextWidth <= 0){ + labelTextWidth = width - getPaddingLeft() - getPaddingRight(); + } + + float leftOffsets = (width - frameWidth) / 2 + framePaddingLeft - framePaddingRight; + float topOffsets = (height - frameHeight) / 2 + framePaddingTop - framePaddingBottom; + switch (frameGravity){ + case LEFT: + leftOffsets = framePaddingLeft; + break; + case TOP: + topOffsets = framePaddingTop; + break; + case RIGHT: + leftOffsets = width - frameWidth + framePaddingRight; + break; + case BOTTOM: + topOffsets = height - frameHeight + framePaddingBottom; + break; + } + + frame = new Rect((int)leftOffsets, (int)topOffsets, (int)leftOffsets + frameWidth, (int)topOffsets + frameHeight); + } + + @Override + public void onDraw(Canvas canvas) { + + if (frame == null) { + return; + } + + if(scannerStart == 0 || scannerEnd == 0) { + scannerStart = frame.top; + scannerEnd = frame.bottom - scannerLineHeight; + } + + int width = canvas.getWidth(); + int height = canvas.getHeight(); + + // 绘制模糊区域 + drawExterior(canvas,frame,width,height); + // 绘制扫描动画 + drawLaserScanner(canvas,frame); + // 绘制取景区域框 + drawFrame(canvas, frame); + // 绘制取景区域边角 + drawCorner(canvas, frame); + //绘制提示信息 + drawTextInfo(canvas, frame); + // 间隔更新取景区域 + postInvalidateDelayed(scannerAnimationDelay, frame.left, frame.top, frame.right, frame.bottom); + } + + /** + * 绘制文本 + * @param canvas + * @param frame + */ + private void drawTextInfo(Canvas canvas, Rect frame) { + if(!TextUtils.isEmpty(labelText)){ + textPaint.setColor(labelTextColor); + textPaint.setTextSize(labelTextSize); + textPaint.setTextAlign(Paint.Align.CENTER); + StaticLayout staticLayout = new StaticLayout(labelText,textPaint,labelTextWidth, Layout.Alignment.ALIGN_NORMAL,1.2f,0.0f,true); + if(labelTextLocation == TextLocation.BOTTOM){ + canvas.translate(frame.left + frame.width() / 2,frame.bottom + labelTextPadding); + }else{ + canvas.translate(frame.left + frame.width() / 2,frame.top - labelTextPadding - staticLayout.getHeight()); + } + staticLayout.draw(canvas); + } + + } + + /** + * 绘制边角 + * @param canvas + * @param frame + */ + private void drawCorner(Canvas canvas, Rect frame) { + paint.setColor(cornerColor); + //左上 + canvas.drawRect(frame.left, frame.top, frame.left + cornerRectWidth, frame.top + cornerRectHeight, paint); + canvas.drawRect(frame.left, frame.top, frame.left + cornerRectHeight, frame.top + cornerRectWidth, paint); + //右上 + canvas.drawRect(frame.right - cornerRectWidth, frame.top, frame.right, frame.top + cornerRectHeight, paint); + canvas.drawRect(frame.right - cornerRectHeight, frame.top, frame.right, frame.top + cornerRectWidth, paint); + //左下 + canvas.drawRect(frame.left, frame.bottom - cornerRectWidth, frame.left + cornerRectHeight, frame.bottom, paint); + canvas.drawRect(frame.left, frame.bottom - cornerRectHeight, frame.left + cornerRectWidth, frame.bottom, paint); + //右下 + canvas.drawRect(frame.right - cornerRectWidth, frame.bottom - cornerRectHeight, frame.right, frame.bottom, paint); + canvas.drawRect(frame.right - cornerRectHeight, frame.bottom - cornerRectWidth, frame.right, frame.bottom, paint); + } + + /** + * 绘制激光扫描线 + * @param canvas + * @param frame + */ + private void drawLaserScanner(Canvas canvas, Rect frame) { + if(laserStyle != null){ + paint.setColor(laserColor); + switch (laserStyle){ + case LINE://线 + drawLineScanner(canvas,frame); + break; + case GRID://网格 + drawGridScanner(canvas,frame); + break; + } + paint.setShader(null); + } + } + + /** + * 绘制线性式扫描 + * @param canvas + * @param frame + */ + private void drawLineScanner(Canvas canvas,Rect frame){ + //线性渐变 + LinearGradient linearGradient = new LinearGradient( + frame.left, scannerStart, + frame.left, scannerStart + scannerLineHeight, + shadeColor(laserColor), + laserColor, + Shader.TileMode.MIRROR); + + paint.setShader(linearGradient); + if(scannerStart <= scannerEnd) { + //椭圆 + RectF rectF = new RectF(frame.left + 2 * scannerLineHeight, scannerStart, frame.right - 2 * scannerLineHeight, scannerStart + scannerLineHeight); + canvas.drawOval(rectF, paint); + scannerStart += scannerLineMoveDistance; + } else { + scannerStart = frame.top; + } + } + + /** + * 绘制网格式扫描 + * @param canvas + * @param frame + */ + private void drawGridScanner(Canvas canvas,Rect frame){ + int stroke = 2; + paint.setStrokeWidth(stroke); + //计算Y轴开始位置 + int startY = gridHeight > 0 && scannerStart - frame.top > gridHeight ? scannerStart - gridHeight : frame.top; + + LinearGradient linearGradient = new LinearGradient(frame.left + frame.width()/2, startY, frame.left + frame.width()/2, scannerStart, new int[]{shadeColor(laserColor), laserColor}, new float[]{0,1f}, LinearGradient.TileMode.CLAMP); + //给画笔设置着色器 + paint.setShader(linearGradient); + + float wUnit = frame.width() * 1.0f/ gridColumn; + float hUnit = wUnit; + //遍历绘制网格纵线 + for (int i = 1; i < gridColumn; i++) { + canvas.drawLine(frame.left + i * wUnit, startY,frame.left + i * wUnit, scannerStart,paint); + } + + int height = gridHeight > 0 && scannerStart - frame.top > gridHeight ? gridHeight : scannerStart - frame.top; + + //遍历绘制网格横线 + for (int i = 0; i <= height/hUnit; i++) { + canvas.drawLine(frame.left, scannerStart - i * hUnit,frame.right, scannerStart - i * hUnit,paint); + } + + if(scannerStartJenly - */ -public class AmbientLightManager implements SensorEventListener { - - private static final int INTERVAL_TIME = 200; - - protected static final float DARK_LUX = 45.0f; - protected static final float BRIGHT_LUX = 100.0f; - - /** - * 光线太暗时,默认:照度45 lux - */ - private float darkLightLux = DARK_LUX; - /** - * 光线足够亮时,默认:照度100 lux - */ - private float brightLightLux = BRIGHT_LUX; - - private SensorManager sensorManager; - private Sensor lightSensor; - - private long lastTime; - - private boolean isLightSensorEnabled; - - private OnLightSensorEventListener mOnLightSensorEventListener; - - AmbientLightManager(Context context) { - sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); - lightSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); - isLightSensorEnabled = true; - } - - public void register() { - if (sensorManager != null && lightSensor != null) { - sensorManager.registerListener(this, lightSensor, SensorManager.SENSOR_DELAY_NORMAL); - } - } - - public void unregister() { - if (sensorManager != null && lightSensor != null) { - sensorManager.unregisterListener(this); - } - } - - - @Override - public void onSensorChanged(SensorEvent sensorEvent) { - if(isLightSensorEnabled){ - long currentTime = System.currentTimeMillis(); - if(currentTime - lastTime < INTERVAL_TIME){//降低频率 - return; - } - lastTime = currentTime; - - if (mOnLightSensorEventListener != null) { - float lightLux = sensorEvent.values[0]; - mOnLightSensorEventListener.onSensorChanged(lightLux); - if (lightLux <= darkLightLux) { - mOnLightSensorEventListener.onSensorChanged(true,darkLightLux); - } else if (lightLux >= brightLightLux) { - mOnLightSensorEventListener.onSensorChanged(false,darkLightLux); - } - } - } - } - - /** - * 设置光线足够暗的阈值(单位:lux) - * @param lightLux - */ - public void setDarkLightLux(float lightLux){ - this.darkLightLux = lightLux; - } - - /** - * 设置光线足够明亮的阈值(单位:lux) - * @param lightLux - */ - public void setBrightLightLux(float lightLux){ - this.brightLightLux = lightLux; - } - - @Override - public void onAccuracyChanged(Sensor sensor, int accuracy) { - // do nothing - } - - public boolean isLightSensorEnabled() { - return isLightSensorEnabled; - } - - /** - * 设置是否启用光线亮度传感器 - * @param lightSensorEnabled - */ - public void setLightSensorEnabled(boolean lightSensorEnabled) { - isLightSensorEnabled = lightSensorEnabled; - } - - /** - * 设置光线亮度传感器监听器,只有在 {@link #isLightSensorEnabled} 为{@code true} 才有效 - * @param listener - */ - public void setOnLightSensorEventListener(OnLightSensorEventListener listener){ - mOnLightSensorEventListener = listener; - } - - public interface OnLightSensorEventListener{ - /** - * - * @param lightLux 当前检测到的光线照度值 - */ - default void onSensorChanged(float lightLux){ - - } - - /** - * 传感器改变事件 - * @param dark 是否太暗了,当检测到的光线照度值小于{@link #darkLightLux}时,为{@code true} - * @param lightLux 当前检测到的光线照度值 - */ - void onSensorChanged(boolean dark,float lightLux); - } -} +package com.king.zxing.manager; + +/* + * Copyright (C) 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import android.content.Context; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; + +/** + * @author Jenly + */ +public class AmbientLightManager implements SensorEventListener { + + private static final int INTERVAL_TIME = 200; + + protected static final float DARK_LUX = 45.0f; + protected static final float BRIGHT_LUX = 100.0f; + + /** + * 光线太暗时,默认:照度45 lux + */ + private float darkLightLux = DARK_LUX; + /** + * 光线足够亮时,默认:照度100 lux + */ + private float brightLightLux = BRIGHT_LUX; + + private SensorManager sensorManager; + private Sensor lightSensor; + + private long lastTime; + + private boolean isLightSensorEnabled; + + private OnLightSensorEventListener mOnLightSensorEventListener; + + public AmbientLightManager(Context context) { + sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); + lightSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); + isLightSensorEnabled = true; + } + + public void register() { + if (sensorManager != null && lightSensor != null) { + sensorManager.registerListener(this, lightSensor, SensorManager.SENSOR_DELAY_NORMAL); + } + } + + public void unregister() { + if (sensorManager != null && lightSensor != null) { + sensorManager.unregisterListener(this); + } + } + + + @Override + public void onSensorChanged(SensorEvent sensorEvent) { + if(isLightSensorEnabled){ + long currentTime = System.currentTimeMillis(); + if(currentTime - lastTime < INTERVAL_TIME){//降低频率 + return; + } + lastTime = currentTime; + + if (mOnLightSensorEventListener != null) { + float lightLux = sensorEvent.values[0]; + mOnLightSensorEventListener.onSensorChanged(lightLux); + if (lightLux <= darkLightLux) { + mOnLightSensorEventListener.onSensorChanged(true,lightLux); + } else if (lightLux >= brightLightLux) { + mOnLightSensorEventListener.onSensorChanged(false,lightLux); + } + } + } + } + + /** + * 设置光线足够暗的阈值(单位:lux) + * @param lightLux + */ + public void setDarkLightLux(float lightLux){ + this.darkLightLux = lightLux; + } + + /** + * 设置光线足够明亮的阈值(单位:lux) + * @param lightLux + */ + public void setBrightLightLux(float lightLux){ + this.brightLightLux = lightLux; + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + // do nothing + } + + public boolean isLightSensorEnabled() { + return isLightSensorEnabled; + } + + /** + * 设置是否启用光线亮度传感器 + * @param lightSensorEnabled + */ + public void setLightSensorEnabled(boolean lightSensorEnabled) { + isLightSensorEnabled = lightSensorEnabled; + } + + /** + * 设置光线亮度传感器监听器,只有在 {@link #isLightSensorEnabled} 为{@code true} 才有效 + * @param listener + */ + public void setOnLightSensorEventListener(OnLightSensorEventListener listener){ + mOnLightSensorEventListener = listener; + } + + public interface OnLightSensorEventListener{ + /** + * + * @param lightLux 当前检测到的光线照度值 + */ + default void onSensorChanged(float lightLux){ + + } + + /** + * 传感器改变事件 + * @param dark 是否太暗了,当检测到的光线照度值小于{@link #darkLightLux}时,为{@code true} + * @param lightLux 当前检测到的光线照度值 + */ + void onSensorChanged(boolean dark,float lightLux); + } +} diff --git a/lib/src/main/java/com/king/zxing/BeepManager.java b/zxing-lite/src/main/java/com/king/zxing/manager/BeepManager.java similarity index 94% rename from lib/src/main/java/com/king/zxing/BeepManager.java rename to zxing-lite/src/main/java/com/king/zxing/manager/BeepManager.java index 68aefb6..d9d8bc9 100644 --- a/lib/src/main/java/com/king/zxing/BeepManager.java +++ b/zxing-lite/src/main/java/com/king/zxing/manager/BeepManager.java @@ -1,110 +1,111 @@ -package com.king.zxing; -/* - * Copyright (C) 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -import android.content.Context; -import android.content.res.AssetFileDescriptor; -import android.media.AudioManager; -import android.media.MediaPlayer; -import android.os.Vibrator; - -import com.king.zxing.util.LogUtils; - -import java.io.Closeable; - -/** - * @author Jenly - */ -public final class BeepManager implements MediaPlayer.OnErrorListener, Closeable { - - private static final long VIBRATE_DURATION = 200L; - - private final Context context; - private MediaPlayer mediaPlayer; - private Vibrator vibrator; - private boolean playBeep; - private boolean vibrate; - - BeepManager(Context context) { - this.context = context; - this.mediaPlayer = null; - updatePrefs(); - } - - public void setVibrate(boolean vibrate){ - this.vibrate = vibrate; - } - - public void setPlayBeep(boolean playBeep){ - this.playBeep = playBeep; - } - - private synchronized void updatePrefs() { - if (mediaPlayer == null) { - mediaPlayer = buildMediaPlayer(context); - } - if(vibrator == null){ - vibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE); - } - } - - public synchronized void playBeepSoundAndVibrate() { - if (playBeep && mediaPlayer != null) { - mediaPlayer.start(); - } - if (vibrate) { - vibrator.vibrate(VIBRATE_DURATION); - } - } - - private MediaPlayer buildMediaPlayer(Context context) { - MediaPlayer mediaPlayer = new MediaPlayer(); - try { - AssetFileDescriptor file = context.getResources().openRawResourceFd(R.raw.zxl_beep); - mediaPlayer.setDataSource(file.getFileDescriptor(), file.getStartOffset(), file.getLength()); - mediaPlayer.setOnErrorListener(this); - mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); - mediaPlayer.setLooping(false); - mediaPlayer.prepare(); - return mediaPlayer; - } catch (Exception e) { - LogUtils.w(e); - mediaPlayer.release(); - return null; - } - } - - @Override - public synchronized boolean onError(MediaPlayer mp, int what, int extra) { - close(); - updatePrefs(); - return true; - } - - @Override - public synchronized void close() { - try{ - if (mediaPlayer != null) { - mediaPlayer.release(); - mediaPlayer = null; - } - }catch (Exception e){ - LogUtils.e(e); - } - } - +package com.king.zxing.manager; +/* + * Copyright (C) 2010 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import android.content.Context; +import android.content.res.AssetFileDescriptor; +import android.media.AudioManager; +import android.media.MediaPlayer; +import android.os.Vibrator; + +import com.king.zxing.R; +import com.king.zxing.util.LogUtils; + +import java.io.Closeable; + +/** + * @author Jenly + */ +public final class BeepManager implements MediaPlayer.OnErrorListener, Closeable { + + private static final long VIBRATE_DURATION = 200L; + + private final Context context; + private MediaPlayer mediaPlayer; + private Vibrator vibrator; + private boolean playBeep; + private boolean vibrate; + + public BeepManager(Context context) { + this.context = context; + this.mediaPlayer = null; + updatePrefs(); + } + + public void setVibrate(boolean vibrate){ + this.vibrate = vibrate; + } + + public void setPlayBeep(boolean playBeep){ + this.playBeep = playBeep; + } + + private synchronized void updatePrefs() { + if (mediaPlayer == null) { + mediaPlayer = buildMediaPlayer(context); + } + if(vibrator == null){ + vibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE); + } + } + + public synchronized void playBeepSoundAndVibrate() { + if (playBeep && mediaPlayer != null) { + mediaPlayer.start(); + } + if (vibrate) { + vibrator.vibrate(VIBRATE_DURATION); + } + } + + private MediaPlayer buildMediaPlayer(Context context) { + MediaPlayer mediaPlayer = new MediaPlayer(); + try { + AssetFileDescriptor file = context.getResources().openRawResourceFd(R.raw.zxl_beep); + mediaPlayer.setDataSource(file.getFileDescriptor(), file.getStartOffset(), file.getLength()); + mediaPlayer.setOnErrorListener(this); + mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); + mediaPlayer.setLooping(false); + mediaPlayer.prepare(); + return mediaPlayer; + } catch (Exception e) { + LogUtils.w(e); + mediaPlayer.release(); + return null; + } + } + + @Override + public synchronized boolean onError(MediaPlayer mp, int what, int extra) { + close(); + updatePrefs(); + return true; + } + + @Override + public synchronized void close() { + try{ + if (mediaPlayer != null) { + mediaPlayer.release(); + mediaPlayer = null; + } + }catch (Exception e){ + LogUtils.e(e); + } + } + } \ No newline at end of file diff --git a/lib/src/main/java/com/king/zxing/util/CodeUtils.java b/zxing-lite/src/main/java/com/king/zxing/util/CodeUtils.java similarity index 97% rename from lib/src/main/java/com/king/zxing/util/CodeUtils.java rename to zxing-lite/src/main/java/com/king/zxing/util/CodeUtils.java index ce751fe..513b21a 100644 --- a/lib/src/main/java/com/king/zxing/util/CodeUtils.java +++ b/zxing-lite/src/main/java/com/king/zxing/util/CodeUtils.java @@ -1,666 +1,666 @@ -/* - * Copyright (C) 2018 Jenly Yu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.king.zxing.util; - -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; - -import android.text.TextPaint; -import android.text.TextUtils; - -import androidx.annotation.ColorInt; -import androidx.annotation.FloatRange; -import androidx.annotation.NonNull; - -import com.google.zxing.BarcodeFormat; -import com.google.zxing.BinaryBitmap; -import com.google.zxing.DecodeHintType; -import com.google.zxing.EncodeHintType; -import com.google.zxing.LuminanceSource; -import com.google.zxing.MultiFormatReader; -import com.google.zxing.MultiFormatWriter; -import com.google.zxing.RGBLuminanceSource; -import com.google.zxing.Result; -import com.google.zxing.WriterException; -import com.google.zxing.common.BitMatrix; -import com.google.zxing.common.GlobalHistogramBinarizer; -import com.google.zxing.common.HybridBinarizer; -import com.google.zxing.qrcode.QRCodeWriter; -import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; -import com.king.zxing.DecodeFormatManager; - -import java.util.HashMap; -import java.util.Map; - - -/** - * @author Jenly Jenly - */ -public final class CodeUtils { - - public static final int DEFAULT_REQ_WIDTH = 480; - public static final int DEFAULT_REQ_HEIGHT = 640; - - private CodeUtils(){ - throw new AssertionError(); - } - - /** - * 生成二维码 - * @param content 二维码的内容 - * @param heightPix 二维码的高 - * @return - */ - public static Bitmap createQRCode(String content, int heightPix) { - return createQRCode(content,heightPix,null); - } - - /** - * 生成二维码 - * @param content 二维码的内容 - * @param heightPix 二维码的高 - * @param codeColor 二维码的颜色 - * @return - */ - public static Bitmap createQRCode(String content, int heightPix,int codeColor) { - return createQRCode(content,heightPix,null,codeColor); - } - - /** - * 生成我二维码 - * @param content 二维码的内容 - * @param heightPix 二维码的高 - * @param logo logo大小默认占二维码的20% - * @return - */ - public static Bitmap createQRCode(String content, int heightPix, Bitmap logo) { - return createQRCode(content,heightPix,logo,Color.BLACK); - } - - /** - * 生成我二维码 - * @param content 二维码的内容 - * @param heightPix 二维码的高 - * @param logo logo大小默认占二维码的20% - * @param codeColor 二维码的颜色 - * @return - */ - public static Bitmap createQRCode(String content, int heightPix, Bitmap logo,int codeColor) { - return createQRCode(content,heightPix,logo,0.2f,codeColor); - } - - /** - * 生成二维码 - * @param content 二维码的内容 - * @param heightPix 二维码的高 - * @param logo 二维码中间的logo - * @param ratio logo所占比例 因为二维码的最大容错率为30%,所以建议ratio的范围小于0.3 - * @return - */ - public static Bitmap createQRCode(String content, int heightPix, Bitmap logo,@FloatRange(from = 0.0f,to = 1.0f)float ratio) { - //配置参数 - Map hints = new HashMap<>(); - hints.put( EncodeHintType.CHARACTER_SET, "utf-8"); - //容错级别 - hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); - //设置空白边距的宽度 - hints.put(EncodeHintType.MARGIN, 1); //default is 4 - return createQRCode(content,heightPix,logo,ratio,hints); - } - - /** - * 生成二维码 - * @param content 二维码的内容 - * @param heightPix 二维码的高 - * @param logo 二维码中间的logo - * @param ratio logo所占比例 因为二维码的最大容错率为30%,所以建议ratio的范围小于0.3 - * @param codeColor 二维码的颜色 - * @return - */ - public static Bitmap createQRCode(String content, int heightPix, Bitmap logo,@FloatRange(from = 0.0f,to = 1.0f)float ratio,int codeColor) { - //配置参数 - Map hints = new HashMap<>(); - hints.put( EncodeHintType.CHARACTER_SET, "utf-8"); - //容错级别 - hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); - //设置空白边距的宽度 - hints.put(EncodeHintType.MARGIN, 1); //default is 1 - return createQRCode(content,heightPix,logo,ratio,hints,codeColor); - } - - public static Bitmap createQRCode(String content, int heightPix, Bitmap logo,@FloatRange(from = 0.0f,to = 1.0f)float ratio,Map hints) { - return createQRCode(content,heightPix,logo,ratio,hints,Color.BLACK); - } - - /** - * 生成二维码 - * @param content 二维码的内容 - * @param heightPix 二维码的高 - * @param logo 二维码中间的logo - * @param ratio logo所占比例 因为二维码的最大容错率为30%,所以建议ratio的范围小于0.3 - * @param hints - * @param codeColor 二维码的颜色 - * @return - */ - public static Bitmap createQRCode(String content, int heightPix, Bitmap logo,@FloatRange(from = 0.0f,to = 1.0f)float ratio,Map hints,int codeColor) { - try { - - // 图像数据转换,使用了矩阵转换 - BitMatrix bitMatrix = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, heightPix, heightPix, hints); - int[] pixels = new int[heightPix * heightPix]; - // 下面这里按照二维码的算法,逐个生成二维码的图片, - // 两个for循环是图片横列扫描的结果 - for (int y = 0; y < heightPix; y++) { - for (int x = 0; x < heightPix; x++) { - if (bitMatrix.get(x, y)) { - pixels[y * heightPix + x] = codeColor; - } else { - pixels[y * heightPix + x] = Color.WHITE; - } - } - } - - // 生成二维码图片的格式 - Bitmap bitmap = Bitmap.createBitmap(heightPix, heightPix, Bitmap.Config.ARGB_8888); - bitmap.setPixels(pixels, 0, heightPix, 0, 0, heightPix, heightPix); - - if (logo != null) { - bitmap = addLogo(bitmap, logo,ratio); - } - - return bitmap; - } catch (Exception e) { - LogUtils.w(e.getMessage()); - } - - return null; - } - - /** - * 在二维码中间添加Logo图案 - * @param src - * @param logo - * @param ratio logo所占比例 因为二维码的最大容错率为30%,所以建议ratio的范围小于0.3 - * @return - */ - private static Bitmap addLogo(Bitmap src, Bitmap logo,@FloatRange(from = 0.0f,to = 1.0f) float ratio) { - if (src == null) { - return null; - } - - if (logo == null) { - return src; - } - - //获取图片的宽高 - int srcWidth = src.getWidth(); - int srcHeight = src.getHeight(); - int logoWidth = logo.getWidth(); - int logoHeight = logo.getHeight(); - - if (srcWidth == 0 || srcHeight == 0) { - return null; - } - - if (logoWidth == 0 || logoHeight == 0) { - return src; - } - - //logo大小为二维码整体大小 - float scaleFactor = srcWidth * ratio / logoWidth; - Bitmap bitmap; - try { - bitmap = Bitmap.createBitmap(srcWidth, srcHeight, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bitmap); - canvas.drawBitmap(src, 0, 0, null); - canvas.scale(scaleFactor, scaleFactor, srcWidth / 2, srcHeight / 2); - canvas.drawBitmap(logo, (srcWidth - logoWidth) / 2, (srcHeight - logoHeight) / 2, null); - canvas.save(); - canvas.restore(); - } catch (Exception e) { - bitmap = null; - LogUtils.w(e.getMessage()); - } - - return bitmap; - } - - /** - * 解析二维码图片 - * @param bitmapPath 需要解析的图片路径 - * @return - */ - public static String parseQRCode(String bitmapPath){ - Result result = parseQRCodeResult(bitmapPath); - if(result != null){ - return result.getText(); - } - return null; - } - - /** - * 解析二维码图片 - * @param bitmapPath 需要解析的图片路径 - * @return - */ - public static Result parseQRCodeResult(String bitmapPath){ - return parseQRCodeResult(bitmapPath,DEFAULT_REQ_WIDTH,DEFAULT_REQ_HEIGHT); - } - - /** - * 解析二维码图片 - * @param bitmapPath 需要解析的图片路径 - * @param reqWidth 请求目标宽度,如果实际图片宽度大于此值,会自动进行压缩处理,当 reqWidth 和 reqHeight都小于或等于0时,则不进行压缩处理 - * @param reqHeight 请求目标高度,如果实际图片高度大于此值,会自动进行压缩处理,当 reqWidth 和 reqHeight都小于或等于0时,则不进行压缩处理 - * @return - */ - public static Result parseQRCodeResult(String bitmapPath,int reqWidth,int reqHeight){ - return parseCodeResult(bitmapPath,reqWidth,reqHeight, DecodeFormatManager.QR_CODE_HINTS); - } - - /** - * 解析一维码/二维码图片 - * @param bitmapPath 需要解析的图片路径 - * @return - */ - public static String parseCode(String bitmapPath){ - return parseCode(bitmapPath, DecodeFormatManager.ALL_HINTS); - } - - /** - * 解析一维码/二维码图片 - * @param bitmapPath 需要解析的图片路径 - * @param hints 解析编码类型 - * @return - */ - public static String parseCode(String bitmapPath, Map hints){ - Result result = parseCodeResult(bitmapPath,hints); - if(result != null){ - return result.getText(); - } - return null; - } - - /** - * 解析二维码图片 - * @param bitmap 解析的图片 - * @return - */ - public static String parseQRCode(Bitmap bitmap){ - return parseCode(bitmap,DecodeFormatManager.QR_CODE_HINTS); - } - - /** - * 解析一维码/二维码图片 - * @param bitmap 解析的图片 - * @return - */ - public static String parseCode(Bitmap bitmap){ - return parseCode(bitmap,DecodeFormatManager.ALL_HINTS); - } - - /** - * 解析一维码/二维码图片 - * @param bitmap 解析的图片 - * @param hints 解析编码类型 - * @return - */ - public static String parseCode(Bitmap bitmap,Map hints){ - Result result = parseCodeResult(bitmap,hints); - if(result != null){ - return result.getText(); - } - return null; - } - - /** - * 解析一维码/二维码图片 - * @param bitmapPath - * @param hints 解析编码类型 - * @return - */ - public static Result parseCodeResult(String bitmapPath, Map hints){ - return parseCodeResult(bitmapPath,DEFAULT_REQ_WIDTH,DEFAULT_REQ_HEIGHT,hints); - } - - /** - * 解析一维码/二维码图片 - * @param bitmapPath 需要解析的图片路径 - * @param reqWidth 请求目标宽度,如果实际图片宽度大于此值,会自动进行压缩处理,当 reqWidth 和 reqHeight都小于或等于0时,则不进行压缩处理 - * @param reqHeight 请求目标高度,如果实际图片高度大于此值,会自动进行压缩处理,当 reqWidth 和 reqHeight都小于或等于0时,则不进行压缩处理 - * @param hints 解析编码类型 - * @return - */ - public static Result parseCodeResult(String bitmapPath,int reqWidth,int reqHeight, Map hints){ - return parseCodeResult(compressBitmap(bitmapPath,reqWidth,reqHeight),hints); - } - - /** - * 解析一维码/二维码图片 - * @param bitmap 解析的图片 - * @return - */ - public static Result parseCodeResult(Bitmap bitmap){ - return parseCodeResult(getRGBLuminanceSource(bitmap),DecodeFormatManager.ALL_HINTS); - } - - /** - * 解析一维码/二维码图片 - * @param bitmap 解析的图片 - * @param hints 解析编码类型 - * @return - */ - public static Result parseCodeResult(Bitmap bitmap,Map hints){ - return parseCodeResult(getRGBLuminanceSource(bitmap),hints); - } - - /** - * 解析一维码/二维码图片 - * @param source - * @param hints - * @return - */ - public static Result parseCodeResult(LuminanceSource source, Map hints){ - Result result = null; - MultiFormatReader reader = new MultiFormatReader(); - try{ - reader.setHints(hints); - if (source != null) { - result = decodeInternal(reader,source); - if(result == null){ - result = decodeInternal(reader,source.invert()); - } - if(result == null && source.isRotateSupported()){ - result = decodeInternal(reader,source.rotateCounterClockwise()); - } - } - - }catch (Exception e){ - LogUtils.w(e.getMessage()); - }finally { - reader.reset(); - } - - return result; - } - - private static Result decodeInternal(MultiFormatReader reader,LuminanceSource source){ - Result result = null; - try{ - try{ - //采用HybridBinarizer解析 - result = reader.decodeWithState(new BinaryBitmap(new HybridBinarizer(source))); - }catch (Exception e){ - - } - if(result == null){ - //如果没有解析成功,再采用GlobalHistogramBinarizer解析一次 - result = reader.decodeWithState(new BinaryBitmap(new GlobalHistogramBinarizer(source))); - } - }catch (Exception e){ - - } - return result; - } - - - - /** - * 压缩图片 - * @param path - * @return - */ - private static Bitmap compressBitmap(String path,int reqWidth,int reqHeight){ - if(reqWidth > 0 && reqHeight > 0){//都大于进行判断是否压缩 - - BitmapFactory.Options newOpts = new BitmapFactory.Options(); - // 开始读入图片,此时把options.inJustDecodeBounds 设回true了 - newOpts.inJustDecodeBounds = true;//获取原始图片大小 - BitmapFactory.decodeFile(path, newOpts);// 此时返回bm为空 - float width = newOpts.outWidth; - float height = newOpts.outHeight; - // 缩放比,由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可 - int wSize = 1;// wSize=1表示不缩放 - if (width > reqWidth) {// 如果宽度大的话根据宽度固定大小缩放 - wSize = (int) (width / reqWidth); - } - int hSize = 1;// wSize=1表示不缩放 - if (height > reqHeight) {// 如果高度高的话根据宽度固定大小缩放 - hSize = (int) (height / reqHeight); - } - int size = Math.max(wSize,hSize); - if (size <= 0) - size = 1; - newOpts.inSampleSize = size;// 设置缩放比例 - // 重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了 - newOpts.inJustDecodeBounds = false; - - return BitmapFactory.decodeFile(path, newOpts); - - } - - return BitmapFactory.decodeFile(path); - } - - - /** - * 获取RGBLuminanceSource - * @param bitmap - * @return - */ - private static RGBLuminanceSource getRGBLuminanceSource(@NonNull Bitmap bitmap){ - int width = bitmap.getWidth(); - int height = bitmap.getHeight(); - - int[] pixels = new int[width * height]; - bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight()); - return new RGBLuminanceSource(width, height, pixels); - - } - - /** - * 生成条形码 - * @param content - * @param desiredWidth - * @param desiredHeight - * @return - */ - public static Bitmap createBarCode(String content, int desiredWidth, int desiredHeight) { - return createBarCode(content,BarcodeFormat.CODE_128,desiredWidth,desiredHeight,null); - } - - /** - * 生成条形码 - * @param content - * @param format - * @param desiredWidth - * @param desiredHeight - * @return - */ - public static Bitmap createBarCode(String content,BarcodeFormat format, int desiredWidth, int desiredHeight) { - return createBarCode(content,format,desiredWidth,desiredHeight,null); - } - - public static Bitmap createBarCode(String content, int desiredWidth, int desiredHeight, boolean isShowText) { - return createBarCode(content,BarcodeFormat.CODE_128,desiredWidth,desiredHeight,null,isShowText,40,Color.BLACK); - } - - /** - * 生成条形码 - * @param content - * @param desiredWidth - * @param desiredHeight - * @param isShowText - * @param codeColor - * @return - */ - public static Bitmap createBarCode(String content, int desiredWidth, int desiredHeight, boolean isShowText,@ColorInt int codeColor) { - return createBarCode(content,BarcodeFormat.CODE_128,desiredWidth,desiredHeight,null,isShowText,40,codeColor); - } - - /** - * 生成条形码 - * @param content - * @param format - * @param desiredWidth - * @param desiredHeight - * @param hints - * @return - */ - public static Bitmap createBarCode(String content, BarcodeFormat format, int desiredWidth, int desiredHeight, Map hints) { - return createBarCode(content,format,desiredWidth,desiredHeight,hints,false,40,Color.BLACK); - } - - /** - * 生成条形码 - * @param content - * @param format - * @param desiredWidth - * @param desiredHeight - * @param hints - * @param isShowText - * @return - */ - public static Bitmap createBarCode(String content, BarcodeFormat format, int desiredWidth, int desiredHeight, Map hints, boolean isShowText) { - return createBarCode(content,format,desiredWidth,desiredHeight,hints,isShowText,40,Color.BLACK); - } - - /** - * 生成条形码 - * @param content - * @param format - * @param desiredWidth - * @param desiredHeight - * @param isShowText - * @param codeColor - * @return - */ - public static Bitmap createBarCode(String content, BarcodeFormat format, int desiredWidth, int desiredHeight, boolean isShowText,@ColorInt int codeColor) { - return createBarCode(content,format,desiredWidth,desiredHeight,null,isShowText,40,codeColor); - } - - /** - * 生成条形码 - * @param content - * @param format - * @param desiredWidth - * @param desiredHeight - * @param hints - * @param isShowText - * @return - */ - public static Bitmap createBarCode(String content, BarcodeFormat format, int desiredWidth, int desiredHeight, Map hints, boolean isShowText,@ColorInt int codeColor) { - return createBarCode(content,format,desiredWidth,desiredHeight,hints,isShowText,40,codeColor); - } - - /** - * 生成条形码 - * @param content - * @param format - * @param desiredWidth - * @param desiredHeight - * @param hints - * @param isShowText - * @param textSize - * @param codeColor - * @return - */ - public static Bitmap createBarCode(String content,BarcodeFormat format, int desiredWidth, int desiredHeight,Map hints,boolean isShowText,int textSize,@ColorInt int codeColor) { - if(TextUtils.isEmpty(content)){ - return null; - } - final int WHITE = Color.WHITE; - final int BLACK = codeColor; - - MultiFormatWriter writer = new MultiFormatWriter(); - try { - BitMatrix result = writer.encode(content, format, desiredWidth, - desiredHeight, hints); - int width = result.getWidth(); - int height = result.getHeight(); - int[] pixels = new int[width * height]; - // All are 0, or black, by default - for (int y = 0; y < height; y++) { - int offset = y * width; - for (int x = 0; x < width; x++) { - pixels[offset + x] = result.get(x, y) ? BLACK : WHITE; - } - } - - Bitmap bitmap = Bitmap.createBitmap(width, height, - Bitmap.Config.ARGB_8888); - bitmap.setPixels(pixels, 0, width, 0, 0, width, height); - if(isShowText){ - return addCode(bitmap,content,textSize,codeColor,textSize/2); - } - return bitmap; - } catch (WriterException e) { - LogUtils.w(e.getMessage()); - } - return null; - } - - /** - * 条形码下面添加文本信息 - * @param src - * @param code - * @param textSize - * @param textColor - * @return - */ - private static Bitmap addCode(Bitmap src, String code, int textSize, @ColorInt int textColor, int offset) { - if (src == null) { - return null; - } - - if (TextUtils.isEmpty(code)) { - return src; - } - - //获取图片的宽高 - int srcWidth = src.getWidth(); - int srcHeight = src.getHeight(); - - if (srcWidth <= 0 || srcHeight <= 0) { - return null; - } - - Bitmap bitmap; - try { - bitmap = Bitmap.createBitmap(srcWidth, srcHeight + textSize + offset * 2, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bitmap); - canvas.drawBitmap(src, 0, 0, null); - TextPaint paint = new TextPaint(); - paint.setTextSize(textSize); - paint.setColor(textColor); - paint.setTextAlign(Paint.Align.CENTER); - canvas.drawText(code,srcWidth/2,srcHeight + textSize /2 + offset,paint); - canvas.save(); - canvas.restore(); - } catch (Exception e) { - bitmap = null; - LogUtils.w(e.getMessage()); - } - - return bitmap; - } - - - +/* + * Copyright (C) 2018 Jenly Yu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.king.zxing.util; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; + +import android.text.TextPaint; +import android.text.TextUtils; + +import androidx.annotation.ColorInt; +import androidx.annotation.FloatRange; +import androidx.annotation.NonNull; + +import com.google.zxing.BarcodeFormat; +import com.google.zxing.BinaryBitmap; +import com.google.zxing.DecodeHintType; +import com.google.zxing.EncodeHintType; +import com.google.zxing.LuminanceSource; +import com.google.zxing.MultiFormatReader; +import com.google.zxing.MultiFormatWriter; +import com.google.zxing.RGBLuminanceSource; +import com.google.zxing.Result; +import com.google.zxing.WriterException; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.common.GlobalHistogramBinarizer; +import com.google.zxing.common.HybridBinarizer; +import com.google.zxing.qrcode.QRCodeWriter; +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; +import com.king.zxing.DecodeFormatManager; + +import java.util.HashMap; +import java.util.Map; + + +/** + * @author Jenly Jenly + */ +public final class CodeUtils { + + public static final int DEFAULT_REQ_WIDTH = 480; + public static final int DEFAULT_REQ_HEIGHT = 640; + + private CodeUtils(){ + throw new AssertionError(); + } + + /** + * 生成二维码 + * @param content 二维码的内容 + * @param heightPix 二维码的高 + * @return + */ + public static Bitmap createQRCode(String content, int heightPix) { + return createQRCode(content,heightPix,null); + } + + /** + * 生成二维码 + * @param content 二维码的内容 + * @param heightPix 二维码的高 + * @param codeColor 二维码的颜色 + * @return + */ + public static Bitmap createQRCode(String content, int heightPix,int codeColor) { + return createQRCode(content,heightPix,null,codeColor); + } + + /** + * 生成我二维码 + * @param content 二维码的内容 + * @param heightPix 二维码的高 + * @param logo logo大小默认占二维码的20% + * @return + */ + public static Bitmap createQRCode(String content, int heightPix, Bitmap logo) { + return createQRCode(content,heightPix,logo,Color.BLACK); + } + + /** + * 生成我二维码 + * @param content 二维码的内容 + * @param heightPix 二维码的高 + * @param logo logo大小默认占二维码的20% + * @param codeColor 二维码的颜色 + * @return + */ + public static Bitmap createQRCode(String content, int heightPix, Bitmap logo,int codeColor) { + return createQRCode(content,heightPix,logo,0.2f,codeColor); + } + + /** + * 生成二维码 + * @param content 二维码的内容 + * @param heightPix 二维码的高 + * @param logo 二维码中间的logo + * @param ratio logo所占比例 因为二维码的最大容错率为30%,所以建议ratio的范围小于0.3 + * @return + */ + public static Bitmap createQRCode(String content, int heightPix, Bitmap logo,@FloatRange(from = 0.0f,to = 1.0f)float ratio) { + //配置参数 + Map hints = new HashMap<>(); + hints.put( EncodeHintType.CHARACTER_SET, "utf-8"); + //容错级别 + hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); + //设置空白边距的宽度 + hints.put(EncodeHintType.MARGIN, 1); //default is 4 + return createQRCode(content,heightPix,logo,ratio,hints); + } + + /** + * 生成二维码 + * @param content 二维码的内容 + * @param heightPix 二维码的高 + * @param logo 二维码中间的logo + * @param ratio logo所占比例 因为二维码的最大容错率为30%,所以建议ratio的范围小于0.3 + * @param codeColor 二维码的颜色 + * @return + */ + public static Bitmap createQRCode(String content, int heightPix, Bitmap logo,@FloatRange(from = 0.0f,to = 1.0f)float ratio,int codeColor) { + //配置参数 + Map hints = new HashMap<>(); + hints.put( EncodeHintType.CHARACTER_SET, "utf-8"); + //容错级别 + hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); + //设置空白边距的宽度 + hints.put(EncodeHintType.MARGIN, 1); //default is 1 + return createQRCode(content,heightPix,logo,ratio,hints,codeColor); + } + + public static Bitmap createQRCode(String content, int heightPix, Bitmap logo,@FloatRange(from = 0.0f,to = 1.0f)float ratio,Map hints) { + return createQRCode(content,heightPix,logo,ratio,hints,Color.BLACK); + } + + /** + * 生成二维码 + * @param content 二维码的内容 + * @param heightPix 二维码的高 + * @param logo 二维码中间的logo + * @param ratio logo所占比例 因为二维码的最大容错率为30%,所以建议ratio的范围小于0.3 + * @param hints + * @param codeColor 二维码的颜色 + * @return + */ + public static Bitmap createQRCode(String content, int heightPix, Bitmap logo,@FloatRange(from = 0.0f,to = 1.0f)float ratio,Map hints,int codeColor) { + try { + + // 图像数据转换,使用了矩阵转换 + BitMatrix bitMatrix = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, heightPix, heightPix, hints); + int[] pixels = new int[heightPix * heightPix]; + // 下面这里按照二维码的算法,逐个生成二维码的图片, + // 两个for循环是图片横列扫描的结果 + for (int y = 0; y < heightPix; y++) { + for (int x = 0; x < heightPix; x++) { + if (bitMatrix.get(x, y)) { + pixels[y * heightPix + x] = codeColor; + } else { + pixels[y * heightPix + x] = Color.WHITE; + } + } + } + + // 生成二维码图片的格式 + Bitmap bitmap = Bitmap.createBitmap(heightPix, heightPix, Bitmap.Config.ARGB_8888); + bitmap.setPixels(pixels, 0, heightPix, 0, 0, heightPix, heightPix); + + if (logo != null) { + bitmap = addLogo(bitmap, logo,ratio); + } + + return bitmap; + } catch (Exception e) { + LogUtils.w(e.getMessage()); + } + + return null; + } + + /** + * 在二维码中间添加Logo图案 + * @param src + * @param logo + * @param ratio logo所占比例 因为二维码的最大容错率为30%,所以建议ratio的范围小于0.3 + * @return + */ + private static Bitmap addLogo(Bitmap src, Bitmap logo,@FloatRange(from = 0.0f,to = 1.0f) float ratio) { + if (src == null) { + return null; + } + + if (logo == null) { + return src; + } + + //获取图片的宽高 + int srcWidth = src.getWidth(); + int srcHeight = src.getHeight(); + int logoWidth = logo.getWidth(); + int logoHeight = logo.getHeight(); + + if (srcWidth == 0 || srcHeight == 0) { + return null; + } + + if (logoWidth == 0 || logoHeight == 0) { + return src; + } + + //logo大小为二维码整体大小 + float scaleFactor = srcWidth * ratio / logoWidth; + Bitmap bitmap; + try { + bitmap = Bitmap.createBitmap(srcWidth, srcHeight, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + canvas.drawBitmap(src, 0, 0, null); + canvas.scale(scaleFactor, scaleFactor, srcWidth / 2, srcHeight / 2); + canvas.drawBitmap(logo, (srcWidth - logoWidth) / 2, (srcHeight - logoHeight) / 2, null); + canvas.save(); + canvas.restore(); + } catch (Exception e) { + bitmap = null; + LogUtils.w(e.getMessage()); + } + + return bitmap; + } + + /** + * 解析二维码图片 + * @param bitmapPath 需要解析的图片路径 + * @return + */ + public static String parseQRCode(String bitmapPath){ + Result result = parseQRCodeResult(bitmapPath); + if(result != null){ + return result.getText(); + } + return null; + } + + /** + * 解析二维码图片 + * @param bitmapPath 需要解析的图片路径 + * @return + */ + public static Result parseQRCodeResult(String bitmapPath){ + return parseQRCodeResult(bitmapPath,DEFAULT_REQ_WIDTH,DEFAULT_REQ_HEIGHT); + } + + /** + * 解析二维码图片 + * @param bitmapPath 需要解析的图片路径 + * @param reqWidth 请求目标宽度,如果实际图片宽度大于此值,会自动进行压缩处理,当 reqWidth 和 reqHeight都小于或等于0时,则不进行压缩处理 + * @param reqHeight 请求目标高度,如果实际图片高度大于此值,会自动进行压缩处理,当 reqWidth 和 reqHeight都小于或等于0时,则不进行压缩处理 + * @return + */ + public static Result parseQRCodeResult(String bitmapPath,int reqWidth,int reqHeight){ + return parseCodeResult(bitmapPath,reqWidth,reqHeight, DecodeFormatManager.QR_CODE_HINTS); + } + + /** + * 解析一维码/二维码图片 + * @param bitmapPath 需要解析的图片路径 + * @return + */ + public static String parseCode(String bitmapPath){ + return parseCode(bitmapPath, DecodeFormatManager.ALL_HINTS); + } + + /** + * 解析一维码/二维码图片 + * @param bitmapPath 需要解析的图片路径 + * @param hints 解析编码类型 + * @return + */ + public static String parseCode(String bitmapPath, Map hints){ + Result result = parseCodeResult(bitmapPath,hints); + if(result != null){ + return result.getText(); + } + return null; + } + + /** + * 解析二维码图片 + * @param bitmap 解析的图片 + * @return + */ + public static String parseQRCode(Bitmap bitmap){ + return parseCode(bitmap,DecodeFormatManager.QR_CODE_HINTS); + } + + /** + * 解析一维码/二维码图片 + * @param bitmap 解析的图片 + * @return + */ + public static String parseCode(Bitmap bitmap){ + return parseCode(bitmap,DecodeFormatManager.ALL_HINTS); + } + + /** + * 解析一维码/二维码图片 + * @param bitmap 解析的图片 + * @param hints 解析编码类型 + * @return + */ + public static String parseCode(Bitmap bitmap,Map hints){ + Result result = parseCodeResult(bitmap,hints); + if(result != null){ + return result.getText(); + } + return null; + } + + /** + * 解析一维码/二维码图片 + * @param bitmapPath + * @param hints 解析编码类型 + * @return + */ + public static Result parseCodeResult(String bitmapPath, Map hints){ + return parseCodeResult(bitmapPath,DEFAULT_REQ_WIDTH,DEFAULT_REQ_HEIGHT,hints); + } + + /** + * 解析一维码/二维码图片 + * @param bitmapPath 需要解析的图片路径 + * @param reqWidth 请求目标宽度,如果实际图片宽度大于此值,会自动进行压缩处理,当 reqWidth 和 reqHeight都小于或等于0时,则不进行压缩处理 + * @param reqHeight 请求目标高度,如果实际图片高度大于此值,会自动进行压缩处理,当 reqWidth 和 reqHeight都小于或等于0时,则不进行压缩处理 + * @param hints 解析编码类型 + * @return + */ + public static Result parseCodeResult(String bitmapPath,int reqWidth,int reqHeight, Map hints){ + return parseCodeResult(compressBitmap(bitmapPath,reqWidth,reqHeight),hints); + } + + /** + * 解析一维码/二维码图片 + * @param bitmap 解析的图片 + * @return + */ + public static Result parseCodeResult(Bitmap bitmap){ + return parseCodeResult(getRGBLuminanceSource(bitmap),DecodeFormatManager.ALL_HINTS); + } + + /** + * 解析一维码/二维码图片 + * @param bitmap 解析的图片 + * @param hints 解析编码类型 + * @return + */ + public static Result parseCodeResult(Bitmap bitmap,Map hints){ + return parseCodeResult(getRGBLuminanceSource(bitmap),hints); + } + + /** + * 解析一维码/二维码图片 + * @param source + * @param hints + * @return + */ + public static Result parseCodeResult(LuminanceSource source, Map hints){ + Result result = null; + MultiFormatReader reader = new MultiFormatReader(); + try{ + reader.setHints(hints); + if (source != null) { + result = decodeInternal(reader,source); + if(result == null){ + result = decodeInternal(reader,source.invert()); + } + if(result == null && source.isRotateSupported()){ + result = decodeInternal(reader,source.rotateCounterClockwise()); + } + } + + }catch (Exception e){ + LogUtils.w(e.getMessage()); + }finally { + reader.reset(); + } + + return result; + } + + private static Result decodeInternal(MultiFormatReader reader,LuminanceSource source){ + Result result = null; + try{ + try{ + //采用HybridBinarizer解析 + result = reader.decodeWithState(new BinaryBitmap(new HybridBinarizer(source))); + }catch (Exception e){ + + } + if(result == null){ + //如果没有解析成功,再采用GlobalHistogramBinarizer解析一次 + result = reader.decodeWithState(new BinaryBitmap(new GlobalHistogramBinarizer(source))); + } + }catch (Exception e){ + + } + return result; + } + + + + /** + * 压缩图片 + * @param path + * @return + */ + private static Bitmap compressBitmap(String path,int reqWidth,int reqHeight){ + if(reqWidth > 0 && reqHeight > 0){//都大于进行判断是否压缩 + + BitmapFactory.Options newOpts = new BitmapFactory.Options(); + // 开始读入图片,此时把options.inJustDecodeBounds 设回true了 + newOpts.inJustDecodeBounds = true;//获取原始图片大小 + BitmapFactory.decodeFile(path, newOpts);// 此时返回bm为空 + float width = newOpts.outWidth; + float height = newOpts.outHeight; + // 缩放比,由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可 + int wSize = 1;// wSize=1表示不缩放 + if (width > reqWidth) {// 如果宽度大的话根据宽度固定大小缩放 + wSize = (int) (width / reqWidth); + } + int hSize = 1;// wSize=1表示不缩放 + if (height > reqHeight) {// 如果高度高的话根据宽度固定大小缩放 + hSize = (int) (height / reqHeight); + } + int size = Math.max(wSize,hSize); + if (size <= 0) + size = 1; + newOpts.inSampleSize = size;// 设置缩放比例 + // 重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了 + newOpts.inJustDecodeBounds = false; + + return BitmapFactory.decodeFile(path, newOpts); + + } + + return BitmapFactory.decodeFile(path); + } + + + /** + * 获取RGBLuminanceSource + * @param bitmap + * @return + */ + private static RGBLuminanceSource getRGBLuminanceSource(@NonNull Bitmap bitmap){ + int width = bitmap.getWidth(); + int height = bitmap.getHeight(); + + int[] pixels = new int[width * height]; + bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight()); + return new RGBLuminanceSource(width, height, pixels); + + } + + /** + * 生成条形码 + * @param content + * @param desiredWidth + * @param desiredHeight + * @return + */ + public static Bitmap createBarCode(String content, int desiredWidth, int desiredHeight) { + return createBarCode(content,BarcodeFormat.CODE_128,desiredWidth,desiredHeight,null); + } + + /** + * 生成条形码 + * @param content + * @param format + * @param desiredWidth + * @param desiredHeight + * @return + */ + public static Bitmap createBarCode(String content,BarcodeFormat format, int desiredWidth, int desiredHeight) { + return createBarCode(content,format,desiredWidth,desiredHeight,null); + } + + public static Bitmap createBarCode(String content, int desiredWidth, int desiredHeight, boolean isShowText) { + return createBarCode(content,BarcodeFormat.CODE_128,desiredWidth,desiredHeight,null,isShowText,40,Color.BLACK); + } + + /** + * 生成条形码 + * @param content + * @param desiredWidth + * @param desiredHeight + * @param isShowText + * @param codeColor + * @return + */ + public static Bitmap createBarCode(String content, int desiredWidth, int desiredHeight, boolean isShowText,@ColorInt int codeColor) { + return createBarCode(content,BarcodeFormat.CODE_128,desiredWidth,desiredHeight,null,isShowText,40,codeColor); + } + + /** + * 生成条形码 + * @param content + * @param format + * @param desiredWidth + * @param desiredHeight + * @param hints + * @return + */ + public static Bitmap createBarCode(String content, BarcodeFormat format, int desiredWidth, int desiredHeight, Map hints) { + return createBarCode(content,format,desiredWidth,desiredHeight,hints,false,40,Color.BLACK); + } + + /** + * 生成条形码 + * @param content + * @param format + * @param desiredWidth + * @param desiredHeight + * @param hints + * @param isShowText + * @return + */ + public static Bitmap createBarCode(String content, BarcodeFormat format, int desiredWidth, int desiredHeight, Map hints, boolean isShowText) { + return createBarCode(content,format,desiredWidth,desiredHeight,hints,isShowText,40,Color.BLACK); + } + + /** + * 生成条形码 + * @param content + * @param format + * @param desiredWidth + * @param desiredHeight + * @param isShowText + * @param codeColor + * @return + */ + public static Bitmap createBarCode(String content, BarcodeFormat format, int desiredWidth, int desiredHeight, boolean isShowText,@ColorInt int codeColor) { + return createBarCode(content,format,desiredWidth,desiredHeight,null,isShowText,40,codeColor); + } + + /** + * 生成条形码 + * @param content + * @param format + * @param desiredWidth + * @param desiredHeight + * @param hints + * @param isShowText + * @return + */ + public static Bitmap createBarCode(String content, BarcodeFormat format, int desiredWidth, int desiredHeight, Map hints, boolean isShowText,@ColorInt int codeColor) { + return createBarCode(content,format,desiredWidth,desiredHeight,hints,isShowText,40,codeColor); + } + + /** + * 生成条形码 + * @param content + * @param format + * @param desiredWidth + * @param desiredHeight + * @param hints + * @param isShowText + * @param textSize + * @param codeColor + * @return + */ + public static Bitmap createBarCode(String content,BarcodeFormat format, int desiredWidth, int desiredHeight,Map hints,boolean isShowText,int textSize,@ColorInt int codeColor) { + if(TextUtils.isEmpty(content)){ + return null; + } + final int WHITE = Color.WHITE; + final int BLACK = codeColor; + + MultiFormatWriter writer = new MultiFormatWriter(); + try { + BitMatrix result = writer.encode(content, format, desiredWidth, + desiredHeight, hints); + int width = result.getWidth(); + int height = result.getHeight(); + int[] pixels = new int[width * height]; + // All are 0, or black, by default + for (int y = 0; y < height; y++) { + int offset = y * width; + for (int x = 0; x < width; x++) { + pixels[offset + x] = result.get(x, y) ? BLACK : WHITE; + } + } + + Bitmap bitmap = Bitmap.createBitmap(width, height, + Bitmap.Config.ARGB_8888); + bitmap.setPixels(pixels, 0, width, 0, 0, width, height); + if(isShowText){ + return addCode(bitmap,content,textSize,codeColor,textSize/2); + } + return bitmap; + } catch (WriterException e) { + LogUtils.w(e.getMessage()); + } + return null; + } + + /** + * 条形码下面添加文本信息 + * @param src + * @param code + * @param textSize + * @param textColor + * @return + */ + private static Bitmap addCode(Bitmap src, String code, int textSize, @ColorInt int textColor, int offset) { + if (src == null) { + return null; + } + + if (TextUtils.isEmpty(code)) { + return src; + } + + //获取图片的宽高 + int srcWidth = src.getWidth(); + int srcHeight = src.getHeight(); + + if (srcWidth <= 0 || srcHeight <= 0) { + return null; + } + + Bitmap bitmap; + try { + bitmap = Bitmap.createBitmap(srcWidth, srcHeight + textSize + offset * 2, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + canvas.drawBitmap(src, 0, 0, null); + TextPaint paint = new TextPaint(); + paint.setTextSize(textSize); + paint.setColor(textColor); + paint.setTextAlign(Paint.Align.CENTER); + canvas.drawText(code,srcWidth/2,srcHeight + textSize /2 + offset,paint); + canvas.save(); + canvas.restore(); + } catch (Exception e) { + bitmap = null; + LogUtils.w(e.getMessage()); + } + + return bitmap; + } + + + } \ No newline at end of file diff --git a/lib/src/main/java/com/king/zxing/util/LogUtils.java b/zxing-lite/src/main/java/com/king/zxing/util/LogUtils.java similarity index 100% rename from lib/src/main/java/com/king/zxing/util/LogUtils.java rename to zxing-lite/src/main/java/com/king/zxing/util/LogUtils.java diff --git a/lib/src/main/java/com/king/zxing/util/PermissionUtils.java b/zxing-lite/src/main/java/com/king/zxing/util/PermissionUtils.java similarity index 100% rename from lib/src/main/java/com/king/zxing/util/PermissionUtils.java rename to zxing-lite/src/main/java/com/king/zxing/util/PermissionUtils.java diff --git a/lib/src/main/res/drawable-xxhdpi/zxl_flashlight_off.png b/zxing-lite/src/main/res/drawable-xxhdpi/zxl_flashlight_off.png similarity index 100% rename from lib/src/main/res/drawable-xxhdpi/zxl_flashlight_off.png rename to zxing-lite/src/main/res/drawable-xxhdpi/zxl_flashlight_off.png diff --git a/lib/src/main/res/drawable-xxhdpi/zxl_flashlight_on.png b/zxing-lite/src/main/res/drawable-xxhdpi/zxl_flashlight_on.png similarity index 100% rename from lib/src/main/res/drawable-xxhdpi/zxl_flashlight_on.png rename to zxing-lite/src/main/res/drawable-xxhdpi/zxl_flashlight_on.png diff --git a/lib/src/main/res/drawable/zxl_flashlight_selector.xml b/zxing-lite/src/main/res/drawable/zxl_flashlight_selector.xml similarity index 100% rename from lib/src/main/res/drawable/zxl_flashlight_selector.xml rename to zxing-lite/src/main/res/drawable/zxl_flashlight_selector.xml diff --git a/lib/src/main/res/layout/zxl_capture.xml b/zxing-lite/src/main/res/layout/zxl_capture.xml similarity index 100% rename from lib/src/main/res/layout/zxl_capture.xml rename to zxing-lite/src/main/res/layout/zxl_capture.xml diff --git a/lib/src/main/res/raw/zxl_beep.mp3 b/zxing-lite/src/main/res/raw/zxl_beep.mp3 similarity index 100% rename from lib/src/main/res/raw/zxl_beep.mp3 rename to zxing-lite/src/main/res/raw/zxl_beep.mp3 diff --git a/lib/src/main/res/values/attrs.xml b/zxing-lite/src/main/res/values/attrs.xml similarity index 97% rename from lib/src/main/res/values/attrs.xml rename to zxing-lite/src/main/res/values/attrs.xml index 51e8d3c..b73f114 100644 --- a/lib/src/main/res/values/attrs.xml +++ b/zxing-lite/src/main/res/values/attrs.xml @@ -1,46 +1,46 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/src/main/res/values/colors.xml b/zxing-lite/src/main/res/values/colors.xml similarity index 97% rename from lib/src/main/res/values/colors.xml rename to zxing-lite/src/main/res/values/colors.xml index ed3984c..62348b6 100644 --- a/lib/src/main/res/values/colors.xml +++ b/zxing-lite/src/main/res/values/colors.xml @@ -1,13 +1,13 @@ - - - - #60000000 - #7F1FB3E2 - #FF1FB3E2 - #FF1FB3E2 - #FFC0C0C0 - - #00000000 - #00000000 - + + + + #60000000 + #7F1FB3E2 + #FF1FB3E2 + #FF1FB3E2 + #FFC0C0C0 + + #00000000 + #00000000 + \ No newline at end of file diff --git a/lib/src/main/res/values/dimens.xml b/zxing-lite/src/main/res/values/dimens.xml similarity index 100% rename from lib/src/main/res/values/dimens.xml rename to zxing-lite/src/main/res/values/dimens.xml diff --git a/lib/src/main/res/values/styles.xml b/zxing-lite/src/main/res/values/styles.xml similarity index 100% rename from lib/src/main/res/values/styles.xml rename to zxing-lite/src/main/res/values/styles.xml diff --git a/lib/src/test/java/com/king/zxing/ExampleUnitTest.java b/zxing-lite/src/test/java/com/king/zxing/ExampleUnitTest.java similarity index 95% rename from lib/src/test/java/com/king/zxing/ExampleUnitTest.java rename to zxing-lite/src/test/java/com/king/zxing/ExampleUnitTest.java index 9d0a385..efef26a 100644 --- a/lib/src/test/java/com/king/zxing/ExampleUnitTest.java +++ b/zxing-lite/src/test/java/com/king/zxing/ExampleUnitTest.java @@ -1,17 +1,17 @@ -package com.king.zxing; - -import org.junit.Test; - -import static org.junit.Assert.*; - -/** - * Example local unit test, which will execute on the development machine (host). - * - * @see Testing documentation - */ -public class ExampleUnitTest { - @Test - public void addition_isCorrect() { - assertEquals(4, 2 + 2); - } +package com.king.zxing; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() { + assertEquals(4, 2 + 2); + } } \ No newline at end of file