From 02ff7694e418c9341c26303a63f50c98c75e5f85 Mon Sep 17 00:00:00 2001 From: jenly1314 Date: Wed, 16 Jan 2019 17:52:44 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E6=94=AF=E6=8C=81=E8=BF=9E=E7=BB=AD?= =?UTF-8?q?=E6=89=AB=E7=A0=81=202=E3=80=81=E6=94=AF=E6=8C=81=E6=A8=AA?= =?UTF-8?q?=E5=B1=8F=E6=89=AB=E7=A0=81(=E4=B8=BB=E8=A6=81=E4=B8=BA?= =?UTF-8?q?=E4=BA=86=E6=94=AF=E6=8C=81Pad)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/caches/build_file_checksums.ser | Bin 590 -> 590 bytes README.md | 14 ++++- .../king/zxing/app/CustomCaptureActivity.java | 35 +++++++++++ .../java/com/king/zxing/CaptureActivity.java | 59 ++++++++++++++---- .../king/zxing/CaptureActivityHandler.java | 2 +- .../java/com/king/zxing/DecodeHandler.java | 48 ++++++++++---- .../camera/CameraConfigurationManager.java | 4 +- .../camera/CameraConfigurationUtils.java | 26 +++----- .../java/com/king/zxing/util/CodeUtils.java | 52 ++++++++++++--- versions.gradle | 4 +- 10 files changed, 188 insertions(+), 56 deletions(-) diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser index 87e65cf7860fb38a0894618aad4ab7643e4a53fd..71ac3c47e3c08baf0b616a3e7a7a2dd8c97e043e 100644 GIT binary patch delta 16 YcmX@da*k!fbk>Y8&R518=WJpG068KCwEzGB delta 16 YcmX@da*k!fbk_8rQoMc}=WJpG06GB%rT_o{ diff --git a/README.md b/README.md index 1732b4c..82aee78 100644 --- a/README.md +++ b/README.md @@ -40,17 +40,17 @@ ZXingLite for Android 是ZXing的精简版,基于ZXing库优化扫码和生成 com.king.zxing zxing-lite - 1.0.5 + 1.0.6 pom ``` ### Gradle: ```gradle -implementation 'com.king.zxing:zxing-lite:1.0.5' +implementation 'com.king.zxing:zxing-lite:1.0.6' ``` ### Lvy: ```lvy - + ``` @@ -99,6 +99,14 @@ api 'com.google.zxing:core:3.3.3' 更多使用详情,请查看[app](app)中的源码使用示例 +## 版本记录 +#### v1.0.6:2019-1-16 +* 支持连续扫码 +* 支持横屏扫码(主要为了支持Pad) + +#### v1.0.5:2018-12-29 +* 支持自定义扫码框宽高 + ## 关于我 Name: Jenly diff --git a/app/src/main/java/com/king/zxing/app/CustomCaptureActivity.java b/app/src/main/java/com/king/zxing/app/CustomCaptureActivity.java index 054aa1c..ec9dc9e 100644 --- a/app/src/main/java/com/king/zxing/app/CustomCaptureActivity.java +++ b/app/src/main/java/com/king/zxing/app/CustomCaptureActivity.java @@ -21,6 +21,7 @@ import android.support.v7.widget.Toolbar; import android.view.View; import android.widget.TextView; +import com.google.zxing.Result; import com.king.zxing.CaptureActivity; import com.king.zxing.app.util.StatusBarUtils; @@ -46,6 +47,9 @@ public class CustomCaptureActivity extends CaptureActivity { getBeepManager().setVibrate(true); } + /** + * 关闭闪光灯(手电筒) + */ private void offFlash(){ Camera camera = getCameraManager().getOpenCamera().getCamera(); Camera.Parameters parameters = camera.getParameters(); @@ -53,6 +57,9 @@ public class CustomCaptureActivity extends CaptureActivity { camera.setParameters(parameters); } + /** + * 开启闪光灯(手电筒) + */ public void openFlash(){ Camera camera = getCameraManager().getOpenCamera().getCamera(); Camera.Parameters parameters = camera.getParameters(); @@ -60,6 +67,34 @@ public class CustomCaptureActivity extends CaptureActivity { camera.setParameters(parameters); } + /** + * 接收扫码结果,想支持连扫时,可将{@link #isContinuousScan()}返回为{@code true}并重写此方法 + * 如果{@link #isContinuousScan()}支持连扫,则默认重启扫码和解码器;当连扫逻辑太复杂时, + * 请将{@link #isAutoRestartPreviewAndDecode()}返回为{@code false},并手动调用{@link #restartPreviewAndDecode()} + * @param result 扫码结果 + */ + @Override + public void onResult(Result result) { + super.onResult(result); + } + + /** + * 是否连续扫码,如果想支持连续扫码,则将此方法返回{@code true}并重写{@link #onResult(Result)} + * @return 默认返回 false + */ + @Override + public boolean isContinuousScan() { + return super.isContinuousScan(); + } + + /** + * 是否自动重启扫码和解码器,当支持连扫时才起作用。 + * @return 默认返回 true + */ + @Override + public boolean isAutoRestartPreviewAndDecode() { + return super.isAutoRestartPreviewAndDecode(); + } private void clickFlash(View v){ if(v.isSelected()){ diff --git a/lib/src/main/java/com/king/zxing/CaptureActivity.java b/lib/src/main/java/com/king/zxing/CaptureActivity.java index 90e4b33..a56145f 100644 --- a/lib/src/main/java/com/king/zxing/CaptureActivity.java +++ b/lib/src/main/java/com/king/zxing/CaptureActivity.java @@ -38,6 +38,7 @@ import android.view.SurfaceView; import android.view.View; import android.view.Window; import android.view.WindowManager; +import android.widget.Toast; import com.google.zxing.BarcodeFormat; import com.google.zxing.DecodeHintType; @@ -178,12 +179,6 @@ public class CaptureActivity extends Activity implements SurfaceHolder.Callback handler = null; lastResult = null; - if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); - } else { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); - } - resetStatusView(); @@ -443,6 +438,50 @@ public class CaptureActivity extends Activity implements SurfaceHolder.Callback // do nothing } + /** + * 重新启动扫码和解码器 + */ + public void restartPreviewAndDecode(){ + if(handler!=null){ + handler.restartPreviewAndDecode(); + } + } + + /** + * 接收扫码结果,想支持连扫时,可将{@link #isContinuousScan()}返回为{@code true}并重写此方法 + * 如果{@link #isContinuousScan()}支持连扫,则默认重启扫码和解码器;当连扫逻辑太复杂时, + * 请将{@link #isAutoRestartPreviewAndDecode()}返回为{@code false},并手动调用{@link #restartPreviewAndDecode()} + * @param result 扫码结果 + */ + public void onResult(Result result){ + if(isContinuousScan()){ + if(isAutoRestartPreviewAndDecode()){ + restartPreviewAndDecode(); + } + }else{ + Intent intent = new Intent(); + intent.putExtra(KEY_RESULT,result.getText()); + setResult(RESULT_OK,intent); + finish(); + } + } + + /** + * 是否连续扫码,如果想支持连续扫码,则将此方法返回{@code true}并重写{@link #onResult(Result)} + * @return 默认返回 false + */ + public boolean isContinuousScan(){ + return false; + } + + /** + * 是否自动重启扫码和解码器,当支持连扫时才起作用。 + * @return 默认返回 true + */ + public boolean isAutoRestartPreviewAndDecode(){ + return true; + } + /** * A valid barcode has been found, so give an indication of success and show the results. * @@ -456,11 +495,9 @@ public class CaptureActivity extends Activity implements SurfaceHolder.Callback if(isBeepSoundAndVibrate()){ beepManager.playBeepSoundAndVibrate(); } - String resultString = rawResult.getText(); - Intent intent = new Intent(); - intent.putExtra(KEY_RESULT,resultString); - setResult(RESULT_OK,intent); - finish(); + + onResult(rawResult); + // ResultHandler resultHandler = ResultHandlerFactory.makeResultHandler(this, rawResult); diff --git a/lib/src/main/java/com/king/zxing/CaptureActivityHandler.java b/lib/src/main/java/com/king/zxing/CaptureActivityHandler.java index 8af9ccb..1af3c59 100644 --- a/lib/src/main/java/com/king/zxing/CaptureActivityHandler.java +++ b/lib/src/main/java/com/king/zxing/CaptureActivityHandler.java @@ -158,7 +158,7 @@ public final class CaptureActivityHandler extends Handler { removeMessages(R.id.decode_failed); } - private void restartPreviewAndDecode() { + public void restartPreviewAndDecode() { if (state == State.SUCCESS) { state = State.PREVIEW; cameraManager.requestPreviewFrame(decodeThread.getHandler(), R.id.decode); diff --git a/lib/src/main/java/com/king/zxing/DecodeHandler.java b/lib/src/main/java/com/king/zxing/DecodeHandler.java index fd47e76..c6c5860 100644 --- a/lib/src/main/java/com/king/zxing/DecodeHandler.java +++ b/lib/src/main/java/com/king/zxing/DecodeHandler.java @@ -16,20 +16,26 @@ 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.ReaderException; import com.google.zxing.Result; +import com.google.zxing.common.GlobalHistogramBinarizer; import com.google.zxing.common.HybridBinarizer; +import android.graphics.Point; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; +import android.view.Display; +import android.view.WindowManager; import java.io.ByteArrayOutputStream; import java.util.Map; @@ -54,7 +60,7 @@ final class DecodeHandler extends Handler { return; } if (message.what == R.id.decode) { - decode((byte[]) message.obj, message.arg1, message.arg2); + decode((byte[]) message.obj, message.arg1, message.arg2,isScreenPortrait()); } else if (message.what == R.id.quit) { running = false; @@ -63,6 +69,14 @@ final class DecodeHandler extends Handler { } } + private boolean isScreenPortrait(){ + WindowManager manager = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE); + Display display = manager.getDefaultDisplay(); + Point screenResolution = new Point(); + display.getSize(screenResolution); + return screenResolution.x < screenResolution.y; + } + /** * Decode the data within the viewfinder rectangle, and time how long it took. For efficiency, * reuse the same reader objects from one decode to the next. @@ -71,24 +85,34 @@ 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) { + private void decode(byte[] data, int width, int height,boolean isScreenPortrait) { long start = System.currentTimeMillis(); Result rawResult = null; - byte[] rotatedData = new byte[data.length]; - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) - rotatedData[x * height + height - y - 1] = data[x + y * width]; + PlanarYUVLuminanceSource source; + if(isScreenPortrait){ + byte[] rotatedData = new byte[data.length]; + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) + rotatedData[x * height + height - y - 1] = data[x + y * width]; + } + int tmp = width; + width = height; + height = tmp; + source = activity.getCameraManager().buildLuminanceSource(rotatedData, width, height); + }else{ + source = activity.getCameraManager().buildLuminanceSource(data, width, height); } - int tmp = width; - width = height; - height = tmp; - PlanarYUVLuminanceSource source = activity.getCameraManager().buildLuminanceSource(rotatedData, width, height); if (source != null) { BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); try { rawResult = multiFormatReader.decodeWithState(bitmap); - } catch (ReaderException re) { - // continue + } catch (Exception e) { + BinaryBitmap bitmap1 = new BinaryBitmap(new GlobalHistogramBinarizer(source)); + try { + rawResult = multiFormatReader.decode(bitmap1); + } catch (NotFoundException ne) { + + } } finally { multiFormatReader.reset(); } diff --git a/lib/src/main/java/com/king/zxing/camera/CameraConfigurationManager.java b/lib/src/main/java/com/king/zxing/camera/CameraConfigurationManager.java index d6813d0..61b1576 100644 --- a/lib/src/main/java/com/king/zxing/camera/CameraConfigurationManager.java +++ b/lib/src/main/java/com/king/zxing/camera/CameraConfigurationManager.java @@ -108,8 +108,7 @@ final class CameraConfigurationManager { } */ - cwRotationFromDisplayToCamera = - (360 + cwRotationFromNaturalToCamera - cwRotationFromNaturalToDisplay) % 360; + cwRotationFromDisplayToCamera = (360 + cwRotationFromNaturalToCamera - cwRotationFromNaturalToDisplay) % 360; Log.i(TAG, "Final display orientation: " + cwRotationFromDisplayToCamera); if (camera.getFacing() == CameraFacing.FRONT) { Log.i(TAG, "Compensating rotation for front camera"); @@ -162,7 +161,6 @@ final class CameraConfigurationManager { parameters.setZoom(parameters.getMaxZoom() / 10); } - theCamera.setDisplayOrientation(90); theCamera.setParameters(parameters); initializeTorch(parameters, prefs, safeMode); diff --git a/lib/src/main/java/com/king/zxing/camera/CameraConfigurationUtils.java b/lib/src/main/java/com/king/zxing/camera/CameraConfigurationUtils.java index ebddc20..15efb04 100644 --- a/lib/src/main/java/com/king/zxing/camera/CameraConfigurationUtils.java +++ b/lib/src/main/java/com/king/zxing/camera/CameraConfigurationUtils.java @@ -45,7 +45,7 @@ public final class CameraConfigurationUtils { private static final int MIN_PREVIEW_PIXELS = 480 * 320; // normal screen private static final float MAX_EXPOSURE_COMPENSATION = 1.5f; private static final float MIN_EXPOSURE_COMPENSATION = 0.0f; - private static final double MAX_ASPECT_DISTORTION = 0.10; + private static final double MAX_ASPECT_DISTORTION = 0.05; private static final int MIN_FPS = 10; private static final int MAX_FPS = 20; private static final int AREA_PER_1000 = 400; @@ -292,10 +292,16 @@ public final class CameraConfigurationUtils { Log.i(TAG, "Supported preview sizes: " + previewSizesString); } - double screenAspectRatio = screenResolution.x / (double) screenResolution.y; + double screenAspectRatio; + if(screenResolution.x < screenResolution.y){ + screenAspectRatio = screenResolution.x / (double) screenResolution.y; + }else{ + screenAspectRatio = screenResolution.y / (double) screenResolution.x; + } Log.i(TAG, "screenAspectRatio: " + screenAspectRatio); // Find a suitable size, with max resolution int maxResolution = 0; + Camera.Size maxResPreviewSize = null; for (Camera.Size size : rawSupportedSizes) { int realWidth = size.width; @@ -309,6 +315,7 @@ public final class CameraConfigurationUtils { int maybeFlippedWidth = isCandidatePortrait ? realWidth: realHeight ; int maybeFlippedHeight = isCandidatePortrait ? realHeight : realWidth; Log.i(TAG, String.format("maybeFlipped:%d * %d",maybeFlippedWidth,maybeFlippedHeight)); + double aspectRatio = maybeFlippedWidth / (double) maybeFlippedHeight; Log.i(TAG, "aspectRatio: " + aspectRatio); double distortion = Math.abs(aspectRatio - screenAspectRatio); @@ -330,21 +337,6 @@ public final class CameraConfigurationUtils { } } - if (!rawSupportedSizes.isEmpty()) { - Collections.sort(rawSupportedSizes, new Comparator() { - @Override - public int compare(Camera.Size o1, Camera.Size o2) { - int delta1 = Math.abs(o1.height-screenResolution.x); - int delta2 = Math.abs(o2.height-screenResolution.x); - return delta1 - delta2; - } - }); - Camera.Size bestPreview = rawSupportedSizes.get(0); - Point bestSize = new Point(bestPreview.width, bestPreview.height); - Log.i(TAG, "Using largest suitable bestSize: " + bestSize); - return bestSize; - } - // If no exact match, use largest preview size. This was not a great idea on older devices because // of the additional computation needed. We're likely to get here on newer Android 4+ devices, where // the CPU is much more powerful. diff --git a/lib/src/main/java/com/king/zxing/util/CodeUtils.java b/lib/src/main/java/com/king/zxing/util/CodeUtils.java index b7bdc90..dfa9a8a 100644 --- a/lib/src/main/java/com/king/zxing/util/CodeUtils.java +++ b/lib/src/main/java/com/king/zxing/util/CodeUtils.java @@ -31,10 +31,12 @@ import com.google.zxing.DecodeHintType; import com.google.zxing.EncodeHintType; import com.google.zxing.MultiFormatReader; import com.google.zxing.MultiFormatWriter; +import com.google.zxing.NotFoundException; 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.QRCodeReader; import com.google.zxing.qrcode.QRCodeWriter; @@ -188,7 +190,25 @@ public class CodeUtils { */ public static String parseQRCode(String bitmapPath, Map hints){ try { - Result result = new QRCodeReader().decode(getBinaryBitmap(compressBitmap(bitmapPath)), hints); + QRCodeReader reader = new QRCodeReader(); + + Result result = null; + RGBLuminanceSource source = getRGBLuminanceSource(compressBitmap(bitmapPath)); + if (source != null) { + BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); + try { + result = reader.decode(bitmap,hints); + } catch (Exception e) {//解析失败则通过GlobalHistogramBinarizer 再试一次 + BinaryBitmap bitmap1 = new BinaryBitmap(new GlobalHistogramBinarizer(source)); + try { + result = reader.decode(bitmap1); + } catch (NotFoundException ne) { + + } + } finally { + reader.reset(); + } + } return result.getText(); } catch (Exception e) { e.printStackTrace(); @@ -223,10 +243,27 @@ public class CodeUtils { * @return */ public static String parseCode(String bitmapPath, Map hints){ + try { MultiFormatReader reader = new MultiFormatReader(); reader.setHints(hints); - Result result = reader.decodeWithState(getBinaryBitmap(compressBitmap(bitmapPath))); + Result result = null; + RGBLuminanceSource source = getRGBLuminanceSource(compressBitmap(bitmapPath)); + if (source != null) { + BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); + try { + result = reader.decodeWithState(bitmap); + } catch (Exception e) {//解析失败则通过GlobalHistogramBinarizer 再试一次 + BinaryBitmap bitmap1 = new BinaryBitmap(new GlobalHistogramBinarizer(source)); + try { + result = reader.decodeWithState(bitmap1); + } catch (NotFoundException ne) { + + } + } finally { + reader.reset(); + } + } return result.getText(); } catch (Exception e) { e.printStackTrace(); @@ -234,6 +271,8 @@ public class CodeUtils { return null; } + + /** * 压缩图片 * @param path @@ -265,19 +304,18 @@ public class CodeUtils { } /** - * 获取二进制图片 + * 获取RGBLuminanceSource * @param bitmap * @return */ - private static BinaryBitmap getBinaryBitmap(@NonNull Bitmap bitmap){ + 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()); - RGBLuminanceSource source = new RGBLuminanceSource(width, height, pixels); - //得到二进制图片 - return new BinaryBitmap(new HybridBinarizer(source)); + return new RGBLuminanceSource(width, height, pixels); + } /** diff --git a/versions.gradle b/versions.gradle index 9bf86aa..9ae88d2 100644 --- a/versions.gradle +++ b/versions.gradle @@ -1,7 +1,7 @@ //App def app_version = [:] -app_version.versionCode = 6 -app_version.versionName = "1.0.5" +app_version.versionCode = 7 +app_version.versionName = "1.0.6" ext.app_version = app_version //build version