支持扫二维码过小时,自动缩放

This commit is contained in:
jenly1314
2019-05-20 12:46:57 +08:00
parent 36ccf48b7f
commit c4b9bca4cf
16 changed files with 393 additions and 456 deletions

View File

@@ -1,22 +1,21 @@
package com.king.zxing;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.graphics.Point;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.Browser;
import android.util.Log;
import android.view.Display;
import android.view.WindowManager;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.DecodeHintType;
import com.google.zxing.Result;
import com.google.zxing.ResultPoint;
import com.google.zxing.ResultPointCallback;
import com.king.zxing.camera.CameraManager;
import java.util.Collection;
@@ -25,7 +24,7 @@ import java.util.Map;
/**
* @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();
@@ -35,6 +34,20 @@ public class CaptureHandler extends Handler {
private final CameraManager cameraManager;
private final Activity activity;
private final ViewfinderView viewfinderView;
/**
* 是否支持垂直的条形码
*/
private boolean isSupportVerticalCode;
/**
* 是否返回扫码原图
*/
private boolean isReturnBitmap;
/**
* 是否支持自动缩放
*/
private boolean isSupportAutoZoom;
private enum State {
@@ -51,8 +64,7 @@ public class CaptureHandler extends Handler {
this.activity = activity;
this.viewfinderView = viewfinderView;
this.onCaptureListener = onCaptureListener;
decodeThread = new DecodeThread(activity,cameraManager,this, decodeFormats, baseHints, characterSet,
new ViewfinderResultPointCallback(viewfinderView));
decodeThread = new DecodeThread(activity,cameraManager,this, decodeFormats, baseHints, characterSet, this);
decodeThread.start();
state = State.SUCCESS;
@@ -83,47 +95,11 @@ public class CaptureHandler extends Handler {
}
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.
state = State.PREVIEW;
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();
}
}
@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;
}
}

View File

@@ -75,6 +75,12 @@ public class CaptureHelper implements CaptureLifecycle,CaptureTouchEvent,Capture
*/
private boolean isSupportZoom = true;
private float oldDistance;
/**
* 是否支持自动缩放(变焦),默认支持
*/
private boolean isSupportAutoZoom = true;
/**
* 是否支持连扫,默认不支持
*/
@@ -92,6 +98,21 @@ public class CaptureHelper implements CaptureLifecycle,CaptureTouchEvent,Capture
*/
private boolean isVibrate;
/**
* 是否支持垂直的条形码
*/
private boolean isSupportVerticalCode;
/**
* 是否返回扫码原图
*/
private boolean isReturnBitmap;
/**
* 是否支持全屏扫码识别
*/
private boolean isFullScreenScan;
private OnCaptureCallback onCaptureCallback;
@@ -115,7 +136,7 @@ public class CaptureHelper implements CaptureLifecycle,CaptureTouchEvent,Capture
ambientLightManager = new AmbientLightManager(activity);
cameraManager = new CameraManager(activity);
cameraManager.setFullScreenScan(isFullScreenScan);
callback = new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
@@ -236,6 +257,10 @@ public class CaptureHelper implements CaptureLifecycle,CaptureTouchEvent,Capture
return false;
}
/**
* 初始化Camera
* @param surfaceHolder
*/
private void initCamera(SurfaceHolder surfaceHolder) {
if (surfaceHolder == null) {
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.
if (captureHandler == null) {
captureHandler = new CaptureHandler(activity,viewfinderView,onCaptureListener, decodeFormats, decodeHints, characterSet, cameraManager);
captureHandler.setSupportVerticalCode(isSupportVerticalCode);
captureHandler.setReturnBitmap(isReturnBitmap);
captureHandler.setSupportAutoZoom(isSupportAutoZoom);
}
} catch (IOException ioe) {
Log.w(TAG, ioe);
@@ -388,10 +416,10 @@ public class CaptureHelper implements CaptureLifecycle,CaptureTouchEvent,Capture
public void onResult(Result result){
String text = result.getText();
if(isContinuousScan){
if(onCaptureCallback!=null){
onCaptureCallback.onResultCallback(text);
}
if(isAutoRestartPreviewAndDecode){
if(onCaptureCallback!=null){
onCaptureCallback.onResultCallback(text);
}
restartPreviewAndDecode();
}
}else{
@@ -461,7 +489,7 @@ public class CaptureHelper implements CaptureLifecycle,CaptureTouchEvent,Capture
}
/**
*
* 设置支持的解码一/二维码格式,默认常规的码都支持
* @param decodeFormats
* @return
*/
@@ -471,7 +499,7 @@ public class CaptureHelper implements CaptureLifecycle,CaptureTouchEvent,Capture
}
/**
*
* {@link DecodeHintType}
* @param decodeHints
* @return
*/
@@ -481,7 +509,7 @@ public class CaptureHelper implements CaptureLifecycle,CaptureTouchEvent,Capture
}
/**
*
* 设置解码时编码字符集
* @param characterSet
* @return
*/
@@ -490,6 +518,60 @@ public class CaptureHelper implements CaptureLifecycle,CaptureTouchEvent,Capture
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

View File

@@ -18,17 +18,9 @@ package com.king.zxing;
import android.content.Context;
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.PointF;
import android.hardware.Camera;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -37,6 +29,16 @@ import android.util.Log;
import android.view.Display;
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.util.Map;
@@ -46,11 +48,13 @@ final class DecodeHandler extends Handler {
private final Context context;
private final CameraManager cameraManager;
private final Handler handler;
private final CaptureHandler handler;
private final MultiFormatReader multiFormatReader;
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.setHints(hints);
this.context = context;
@@ -64,7 +68,7 @@ final class DecodeHandler extends Handler {
return;
}
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) {
running = false;
@@ -89,11 +93,85 @@ final class DecodeHandler extends Handler {
* @param width The width 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();
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;
if(isScreenPortrait){
if(isRotate){
byte[] rotatedData = new byte[data.length];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++)
@@ -106,39 +184,7 @@ final class DecodeHandler extends Handler {
}else{
source = cameraManager.buildLuminanceSource(data, width, height);
}
if (source != null) {
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();
}
}
return source;
}
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());
}
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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -27,9 +27,11 @@ import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.support.annotation.ColorInt;
import android.support.annotation.ColorRes;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
@@ -39,6 +41,7 @@ import android.text.TextPaint;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
@@ -58,7 +61,7 @@ public final class ViewfinderView extends View {
private static final long ANIMATION_DELAY = 15L;
private static final int CURRENT_POINT_OPACITY = 0xA0;
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_HEIGHT = 40; //扫描区边角的高
@@ -67,7 +70,6 @@ public final class ViewfinderView extends View {
private Paint paint;
private TextPaint textPaint;
private Bitmap resultBitmap;
private int maskColor;
//扫描区域边框颜色
private int frameColor;
@@ -217,7 +219,7 @@ public final class ViewfinderView extends View {
this.labelText = labelText;
}
public void setLabelTextColor(int color) {
public void setLabelTextColor(@ColorInt int color) {
this.labelTextColor = color;
}
@@ -256,31 +258,23 @@ public final class ViewfinderView extends View {
// Draw the exterior (i.e. outside the framing rect) darkened
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
drawLaserScanner(canvas,frame);
// Draw a two pixel solid black border inside the framing rect
drawFrame(canvas, frame);
// 绘制边角
drawCorner(canvas, frame);
//绘制提示信息
drawTextInfo(canvas, frame);
//绘制扫码结果点
drawResultPoint(canvas,frame);
// Request another update at the animation interval, but only repaint the laser line,
// not the entire viewfinder mask.
postInvalidateDelayed(ANIMATION_DELAY,
frame.left - POINT_SIZE,
frame.top - POINT_SIZE,
frame.right + POINT_SIZE,
frame.bottom + POINT_SIZE);
}
// Draw a red "laser scanner" line through the middle to show decoding is active
drawLaserScanner(canvas,frame);
// Draw a two pixel solid black border inside the framing rect
drawFrame(canvas, frame);
// 绘制边角
drawCorner(canvas, frame);
//绘制提示信息
drawTextInfo(canvas, frame);
//绘制扫码结果点
drawResultPoint(canvas,frame);
// Request another update at the animation interval, but only repaint the laser line,
// not the entire viewfinder mask.
postInvalidateDelayed(ANIMATION_DELAY,
frame.left - POINT_SIZE,
frame.top - POINT_SIZE,
frame.right + POINT_SIZE,
frame.bottom + POINT_SIZE);
}
/**
@@ -469,12 +463,9 @@ public final class ViewfinderView extends View {
paint.setAlpha(CURRENT_POINT_OPACITY);
paint.setColor(resultPointColor);
synchronized (currentPossible) {
float radius = POINT_SIZE / 2.0f;
for (ResultPoint point : currentPossible) {
if(point.getX()<frame.left || point.getX()>frame.right ||
point.getY()<frame.top || point.getY()>frame.bottom){
continue;
}
canvas.drawCircle( point.getX(),point.getY(), POINT_SIZE, paint);
canvas.drawCircle( point.getX(),point.getY(), radius, paint);
}
}
}
@@ -484,10 +475,6 @@ public final class ViewfinderView extends View {
synchronized (currentLast) {
float radius = POINT_SIZE / 2.0f;
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);
}
}
@@ -495,11 +482,6 @@ public final class ViewfinderView extends View {
}
public void drawViewfinder() {
Bitmap resultBitmap = this.resultBitmap;
this.resultBitmap = null;
if (resultBitmap != null) {
resultBitmap.recycle();
}
invalidate();
}
@@ -519,15 +501,6 @@ public final class ViewfinderView extends View {
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) {
if(isShowResultPoint){
@@ -544,4 +517,6 @@ public final class ViewfinderView extends View {
}
}

View File

@@ -21,6 +21,7 @@ import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.Camera;
import android.media.FaceDetector;
import android.os.Handler;
import android.util.Log;
import android.view.SurfaceHolder;
@@ -58,6 +59,7 @@ public final class CameraManager {
private int requestedCameraId = OpenCameraInterface.NO_REQUESTED_CAMERA;
private int requestedFramingRectWidth;
private int requestedFramingRectHeight;
private boolean isFullScreenScan;
/**
* 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) {
return null;
}
Point screenResolution = configManager.getScreenResolution();
if (screenResolution == null) {
Point point = configManager.getCameraResolution();
if (point == null) {
// Called early, before init even finished
return null;
}
int width = findDesiredDimensionInRange(screenResolution.x, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);
int height = findDesiredDimensionInRange(screenResolution.y, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);
int width = point.x;
int height = point.y;
int size = Math.min(width,height);
if(isFullScreenScan){
framingRect = new Rect(0,0,width,height);
}else{
int size = Math.min(width,height);
int leftOffset = (width - size) / 2;
int topOffset = (height - size) / 2;
framingRect = new Rect(leftOffset, topOffset, leftOffset + size, topOffset + size);
}
int leftOffset = (screenResolution.x - size) / 2;
int topOffset = (screenResolution.y - size) / 2;
framingRect = new Rect(leftOffset, topOffset, leftOffset + size, topOffset + size);
Log.d(TAG, "Calculated framing rect: " + 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,
@@ -270,6 +266,7 @@ public final class CameraManager {
// Called early, before init even finished
return null;
}
// rect.left = rect.left * cameraResolution.x / screenResolution.x;
// rect.right = rect.right * cameraResolution.x / screenResolution.x;
// 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.bottom = rect.bottom * cameraResolution.x / screenResolution.y;
framingRectInPreview = rect;
}
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
@@ -337,12 +351,16 @@ public final class CameraManager {
if (rect == null) {
return null;
}
if(isFullScreenScan){
return new PlanarYUVLuminanceSource(data,width,height,0,0,width,height,false);
}
int size = Math.min(width,height);
int left = (width-size)/2;
int top = (height-size)/2;
// Go ahead and assume it's YUV rather than die.
return new PlanarYUVLuminanceSource(data, width, height, left, top,
left + size, top + size, false);
size, size, false);
}
}