【Android 学习】之二维码扫描开发(闪光灯功能)
16lz
2021-01-23
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
Android二维码扫描我们可以调用Zing.jar包,用人家写好的代码,我们只需要根据自己的需要修改布局即可.下面我简单介绍一下Android我们怎么来用和修改人家的代码.
1、下载Zing.jar包http://download.csdn.net/detail/u013132758/9361939
2、解压导入项目可以用了。
效图如下:
详细介绍一下如何根据自己的需求来修改代码:
首先在AndroidMainfest。xml中添加权限
1、项目结构如下所示
2、若修改扫描框的大小可在CameraManager里面修改参数width,height该项目中我设置为0.7倍的屏幕宽度。
CameraManager.java
package com.zm.app.zxing.camera;/* * Copyright (C) 2008 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */import java.io.IOException;import java.util.List;import android.content.Context;import android.graphics.PixelFormat;import android.graphics.Point;import android.graphics.Rect;import android.hardware.Camera;import android.os.Build;import android.os.Handler;import android.util.DisplayMetrics;import android.util.Log;import android.view.SurfaceHolder;import com.zm.app.zxing.camera.PlanarYUVLuminanceSource;/** * This object wraps the Camera service object and expects to be the only one talking to it. The * implementation encapsulates the steps needed to take preview-sized images, which are used for * both preview and decoding. * */public final class CameraManager { private static final String TAG = CameraManager.class.getSimpleName(); private static CameraManager cameraManager; static final int SDK_INT; // Later we can use Build.VERSION.SDK_INT static { int sdkInt; try { sdkInt = Integer.parseInt(Build.VERSION.SDK); } catch (NumberFormatException nfe) { // Just to be safe sdkInt = 10000; } SDK_INT = sdkInt; } private final Context context; private final CameraConfigurationManager configManager; private Camera camera; private Rect framingRect; private Rect framingRectInPreview; private boolean initialized; private boolean previewing; private final boolean useOneShotPreviewCallback; /** * Preview frames are delivered here, which we pass on to the registered handler. Make sure to * clear the handler so it will only receive one message. */ private final PreviewCallback previewCallback; /** Autofocus callbacks arrive here, and are dispatched to the Handler which requested them. */ private final AutoFocusCallback autoFocusCallback; /** * Initializes this static object with the Context of the calling Activity. * * @param context The Activity which wants to use the camera. */ public static void init(Context context) { if (cameraManager == null) { cameraManager = new CameraManager(context); } } /** * Gets the CameraManager singleton instance. * * @return A reference to the CameraManager singleton. */ public static CameraManager get() { return cameraManager; } private CameraManager(Context context) { this.context = context; this.configManager = new CameraConfigurationManager(context); // Camera.setOneShotPreviewCallback() has a race condition in Cupcake, so we use the older // Camera.setPreviewCallback() on 1.5 and earlier. For Donut and later, we need to use // the more efficient one shot callback, as the older one can swamp the system and cause it // to run out of memory. We can't use SDK_INT because it was introduced in the Donut SDK. //useOneShotPreviewCallback = Integer.parseInt(Build.VERSION.SDK) > Build.VERSION_CODES.CUPCAKE; useOneShotPreviewCallback = Integer.parseInt(Build.VERSION.SDK) > 3; // 3 = Cupcake previewCallback = new PreviewCallback(configManager, useOneShotPreviewCallback); autoFocusCallback = new AutoFocusCallback(); } /** * Opens the camera driver and initializes the hardware parameters. * * @param holder The surface object which the camera will draw preview frames into. * @throws IOException Indicates the camera driver failed to open. */ public void openDriver(SurfaceHolder holder) throws IOException { if (camera == null) { camera = Camera.open(); if (camera == null) { throw new IOException(); } camera.setPreviewDisplay(holder); if (!initialized) { initialized = true; configManager.initFromCameraParameters(camera); } configManager.setDesiredCameraParameters(camera); //FIXME // SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); //�Ƿ�ʹ��ǰ��// if (prefs.getBoolean(PreferencesActivity.KEY_FRONT_LIGHT, false)) {// FlashlightManager.enableFlashlight();// } FlashlightManager.enableFlashlight(); } } public void openLight(){ if (camera != null) { Camera.Parameters parameter; parameter = camera.getParameters(); parameter.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH); camera.setParameters(parameter); } } public void offLight(){ if (camera != null) { Camera.Parameters parameter; parameter = camera.getParameters(); parameter.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); camera.setParameters(parameter); } } /** * Closes the camera driver if still in use. */ public void closeDriver() { if (camera != null) { FlashlightManager.disableFlashlight(); camera.release(); camera = null; } } /** * Asks the camera hardware to begin drawing preview frames to the screen. */ public void startPreview() { if (camera != null && !previewing) { camera.startPreview(); previewing = true; } } /** * Tells the camera to stop drawing preview frames. */ public void stopPreview() { if (camera != null && previewing) { if (!useOneShotPreviewCallback) { camera.setPreviewCallback(null); } camera.stopPreview(); previewCallback.setHandler(null, 0); autoFocusCallback.setHandler(null, 0); previewing = false; } } /** * A single preview frame will be returned to the handler supplied. The data will arrive as byte[] * in the message.obj field, with width and height encoded as message.arg1 and message.arg2, * respectively. * * @param handler The handler to send the message to. * @param message The what field of the message to be sent. */ public void requestPreviewFrame(Handler handler, int message) { if (camera != null && previewing) { previewCallback.setHandler(handler, message); if (useOneShotPreviewCallback) { camera.setOneShotPreviewCallback(previewCallback); } else { camera.setPreviewCallback(previewCallback); } } } /** * Asks the camera hardware to perform an autofocus. * * @param handler The Handler to notify when the autofocus completes. * @param message The message to deliver. */ public void requestAutoFocus(Handler handler, int message) { if (camera != null && previewing) { autoFocusCallback.setHandler(handler, message); //Log.d(TAG, "Requesting auto-focus callback"); camera.autoFocus(autoFocusCallback); } } /** * Calculates the framing rect which the UI should draw to show the user where to place the * barcode. This target helps with alignment as well as forces the user to hold the device * far enough away to ensure the image will be in focus. * * @return The rectangle to draw on screen in window coordinates. */ public Rect getFramingRect() { Point screenResolution = configManager.getScreenResolution(); if (framingRect == null) { if (camera == null) { return null; } DisplayMetrics metrics = context.getResources().getDisplayMetrics(); //定义扫描矿的宽和高分别为0.7倍的屏幕宽度和高度 int width = (int)(metrics.widthPixels*0.7); int height = width; int leftOffset = (screenResolution.x - width) / 2; int topOffset = (screenResolution.y - height) / 2; framingRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height); Log.d(TAG, "Calculated framing rect: " + framingRect); } return framingRect; } /** * Like {@link #getFramingRect} but coordinates are in terms of the preview frame, * not UI / screen. */ public Rect getFramingRectInPreview() { if (framingRectInPreview == null) { Rect rect = new Rect(getFramingRect()); Point cameraResolution = configManager.getCameraResolution(); Point screenResolution = configManager.getScreenResolution(); //modify here// rect.left = rect.left * cameraResolution.x / screenResolution.x;// rect.right = rect.right * cameraResolution.x / screenResolution.x;// rect.top = rect.top * cameraResolution.y / screenResolution.y;// rect.bottom = rect.bottom * cameraResolution.y / screenResolution.y; rect.left = rect.left * cameraResolution.y / screenResolution.x; rect.right = rect.right * cameraResolution.y / screenResolution.x; rect.top = rect.top * cameraResolution.x / screenResolution.y; rect.bottom = rect.bottom * cameraResolution.x / screenResolution.y; framingRectInPreview = rect; } return framingRectInPreview; } /** * 通过设置Camera打开闪光灯 */ public void turnLightOn() { Log.e(TAG,"闪光灯相机=======没开"); if (camera == null) { Log.e(TAG,"闪光灯相机没开"); return; } Log.e(TAG,"闪光灯相机====%%%%%%%===没开"); Camera.Parameters parameters = camera.getParameters(); if (parameters == null) { return; } List flashModes = parameters.getSupportedFlashModes(); if (flashModes == null) { return; } String flashMode = parameters.getFlashMode();// Log.i(TAG, Flash mode: + flashMode);// Log.i(TAG, Flash modes: + flashModes);// // 闪光灯关闭状态 if (!Camera.Parameters.FLASH_MODE_TORCH.equals(flashMode)) { // Turn on the flash if (flashModes.contains(Camera.Parameters.FLASH_MODE_TORCH)) { parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH); camera.setParameters(parameters); camera.startPreview(); } else { } } } /** * 通过设置Camera关闭闪光灯 * */ public void turnLightOff() { if (camera == null) { Log.e(TAG,"闪光灯相机没开"); return; } Camera.Parameters parameters = camera.getParameters(); if (parameters == null) { return; } List flashModes = parameters.getSupportedFlashModes(); String flashMode = parameters.getFlashMode(); // Check if camera flash exists if (flashModes == null) { return; } // 闪光灯打开状态 if (!Camera.Parameters.FLASH_MODE_OFF.equals(flashMode)) { // Turn off the flash if (flashModes.contains(Camera.Parameters.FLASH_MODE_OFF)) { parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); camera.setParameters(parameters); } else { Log.e(TAG, "FLASH_MODE_OFF not supported"); } } } /** * Converts the result points from still resolution coordinates to screen coordinates. * * @param points The points returned by the Reader subclass through Result.getResultPoints(). * @return An array of Points scaled to the size of the framing rect and offset appropriately * so they can be drawn in screen coordinates. */ /* public Point[] convertResultPoints(ResultPoint[] points) { Rect frame = getFramingRectInPreview(); int count = points.length; Point[] output = new Point[count]; for (int x = 0; x < count; x++) { output[x] = new Point(); output[x].x = frame.left + (int) (points[x].getX() + 0.5f); output[x].y = frame.top + (int) (points[x].getY() + 0.5f); } return output; } */ /** * A factory method to build the appropriate LuminanceSource object based on the format * of the preview buffers, as described by Camera.Parameters. * * @param data A preview frame. * @param width The width of the image. * @param height The height of the image. * @return A PlanarYUVLuminanceSource instance. */ public PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int width, int height) { Rect rect = getFramingRectInPreview(); int previewFormat = configManager.getPreviewFormat(); String previewFormatString = configManager.getPreviewFormatString(); switch (previewFormat) { // This is the standard Android format which all devices are REQUIRED to support. // In theory, it's the only one we should ever care about. case PixelFormat.YCbCr_420_SP: // This format has never been seen in the wild, but is compatible as we only care // about the Y channel, so allow it. case PixelFormat.YCbCr_422_SP: return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top, rect.width(), rect.height()); default: // The Samsung Moment incorrectly uses this variant instead of the 'sp' version. // Fortunately, it too has all the Y data up front, so we can read it. if ("yuv420p".equals(previewFormatString)) { return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top, rect.width(), rect.height()); } } throw new IllegalArgumentException("Unsupported picture format: " + previewFormat + '/' + previewFormatString); } public Context getContext() { return context; }}
3、要修改扫描界面,自己画界面可在ViewfinderView中修改 ViewfinderView.java
package com.zm.app.zxing.view;import android.content.Context;import android.content.res.Resources;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Rect;import android.graphics.Typeface;import android.util.AttributeSet;import android.view.View;import com.example.qr_codescan.R;import com.google.zxing.ResultPoint;import java.util.Collection;import java.util.HashSet;/** * Created by leiqi on 15-12-9. */public class ViewfinderView extends View {private static final String TAG = "log";/** * 刷新界面的时间 */private static final long ANIMATION_DELAY = 10L;private static final int OPAQUE = 0xFF;/** * 四个绿色边角对应的长度 */private int ScreenRate;/** * 四个绿色边角对应的宽度 */private static final int CORNER_WIDTH = 5;/** * 扫描框中的中间线的宽度 */private static final int MIDDLE_LINE_WIDTH = 5;/** * 扫描框中的中间线的与扫描框左右的间隙 */private static final int MIDDLE_LINE_PADDING = 5;/** * 中间那条线每次刷新移动的距离 */private static final int SPEEN_DISTANCE = 5;/** * 手机的屏幕密度 */private static float density;/** * 字体大小 */private static final int TEXT_SIZE = 18;private static final int TEXT_SIZE1 = 22;/** * 字体距离扫描框下面的距离 */private static final int TEXT_PADDING_TOP = 30;/** * 画笔对象的引用 */private Paint paint;/** * 中间滑动线的最顶端位置 */private int slideTop;/** * 中间滑动线的最底端位置 */private int slideBottom;/** * 将扫描的二维码拍下来,这里没有这个功能,暂时不考虑 */private Bitmap resultBitmap;private final int maskColor;private final int resultColor;private final int resultPointColor;private Collection possibleResultPoints;private Collection lastPossibleResultPoints;boolean isFirst;public ViewfinderView(Context context, AttributeSet attrs) {super(context, attrs);density = context.getResources().getDisplayMetrics().density;//将像素转换成dpScreenRate = (int) (20 * density);paint = new Paint();Resources resources = getResources();maskColor = resources.getColor(R.color.viewfinder_mask);resultColor = resources.getColor(R.color.result_view);resultPointColor = resources.getColor(R.color.possible_result_points);possibleResultPoints = new HashSet(5);}@Overridepublic void onDraw(Canvas canvas) {//中间的扫描框,你要修改扫描框的大小,去CameraManager里面修改Rect frame = com.zm.app.zxing.camera.CameraManager.get().getFramingRect();if (frame == null) {return;}//初始化中间线滑动的最上边和最下边if (!isFirst) {isFirst = true;slideTop = frame.top;slideBottom = frame.bottom;}//获取屏幕的宽和高int width = canvas.getWidth();int height = canvas.getHeight();paint.setColor(resultBitmap != null ? resultColor : maskColor);//画出扫描框外面的阴影部分,共四个部分,扫描框的上面到屏幕上面,扫描框的下面到屏幕下面//扫描框的左边面到屏幕左边,扫描框的右边到屏幕右边canvas.drawRect(0, 0, width, frame.top, paint);canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint);canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1,paint);canvas.drawRect(0, frame.bottom + 1, width, height, paint);if (resultBitmap != null) {// Draw the opaque result bitmap over the scanning rectanglepaint.setAlpha(OPAQUE);canvas.drawBitmap(resultBitmap, frame.left, frame.top, paint);} else {////画扫描框上面的字//paint.setColor(Color.rgb(255,255,255));//paint.setTextSize(TEXT_SIZE1 * density);//paint.setAlpha(0x40);//paint.setTypeface(Typeface.create("System", Typeface.BOLD));//canvas.drawText(getResources().getString(R.string.Return_car), frame.left, (float) (frame.top - (float) TEXT_PADDING_TOP * density), paint);//画扫描框边上的角,总共8个部分paint.setColor(Color.rgb(33,134,116));canvas.drawRect(frame.left, frame.top, frame.left + ScreenRate,frame.top + CORNER_WIDTH, paint);canvas.drawRect(frame.left, frame.top, frame.left + CORNER_WIDTH, frame.top+ ScreenRate, paint);canvas.drawRect(frame.right - ScreenRate, frame.top, frame.right,frame.top + CORNER_WIDTH, paint);canvas.drawRect(frame.right - CORNER_WIDTH, frame.top, frame.right, frame.top+ ScreenRate, paint);canvas.drawRect(frame.left, frame.bottom - CORNER_WIDTH, frame.left+ ScreenRate, frame.bottom, paint);canvas.drawRect(frame.left, frame.bottom - ScreenRate,frame.left + CORNER_WIDTH, frame.bottom, paint);canvas.drawRect(frame.right - ScreenRate, frame.bottom - CORNER_WIDTH,frame.right, frame.bottom, paint);canvas.drawRect(frame.right - CORNER_WIDTH, frame.bottom - ScreenRate,frame.right, frame.bottom, paint);//绘制中间的线,每次刷新界面,中间的线往下移动SPEEN_DISTANCEslideTop += SPEEN_DISTANCE;if (slideTop >= frame.bottom) {slideTop = frame.top;}canvas.drawRect(frame.left + MIDDLE_LINE_PADDING, slideTop - MIDDLE_LINE_WIDTH / 2, frame.right - MIDDLE_LINE_PADDING, slideTop + MIDDLE_LINE_WIDTH / 2, paint);//画扫描框下面的字paint.setColor(Color.WHITE);paint.setTextSize(TEXT_SIZE * density);paint.setAlpha(0x40);paint.setTypeface(Typeface.create("System", Typeface.BOLD));canvas.drawText(getResources().getString(R.string.scan_text), frame.left, (float) (frame.bottom + (float) TEXT_PADDING_TOP * density), paint);Collection currentPossible = possibleResultPoints;Collection currentLast = lastPossibleResultPoints;if (currentPossible.isEmpty()) {lastPossibleResultPoints = null;} else {possibleResultPoints = new HashSet(5);lastPossibleResultPoints = currentPossible;paint.setAlpha(OPAQUE);paint.setColor(resultPointColor);for (ResultPoint point : currentPossible) {canvas.drawCircle(frame.left + point.getX(), frame.top+ point.getY(), 6.0f, paint);}}if (currentLast != null) {paint.setAlpha(OPAQUE / 2);paint.setColor(resultPointColor);for (ResultPoint point : currentLast) {canvas.drawCircle(frame.left + point.getX(), frame.top+ point.getY(), 3.0f, paint);}}//只刷新扫描框的内容,其他地方不刷新postInvalidateDelayed(ANIMATION_DELAY, frame.left, frame.top,frame.right, frame.bottom);}}public void drawViewfinder() {resultBitmap = null;invalidate();}/** * 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) {possibleResultPoints.add(point);}}
4、打开关闭闪光灯
打开关闭闪光灯直接调用
CameraManager.get().openLight();
CameraManager.get().offLight();
public void openLight(){ if (camera != null) { Camera.Parameters parameter; parameter = camera.getParameters(); parameter.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH); camera.setParameters(parameter); } } public void offLight(){ if (camera != null) { Camera.Parameters parameter; parameter = camera.getParameters(); parameter.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); camera.setParameters(parameter); } }
更多相关文章
- Android Webview适配屏幕宽度
- Android虚拟机大屏幕设置(开发平板电脑程序)
- android屏幕适配
- android各种分辨率和屏幕密度
- SmartQ7 Android 改变屏幕 分辨率
- android打开关闭屏幕
- android 唤醒屏幕
- Android中获取屏幕的宽和高
- 【按键】灭屏后瞬间按返回键,可以点亮屏幕