支持扫二维码过小时,自动缩放
This commit is contained in:
BIN
.idea/caches/build_file_checksums.ser
generated
BIN
.idea/caches/build_file_checksums.ser
generated
Binary file not shown.
19
README.md
19
README.md
@@ -45,17 +45,17 @@ ZXingLite for Android 是ZXing的精简版,基于ZXing库优化扫码和生成
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.king.zxing</groupId>
|
<groupId>com.king.zxing</groupId>
|
||||||
<artifactId>zxing-lite</artifactId>
|
<artifactId>zxing-lite</artifactId>
|
||||||
<version>1.1.0</version>
|
<version>1.1.1</version>
|
||||||
<type>pom</type>
|
<type>pom</type>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
### Gradle:
|
### Gradle:
|
||||||
```gradle
|
```gradle
|
||||||
implementation 'com.king.zxing:zxing-lite:1.1.0'
|
implementation 'com.king.zxing:zxing-lite:1.1.1'
|
||||||
```
|
```
|
||||||
### Lvy:
|
### Lvy:
|
||||||
```lvy
|
```lvy
|
||||||
<dependency org='com.king.zxing' name='zxing-lite' rev='1.1.0'>
|
<dependency org='com.king.zxing' name='zxing-lite' rev='1.1.1'>
|
||||||
<artifact name='$AID' ext='pom'></artifact>
|
<artifact name='$AID' ext='pom'></artifact>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
@@ -106,6 +106,13 @@ api 'com.google.zxing:core:3.3.3'
|
|||||||
CodeUtils.createBarCode(content, BarcodeFormat.CODE_128,800,200);
|
CodeUtils.createBarCode(content, BarcodeFormat.CODE_128,800,200);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
如果直接使用CaptureActivity需在您项目的AndroidManifest中添加如下配置
|
||||||
|
```Xml
|
||||||
|
<activity
|
||||||
|
android:name="com.king.zxing.CaptureActivity"
|
||||||
|
android:screenOrientation="portrait"/>
|
||||||
|
```
|
||||||
|
|
||||||
### 快速实现扫码有以下几种方式:
|
### 快速实现扫码有以下几种方式:
|
||||||
|
|
||||||
> 1、直接使用CaptureActivity或者CaptureFragment。(纯洁的扫码,无任何添加剂)
|
> 1、直接使用CaptureActivity或者CaptureFragment。(纯洁的扫码,无任何添加剂)
|
||||||
@@ -121,8 +128,12 @@ api 'com.google.zxing:core:3.3.3'
|
|||||||
|
|
||||||
## 版本记录
|
## 版本记录
|
||||||
|
|
||||||
|
#### v1.1.1:2019-5-20
|
||||||
|
* 支持扫二维码过小时,自动缩放
|
||||||
|
* 支持垂直条形码识别(增强条形码识别,默认不支持,需CaptureHelper.supportVerticalCode(true)开启)
|
||||||
|
|
||||||
#### v1.1.0:2019-4-19
|
#### v1.1.0:2019-4-19
|
||||||
* 将扫码相关逻辑与界面分离,ZXingLite使用更容易扩展。
|
* 将扫码相关逻辑与界面分离,ZXingLite使用更容易扩展
|
||||||
* 新增CaptureFragment
|
* 新增CaptureFragment
|
||||||
|
|
||||||
#### v1.0.7:2019-4-9
|
#### v1.0.7:2019-4-9
|
||||||
|
|||||||
Binary file not shown.
@@ -1 +1 @@
|
|||||||
[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":9,"versionName":"1.1.0","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}]
|
[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":10,"versionName":"1.1.1","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}]
|
||||||
@@ -29,8 +29,7 @@
|
|||||||
android:name=".EasyCaptureActivity"
|
android:name=".EasyCaptureActivity"
|
||||||
android:screenOrientation="portrait"/>
|
android:screenOrientation="portrait"/>
|
||||||
<activity
|
<activity
|
||||||
android:name=".CustomCaptureActivity"
|
android:name=".CustomCaptureActivity"/>
|
||||||
android:screenOrientation="portrait"/>
|
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".CaptureFragmentActivity"
|
android:name=".CaptureFragmentActivity"
|
||||||
|
|||||||
@@ -57,7 +57,10 @@ public class CustomActivity extends AppCompatActivity implements OnCaptureCallba
|
|||||||
mCaptureHelper = new CaptureHelper(this,surfaceView,viewfinderView);
|
mCaptureHelper = new CaptureHelper(this,surfaceView,viewfinderView);
|
||||||
mCaptureHelper.onCreate();
|
mCaptureHelper.onCreate();
|
||||||
mCaptureHelper.vibrate(true)
|
mCaptureHelper.vibrate(true)
|
||||||
|
.fullScreenScan(true)//全屏扫码
|
||||||
|
.supportVerticalCode(true)//支持扫垂直条码,建议有此需求时才使用。
|
||||||
.continuousScan(isContinuousScan);
|
.continuousScan(isContinuousScan);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -50,7 +50,9 @@ public class CustomCaptureActivity extends CaptureActivity {
|
|||||||
//获取CaptureHelper,里面有扫码相关的配置设置
|
//获取CaptureHelper,里面有扫码相关的配置设置
|
||||||
getCaptureHelper().playBeep(true)//播放音效
|
getCaptureHelper().playBeep(true)//播放音效
|
||||||
.vibrate(true)//震动
|
.vibrate(true)//震动
|
||||||
|
.supportVerticalCode(true)//支持扫垂直条码,建议有此需求时才使用。
|
||||||
.continuousScan(isContinuousScan);//是否连扫
|
.continuousScan(isContinuousScan);//是否连扫
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -222,7 +222,7 @@ public class MainActivity extends AppCompatActivity implements EasyPermissions.P
|
|||||||
checkCameraPermissions();
|
checkCameraPermissions();
|
||||||
break;
|
break;
|
||||||
case R.id.btn3:
|
case R.id.btn3:
|
||||||
this.cls = CustomCaptureActivity.class;
|
this.cls = EasyCaptureActivity.class;
|
||||||
this.title = ((Button)v).getText().toString();
|
this.title = ((Button)v).getText().toString();
|
||||||
checkCameraPermissions();
|
checkCameraPermissions();
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,22 +1,21 @@
|
|||||||
package com.king.zxing;
|
package com.king.zxing;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.ActivityNotFoundException;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.content.pm.ResolveInfo;
|
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.net.Uri;
|
import android.graphics.Point;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.provider.Browser;
|
import android.view.Display;
|
||||||
import android.util.Log;
|
import android.view.WindowManager;
|
||||||
|
|
||||||
import com.google.zxing.BarcodeFormat;
|
import com.google.zxing.BarcodeFormat;
|
||||||
import com.google.zxing.DecodeHintType;
|
import com.google.zxing.DecodeHintType;
|
||||||
import com.google.zxing.Result;
|
import com.google.zxing.Result;
|
||||||
|
import com.google.zxing.ResultPoint;
|
||||||
|
import com.google.zxing.ResultPointCallback;
|
||||||
import com.king.zxing.camera.CameraManager;
|
import com.king.zxing.camera.CameraManager;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -25,7 +24,7 @@ import java.util.Map;
|
|||||||
/**
|
/**
|
||||||
* @author <a href="mailto:jenly1314@gmail.com">Jenly</a>
|
* @author <a href="mailto:jenly1314@gmail.com">Jenly</a>
|
||||||
*/
|
*/
|
||||||
public class CaptureHandler extends Handler {
|
public class CaptureHandler extends Handler implements ResultPointCallback {
|
||||||
|
|
||||||
private static final String TAG = CaptureHandler.class.getSimpleName();
|
private static final String TAG = CaptureHandler.class.getSimpleName();
|
||||||
|
|
||||||
@@ -35,6 +34,20 @@ public class CaptureHandler extends Handler {
|
|||||||
private final CameraManager cameraManager;
|
private final CameraManager cameraManager;
|
||||||
private final Activity activity;
|
private final Activity activity;
|
||||||
private final ViewfinderView viewfinderView;
|
private final ViewfinderView viewfinderView;
|
||||||
|
/**
|
||||||
|
* 是否支持垂直的条形码
|
||||||
|
*/
|
||||||
|
private boolean isSupportVerticalCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否返回扫码原图
|
||||||
|
*/
|
||||||
|
private boolean isReturnBitmap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否支持自动缩放
|
||||||
|
*/
|
||||||
|
private boolean isSupportAutoZoom;
|
||||||
|
|
||||||
|
|
||||||
private enum State {
|
private enum State {
|
||||||
@@ -51,8 +64,7 @@ public class CaptureHandler extends Handler {
|
|||||||
this.activity = activity;
|
this.activity = activity;
|
||||||
this.viewfinderView = viewfinderView;
|
this.viewfinderView = viewfinderView;
|
||||||
this.onCaptureListener = onCaptureListener;
|
this.onCaptureListener = onCaptureListener;
|
||||||
decodeThread = new DecodeThread(activity,cameraManager,this, decodeFormats, baseHints, characterSet,
|
decodeThread = new DecodeThread(activity,cameraManager,this, decodeFormats, baseHints, characterSet, this);
|
||||||
new ViewfinderResultPointCallback(viewfinderView));
|
|
||||||
decodeThread.start();
|
decodeThread.start();
|
||||||
state = State.SUCCESS;
|
state = State.SUCCESS;
|
||||||
|
|
||||||
@@ -83,47 +95,11 @@ public class CaptureHandler extends Handler {
|
|||||||
}
|
}
|
||||||
onCaptureListener.onHandleDecode((Result) message.obj, barcode, scaleFactor);
|
onCaptureListener.onHandleDecode((Result) message.obj, barcode, scaleFactor);
|
||||||
|
|
||||||
|
|
||||||
} else if (message.what == R.id.decode_failed) {// We're decoding as fast as possible, so when one decode fails, start another.
|
} else if (message.what == R.id.decode_failed) {// We're decoding as fast as possible, so when one decode fails, start another.
|
||||||
state = State.PREVIEW;
|
state = State.PREVIEW;
|
||||||
cameraManager.requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
|
cameraManager.requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
|
||||||
|
|
||||||
} else if (message.what == R.id.return_scan_result) {
|
|
||||||
activity.setResult(Activity.RESULT_OK, (Intent) message.obj);
|
|
||||||
activity.finish();
|
|
||||||
|
|
||||||
} else if (message.what == R.id.launch_product_query) {
|
|
||||||
String url = (String) message.obj;
|
|
||||||
|
|
||||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
|
||||||
intent.addFlags(Intents.FLAG_NEW_DOC);
|
|
||||||
intent.setData(Uri.parse(url));
|
|
||||||
|
|
||||||
ResolveInfo resolveInfo =
|
|
||||||
activity.getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
|
|
||||||
String browserPackageName = null;
|
|
||||||
if (resolveInfo != null && resolveInfo.activityInfo != null) {
|
|
||||||
browserPackageName = resolveInfo.activityInfo.packageName;
|
|
||||||
Log.d(TAG, "Using browser in package " + browserPackageName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Needed for default Android browser / Chrome only apparently
|
|
||||||
if (browserPackageName != null) {
|
|
||||||
switch (browserPackageName) {
|
|
||||||
case "com.android.browser":
|
|
||||||
case "com.android.chrome":
|
|
||||||
intent.setPackage(browserPackageName);
|
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
||||||
intent.putExtra(Browser.EXTRA_APPLICATION_ID, browserPackageName);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
activity.startActivity(intent);
|
|
||||||
} catch (ActivityNotFoundException ignored) {
|
|
||||||
Log.w(TAG, "Can't find anything to handle VIEW of URI " + url);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,4 +127,75 @@ public class CaptureHandler extends Handler {
|
|||||||
viewfinderView.drawViewfinder();
|
viewfinderView.drawViewfinder();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void foundPossibleResultPoint(ResultPoint point) {
|
||||||
|
if(viewfinderView!=null){
|
||||||
|
ResultPoint resultPoint = transform(point);
|
||||||
|
viewfinderView.addPossibleResultPoint(resultPoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isScreenPortrait(Context context){
|
||||||
|
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||||
|
Display display = manager.getDefaultDisplay();
|
||||||
|
Point screenResolution = new Point();
|
||||||
|
display.getSize(screenResolution);
|
||||||
|
return screenResolution.x < screenResolution.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private ResultPoint transform(ResultPoint originPoint) {
|
||||||
|
Point screenPoint = cameraManager.getScreenResolution();
|
||||||
|
Point cameraPoint = cameraManager.getCameraResolution();
|
||||||
|
|
||||||
|
float scaleX;
|
||||||
|
float scaleY;
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
|
||||||
|
if(screenPoint.x < screenPoint.y){
|
||||||
|
scaleX = 1.0f * screenPoint.x / cameraPoint.y;
|
||||||
|
scaleY = 1.0f * screenPoint.y / cameraPoint.x;
|
||||||
|
|
||||||
|
x = originPoint.getX() * scaleX - Math.max(screenPoint.x,cameraPoint.y)/2;
|
||||||
|
y = originPoint.getY() * scaleY - Math.min(screenPoint.y,cameraPoint.x)/2;
|
||||||
|
}else{
|
||||||
|
scaleX = 1.0f * screenPoint.x / cameraPoint.x;
|
||||||
|
scaleY = 1.0f * screenPoint.y / cameraPoint.y;
|
||||||
|
|
||||||
|
x = originPoint.getX() * scaleX - Math.min(screenPoint.y,cameraPoint.y)/2;
|
||||||
|
y = originPoint.getY() * scaleY - Math.max(screenPoint.x,cameraPoint.x)/2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return new ResultPoint(x,y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSupportVerticalCode() {
|
||||||
|
return isSupportVerticalCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSupportVerticalCode(boolean supportVerticalCode) {
|
||||||
|
isSupportVerticalCode = supportVerticalCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isReturnBitmap() {
|
||||||
|
return isReturnBitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReturnBitmap(boolean returnBitmap) {
|
||||||
|
isReturnBitmap = returnBitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSupportAutoZoom() {
|
||||||
|
return isSupportAutoZoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSupportAutoZoom(boolean supportAutoZoom) {
|
||||||
|
isSupportAutoZoom = supportAutoZoom;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,6 +75,12 @@ public class CaptureHelper implements CaptureLifecycle,CaptureTouchEvent,Capture
|
|||||||
*/
|
*/
|
||||||
private boolean isSupportZoom = true;
|
private boolean isSupportZoom = true;
|
||||||
private float oldDistance;
|
private float oldDistance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否支持自动缩放(变焦),默认支持
|
||||||
|
*/
|
||||||
|
private boolean isSupportAutoZoom = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否支持连扫,默认不支持
|
* 是否支持连扫,默认不支持
|
||||||
*/
|
*/
|
||||||
@@ -92,6 +98,21 @@ public class CaptureHelper implements CaptureLifecycle,CaptureTouchEvent,Capture
|
|||||||
*/
|
*/
|
||||||
private boolean isVibrate;
|
private boolean isVibrate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否支持垂直的条形码
|
||||||
|
*/
|
||||||
|
private boolean isSupportVerticalCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否返回扫码原图
|
||||||
|
*/
|
||||||
|
private boolean isReturnBitmap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否支持全屏扫码识别
|
||||||
|
*/
|
||||||
|
private boolean isFullScreenScan;
|
||||||
|
|
||||||
private OnCaptureCallback onCaptureCallback;
|
private OnCaptureCallback onCaptureCallback;
|
||||||
|
|
||||||
|
|
||||||
@@ -115,7 +136,7 @@ public class CaptureHelper implements CaptureLifecycle,CaptureTouchEvent,Capture
|
|||||||
ambientLightManager = new AmbientLightManager(activity);
|
ambientLightManager = new AmbientLightManager(activity);
|
||||||
|
|
||||||
cameraManager = new CameraManager(activity);
|
cameraManager = new CameraManager(activity);
|
||||||
|
cameraManager.setFullScreenScan(isFullScreenScan);
|
||||||
callback = new SurfaceHolder.Callback() {
|
callback = new SurfaceHolder.Callback() {
|
||||||
@Override
|
@Override
|
||||||
public void surfaceCreated(SurfaceHolder holder) {
|
public void surfaceCreated(SurfaceHolder holder) {
|
||||||
@@ -236,6 +257,10 @@ public class CaptureHelper implements CaptureLifecycle,CaptureTouchEvent,Capture
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化Camera
|
||||||
|
* @param surfaceHolder
|
||||||
|
*/
|
||||||
private void initCamera(SurfaceHolder surfaceHolder) {
|
private void initCamera(SurfaceHolder surfaceHolder) {
|
||||||
if (surfaceHolder == null) {
|
if (surfaceHolder == null) {
|
||||||
throw new IllegalStateException("No SurfaceHolder provided");
|
throw new IllegalStateException("No SurfaceHolder provided");
|
||||||
@@ -249,6 +274,9 @@ public class CaptureHelper implements CaptureLifecycle,CaptureTouchEvent,Capture
|
|||||||
// Creating the handler starts the preview, which can also throw a RuntimeException.
|
// Creating the handler starts the preview, which can also throw a RuntimeException.
|
||||||
if (captureHandler == null) {
|
if (captureHandler == null) {
|
||||||
captureHandler = new CaptureHandler(activity,viewfinderView,onCaptureListener, decodeFormats, decodeHints, characterSet, cameraManager);
|
captureHandler = new CaptureHandler(activity,viewfinderView,onCaptureListener, decodeFormats, decodeHints, characterSet, cameraManager);
|
||||||
|
captureHandler.setSupportVerticalCode(isSupportVerticalCode);
|
||||||
|
captureHandler.setReturnBitmap(isReturnBitmap);
|
||||||
|
captureHandler.setSupportAutoZoom(isSupportAutoZoom);
|
||||||
}
|
}
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
Log.w(TAG, ioe);
|
Log.w(TAG, ioe);
|
||||||
@@ -388,10 +416,10 @@ public class CaptureHelper implements CaptureLifecycle,CaptureTouchEvent,Capture
|
|||||||
public void onResult(Result result){
|
public void onResult(Result result){
|
||||||
String text = result.getText();
|
String text = result.getText();
|
||||||
if(isContinuousScan){
|
if(isContinuousScan){
|
||||||
if(isAutoRestartPreviewAndDecode){
|
|
||||||
if(onCaptureCallback!=null){
|
if(onCaptureCallback!=null){
|
||||||
onCaptureCallback.onResultCallback(text);
|
onCaptureCallback.onResultCallback(text);
|
||||||
}
|
}
|
||||||
|
if(isAutoRestartPreviewAndDecode){
|
||||||
restartPreviewAndDecode();
|
restartPreviewAndDecode();
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
@@ -461,7 +489,7 @@ public class CaptureHelper implements CaptureLifecycle,CaptureTouchEvent,Capture
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* 设置支持的解码一/二维码格式,默认常规的码都支持
|
||||||
* @param decodeFormats
|
* @param decodeFormats
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@@ -471,7 +499,7 @@ public class CaptureHelper implements CaptureLifecycle,CaptureTouchEvent,Capture
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* {@link DecodeHintType}
|
||||||
* @param decodeHints
|
* @param decodeHints
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@@ -481,7 +509,7 @@ public class CaptureHelper implements CaptureLifecycle,CaptureTouchEvent,Capture
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* 设置解码时编码字符集
|
||||||
* @param characterSet
|
* @param characterSet
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@@ -490,6 +518,60 @@ public class CaptureHelper implements CaptureLifecycle,CaptureTouchEvent,Capture
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置是否支持扫垂直的条码
|
||||||
|
* @param supportVerticalCode 默认为false,想要增强扫条码识别度时可使用,相应的会增加性能消耗。
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public CaptureHelper supportVerticalCode(boolean supportVerticalCode) {
|
||||||
|
this.isSupportVerticalCode = supportVerticalCode;
|
||||||
|
if(captureHandler!=null){
|
||||||
|
captureHandler.setSupportVerticalCode(isSupportVerticalCode);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置返回扫码原图
|
||||||
|
* @param returnBitmap 默认为false,当返回true表示扫码就结果会返回扫码原图,相应的会增加性能消耗。
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public CaptureHelper returnBitmap(boolean returnBitmap) {
|
||||||
|
isReturnBitmap = returnBitmap;
|
||||||
|
if(captureHandler!=null){
|
||||||
|
captureHandler.setReturnBitmap(isReturnBitmap);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置是否支持自动缩放
|
||||||
|
* @param supportAutoZoom
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public CaptureHelper supportAutoZoom(boolean supportAutoZoom) {
|
||||||
|
isSupportAutoZoom = supportAutoZoom;
|
||||||
|
if(captureHandler!=null){
|
||||||
|
captureHandler.setSupportAutoZoom(isSupportAutoZoom);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置是否支持全屏扫码识别
|
||||||
|
* @param fullScreenScan
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public CaptureHelper fullScreenScan(boolean fullScreenScan) {
|
||||||
|
isFullScreenScan = fullScreenScan;
|
||||||
|
if(cameraManager!=null){
|
||||||
|
cameraManager.setFullScreenScan(isFullScreenScan);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置扫码回调
|
* 设置扫码回调
|
||||||
* @param callback
|
* @param callback
|
||||||
|
|||||||
@@ -18,17 +18,9 @@ package com.king.zxing;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import com.google.zxing.BinaryBitmap;
|
|
||||||
import com.google.zxing.DecodeHintType;
|
|
||||||
import com.google.zxing.MultiFormatReader;
|
|
||||||
import com.google.zxing.NotFoundException;
|
|
||||||
import com.google.zxing.PlanarYUVLuminanceSource;
|
|
||||||
import com.google.zxing.Result;
|
|
||||||
import com.google.zxing.common.GlobalHistogramBinarizer;
|
|
||||||
import com.google.zxing.common.HybridBinarizer;
|
|
||||||
import com.king.zxing.camera.CameraManager;
|
|
||||||
|
|
||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
|
import android.graphics.PointF;
|
||||||
|
import android.hardware.Camera;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
@@ -37,6 +29,16 @@ import android.util.Log;
|
|||||||
import android.view.Display;
|
import android.view.Display;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
|
|
||||||
|
import com.google.zxing.BarcodeFormat;
|
||||||
|
import com.google.zxing.BinaryBitmap;
|
||||||
|
import com.google.zxing.DecodeHintType;
|
||||||
|
import com.google.zxing.MultiFormatReader;
|
||||||
|
import com.google.zxing.PlanarYUVLuminanceSource;
|
||||||
|
import com.google.zxing.Result;
|
||||||
|
import com.google.zxing.ResultPoint;
|
||||||
|
import com.google.zxing.common.HybridBinarizer;
|
||||||
|
import com.king.zxing.camera.CameraManager;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -46,11 +48,13 @@ final class DecodeHandler extends Handler {
|
|||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final CameraManager cameraManager;
|
private final CameraManager cameraManager;
|
||||||
private final Handler handler;
|
private final CaptureHandler handler;
|
||||||
private final MultiFormatReader multiFormatReader;
|
private final MultiFormatReader multiFormatReader;
|
||||||
private boolean running = true;
|
private boolean running = true;
|
||||||
|
|
||||||
DecodeHandler(Context context, CameraManager cameraManager,Handler handler, Map<DecodeHintType,Object> hints) {
|
private long lastZoomTime;
|
||||||
|
|
||||||
|
DecodeHandler(Context context, CameraManager cameraManager,CaptureHandler handler, Map<DecodeHintType,Object> hints) {
|
||||||
multiFormatReader = new MultiFormatReader();
|
multiFormatReader = new MultiFormatReader();
|
||||||
multiFormatReader.setHints(hints);
|
multiFormatReader.setHints(hints);
|
||||||
this.context = context;
|
this.context = context;
|
||||||
@@ -64,7 +68,7 @@ final class DecodeHandler extends Handler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (message.what == R.id.decode) {
|
if (message.what == R.id.decode) {
|
||||||
decode((byte[]) message.obj, message.arg1, message.arg2,isScreenPortrait());
|
decode((byte[]) message.obj, message.arg1, message.arg2,isScreenPortrait(),handler.isSupportVerticalCode());
|
||||||
|
|
||||||
} else if (message.what == R.id.quit) {
|
} else if (message.what == R.id.quit) {
|
||||||
running = false;
|
running = false;
|
||||||
@@ -89,11 +93,85 @@ final class DecodeHandler extends Handler {
|
|||||||
* @param width The width of the preview frame.
|
* @param width The width of the preview frame.
|
||||||
* @param height The height of the preview frame.
|
* @param height The height of the preview frame.
|
||||||
*/
|
*/
|
||||||
private void decode(byte[] data, int width, int height,boolean isScreenPortrait) {
|
private void decode(byte[] data, int width, int height,boolean isScreenPortrait,boolean isSupportVerticalCode) {
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
Result rawResult = null;
|
Result rawResult = null;
|
||||||
|
PlanarYUVLuminanceSource source = buildPlanarYUVLuminanceSource(data,width,height,isScreenPortrait);
|
||||||
|
|
||||||
|
if (source != null) {
|
||||||
|
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
|
||||||
|
try {
|
||||||
|
rawResult = multiFormatReader.decodeWithState(bitmap);
|
||||||
|
} catch (Exception e) {
|
||||||
|
if(isSupportVerticalCode){
|
||||||
|
source = buildPlanarYUVLuminanceSource(data,width,height,!isScreenPortrait);
|
||||||
|
if(source!=null){
|
||||||
|
BinaryBitmap bitmap1 = new BinaryBitmap(new HybridBinarizer(source));
|
||||||
|
try{
|
||||||
|
rawResult = multiFormatReader.decodeWithState(bitmap1);
|
||||||
|
}catch (Exception e1){
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
multiFormatReader.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rawResult != null) {
|
||||||
|
// Don't log the barcode contents for security.
|
||||||
|
long end = System.currentTimeMillis();
|
||||||
|
Log.d(TAG, "Found barcode in " + (end - start) + " ms");
|
||||||
|
|
||||||
|
BarcodeFormat barcodeFormat = rawResult.getBarcodeFormat();
|
||||||
|
if(handler!=null && handler.isSupportAutoZoom() && barcodeFormat == BarcodeFormat.QR_CODE){
|
||||||
|
|
||||||
|
ResultPoint[] resultPoints = rawResult.getResultPoints();
|
||||||
|
if(resultPoints.length >= 3){
|
||||||
|
float distance1 = ResultPoint.distance(resultPoints[0],resultPoints[1]);
|
||||||
|
float distance2 = ResultPoint.distance(resultPoints[1],resultPoints[2]);
|
||||||
|
float distance3 = ResultPoint.distance(resultPoints[0],resultPoints[2]);
|
||||||
|
int maxDistance = (int)Math.max(Math.max(distance1,distance2),distance3);
|
||||||
|
if(handleAutoZoom(maxDistance,width)){
|
||||||
|
Message message = Message.obtain();
|
||||||
|
message.what = R.id.decode_succeeded;
|
||||||
|
message.obj = rawResult;
|
||||||
|
if(handler.isReturnBitmap()){
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundleThumbnail(source, bundle);
|
||||||
|
message.setData(bundle);
|
||||||
|
}
|
||||||
|
handler.sendMessageDelayed(message,300);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handler != null) {
|
||||||
|
Message message = Message.obtain(handler, R.id.decode_succeeded, rawResult);
|
||||||
|
if(handler.isReturnBitmap()){
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundleThumbnail(source, bundle);
|
||||||
|
message.setData(bundle);
|
||||||
|
}
|
||||||
|
message.sendToTarget();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (handler != null) {
|
||||||
|
Message message = Message.obtain(handler, R.id.decode_failed);
|
||||||
|
message.sendToTarget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private PlanarYUVLuminanceSource buildPlanarYUVLuminanceSource(byte[] data, int width, int height,boolean isRotate){
|
||||||
PlanarYUVLuminanceSource source;
|
PlanarYUVLuminanceSource source;
|
||||||
if(isScreenPortrait){
|
if(isRotate){
|
||||||
byte[] rotatedData = new byte[data.length];
|
byte[] rotatedData = new byte[data.length];
|
||||||
for (int y = 0; y < height; y++) {
|
for (int y = 0; y < height; y++) {
|
||||||
for (int x = 0; x < width; x++)
|
for (int x = 0; x < width; x++)
|
||||||
@@ -106,39 +184,7 @@ final class DecodeHandler extends Handler {
|
|||||||
}else{
|
}else{
|
||||||
source = cameraManager.buildLuminanceSource(data, width, height);
|
source = cameraManager.buildLuminanceSource(data, width, height);
|
||||||
}
|
}
|
||||||
if (source != null) {
|
return source;
|
||||||
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
|
|
||||||
try {
|
|
||||||
rawResult = multiFormatReader.decodeWithState(bitmap);
|
|
||||||
} catch (Exception e) {
|
|
||||||
BinaryBitmap bitmap1 = new BinaryBitmap(new GlobalHistogramBinarizer(source));
|
|
||||||
try {
|
|
||||||
rawResult = multiFormatReader.decode(bitmap1);
|
|
||||||
} catch (NotFoundException ne) {
|
|
||||||
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
multiFormatReader.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rawResult != null) {
|
|
||||||
// Don't log the barcode contents for security.
|
|
||||||
long end = System.currentTimeMillis();
|
|
||||||
Log.d(TAG, "Found barcode in " + (end - start) + " ms");
|
|
||||||
if (handler != null) {
|
|
||||||
Message message = Message.obtain(handler, R.id.decode_succeeded, rawResult);
|
|
||||||
Bundle bundle = new Bundle();
|
|
||||||
bundleThumbnail(source, bundle);
|
|
||||||
message.setData(bundle);
|
|
||||||
message.sendToTarget();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (handler != null) {
|
|
||||||
Message message = Message.obtain(handler, R.id.decode_failed);
|
|
||||||
message.sendToTarget();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void bundleThumbnail(PlanarYUVLuminanceSource source, Bundle bundle) {
|
private static void bundleThumbnail(PlanarYUVLuminanceSource source, Bundle bundle) {
|
||||||
@@ -152,4 +198,31 @@ final class DecodeHandler extends Handler {
|
|||||||
bundle.putFloat(DecodeThread.BARCODE_SCALED_FACTOR, (float) width / source.getWidth());
|
bundle.putFloat(DecodeThread.BARCODE_SCALED_FACTOR, (float) width / source.getWidth());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean handleAutoZoom(int length,int width){
|
||||||
|
if(lastZoomTime > System.currentTimeMillis() - 1000){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(length<width/5){
|
||||||
|
|
||||||
|
Camera camera = cameraManager.getOpenCamera().getCamera();
|
||||||
|
if(camera!=null){
|
||||||
|
Camera.Parameters params = camera.getParameters();
|
||||||
|
if (params.isZoomSupported()) {
|
||||||
|
int maxZoom = params.getMaxZoom();
|
||||||
|
int zoom = params.getZoom();
|
||||||
|
params.setZoom(Math.min(zoom + maxZoom/5,maxZoom));
|
||||||
|
camera.setParameters(params);
|
||||||
|
lastZoomTime = System.currentTimeMillis();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
Log.i(TAG, "zoom not supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,237 +0,0 @@
|
|||||||
package com.king.zxing;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2013 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 java.util.EnumMap;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import com.google.zxing.DecodeHintType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Lachezar Dobrev
|
|
||||||
*/
|
|
||||||
public final class DecodeHintManager {
|
|
||||||
|
|
||||||
private static final String TAG = DecodeHintManager.class.getSimpleName();
|
|
||||||
|
|
||||||
// This pattern is used in decoding integer arrays.
|
|
||||||
private static final Pattern COMMA = Pattern.compile(",");
|
|
||||||
|
|
||||||
private DecodeHintManager() {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Split a query string into a list of name-value pairs.</p>
|
|
||||||
*
|
|
||||||
* <p>This is an alternative to the {@link Uri#getQueryParameterNames()} and
|
|
||||||
* {@link Uri#getQueryParameters(String)}, which are quirky and not suitable
|
|
||||||
* for exist-only Uri parameters.</p>
|
|
||||||
*
|
|
||||||
* <p>This method ignores multiple parameters with the same name and returns the
|
|
||||||
* first one only. This is technically incorrect, but should be acceptable due
|
|
||||||
* to the method of processing Hints: no multiple values for a hint.</p>
|
|
||||||
*
|
|
||||||
* @param query query to split
|
|
||||||
* @return name-value pairs
|
|
||||||
*/
|
|
||||||
private static Map<String,String> splitQuery(String query) {
|
|
||||||
Map<String,String> map = new HashMap<>();
|
|
||||||
int pos = 0;
|
|
||||||
while (pos < query.length()) {
|
|
||||||
if (query.charAt(pos) == '&') {
|
|
||||||
// Skip consecutive ampersand separators.
|
|
||||||
pos ++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
int amp = query.indexOf('&', pos);
|
|
||||||
int equ = query.indexOf('=', pos);
|
|
||||||
if (amp < 0) {
|
|
||||||
// This is the last element in the query, no more ampersand elements.
|
|
||||||
String name;
|
|
||||||
String text;
|
|
||||||
if (equ < 0) {
|
|
||||||
// No equal sign
|
|
||||||
name = query.substring(pos);
|
|
||||||
name = name.replace('+', ' '); // Preemptively decode +
|
|
||||||
name = Uri.decode(name);
|
|
||||||
text = "";
|
|
||||||
} else {
|
|
||||||
// Split name and text.
|
|
||||||
name = query.substring(pos, equ);
|
|
||||||
name = name.replace('+', ' '); // Preemptively decode +
|
|
||||||
name = Uri.decode(name);
|
|
||||||
text = query.substring(equ + 1);
|
|
||||||
text = text.replace('+', ' '); // Preemptively decode +
|
|
||||||
text = Uri.decode(text);
|
|
||||||
}
|
|
||||||
if (!map.containsKey(name)) {
|
|
||||||
map.put(name, text);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (equ < 0 || equ > amp) {
|
|
||||||
// No equal sign until the &: this is a simple parameter with no value.
|
|
||||||
String name = query.substring(pos, amp);
|
|
||||||
name = name.replace('+', ' '); // Preemptively decode +
|
|
||||||
name = Uri.decode(name);
|
|
||||||
if (!map.containsKey(name)) {
|
|
||||||
map.put(name, "");
|
|
||||||
}
|
|
||||||
pos = amp + 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String name = query.substring(pos, equ);
|
|
||||||
name = name.replace('+', ' '); // Preemptively decode +
|
|
||||||
name = Uri.decode(name);
|
|
||||||
String text = query.substring(equ + 1, amp);
|
|
||||||
text = text.replace('+', ' '); // Preemptively decode +
|
|
||||||
text = Uri.decode(text);
|
|
||||||
if (!map.containsKey(name)) {
|
|
||||||
map.put(name, text);
|
|
||||||
}
|
|
||||||
pos = amp + 1;
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Map<DecodeHintType,?> parseDecodeHints(Uri inputUri) {
|
|
||||||
String query = inputUri.getEncodedQuery();
|
|
||||||
if (query == null || query.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract parameters
|
|
||||||
Map<String, String> parameters = splitQuery(query);
|
|
||||||
|
|
||||||
Map<DecodeHintType, Object> hints = new EnumMap<>(DecodeHintType.class);
|
|
||||||
|
|
||||||
for (DecodeHintType hintType: DecodeHintType.values()) {
|
|
||||||
|
|
||||||
if (hintType == DecodeHintType.CHARACTER_SET ||
|
|
||||||
hintType == DecodeHintType.NEED_RESULT_POINT_CALLBACK ||
|
|
||||||
hintType == DecodeHintType.POSSIBLE_FORMATS) {
|
|
||||||
continue; // This hint is specified in another way
|
|
||||||
}
|
|
||||||
|
|
||||||
String parameterName = hintType.name();
|
|
||||||
String parameterText = parameters.get(parameterName);
|
|
||||||
if (parameterText == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (hintType.getValueType().equals(Object.class)) {
|
|
||||||
// This is an unspecified type of hint content. Use the value as is.
|
|
||||||
// TODO: Can we make a different assumption on this?
|
|
||||||
hints.put(hintType, parameterText);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (hintType.getValueType().equals(Void.class)) {
|
|
||||||
// Void hints are just flags: use the constant specified by DecodeHintType
|
|
||||||
hints.put(hintType, Boolean.TRUE);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (hintType.getValueType().equals(String.class)) {
|
|
||||||
// A string hint: use the decoded value.
|
|
||||||
hints.put(hintType, parameterText);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (hintType.getValueType().equals(Boolean.class)) {
|
|
||||||
// A boolean hint: a few values for false, everything else is true.
|
|
||||||
// An empty parameter is simply a flag-style parameter, assuming true
|
|
||||||
if (parameterText.isEmpty()) {
|
|
||||||
hints.put(hintType, Boolean.TRUE);
|
|
||||||
} else if ("0".equals(parameterText) ||
|
|
||||||
"false".equalsIgnoreCase(parameterText) ||
|
|
||||||
"no".equalsIgnoreCase(parameterText)) {
|
|
||||||
hints.put(hintType, Boolean.FALSE);
|
|
||||||
} else {
|
|
||||||
hints.put(hintType, Boolean.TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (hintType.getValueType().equals(int[].class)) {
|
|
||||||
// An integer array. Used to specify valid lengths.
|
|
||||||
// Strip a trailing comma as in Java style array initialisers.
|
|
||||||
if (!parameterText.isEmpty() && parameterText.charAt(parameterText.length() - 1) == ',') {
|
|
||||||
parameterText = parameterText.substring(0, parameterText.length() - 1);
|
|
||||||
}
|
|
||||||
String[] values = COMMA.split(parameterText);
|
|
||||||
int[] array = new int[values.length];
|
|
||||||
for (int i = 0; i < values.length; i++) {
|
|
||||||
try {
|
|
||||||
array[i] = Integer.parseInt(values[i]);
|
|
||||||
} catch (NumberFormatException ignored) {
|
|
||||||
Log.w(TAG, "Skipping array of integers hint " + hintType + " due to invalid numeric value: '" + values[i] + '\'');
|
|
||||||
array = null;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (array != null) {
|
|
||||||
hints.put(hintType, array);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Log.w(TAG, "Unsupported hint type '" + hintType + "' of type " + hintType.getValueType());
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.i(TAG, "Hints from the URI: " + hints);
|
|
||||||
return hints;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Map<DecodeHintType, Object> parseDecodeHints(Intent intent) {
|
|
||||||
Bundle extras = intent.getExtras();
|
|
||||||
if (extras == null || extras.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Map<DecodeHintType,Object> hints = new EnumMap<>(DecodeHintType.class);
|
|
||||||
|
|
||||||
for (DecodeHintType hintType: DecodeHintType.values()) {
|
|
||||||
|
|
||||||
if (hintType == DecodeHintType.CHARACTER_SET ||
|
|
||||||
hintType == DecodeHintType.NEED_RESULT_POINT_CALLBACK ||
|
|
||||||
hintType == DecodeHintType.POSSIBLE_FORMATS) {
|
|
||||||
continue; // This hint is specified in another way
|
|
||||||
}
|
|
||||||
|
|
||||||
String hintName = hintType.name();
|
|
||||||
if (extras.containsKey(hintName)) {
|
|
||||||
if (hintType.getValueType().equals(Void.class)) {
|
|
||||||
// Void hints are just flags: use the constant specified by the DecodeHintType
|
|
||||||
hints.put(hintType, Boolean.TRUE);
|
|
||||||
} else {
|
|
||||||
Object hintData = extras.get(hintName);
|
|
||||||
if (hintType.getValueType().isInstance(hintData)) {
|
|
||||||
hints.put(hintType, hintData);
|
|
||||||
} else {
|
|
||||||
Log.w(TAG, "Ignoring hint " + hintType + " because it is not assignable from " + hintData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.i(TAG, "Hints from the Intent: " + hints);
|
|
||||||
return hints;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
package com.king.zxing;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2009 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 com.google.zxing.ResultPoint;
|
|
||||||
import com.google.zxing.ResultPointCallback;
|
|
||||||
|
|
||||||
final class ViewfinderResultPointCallback implements ResultPointCallback {
|
|
||||||
|
|
||||||
private final ViewfinderView viewfinderView;
|
|
||||||
|
|
||||||
ViewfinderResultPointCallback(ViewfinderView viewfinderView) {
|
|
||||||
this.viewfinderView = viewfinderView;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void foundPossibleResultPoint(ResultPoint point) {
|
|
||||||
viewfinderView.addPossibleResultPoint(point);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -27,9 +27,11 @@ import android.graphics.LinearGradient;
|
|||||||
import android.graphics.Matrix;
|
import android.graphics.Matrix;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Path;
|
import android.graphics.Path;
|
||||||
|
import android.graphics.PointF;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
import android.graphics.Shader;
|
import android.graphics.Shader;
|
||||||
|
import android.support.annotation.ColorInt;
|
||||||
import android.support.annotation.ColorRes;
|
import android.support.annotation.ColorRes;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.content.ContextCompat;
|
import android.support.v4.content.ContextCompat;
|
||||||
@@ -39,6 +41,7 @@ import android.text.TextPaint;
|
|||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
|
import android.util.Log;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
@@ -58,7 +61,7 @@ public final class ViewfinderView extends View {
|
|||||||
private static final long ANIMATION_DELAY = 15L;
|
private static final long ANIMATION_DELAY = 15L;
|
||||||
private static final int CURRENT_POINT_OPACITY = 0xA0;
|
private static final int CURRENT_POINT_OPACITY = 0xA0;
|
||||||
private static final int MAX_RESULT_POINTS = 20;
|
private static final int MAX_RESULT_POINTS = 20;
|
||||||
private static final int POINT_SIZE = 8;
|
private static final int POINT_SIZE = 20;
|
||||||
|
|
||||||
private static final int CORNER_RECT_WIDTH = 8; //扫描区边角的宽
|
private static final int CORNER_RECT_WIDTH = 8; //扫描区边角的宽
|
||||||
private static final int CORNER_RECT_HEIGHT = 40; //扫描区边角的高
|
private static final int CORNER_RECT_HEIGHT = 40; //扫描区边角的高
|
||||||
@@ -67,7 +70,6 @@ public final class ViewfinderView extends View {
|
|||||||
|
|
||||||
private Paint paint;
|
private Paint paint;
|
||||||
private TextPaint textPaint;
|
private TextPaint textPaint;
|
||||||
private Bitmap resultBitmap;
|
|
||||||
private int maskColor;
|
private int maskColor;
|
||||||
//扫描区域边框颜色
|
//扫描区域边框颜色
|
||||||
private int frameColor;
|
private int frameColor;
|
||||||
@@ -217,7 +219,7 @@ public final class ViewfinderView extends View {
|
|||||||
this.labelText = labelText;
|
this.labelText = labelText;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLabelTextColor(int color) {
|
public void setLabelTextColor(@ColorInt int color) {
|
||||||
this.labelTextColor = color;
|
this.labelTextColor = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,13 +258,6 @@ public final class ViewfinderView extends View {
|
|||||||
|
|
||||||
// Draw the exterior (i.e. outside the framing rect) darkened
|
// Draw the exterior (i.e. outside the framing rect) darkened
|
||||||
drawExterior(canvas,frame,width,height);
|
drawExterior(canvas,frame,width,height);
|
||||||
|
|
||||||
if (resultBitmap != null) {
|
|
||||||
// Draw the opaque result bitmap over the scanning rectangle
|
|
||||||
paint.setAlpha(CURRENT_POINT_OPACITY);
|
|
||||||
canvas.drawBitmap(resultBitmap, null, frame, paint);
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// Draw a red "laser scanner" line through the middle to show decoding is active
|
// Draw a red "laser scanner" line through the middle to show decoding is active
|
||||||
drawLaserScanner(canvas,frame);
|
drawLaserScanner(canvas,frame);
|
||||||
// Draw a two pixel solid black border inside the framing rect
|
// Draw a two pixel solid black border inside the framing rect
|
||||||
@@ -281,7 +276,6 @@ public final class ViewfinderView extends View {
|
|||||||
frame.right + POINT_SIZE,
|
frame.right + POINT_SIZE,
|
||||||
frame.bottom + POINT_SIZE);
|
frame.bottom + POINT_SIZE);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 绘制文本
|
* 绘制文本
|
||||||
@@ -469,12 +463,9 @@ public final class ViewfinderView extends View {
|
|||||||
paint.setAlpha(CURRENT_POINT_OPACITY);
|
paint.setAlpha(CURRENT_POINT_OPACITY);
|
||||||
paint.setColor(resultPointColor);
|
paint.setColor(resultPointColor);
|
||||||
synchronized (currentPossible) {
|
synchronized (currentPossible) {
|
||||||
|
float radius = POINT_SIZE / 2.0f;
|
||||||
for (ResultPoint point : currentPossible) {
|
for (ResultPoint point : currentPossible) {
|
||||||
if(point.getX()<frame.left || point.getX()>frame.right ||
|
canvas.drawCircle( point.getX(),point.getY(), radius, paint);
|
||||||
point.getY()<frame.top || point.getY()>frame.bottom){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
canvas.drawCircle( point.getX(),point.getY(), POINT_SIZE, paint);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -484,10 +475,6 @@ public final class ViewfinderView extends View {
|
|||||||
synchronized (currentLast) {
|
synchronized (currentLast) {
|
||||||
float radius = POINT_SIZE / 2.0f;
|
float radius = POINT_SIZE / 2.0f;
|
||||||
for (ResultPoint point : currentLast) {
|
for (ResultPoint point : currentLast) {
|
||||||
if(point.getX()<frame.left || point.getX()>frame.right ||
|
|
||||||
point.getY()<frame.top || point.getY()>frame.bottom){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
canvas.drawCircle( point.getX(),point.getY(), radius, paint);
|
canvas.drawCircle( point.getX(),point.getY(), radius, paint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -495,11 +482,6 @@ public final class ViewfinderView extends View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void drawViewfinder() {
|
public void drawViewfinder() {
|
||||||
Bitmap resultBitmap = this.resultBitmap;
|
|
||||||
this.resultBitmap = null;
|
|
||||||
if (resultBitmap != null) {
|
|
||||||
resultBitmap.recycle();
|
|
||||||
}
|
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -519,15 +501,6 @@ public final class ViewfinderView extends View {
|
|||||||
isShowResultPoint = showResultPoint;
|
isShowResultPoint = showResultPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
|
||||||
// * Draw a bitmap with the result points highlighted instead of the live scanning display.
|
|
||||||
// *
|
|
||||||
// * @param barcode An image of the decoded barcode.
|
|
||||||
// */
|
|
||||||
// public void drawResultBitmap(Bitmap barcode) {
|
|
||||||
// resultBitmap = barcode;
|
|
||||||
// invalidate();
|
|
||||||
// }
|
|
||||||
|
|
||||||
public void addPossibleResultPoint(ResultPoint point) {
|
public void addPossibleResultPoint(ResultPoint point) {
|
||||||
if(isShowResultPoint){
|
if(isShowResultPoint){
|
||||||
@@ -544,4 +517,6 @@ public final class ViewfinderView extends View {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -21,6 +21,7 @@ import android.content.Context;
|
|||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.hardware.Camera;
|
import android.hardware.Camera;
|
||||||
|
import android.media.FaceDetector;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.SurfaceHolder;
|
import android.view.SurfaceHolder;
|
||||||
@@ -58,6 +59,7 @@ public final class CameraManager {
|
|||||||
private int requestedCameraId = OpenCameraInterface.NO_REQUESTED_CAMERA;
|
private int requestedCameraId = OpenCameraInterface.NO_REQUESTED_CAMERA;
|
||||||
private int requestedFramingRectWidth;
|
private int requestedFramingRectWidth;
|
||||||
private int requestedFramingRectHeight;
|
private int requestedFramingRectHeight;
|
||||||
|
private boolean isFullScreenScan;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Preview frames are delivered here, which we pass on to the registered handler. Make sure to
|
* Preview frames are delivered here, which we pass on to the registered handler. Make sure to
|
||||||
@@ -221,35 +223,29 @@ public final class CameraManager {
|
|||||||
if (camera == null) {
|
if (camera == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Point screenResolution = configManager.getScreenResolution();
|
Point point = configManager.getCameraResolution();
|
||||||
if (screenResolution == null) {
|
if (point == null) {
|
||||||
// Called early, before init even finished
|
// Called early, before init even finished
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
int width = findDesiredDimensionInRange(screenResolution.x, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);
|
int width = point.x;
|
||||||
int height = findDesiredDimensionInRange(screenResolution.y, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);
|
int height = point.y;
|
||||||
|
|
||||||
|
if(isFullScreenScan){
|
||||||
|
framingRect = new Rect(0,0,width,height);
|
||||||
|
}else{
|
||||||
int size = Math.min(width,height);
|
int size = Math.min(width,height);
|
||||||
|
|
||||||
int leftOffset = (screenResolution.x - size) / 2;
|
int leftOffset = (width - size) / 2;
|
||||||
int topOffset = (screenResolution.y - size) / 2;
|
int topOffset = (height - size) / 2;
|
||||||
framingRect = new Rect(leftOffset, topOffset, leftOffset + size, topOffset + size);
|
framingRect = new Rect(leftOffset, topOffset, leftOffset + size, topOffset + size);
|
||||||
Log.d(TAG, "Calculated framing rect: " + framingRect);
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return framingRect;
|
return framingRect;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int findDesiredDimensionInRange(int resolution, int hardMin, int hardMax) {
|
|
||||||
int dim = 5 * resolution / 8; // Target 5/8 of each dimension
|
|
||||||
if (dim < hardMin) {
|
|
||||||
return hardMin;
|
|
||||||
}
|
|
||||||
if (dim > hardMax) {
|
|
||||||
return hardMax;
|
|
||||||
}
|
|
||||||
return dim;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Like {@link #getFramingRect} but coordinates are in terms of the preview frame,
|
* Like {@link #getFramingRect} but coordinates are in terms of the preview frame,
|
||||||
@@ -270,6 +266,7 @@ public final class CameraManager {
|
|||||||
// Called early, before init even finished
|
// Called early, before init even finished
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// rect.left = rect.left * cameraResolution.x / screenResolution.x;
|
// rect.left = rect.left * cameraResolution.x / screenResolution.x;
|
||||||
// rect.right = rect.right * cameraResolution.x / screenResolution.x;
|
// rect.right = rect.right * cameraResolution.x / screenResolution.x;
|
||||||
// rect.top = rect.top * cameraResolution.y / screenResolution.y;
|
// rect.top = rect.top * cameraResolution.y / screenResolution.y;
|
||||||
@@ -280,11 +277,28 @@ public final class CameraManager {
|
|||||||
rect.top = rect.top * cameraResolution.x / screenResolution.y;
|
rect.top = rect.top * cameraResolution.x / screenResolution.y;
|
||||||
rect.bottom = rect.bottom * cameraResolution.x / screenResolution.y;
|
rect.bottom = rect.bottom * cameraResolution.x / screenResolution.y;
|
||||||
|
|
||||||
|
|
||||||
framingRectInPreview = rect;
|
framingRectInPreview = rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
return framingRectInPreview;
|
return framingRectInPreview;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isFullScreenScan() {
|
||||||
|
return isFullScreenScan;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFullScreenScan(boolean fullScreenScan) {
|
||||||
|
isFullScreenScan = fullScreenScan;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point getCameraResolution() {
|
||||||
|
return configManager.getCameraResolution();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point getScreenResolution() {
|
||||||
|
return configManager.getScreenResolution();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows third party apps to specify the camera ID, rather than determine
|
* Allows third party apps to specify the camera ID, rather than determine
|
||||||
@@ -337,12 +351,16 @@ public final class CameraManager {
|
|||||||
if (rect == null) {
|
if (rect == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(isFullScreenScan){
|
||||||
|
return new PlanarYUVLuminanceSource(data,width,height,0,0,width,height,false);
|
||||||
|
}
|
||||||
int size = Math.min(width,height);
|
int size = Math.min(width,height);
|
||||||
int left = (width-size)/2;
|
int left = (width-size)/2;
|
||||||
int top = (height-size)/2;
|
int top = (height-size)/2;
|
||||||
// Go ahead and assume it's YUV rather than die.
|
// Go ahead and assume it's YUV rather than die.
|
||||||
return new PlanarYUVLuminanceSource(data, width, height, left, top,
|
return new PlanarYUVLuminanceSource(data, width, height, left, top,
|
||||||
left + size, top + size, false);
|
size, size, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
//App
|
//App
|
||||||
def app_version = [:]
|
def app_version = [:]
|
||||||
app_version.versionCode = 9
|
app_version.versionCode = 10
|
||||||
app_version.versionName = "1.1.0"
|
app_version.versionName = "1.1.1"
|
||||||
ext.app_version = app_version
|
ext.app_version = app_version
|
||||||
|
|
||||||
//build version
|
//build version
|
||||||
|
|||||||
Reference in New Issue
Block a user