昊仔

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

最近公司的Android项目需要用到摄像头做条码或二维码的扫描,Google一下,发现一个开源的 ZXing项目。它提供二维码和条形码的扫描。扫描条形码就是直接读取条形码的内容,扫描二维码是按照自己指定的二维码格式进行编码和解码。

1.什么是二维码和条形码?

                       

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

条形码(barcode)是将宽度不等的多个黑条和空白,按照一定的编码规则排列,用以表达一组信息的图形标识符。常见的条形码是由反射率相差很大的黑条(简称条)和白条(简称空)排成的平行线图案。条形码可以标出物品的生产国、制造厂家、商品名称、生产日期、图书分类号、邮件起止地点、类别、日期等许多信息,因而在商品流通、图书管理、邮政管理、银行系统等许多领域都得到广泛的应用。

2.ZXing基本介绍

ZXing是一个开源Java类库用于解析多种格式的条形码和二维码.官网:http://code.google.com/p/zxing/

截止目前为止最新版本提供以下编码格式的支持:

  • UPC-A and UPC-E
  • EAN-8 and EAN-13
  • Code 39
  • Code 93
  • Code 128
  • QR Code
  • ITF
  • Codabar
  • RSS-14 (all variants)
  • Data Matrix
  • PDF 417 ('alpha' quality)
  • Aztec ('alpha' quality)

同时官网提供了 Android、cpp、C#、iPhone、j2me、j2se、jruby、objc、rim、symbian等多种应用的类库,具体详情可以参考下载的源码包中。

3.Android端编码演示

这里使用的ZXing是经过简化版的,去除了一些一般使用不必要的文件,项目工程和效果截图如下:

   

其中encoding包是在原基础上加上去的,功能是根据传入的字符串来生成二维码图片,返回一个Bitmap,其余的包是ZXing项目自带的。另外对扫描界面的布局也进行了修改,官方的扫描界面是横向的,我改成了纵向的,并加入了顶部的Tab和取消按钮(camera.xml),另外还需要的一些文件是colors.xml、ids.xml,这些都是原本ZXing项目中自带的,最后就是libs下面的jar包。

接下来看如何使用,首先是把ZXing项目中的一些文件拷贝到我们自己的项目中,然后在Mainifest文件中进行配置权限:

  1. <uses-permissionandroid:name="android.permission.VIBRATE"/> 
  2. <uses-permissionandroid:name="android.permission.CAMERA"/> 
  3. <uses-featureandroid:name="android.hardware.camera"/> 
  4. <uses-featureandroid:name="android.hardware.camera.autofocus"/> 

还有就是扫描界面Activity的配置:

  1. <activity 
  2.          android:configChanges="orientation|keyboardHidden" 
  3.          android:name="com.zxing.activity.CaptureActivity" 
  4.          android:screenOrientation="portrait" 
  5.          android:theme="@android:style/Theme.NoTitleBar.Fullscreen" 
  6.          android:windowSoftInputMode="stateAlwaysHidden"> 
  7. </activity> 

接下来是我自己项目的布局文件:

  1. <?xmlversion="1.0"encoding="utf-8"?> 
  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" 
  3.     android:layout_width="fill_parent" 
  4.     android:layout_height="fill_parent" 
  5.     android:background="@android:color/white" 
  6.     android:orientation="vertical"> 
  7.  
  8.     <Button 
  9.         android:id="@+id/btn_scan_barcode" 
  10.         android:layout_width="fill_parent" 
  11.         android:layout_height="wrap_content" 
  12.         android:layout_marginTop="30dp" 
  13.         android:text="Open camera"/> 
  14.      
  15.     <LinearLayout  
  16.         android:orientation="horizontal" 
  17.         android:layout_marginTop="10dp" 
  18.         android:layout_width="fill_parent" 
  19.         android:layout_height="wrap_content"> 
  20.          
  21.         <TextView  
  22.         android:layout_width="wrap_content" 
  23.         android:layout_height="wrap_content" 
  24.         android:textColor="@android:color/black" 
  25.         android:textSize="18sp" 
  26.         android:text="Scan result:"/> 
  27.          
  28.         <TextView  
  29.         android:id="@+id/tv_scan_result" 
  30.         android:layout_width="fill_parent" 
  31.         android:textSize="18sp" 
  32.         android:textColor="@android:color/black" 
  33.         android:layout_height="wrap_content"/> 
  34.     </LinearLayout> 
  35.      
  36.     <EditText  
  37.         android:id="@+id/et_qr_string" 
  38.         android:layout_width="fill_parent" 
  39.         android:layout_height="wrap_content" 
  40.         android:layout_marginTop="30dp" 
  41.         android:hint="Input the text"/> 
  42.      
  43.     <Button 
  44.         android:id="@+id/btn_add_qrcode" 
  45.         android:layout_width="fill_parent" 
  46.         android:layout_height="wrap_content" 
  47.         android:text="Generate QRcode"/> 
  48.      
  49.     <ImageView  
  50.         android:id="@+id/iv_qr_image" 
  51.         android:layout_width="wrap_content" 
  52.         android:layout_height="wrap_content" 
  53.         android:layout_marginTop="10dp" 
  54.         android:layout_gravity="center"/> 
  55.  
  56. </LinearLayout> 

下面是主Activity的代码,主要功能是打开扫描框、显示扫描结果、根据输入的字符串生成二维码图片:

  1. publicclass BarCodeTestActivity extends Activity { 
  2.     /** Called when the activity is first created. */ 
  3.     private TextView resultTextView; 
  4.     private EditText qrStrEditText; 
  5.     private ImageView qrImgImageView; 
  6.      
  7.     @Override 
  8.     publicvoid onCreate(Bundle savedInstanceState) { 
  9.         super.onCreate(savedInstanceState); 
  10.         setContentView(R.layout.main); 
  11.          
  12.         resultTextView = (TextView) this.findViewById(R.id.tv_scan_result); 
  13.         qrStrEditText = (EditText) this.findViewById(R.id.et_qr_string); 
  14.         qrImgImageView = (ImageView) this.findViewById(R.id.iv_qr_image); 
  15.          
  16.         Button scanBarCodeButton = (Button) this.findViewById(R.id.btn_scan_barcode); 
  17.         scanBarCodeButton.setOnClickListener(new OnClickListener() { 
  18.              
  19.             @Override 
  20.             publicvoid onClick(View v) { 
  21.                 //打开扫描界面扫描条形码或二维码  
  22.                 Intent openCameraIntent = new Intent(BarCodeTestActivity.this,CaptureActivity.class); 
  23.                 startActivityForResult(openCameraIntent, 0); 
  24.             } 
  25.         }); 
  26.          
  27.         Button generateQRCodeButton = (Button) this.findViewById(R.id.btn_add_qrcode); 
  28.         generateQRCodeButton.setOnClickListener(new OnClickListener() { 
  29.              
  30.             @Override 
  31.             publicvoid onClick(View v) { 
  32.                 try
  33.                     String contentString = qrStrEditText.getText().toString(); 
  34.                     if (!contentString.equals("")) { 
  35.                         //根据字符串生成二维码图片并显示在界面上,第二个参数为图片的大小(350*350)  
  36.                         Bitmap qrCodeBitmap = EncodingHandler.createQRCode(contentString, 350); 
  37.                         qrImgImageView.setImageBitmap(qrCodeBitmap); 
  38.                     }else
  39.                         Toast.makeText(BarCodeTestActivity.this, "Text can not be empty", Toast.LENGTH_SHORT).show(); 
  40.                     } 
  41.                      
  42.                 } catch (WriterException e) { 
  43.                     // TODO Auto-generated catch block  
  44.                     e.printStackTrace(); 
  45.                 } 
  46.             } 
  47.         }); 
  48.     } 
  49.  
  50.     @Override 
  51.     protectedvoid onActivityResult(int requestCode, int resultCode, Intent data) { 
  52.         super.onActivityResult(requestCode, resultCode, data); 
  53.         //处理扫描结果(在界面上显示)  
  54.         if (resultCode == RESULT_OK) { 
  55.             Bundle bundle = data.getExtras(); 
  56.             String scanResult = bundle.getString("result"); 
  57.             resultTextView.setText(scanResult); 
  58.         } 
  59.     } 

其中生成二维码图片的代码在EncodingHandler.java中:

  1. publicfinalclass EncodingHandler { 
  2.     privatestaticfinalint BLACK = 0xff000000
  3.      
  4.     publicstatic Bitmap createQRCode(String str,int widthAndHeight) throws WriterException { 
  5.         Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>();   
  6.         hints.put(EncodeHintType.CHARACTER_SET, "utf-8");  
  7.         BitMatrix matrix = new MultiFormatWriter().encode(str, 
  8.                 BarcodeFormat.QR_CODE, widthAndHeight, widthAndHeight); 
  9.         int width = matrix.getWidth(); 
  10.         int height = matrix.getHeight(); 
  11.         int[] pixels = newint[width * height]; 
  12.          
  13.         for (int y = 0; y < height; y++) { 
  14.             for (int x = 0; x < width; x++) { 
  15.                 if (matrix.get(x, y)) { 
  16.                     pixels[y * width + x] = BLACK; 
  17.                 } 
  18.             } 
  19.         } 
  20.         Bitmap bitmap = Bitmap.createBitmap(width, height, 
  21.                 Bitmap.Config.ARGB_8888); 
  22.         bitmap.setPixels(pixels, 0, width, 0, 0, width, height); 
  23.         return bitmap; 
  24.     } 

最后是在哪里对扫描结果进行解码,进入CaptureActivity.java找到下面这个方法便可以对自己对结果进行操作:

  1. /**
  2. * Handler scan result
  3. * @param result
  4. * @param barcode
  5. */ 
  6. ublic void handleDecode(Result result, Bitmap barcode) { 
  7. inactivityTimer.onActivity(); 
  8. playBeepSoundAndVibrate(); 
  9. String resultString = result.getText(); 
  10. //FIXME  
  11. if (resultString.equals("")) { 
  12.     Toast.makeText(CaptureActivity.this, "Scan failed!", Toast.LENGTH_SHORT).show(); 
  13. }else
  14.             System.out.println("Result:"+resultString); 
  15.     Intent resultIntent = new Intent(); 
  16.     Bundle bundle = new Bundle(); 
  17.     bundle.putString("result", resultString); 
  18.     resultIntent.putExtras(bundle); 
  19.     this.setResult(RESULT_OK, resultIntent); 
  20. CaptureActivity.this.finish(); 

4.Java端编码演示

在Java端上实现条形码(EAN-13)和二维码(QRCode) 的编码和解码的示例,以供大家参考,用到了源码中core和javase下面的相关源代码,附件提供自己编译之后的lib包:

  • zxing.jar
  • zxing-j2se.jar

    有关各种手机系统的应用,有兴趣的朋友可以下载官方源码包,包下有具体详细的应用介绍。

    1)二维码(QRCode)的编码和解码演示:

    编码示例:

    1. package michael.zxing; 
    2.  
    3. import java.io.File; 
    4. import java.util.Hashtable; 
    5.  
    6. import com.google.zxing.BarcodeFormat; 
    7. import com.google.zxing.EncodeHintType; 
    8. import com.google.zxing.MultiFormatWriter; 
    9. import com.google.zxing.client.j2se.MatrixToImageWriter; 
    10. import com.google.zxing.common.BitMatrix; 
    11. import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; 
    12.  
    13. /**
    14. * @blog http://sjsky.iteye.com
    15. * @author Michael
    16. */ 
    17. publicclass ZxingEncoderHandler { 
    18.  
    19.     /**
    20.      * 编码
    21.      * @param contents
    22.      * @param width
    23.      * @param height
    24.      * @param imgPath
    25.      */ 
    26.     publicvoid encode(String contents, int width, int height, String imgPath) { 
    27.         Hashtable<Object, Object> hints = new Hashtable<Object, Object>(); 
    28.         // 指定纠错等级  
    29.         hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L); 
    30.         // 指定编码格式  
    31.         hints.put(EncodeHintType.CHARACTER_SET, "GBK"); 
    32.         try
    33.             BitMatrix bitMatrix = new MultiFormatWriter().encode(contents, 
    34.                     BarcodeFormat.QR_CODE, width, height, hints); 
    35.  
    36.             MatrixToImageWriter 
    37.                     .writeToFile(bitMatrix, "png", new File(imgPath)); 
    38.  
    39.         } catch (Exception e) { 
    40.             e.printStackTrace(); 
    41.         } 
    42.     } 
    43.  
    44.     /**
    45.      * @param args
    46.      */ 
    47.     publicstaticvoid main(String[] args) { 
    48.         String imgPath = "d:/1.png"
    49.         String contents = "Hello Word!"
    50.         int width = 300, height = 300
    51.         ZxingEncoderHandler handler = new ZxingEncoderHandler(); 
    52.         handler.encode(contents, width, height, imgPath); 
    53.     } 

    运行后生成的二维码图片如下:

    用手机的二维码扫描软件(本人用的:android 快拍二维码 )来测试下,识别成功的截图如下:

   

       解码示例:

    1. package michael.zxing; 
    2.  
    3. import java.awt.image.BufferedImage; 
    4. import java.io.File; 
    5. import java.util.Hashtable; 
    6.  
    7. import javax.imageio.ImageIO; 
    8.  
    9. import com.google.zxing.BinaryBitmap; 
    10. import com.google.zxing.DecodeHintType; 
    11. import com.google.zxing.LuminanceSource; 
    12. import com.google.zxing.MultiFormatReader; 
    13. import com.google.zxing.Result; 
    14. import com.google.zxing.client.j2se.BufferedImageLuminanceSource; 
    15. import com.google.zxing.common.HybridBinarizer; 
    16.  
    17. /**
    18. * @blog http://sjsky.iteye.com
    19. * @author Michael
    20. */ 
    21. publicclass ZxingDecoderHandler { 
    22.  
    23.     /**
    24.      * @param imgPath
    25.      * @return String
    26.      */ 
    27.     public String decode(String imgPath) { 
    28.         BufferedImage image = null
    29.         Result result = null
    30.         try
    31.             image = ImageIO.read(new File(imgPath)); 
    32.             if (image == null) { 
    33.                 System.out.println("the decode image may be not exit."); 
    34.             } 
    35.             LuminanceSource source = new BufferedImageLuminanceSource(image); 
    36.             BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); 
    37.  
    38.             Hashtable<Object, Object> hints = new Hashtable<Object, Object>(); 
    39.             hints.put(DecodeHintType.CHARACTER_SET, "utf-8"); 
    40.  
    41.             result = new MultiFormatReader().decode(bitmap, hints); 
    42.             return result.getText(); 
    43.         } catch (Exception e) { 
    44.             e.printStackTrace(); 
    45.         } 
    46.         returnnull
    47.     } 
    48.  
    49.     /**
    50.      * @param args
    51.      */ 
    52.     publicstaticvoid main(String[] args) { 
    53.         String imgPath = "d:/1.png"
    54.         ZxingDecoderHandler handler = new ZxingDecoderHandler(); 
    55.         String decodeContent = handler.decode(imgPath); 
    56.         System.out.println("解码内容如下:"); 
    57.         System.out.println(decodeContent); 
    58.     } 

    解码内容如下: Hello Word!

    2)条形码(EAN-13)的编码和解码演示:

    编码示例:

    1. package michael.zxing; 
    2.  
    3. import java.io.File; 
    4.  
    5. import com.google.zxing.BarcodeFormat; 
    6. import com.google.zxing.MultiFormatWriter; 
    7. import com.google.zxing.client.j2se.MatrixToImageWriter; 
    8. import com.google.zxing.common.BitMatrix; 
    9.  
    10. /**
    11. * @blog http://sjsky.iteye.com
    12. * @author Michael
    13. */ 
    14. publicclass ZxingEAN13EncoderHandler { 
    15.  
    16.     /**
    17.      * 编码
    18.      * @param contents
    19.      * @param width
    20.      * @param height
    21.      * @param imgPath
    22.      */ 
    23.     publicvoid encode(String contents, int width, int height, String imgPath) { 
    24.         int codeWidth = 3 + // start guard  
    25.                 (7 * 6) + // left bars  
    26.                 5 + // middle guard  
    27.                 (7 * 6) + // right bars  
    28.                 3; // end guard  
    29.         codeWidth = Math.max(codeWidth, width); 
    30.         try
    31.             BitMatrix bitMatrix = new MultiFormatWriter().encode(contents, 
    32.                     BarcodeFormat.EAN_13, codeWidth, height, null); 
    33.  
    34.             MatrixToImageWriter 
    35.                     .writeToFile(bitMatrix, "png", new File(imgPath)); 
    36.  
    37.         } catch (Exception e) { 
    38.             e.printStackTrace(); 
    39.         } 
    40.     } 
    41.  
    42.     /**
    43.      * @param args
    44.      */ 
    45.     publicstaticvoid main(String[] args) { 
    46.         String imgPath = "d:/2.png"
    47.         // 益达无糖口香糖的条形码  
    48.         String contents = "6923450657713"
    49.  
    50.         int width = 105, height = 50
    51.         ZxingEAN13EncoderHandler handler = new ZxingEAN13EncoderHandler(); 
    52.         handler.encode(contents, width, height, imgPath); 
    53.     } 

    运行后生成条形码图片如下:

  • 用手机的条形码扫描软件(本人用的:android 快拍二维码 )来测试下,识别成功的截图如下:

    解码示例:

    1. package michael.zxing; 
    2.  
    3. import java.awt.image.BufferedImage; 
    4. import java.io.File; 
    5.  
    6. import javax.imageio.ImageIO; 
    7.  
    8. import com.google.zxing.BinaryBitmap; 
    9. import com.google.zxing.LuminanceSource; 
    10. import com.google.zxing.MultiFormatReader; 
    11. import com.google.zxing.Result; 
    12. import com.google.zxing.client.j2se.BufferedImageLuminanceSource; 
    13. import com.google.zxing.common.HybridBinarizer; 
    14.  
    15. /**
    16. * @blog http://sjsky.iteye.com
    17. * @author Michael
    18. */ 
    19. publicclass ZxingEAN13DecoderHandler { 
    20.  
    21.     /**
    22.      * @param imgPath
    23.      * @return String
    24.      */ 
    25.     public String decode(String imgPath) { 
    26.         BufferedImage image = null
    27.         Result result = null
    28.         try
    29.             image = ImageIO.read(new File(imgPath)); 
    30.             if (image == null) { 
    31.                 System.out.println("the decode image may be not exit."); 
    32.             } 
    33.             LuminanceSource source = new BufferedImageLuminanceSource(image); 
    34.             BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); 
    35.  
    36.             result = new MultiFormatReader().decode(bitmap, null); 
    37.             return result.getText(); 
    38.         } catch (Exception e) { 
    39.             e.printStackTrace(); 
    40.         } 
    41.         returnnull
    42.     } 
    43.  
    44.     /**
    45.      * @param args
    46.      */ 
    47.     publicstaticvoid main(String[] args) { 
    48.         String imgPath = "d:/2.png"
    49.         ZxingEAN13DecoderHandler handler = new ZxingEAN13DecoderHandler(); 
    50.         String decodeContent = handler.decode(imgPath); 
    51.         System.out.println("解码内容如下:"); 
    52.         System.out.println(decodeContent); 
    53.     } 

    解码内容如下: 6923450657713

    5.源码说明和下载

    官方例子:

    BarcodeScanner (Barcode Scanner 4.31 for Android Featured 必须先将此apk安装才可以运行ZXingTest项目)

    ZXingTest (android端调用BarcodeScanner测试例子)

    简化例子:

    BarCodeTest (android端扫描和解码精简例子)

    QRcode (java端扫描和解码例子)

    源码下载

转载请标明出处http://blog.csdn.net/shimiso 欢迎有识之士加入我们的技术交流群:173711587

posted on 2013-09-04 14:53  昊仔  阅读(844)  评论(0编辑  收藏  举报