Android二维码识别与生成 Android二维码识别与生成

Android二维码识别与生成

        最近几年二维码是越来越火了,特别是随着移动端的便利性,走到哪里都是扫一扫。二维码支付、二维码扫描登录、二维码扫描关注加好友.....越来越多的应用也都加上了二维码扫描的功能,作为移动开发者,对这些新奇的东西当然要尝试一下了。在查阅了一下网上的资料后,自己算是对二维码的扫描和生生成有了个初步的了解,写个笔记,以后想集成进项目时,也会方便很多。

        首先,什么是二维码?

        “二维条码/二维码(2-dimensional bar code)是用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息的;在代码编制上巧妙地利用构成计算机内部逻辑基础的“0”、“1”比特流的概念,使用若干个与二进制相对应的几何形体来表示文字数值信息,通过图象输入设备或光电扫描设备自动识读以实现信息自动处理:它具有条码技术的一些共性:每种码制有其特定的字符集;每个字符占有一定的宽度;具有一定的校验功能等。同时还具有对不同行的信息自动识别功能、及处理图形旋转变化点。 ”

       百科的解释如此。既然有二维码,那么肯定有一维码。相信你们对一维码认识的更早,因为一维码。最为常见的就是各种包装商品或者书籍后面的条码。当然本项目也是支持一维码的识别的。

       二维码在不同的语言和平台下有不同的支持库,Android当然是选择java支持库了,这个项目是google的大神开发的ZXing库。github地址是:https://github.com/zxing/zxing。

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

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


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

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

          

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

[java]  view plain  copy
  1. /** 
  2.     * 处理扫描结果 
  3.     * 
  4.     * @param result 
  5.     * @param barcode 
  6.     */  
  7.    public void handleDecode(Result result, Bitmap barcode) {  
  8.        inactivityTimer.onActivity();  
  9.        playBeepSoundAndVibrate();  
  10.   
  11.        if (result == null || TextUtils.isEmpty(result.getText())) {  
  12.            if (analyzeCallback != null) {  
  13.                analyzeCallback.onAnalyzeFailed();  
  14.            }  
  15.        } else {  
  16.            if (analyzeCallback != null) {  
  17.                analyzeCallback.onAnalyzeSuccess(barcode, result.getText());  
  18.            }  
  19.        }  
  20.    }  

接口函数

[java]  view plain  copy
  1. /** 
  2.     * 解析二维码结果接口函数 
  3.     */  
  4.    public interface AnalyticCallback{  
  5.   
  6.        public void onAnalyzeSuccess(Bitmap mBitmap, String result);  
  7.   
  8.        public void onAnalyzeFailed();  
  9.    }  
解析方法

[java]  view plain  copy
  1. /** 
  2.      * 解析二维码图片方法 
  3.      * @param mBitmap 
  4.      * @param analyzeCallback 
  5.      */  
  6.     public static void analyticBitmap(Bitmap mBitmap, AnalyticCallback analyzeCallback) {  
  7.   
  8.         MultiFormatReader multiFormatReader = new MultiFormatReader();  
  9.   
  10.         // 解码的参数  
  11.         Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>(2);  
  12.         // 可以解析的编码类型  
  13.         Vector<BarcodeFormat> decodeFormats = new Vector<BarcodeFormat>();  
  14.         if (decodeFormats == null || decodeFormats.isEmpty()) {  
  15.             decodeFormats = new Vector<BarcodeFormat>();  
  16.   
  17.             // 这里设置可扫描的类型  
  18.             decodeFormats.addAll(DecodeFormatManager.ONE_D_FORMATS);//条形码  
  19.             decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS);//二维码  
  20.             decodeFormats.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS);//其他码  
  21.         }  
  22.         hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats);  
  23.        
  24.         // 设置解析配置参数  
  25.         multiFormatReader.setHints(hints);  
  26.   
  27.         // 开始对图像资源解码  
  28.         Result rawResult = null;  
  29.         try {  
  30.            
  31.             int width = mBitmap.getWidth();  
  32.             int height = mBitmap.getHeight();  
  33.             int[] pixels = new int[width * height];  
  34.             mBitmap.getPixels(pixels, 0, width, 00, width, height);  
  35.             RGBLuminanceSource source = new RGBLuminanceSource(width, height, pixels);  
  36.             rawResult = multiFormatReader.decode(new BinaryBitmap(new HybridBinarizer(source)));  
  37.         } catch (Exception e) {  
  38.             e.printStackTrace();  
  39.         }  
  40.   
  41.         if (rawResult != null) {  
  42.             if (analyzeCallback != null) {  
  43.                 analyzeCallback.onAnalyzeSuccess(mBitmap, rawResult.getText());  
  44.             }  
  45.         } else {  
  46.             if (analyzeCallback != null) {  
  47.                 analyzeCallback.onAnalyzeFailed();  
  48.             }  
  49.         }  
  50.     }  

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

方法一:

[java]  view plain  copy
  1. Intent intent = new Intent(Intent.ACTION_GET_CONTENT);  
  2. intent.addCategory(Intent.CATEGORY_OPENABLE);  
  3. intent.setType("image/*");//打开的是相册   
  4. startActivityForResult(intent, REQUEST_IMAGE);  
然后在onActivityResult里进行接收处理

[java]  view plain  copy
  1. Uri uri = data.getData();  
  2. ContentResolver mContentResolver= getContentResolver();  
  3. Bitmap mBitmap = MediaStore.Images.Media.getBitmap(mContentResolver, uri);//根据给定的图片uri,将其转换为bitmap  
通过给定的uri转换为Bitmap,接着调用我们的接口函数

[java]  view plain  copy
  1. QRCodeUtils.analyticBitmap(mBitmap, new QRCodeUtils.AnalyticCallback() {  
  2.                    @Override  
  3.                 public void onAnalyzeSuccess(Bitmap mBitmap, String result) {  
  4.                        Toast.makeText(MainActivity.this"解析结果: " + result,1).show();  
  5.                       
  6.                    }  
  7.   
  8.                    @Override  
  9.                 public void onAnalyzeFailed() {  
  10.                       Toast.makeText(MainActivity.this"解析图片失败"1).show();  
  11.                       
  12.                    }  
  13.                });  
但是通过上面的那个打开本地图库的方法找不到截图文件,于是我采用了这个方法

[java]  view plain  copy
  1. Intent intent = new Intent(Intent.ACTION_PICK,  
  2.                   android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);//打开的是所有图片文件夹列表  
  3.           startActivityForResult(intent, REQUEST_IMAGE);  
处理时换成这样的

[java]  view plain  copy
  1.    Cursor cursor = getContentResolver().query(data.getData(), nullnullnullnull);  
  2. if (cursor.moveToFirst()) {  
  3.     photo_path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));  
  4.     Log.e("图片路径-----》", photo_path);  
  5.      
  6. }  
  7. cursor.close();  
  8.      Bitmap mBitmap= getDecodeAbleBitmap(photo_path);  
通过uri去查询ContntResolver,返回的是个coursor对象,然后将其类似于读取数据库一样读出来,得到路径名,接着将本地图片文件转换为bitmao,为避免图片过大,先进行压缩处理。

[java]  view plain  copy
  1. private static Bitmap getDecodeAbleBitmap(String picturePath) {  
  2.        try {  
  3.            BitmapFactory.Options options = new BitmapFactory.Options();  
  4.            options.inJustDecodeBounds = true;  
  5.            BitmapFactory.decodeFile(picturePath, options);  
  6.            int sampleSize = options.outHeight / 400;  
  7.            if (sampleSize <= 0)  
  8.                sampleSize = 1;  
  9.            options.inSampleSize = sampleSize;  
  10.            options.inJustDecodeBounds = false;  
  11.   
  12.            return BitmapFactory.decodeFile(picturePath, options);  
  13.        } catch (Exception e) {  
  14.            return null;  
  15.        }  
  16.    }  

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

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

[java]  view plain  copy
  1. /* 
  2.  * Copyright (C) 2008 ZXing authors 
  3.  * 
  4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  5.  * you may not use this file except in compliance with the License. 
  6.  * You may obtain a copy of the License at 
  7.  * 
  8.  *      http://www.apache.org/licenses/LICENSE-2.0 
  9.  * 
  10.  * Unless required by applicable law or agreed to in writing, software 
  11.  * distributed under the License is distributed on an "AS IS" BASIS, 
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  13.  * See the License for the specific language governing permissions and 
  14.  * limitations under the License. 
  15.  */  
  16.   
  17. package com.example.zxing.view;  
  18.   
  19. import android.content.Context;  
  20. import android.content.res.Resources;  
  21. import android.content.res.TypedArray;  
  22. import android.graphics.Bitmap;  
  23. import android.graphics.BitmapFactory;  
  24. import android.graphics.Canvas;  
  25. import android.graphics.Color;  
  26. import android.graphics.Paint;  
  27. import android.graphics.PixelFormat;  
  28. import android.graphics.Point;  
  29. import android.graphics.Rect;  
  30. import android.graphics.drawable.Drawable;  
  31. import android.util.AttributeSet;  
  32. import android.util.Log;  
  33. import android.view.View;  
  34.   
  35. import com.example.qrcodedemo.R;  
  36. import com.google.zxing.ResultPoint;  
  37. import com.example.zxing.camera.CameraManager;  
  38.   
  39. import java.util.Collection;  
  40. import java.util.HashSet;  
  41.   
  42. /** 
  43.  * 自定义组件实现,扫描功能 
  44.  */  
  45. public final class ViewfinderView extends View {  
  46.     /** 
  47.      * 刷新界面的时间 
  48.      */  
  49.     private static final long ANIMATION_DELAY = 10L;  
  50.     private static final int OPAQUE = 0xFF;  
  51.   
  52.     private final Paint paint;  
  53.     private Bitmap resultBitmap;  
  54.     private final int maskColor;  
  55.     private final int resultColor;  
  56.     private final int resultPointColor;  
  57.     private Collection<ResultPoint> possibleResultPoints;  
  58.     private Collection<ResultPoint> lastPossibleResultPoints;  
  59.       
  60.     // 扫描框边角颜色  
  61.     private int innercornercolor;  
  62.     // 扫描框边角长度  
  63.     private int innercornerlength;  
  64.     // 扫描框边角宽度  
  65.     private int innercornerwidth;  
  66.       
  67.     // 扫描线移动的y  
  68.     private int scanLineTop;  
  69.     // 扫描线移动速度  
  70.     private int SCAN_VELOCITY;  
  71.     // 扫描线  
  72.     Bitmap scanLight;  
  73.       
  74.     public ViewfinderView(Context context, AttributeSet attrs) {  
  75.         super(context, attrs);  
  76.   
  77.         paint = new Paint();  
  78.         Resources resources = getResources();  
  79.         maskColor = resources.getColor(R.color.viewfinder_mask);  
  80.         resultColor = resources.getColor(R.color.result_view);  
  81.         resultPointColor = resources.getColor(R.color.possible_result_points);  
  82.         possibleResultPoints = new HashSet<ResultPoint>(5);  
  83.   
  84.         scanLight = BitmapFactory.decodeResource(resources,  
  85.                 R.drawable.scan_light);//扫描线  
  86.   
  87.         initInnerRect(context, attrs);  
  88.     }  
  89.   
  90.     /** 
  91.      * 初始化内部框的大小 
  92.      *  
  93.      * @param context 
  94.      * @param attrs 
  95.      */  
  96.     private void initInnerRect(Context context, AttributeSet attrs) {  
  97.         TypedArray ta = context.obtainStyledAttributes(attrs,  
  98.                 R.styleable.innerrect);  
  99.   
  100.         // 扫描框距离顶部  
  101.         int innerMarginTop = ta.getInt(R.styleable.innerrect_inner_margintop,  
  102.                 -1);  
  103.         if (innerMarginTop != -1) {  
  104.             CameraManager.FRAME_MARGINTOP = dip2px(context, innerMarginTop);  
  105.         }  
  106.   
  107.         // 扫描框的宽度  
  108.         int innerrectWidth = ta.getInt(R.styleable.innerrect_inner_width, 210);  
  109.         CameraManager.FRAME_WIDTH = dip2px(context, innerrectWidth);  
  110.   
  111.         // 扫描框的高度  
  112.         int innerrectHeight = ta  
  113.                 .getInt(R.styleable.innerrect_inner_height, 210);  
  114.         CameraManager.FRAME_HEIGHT = dip2px(context, innerrectHeight);  
  115.   
  116.         // 扫描框边角颜色  
  117.         innercornercolor = ta.getColor(  
  118.                 R.styleable.innerrect_inner_corner_color,  
  119.                 Color.parseColor("#45DDDD"));  
  120.         // 扫描框边角长度  
  121.         innercornerlength = ta.getInt(  
  122.                 R.styleable.innerrect_inner_corner_length, 65);  
  123.         // 扫描框边角宽度  
  124.         innercornerwidth = ta.getInt(R.styleable.innerrect_inner_corner_width,  
  125.                 15);  
  126.   
  127.         // 扫描bitmap  
  128.         Drawable drawable = ta  
  129.                 .getDrawable(R.styleable.innerrect_inner_scan_bitmap);  
  130.         if (drawable != null) {  
  131.         }  
  132.   
  133.         // 扫描控件  
  134.         scanLight = BitmapFactory.decodeResource(getResources(), ta  
  135.                 .getResourceId(R.styleable.innerrect_inner_scan_bitmap,  
  136.                         R.drawable.scan_light));  
  137.         // 扫描速度  
  138.         SCAN_VELOCITY = ta.getInt(R.styleable.innerrect_inner_scan_speed, 10);  
  139.   
  140.         ta.recycle();  
  141.     }  
  142.   
  143.     @Override  
  144.     public void onDraw(Canvas canvas) {  
  145.         Rect frame = CameraManager.get().getFramingRect();  
  146.         if (frame == null) {  
  147.             return;  
  148.         }  
  149.         int width = canvas.getWidth();  
  150.         int height = canvas.getHeight();  
  151.   
  152.         // Draw the exterior (i.e. outside the framing rect) darkened  
  153.         paint.setColor(resultBitmap != null ? resultColor : maskColor);  
  154.         canvas.drawRect(00, width, frame.top, paint);  
  155.         canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint);  
  156.         canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1,  
  157.                 paint);  
  158.         canvas.drawRect(0, frame.bottom + 1, width, height, paint);  
  159.   
  160.         if (resultBitmap != null) {  
  161.             // Draw the opaque result bitmap over the scanning rectangle  
  162.             paint.setAlpha(OPAQUE);  
  163.             canvas.drawBitmap(resultBitmap, frame.left, frame.top, paint);  
  164.         } else {  
  165.   
  166.             drawFrameBounds(canvas, frame);  
  167.   
  168.             drawScanLight(canvas, frame);  
  169.   
  170.             Collection<ResultPoint> currentPossible = possibleResultPoints;  
  171.             Collection<ResultPoint> currentLast = lastPossibleResultPoints;  
  172.             if (currentPossible.isEmpty()) {  
  173.                 lastPossibleResultPoints = null;  
  174.             } else {  
  175.                 possibleResultPoints = new HashSet<ResultPoint>(5);  
  176.                 lastPossibleResultPoints = currentPossible;  
  177.                 paint.setAlpha(OPAQUE);  
  178.                 paint.setColor(resultPointColor);  
  179.                 for (ResultPoint point : currentPossible) {  
  180.                     canvas.drawCircle(frame.left + point.getX(), frame.top  
  181.                             + point.getY(), 6.0f, paint);  
  182.                 }  
  183.             }  
  184.             if (currentLast != null) {  
  185.                 paint.setAlpha(OPAQUE / 2);  
  186.                 paint.setColor(resultPointColor);  
  187.                 for (ResultPoint point : currentLast) {  
  188.                     canvas.drawCircle(frame.left + point.getX(), frame.top  
  189.                             + point.getY(), 3.0f, paint);  
  190.                 }  
  191.             }  
  192.   
  193.             postInvalidateDelayed(ANIMATION_DELAY, frame.left, frame.top,  
  194.                     frame.right, frame.bottom);  
  195.         }  
  196.     }  
  197.   
  198.   
  199.   
  200.     /** 
  201.      * 绘制移动扫描线 
  202.      * 
  203.      * @param canvas 
  204.      * @param frame 
  205.      */  
  206.     private void drawScanLight(Canvas canvas, Rect frame) {  
  207.   
  208.         if (scanLineTop == 0) {  
  209.             scanLineTop = frame.top;  
  210.         }  
  211.   
  212.         if (scanLineTop >= frame.bottom - 30) {  
  213.             scanLineTop = frame.top;  
  214.         } else {  
  215.             scanLineTop += SCAN_VELOCITY;  
  216.         }  
  217.         Rect scanRect = new Rect(frame.left, scanLineTop, frame.right,  
  218.                 scanLineTop + 30);  
  219.         canvas.drawBitmap(scanLight, null, scanRect, paint);  
  220.     }  
  221.   
  222.   
  223.   
  224.     /** 
  225.      * 绘制取景框边框 
  226.      * 
  227.      * @param canvas 
  228.      * @param frame 
  229.      */  
  230.     private void drawFrameBounds(Canvas canvas, Rect frame) {  
  231.   
  232.         paint.setColor(innercornercolor);  
  233.         paint.setStyle(Paint.Style.FILL);  
  234.   
  235.         int corWidth = innercornerwidth;  
  236.         int corLength = innercornerlength;  
  237.   
  238.         // 左上角  
  239.         canvas.drawRect(frame.left, frame.top, frame.left + corWidth, frame.top  
  240.                 + corLength, paint);  
  241.         canvas.drawRect(frame.left, frame.top, frame.left + corLength,  
  242.                 frame.top + corWidth, paint);  
  243.           // 右上角  
  244.         canvas.drawRect(frame.right - corWidth, frame.top, frame.right,  
  245.                 frame.top + corLength, paint);  
  246.         canvas.drawRect(frame.right - corLength, frame.top, frame.right,  
  247.                 frame.top + corWidth, paint);  
  248.          // 左下角  
  249.         canvas.drawRect(frame.left, frame.bottom - corLength, frame.left  
  250.                 + corWidth, frame.bottom, paint);  
  251.         canvas.drawRect(frame.left, frame.bottom - corWidth, frame.left  
  252.                 + corLength, frame.bottom, paint);  
  253.           // 右下角  
  254.         canvas.drawRect(frame.right - corWidth, frame.bottom - corLength,  
  255.                 frame.right, frame.bottom, paint);  
  256.         canvas.drawRect(frame.right - corLength, frame.bottom - corWidth,  
  257.                 frame.right, frame.bottom, paint);  
  258.     }  
  259.   
  260.     public void drawViewfinder() {  
  261.         resultBitmap = null;  
  262.         invalidate();  
  263.     }  
  264.   
  265.     public void addPossibleResultPoint(ResultPoint point) {  
  266.         possibleResultPoints.add(point);  
  267.     }  
  268.   
  269.     /** 
  270.      * 根据手机的分辨率从 dp 的单位 转成为 px(像素) 
  271.      */  
  272.     public static int dip2px(Context context, float dpValue) {  
  273.         final float scale = context.getResources().getDisplayMetrics().density;  
  274.         return (int) (dpValue * scale + 0.5f);  
  275.     }  
  276.   
  277. }  

至此,扫描二维码和解析本地图片二维码已介绍完了,接下来是如何生成二维码的介绍。

生成二维码采用的是这个方法

[java]  view plain  copy
  1.     BitMatrix bitMatrix = new QRCodeWriter().encode(text, BarcodeFormat.QR_CODE, width, height, hints);  
这个方法得到的是一个bit二维矩阵,然后通过2个for循环,将其放置进一个一维的数组中

[java]  view plain  copy
  1. int[] pixels = new int[width * height];  
  2.  //下面这里按照二维码的算法,逐个生成二维码的图片,  
  3.  //两个for循环是图片横列扫描的结果  
  4.  for (int y = 0; y < height; y++)  
  5.  {  
  6.      for (int x = 0; x < width; x++)  
  7.      {  
  8.          if (bitMatrix.get(x, y))  
  9.          {  
  10.              pixels[y * width + x] = 0xff000000;//当然我们也可以自己更改颜色  
  11.          }  
  12.          else  
  13.          {  
  14.              pixels[y * width + x] = 0xffffffff;  
  15.          }  
  16.      }  
  17.  }  
最后生成二维码bitmap

[java]  view plain  copy
  1. //生成二维码图片的格式,使用ARGB_8888  
  2.   Bitmap bitmap = Bitmap.createBitmap(QR_WIDTH, QR_HEIGHT, Bitmap.Config.ARGB_8888);  
  3.   bitmap.setPixels(pixels, 0, QR_WIDTH, 00, QR_WIDTH, QR_HEIGHT);  

如果想对扫描的界面想增加点自己的按钮或者功能的,因为采用的是fragment,也可以替换,实现定制扫描的UI界面

1,在新的activity中定义我们的布局

[java]  view plain  copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:id="@+id/activity_second"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="match_parent">  
  6.   
  7.     <Button  
  8.         android:id="@+id/second_button1"  
  9.         android:layout_width="wrap_content"  
  10.         android:layout_height="wrap_content"  
  11.         android:text="取消"  
  12.         android:layout_marginTop="20dp"  
  13.         android:layout_marginLeft="20dp"  
  14.         android:layout_marginRight="20dp"  
  15.         android:layout_marginBottom="10dp"  
  16.         android:layout_gravity="bottom|center_horizontal"  
  17.         />  
  18.   
  19.     <FrameLayout  
  20.         android:id="@+id/fl_my_container"  
  21.         android:layout_width="match_parent"  
  22.         android:layout_height="match_parent"  
  23.         ></FrameLayout>  
  24.   
  25. </FrameLayout>  
        启动id为fl_my_container的FrameLayout就是我们需要替换的扫描组件,也就是说我们会将我们定义的扫描Fragment替换到id为fl_my_container的FrameLayout的位置。而上面的button是我们添加的一个额外的控件,在这里你可以添加任意的控件,各种UI效果等。具体可以看下面在Activity的初始化过程。

       在Activity中执行Fragment的初始化操作

[java]  view plain  copy
  1. protected void onCreate(Bundle savedInstanceState) {  
  2.        super.onCreate(savedInstanceState);  
  3.        setContentView(R.layout.activity_second);  
  4.        /** 
  5.         * 执行扫面Fragment的初始化操作 
  6.         */  
  7.        CaptureFragment captureFragment = new CaptureFragment();  
  8.        // 为二维码扫描界面设置定制化界面  
  9.        QRCodeUtils.setFragmentArgs(captureFragment, R.layout.my_camera);  
  10.   
  11.        captureFragment.setAnalyzeCallback(analyzeCallback);  
  12.        /** 
  13.         * 替换我们的扫描控件 
  14.         */                                                                                                                                                        getSupportFragmentManager().beginTransaction().replace(R.id.fl_my_container, captureFragment).commit();  
  15.    }  
注意:因为用到了fragment,假如你集成的是activity,那你要导入v4包,否则在调用getSupportFragmentManager时,会找不到调用方法。

而此activity此时要改成要继承于FragmentActivity。

在上面的onCreate方法中,我们调用了QRCodeUtils.setFragmentArgs(captureFragment, R.layout.my_camera);方法。该方法主要用于修改扫描界面扫描框与透明框相对位置的,与若不调用的话,其会显示默认的组件效果,而如果调用该方法的话,可以修改扫描框与透明框的相对位置等UI效果,我们可以看一下my_camera布局文件的实现。

[java]  view plain  copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:app="http://schemas.android.com/apk/res-auto"  
  4.     android:layout_width="fill_parent"  
  5.     android:layout_height="fill_parent" >  
  6.   
  7.   
  8.     <SurfaceView  
  9.         android:id="@+id/preview_view"  
  10.         android:layout_width="wrap_content"  
  11.         android:layout_height="wrap_content"  
  12.         />  
  13.   
  14.   
  15.     <com.example.zxing.view.ViewfinderView  
  16.     android:id="@+id/viewfinder_view"  
  17.     android:layout_width="wrap_content"  
  18.     android:layout_height="wrap_content"  
  19.     app:inner_width="180"  
  20.     app:inner_height="180"  
  21.     app:inner_margintop="120"  
  22.     app:inner_corner_color="@color/scan_corner_color"  
  23.     app:inner_corner_length="60"  
  24.     app:inner_corner_width="10"  
  25.     app:inner_scan_bitmap="@drawable/scan_image"  
  26.     app:inner_scan_speed="10"  
  27.     />  
  28.   
  29.   
  30. </FrameLayout>  
上面我们自定义的扫描控件的布局文件,下面我们看一下默认的扫描框的布局文件:
[java]  view plain  copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent" >  
  5.   
  6.     <SurfaceView  
  7.         android:id="@+id/preview_view"  
  8.         android:layout_width="wrap_content"  
  9.         android:layout_height="wrap_content"  
  10.         android:layout_gravity="center" />  
  11.   
  12.     <com.example.zxing.view.ViewfinderView  
  13.         android:id="@+id/viewfinder_view"  
  14.         android:layout_width="wrap_content"  
  15.         android:layout_height="wrap_content" />  
  16.   
  17. </FrameLayout>  

好了,项目介绍到这里了,总体来说,效果功能都实现了,待实际需求时,可以直接集成更改即可。源码地址: 点我下载

参考别人的github项目,发现别人的扫描速度稍微快一点,以后有待研究。https://github.com/bingoogolapple/BGAQRCode-Android


注:解决关于扫描时出现图片拉伸的问题。

如果是直接引用的zxing包里面的camera文件时,可能会出现扫描的二维码在扫描框内出现拉伸问题,因为Zxing包里的二维码扫描默认是横屏扫描的,改为竖屏后出现比例问题,所以要修正过来。

可以在camera包里面的CameraConfigurationManager.java文件里的

void initFromCameraParameters(Camera camera)方法

在 Log.d(TAG, "Screen resolution: " + screenResolution);这句之后增加

[java]  view plain  copy
  1. Point screenResolutionForCamera = new Point();    
  2. screenResolutionForCamera.x = screenResolution.x;    
  3. screenResolutionForCamera.y = screenResolution.y;    
  4. // preview size is always something like 480*320, other 320*480    
  5. if (screenResolution.x < screenResolution.y) {    
  6. screenResolutionForCamera.x = screenResolution.y;    
  7. screenResolutionForCamera.y = screenResolution.x;    
  8. }    
然后将
[java]  view plain  copy
  1. cameraResolution = getCameraResolution(parameters, screenResolution);    
注释掉,改为:

[java]  view plain  copy
  1. cameraResolution = getCameraResolution(parameters, screenResolutionForCamera);   
这样就可以了,解决图片拉伸的问题。

8/15日更新
增加二维码生成识别容错率

在我们生产二维码的时候,有时二维码中间放logo的话,识别起来比不放困难点,但是logo又不能太小,否则就起不到宣传认识效果,太大了后识别就稍微困难点了。一方面我们的图片大小要适中,另一方面又要增加二维码的识别容错率,这样可以加快识别速度。

默认的二维码容错率是ErrorCorrectionLevel.L

在QRCodeWriter源码中(位置是com.google.zxing.qrcode)可以看到有默认值

[java]  view plain  copy
  1. ErrorCorrectionLevel errorCorrectionLevel = ErrorCorrectionLevel.L;  
  2.     int quietZone = QUIET_ZONE_SIZE;  
  3.     if (hints != null) {  
  4.       ErrorCorrectionLevel requestedECLevel = (ErrorCorrectionLevel) hints.get(EncodeHintType.ERROR_CORRECTION);  
  5.       if (requestedECLevel != null) {  
  6.         errorCorrectionLevel = requestedECLevel;  
  7.       }  
  8.       Integer quietZoneInt = (Integer) hints.get(EncodeHintType.MARGIN);  
  9.       if (quietZoneInt != null) {  
  10.         quietZone = quietZoneInt;  
  11.       }  
  12.     }  
可以看出他是通过一个hashtable.get获得的,为此,我们可以通过put去修改,将我们要设置的值传进去。
[java]  view plain  copy
  1.             Hashtable hints = new Hashtable();  
  2.             hints.put(EncodeHintType.CHARACTER_SET, "utf-8");//设置编码格式,否则中文会识别不了  
  3.             hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);//容错率默认是7%,现改为30%  
后面的BitMatrix不用变。

猜你喜欢

转载自blog.csdn.net/jhope/article/details/80761774