Android二维码识别与生成(4)

相信大家都和我一样,下载后,都在考虑那怎么样集成进去项目里试一试了?因为这个库文件还是很大的。我们选择自己想要的即可。

首先你得找到zxing.jar包,并添加到项目库中,其次你需要这几个包和里面的文件,包名我改了点。然后将对应的资源也引进去,注意其是放在values文件夹下的。

其中carmera包,是对相机的初始化和一些配置处理;decoding是对相机扫描回的结果的分析处理;view是扫描框和接口处理回调。

项目里还有其他2个包,里面结构如下:

其中MainActivity是程序主入口,CustomScanViewActivity是自定义扫描窗口的FragmentActivity,CaptureFragment是自定义扫描窗口的view,在这进行相机的初始化,和处理扫描结果。扫描成功后将扫描的结果和二维码当作参数传递到handleDecode方法里进行处理,这里采用的是接口回调的方式,进行处理:


 /**

     * 处理扫描结果

     *

     * @param result

     * @param barcode

     */

    public void handleDecode(Result result, Bitmap barcode) {

        inactivityTimer.onActivity();

        playBeepSoundAndVibrate();



        if (result == null || TextUtils.isEmpty(result.getText())) {

            if (analyzeCallback != null) {

                analyzeCallback.onAnalyzeFailed();

            }

        } else {

            if (analyzeCallback != null) {

                analyzeCallback.onAnalyzeSuccess(barcode, result.getText());

            }

        }

    }

接口函数


 /**

     * 解析二维码结果接口函数

     */

    public interface AnalyticCallback{



        public void onAnalyzeSuccess(Bitmap mBitmap, String result);



        public void onAnalyzeFailed();

    }

解析方法


/**

     * 解析二维码图片方法

     * @param mBitmap

     * @param analyzeCallback

     */

    public static void analyticBitmap(Bitmap mBitmap, AnalyticCallback analyzeCallback) {



        MultiFormatReader multiFormatReader = new MultiFormatReader();



        // 解码的参数

        Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>(2);

        // 可以解析的编码类型

        Vector<BarcodeFormat> decodeFormats = new Vector<BarcodeFormat>();

        if (decodeFormats == null || decodeFormats.isEmpty()) {

            decodeFormats = new Vector<BarcodeFormat>();



            // 这里设置可扫描的类型

            decodeFormats.addAll(DecodeFormatManager.ONE_D_FORMATS);//条形码

            decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS);//二维码

            decodeFormats.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS);//其他码

        }

        hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats);

     

        // 设置解析配置参数

        multiFormatReader.setHints(hints);



        // 开始对图像资源解码

        Result rawResult = null;

        try {

         

            int width = mBitmap.getWidth();

            int height = mBitmap.getHeight();

            int[] pixels = new int[width * height];

            mBitmap.getPixels(pixels, 0, width, 0, 0, width, height);

            RGBLuminanceSource source = new RGBLuminanceSource(width, height, pixels);

        	rawResult = multiFormatReader.decode(new BinaryBitmap(new HybridBinarizer(source)));

        } catch (Exception e) {

            e.printStackTrace();

        }



        if (rawResult != null) {

            if (analyzeCallback != null) {

                analyzeCallback.onAnalyzeSuccess(mBitmap, rawResult.getText());

            }

        } else {

            if (analyzeCallback != null) {

                analyzeCallback.onAnalyzeFailed();

            }

        }

    }

由上面可以看出,我把一维码也添加进去了,也就支持扫条形码了。当然还可以扫描本地的二维码图片,首先我们要打开本地的图库,这里有2个方法,但是有个方法有点小bug,他打不开我自己的截图,因为他打开的是手机里的图库(相册)应用,而截图不在图库里,所以不能添加(我华为荣耀手机是这样的,不知道其他型号手机是否是这样),为此我采用了另外一个方法,列出系统图片文件夹表,让用户自己选择。

方法一:


   Intent intent = new Intent(Intent.ACTION_GET_CONTENT);

   intent.addCategory(Intent.CATEGORY_OPENABLE);

   intent.setType("image/*");//打开的是相册 

   startActivityForResult(intent, REQUEST_IMAGE);

然后在onActivityResult里进行接收处理


      Uri uri = data.getData();

      ContentResolver mContentResolver= getContentResolver();

      Bitmap mBitmap = MediaStore.Images.Media.getBitmap(mContentResolver, uri);//根据给定的图片uri,将其转换为bitmap

通过给定的uri转换为Bitmap,接着调用我们的接口函数


       QRCodeUtils.analyticBitmap(mBitmap, new QRCodeUtils.AnalyticCallback() {

		                        @Override

		                     public void onAnalyzeSuccess(Bitmap mBitmap, String result) {

		                            Toast.makeText(MainActivity.this, "解析结果: " + result,1).show();

		                         

		                        }



		                        @Override

		                     public void onAnalyzeFailed() {

		                           Toast.makeText(MainActivity.this, "解析图片失败", 1).show();

		                        	

		                        }

		                    });

但是通过上面的那个打开本地图库的方法找不到截图文件,于是我采用了这个方法


      Intent intent = new Intent(Intent.ACTION_PICK,

                        android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);//打开的是所有图片文件夹列表

                startActivityForResult(intent, REQUEST_IMAGE);

处理时换成这样的


           Cursor cursor = getContentResolver().query(data.getData(), null, null, null, null);

    				if (cursor.moveToFirst()) {

    					photo_path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));

    				    Log.e("图片路径-----》", photo_path);

    				   

    				}

    				cursor.close();

             Bitmap mBitmap= getDecodeAbleBitmap(photo_path);

通过uri去查询ContntResolver,返回的是个coursor对象,然后将其类似于读取数据库一样读出来,得到路径名,接着将本地图片文件转换为bitmao,为避免图片过大,先进行压缩处理。


 private static Bitmap getDecodeAbleBitmap(String picturePath) {

        try {

            BitmapFactory.Options options = new BitmapFactory.Options();

            options.inJustDecodeBounds = true;

            BitmapFactory.decodeFile(picturePath, options);

            int sampleSize = options.outHeight / 400;

            if (sampleSize <= 0)

                sampleSize = 1;

            options.inSampleSize = sampleSize;

            options.inJustDecodeBounds = false;



            return BitmapFactory.decodeFile(picturePath, options);

        } catch (Exception e) {

            return null;

        }

    }

得到bitmap对象后,接下来的步骤就一样了,调用工具类进行解析。

如果对扫描框想更改大小、刷新速度或者外观的,可以在viewfinderView中进行修改


/*

 * 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.

 */



package com.example.zxing.view;



import android.content.Context;

import android.content.res.Resources;

import android.content.res.TypedArray;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.PixelFormat;

import android.graphics.Point;

import android.graphics.Rect;

import android.graphics.drawable.Drawable;

import android.util.AttributeSet;

import android.util.Log;

import android.view.View;



import com.example.qrcodedemo.R;

import com.google.zxing.ResultPoint;

import com.example.zxing.camera.CameraManager;



import java.util.Collection;

import java.util.HashSet;



/**

 * 自定义组件实现,扫描功能

 */

public final class ViewfinderView extends View {

    /**

     * 刷新界面的时间

     */

	private static final long ANIMATION_DELAY = 10L;

	private static final int OPAQUE = 0xFF;



	private final Paint paint;

	private Bitmap resultBitmap;

	private final int maskColor;

	private final int resultColor;

	private final int resultPointColor;

	private Collection<ResultPoint> possibleResultPoints;

	private Collection<ResultPoint> lastPossibleResultPoints;

	

	// 扫描框边角颜色

	private int innercornercolor;

	// 扫描框边角长度

	private int innercornerlength;

	// 扫描框边角宽度

	private int innercornerwidth;

	

	// 扫描线移动的y

	private int scanLineTop;

	// 扫描线移动速度

	private int SCAN_VELOCITY;

	// 扫描线

	Bitmap scanLight;

	

	public ViewfinderView(Context context, AttributeSet attrs) {

		super(context, attrs);



		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<ResultPoint>(5);



		scanLight = BitmapFactory.decodeResource(resources,

				R.drawable.scan_light);//扫描线



		initInnerRect(context, attrs);

	}



	/**

	 * 初始化内部框的大小

	 * 

	 * @param context

	 * @param attrs

	 */

	private void initInnerRect(Context context, AttributeSet attrs) {

		TypedArray ta = context.obtainStyledAttributes(attrs,

				R.styleable.innerrect);



		// 扫描框距离顶部

		int innerMarginTop = ta.getInt(R.styleable.innerrect_inner_margintop,

				-1);

		if (innerMarginTop != -1) {

			CameraManager.FRAME_MARGINTOP = dip2px(context, innerMarginTop);

		}



		// 扫描框的宽度

		int innerrectWidth = ta.getInt(R.styleable.innerrect_inner_width, 210);

		CameraManager.FRAME_WIDTH = dip2px(context, innerrectWidth);



		// 扫描框的高度

		int innerrectHeight = ta

				.getInt(R.styleable.innerrect_inner_height, 210);

		CameraManager.FRAME_HEIGHT = dip2px(context, innerrectHeight);



		// 扫描框边角颜色

		innercornercolor = ta.getColor(

				R.styleable.innerrect_inner_corner_color,

				Color.parseColor("#45DDDD"));

		// 扫描框边角长度

		innercornerlength = ta.getInt(

				R.styleable.innerrect_inner_corner_length, 65);

		// 扫描框边角宽度

		innercornerwidth = ta.getInt(R.styleable.innerrect_inner_corner_width,

				15);



		// 扫描bitmap

		Drawable drawable = ta

				.getDrawable(R.styleable.innerrect_inner_scan_bitmap);

		if (drawable != null) {

		}



		// 扫描控件

		scanLight = BitmapFactory.decodeResource(getResources(), ta

				.getResourceId(R.styleable.innerrect_inner_scan_bitmap,

						R.drawable.scan_light));

		// 扫描速度

		SCAN_VELOCITY = ta.getInt(R.styleable.innerrect_inner_scan_speed, 10);



		ta.recycle();

	}



	@Override

	public void onDraw(Canvas canvas) {

		Rect frame = CameraManager.get().getFramingRect();

		if (frame == null) {

			return;

		}

		int width = canvas.getWidth();

		int height = canvas.getHeight();



		// Draw the exterior (i.e. outside the framing rect) darkened

		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 rectangle

			paint.setAlpha(OPAQUE);

			canvas.drawBitmap(resultBitmap, frame.left, frame.top, paint);

		} else {



			drawFrameBounds(canvas, frame);



			drawScanLight(canvas, frame);



			Collection<ResultPoint> currentPossible = possibleResultPoints;

			Collection<ResultPoint> currentLast = lastPossibleResultPoints;

			if (currentPossible.isEmpty()) {

				lastPossibleResultPoints = null;

			} else {

				possibleResultPoints = new HashSet<ResultPoint>(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);

		}

	}







	/**

	 * 绘制移动扫描线

	 *

	 * @param canvas

	 * @param frame

	 */

	private void drawScanLight(Canvas canvas, Rect frame) {



		if (scanLineTop == 0) {

			scanLineTop = frame.top;

		}



		if (scanLineTop >= frame.bottom - 30) {

			scanLineTop = frame.top;

		} else {

			scanLineTop += SCAN_VELOCITY;

		}

		Rect scanRect = new Rect(frame.left, scanLineTop, frame.right,

				scanLineTop + 30);

		canvas.drawBitmap(scanLight, null, scanRect, paint);

	}







	/**

	 * 绘制取景框边框

	 *

	 * @param canvas

	 * @param frame

	 */

	private void drawFrameBounds(Canvas canvas, Rect frame) {



		paint.setColor(innercornercolor);

		paint.setStyle(Paint.Style.FILL);



		int corWidth = innercornerwidth;

		int corLength = innercornerlength;



		// 左上角

		canvas.drawRect(frame.left, frame.top, frame.left + corWidth, frame.top

				+ corLength, paint);

		canvas.drawRect(frame.left, frame.top, frame.left + corLength,



### 资源分享

![一线互联网面试专题](https://img-blog.csdnimg.cn/img_convert/32fde2d98c63e85ea3e8097948116929.webp?x-oss-process=image/format,png)

![379页的Android进阶知识大全](https://img-blog.csdnimg.cn/img_convert/b8149cecdec49de390c859f2c1b03a4c.webp?x-oss-process=image/format,png)

![379页的Android进阶知识大全](https://img-blog.csdnimg.cn/img_convert/c3103a8e6b9b8b14eee5c7102e1f2632.webp?x-oss-process=image/format,png)

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

> 2020年虽然路途坎坷,都在说Android要没落,但是,不要慌,做自己的计划,学自己的习,竞争无处不在,每个行业都是如此。相信自己,没有做不到的,只有想不到的。祝大家2021年万事大吉。



**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化学习资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618156601)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

int.Style.FILL);



		int corWidth = innercornerwidth;

		int corLength = innercornerlength;



		// 左上角

		canvas.drawRect(frame.left, frame.top, frame.left + corWidth, frame.top

				+ corLength, paint);

		canvas.drawRect(frame.left, frame.top, frame.left + corLength,



### 资源分享

[外链图片转存中...(img-il0NbWkF-1714360239489)]

[外链图片转存中...(img-FMSurCs3-1714360239489)]

[外链图片转存中...(img-GwNiha1G-1714360239490)]

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

> 2020年虽然路途坎坷,都在说Android要没落,但是,不要慌,做自己的计划,学自己的习,竞争无处不在,每个行业都是如此。相信自己,没有做不到的,只有想不到的。祝大家2021年万事大吉。



**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化学习资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618156601)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值