现在的位置: 首页 > 综合 > 正文

Android ZXing 二维码、条形码扫描介绍

2013年04月12日 ⁄ 综合 ⁄ 共 11519字 ⁄ 字号 评论关闭
文章目录

最近公司的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文件中进行配置权限:

    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.camera.autofocus" />

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

   <activity
            android:configChanges="orientation|keyboardHidden"
            android:name="com.zxing.activity.CaptureActivity"
            android:screenOrientation="portrait"
            android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
            android:windowSoftInputMode="stateAlwaysHidden" >
   </activity>

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

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@android:color/white"
    android:orientation="vertical" >

    <Button
        android:id="@+id/btn_scan_barcode"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:text="Open camera" />
    
    <LinearLayout 
        android:orientation="horizontal"
        android:layout_marginTop="10dp"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">
        
        <TextView 
       	android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@android:color/black"
        android:textSize="18sp"
        android:text="Scan result:" />
        
        <TextView 
        android:id="@+id/tv_scan_result"
       	android:layout_width="fill_parent"
       	android:textSize="18sp"
       	android:textColor="@android:color/black"
        android:layout_height="wrap_content" />
    </LinearLayout>
    
    <EditText 
        android:id="@+id/et_qr_string"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:hint="Input the text"/>
    
    <Button
        android:id="@+id/btn_add_qrcode"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Generate QRcode" />
    
    <ImageView 
        android:id="@+id/iv_qr_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:layout_gravity="center"/>

</LinearLayout>

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

public class BarCodeTestActivity extends Activity {
    /** Called when the activity is first created. */
	private TextView resultTextView;
	private EditText qrStrEditText;
	private ImageView qrImgImageView;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        resultTextView = (TextView) this.findViewById(R.id.tv_scan_result);
        qrStrEditText = (EditText) this.findViewById(R.id.et_qr_string);
        qrImgImageView = (ImageView) this.findViewById(R.id.iv_qr_image);
        
        Button scanBarCodeButton = (Button) this.findViewById(R.id.btn_scan_barcode);
        scanBarCodeButton.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				//打开扫描界面扫描条形码或二维码
				Intent openCameraIntent = new Intent(BarCodeTestActivity.this,CaptureActivity.class);
				startActivityForResult(openCameraIntent, 0);
			}
		});
        
        Button generateQRCodeButton = (Button) this.findViewById(R.id.btn_add_qrcode);
        generateQRCodeButton.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				try {
					String contentString = qrStrEditText.getText().toString();
					if (!contentString.equals("")) {
						//根据字符串生成二维码图片并显示在界面上,第二个参数为图片的大小(350*350)
						Bitmap qrCodeBitmap = EncodingHandler.createQRCode(contentString, 350);
						qrImgImageView.setImageBitmap(qrCodeBitmap);
					}else {
						Toast.makeText(BarCodeTestActivity.this, "Text can not be empty", Toast.LENGTH_SHORT).show();
					}
					
				} catch (WriterException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});
    }

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		//处理扫描结果(在界面上显示)
		if (resultCode == RESULT_OK) {
			Bundle bundle = data.getExtras();
			String scanResult = bundle.getString("result");
			resultTextView.setText(scanResult);
		}
	}
}

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

public final class EncodingHandler {
	private static final int BLACK = 0xff000000;
	
	public static Bitmap createQRCode(String str,int widthAndHeight) throws WriterException {
		Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>();  
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); 
		BitMatrix matrix = new MultiFormatWriter().encode(str,
				BarcodeFormat.QR_CODE, widthAndHeight, widthAndHeight);
		int width = matrix.getWidth();
		int height = matrix.getHeight();
		int[] pixels = new int[width * height];
		
		for (int y = 0; y < height; y++) {
			for (int x = 0; x < width; x++) {
				if (matrix.get(x, y)) {
					pixels[y * width + x] = BLACK;
				}
			}
		}
		Bitmap bitmap = Bitmap.createBitmap(width, height,
				Bitmap.Config.ARGB_8888);
		bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
		return bitmap;
	}
}

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

  /**
	 * Handler scan result
	 * @param result
	 * @param barcode
	 */
	public void handleDecode(Result result, Bitmap barcode) {
		inactivityTimer.onActivity();
		playBeepSoundAndVibrate();
		String resultString = result.getText();
		//FIXME
		if (resultString.equals("")) {
			Toast.makeText(CaptureActivity.this, "Scan failed!", Toast.LENGTH_SHORT).show();
		}else {
//			System.out.println("Result:"+resultString);
			Intent resultIntent = new Intent();
			Bundle bundle = new Bundle();
			bundle.putString("result", resultString);
			resultIntent.putExtras(bundle);
			this.setResult(RESULT_OK, resultIntent);
		}
		CaptureActivity.this.finish();
	}

4.Java端编码演示

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

  • zxing.jar
  • zxing-j2se.jar

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

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

    编码示例:

    package michael.zxing;
    
    import java.io.File;
    import java.util.Hashtable;
    
    import com.google.zxing.BarcodeFormat;
    import com.google.zxing.EncodeHintType;
    import com.google.zxing.MultiFormatWriter;
    import com.google.zxing.client.j2se.MatrixToImageWriter;
    import com.google.zxing.common.BitMatrix;
    import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
    
    /**
     * @blog http://sjsky.iteye.com
     * @author Michael
     */
    public class ZxingEncoderHandler {
    
        /**
         * 编码
         * @param contents
         * @param width
         * @param height
         * @param imgPath
         */
        public void encode(String contents, int width, int height, String imgPath) {
            Hashtable<Object, Object> hints = new Hashtable<Object, Object>();
            // 指定纠错等级
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
            // 指定编码格式
            hints.put(EncodeHintType.CHARACTER_SET, "GBK");
            try {
                BitMatrix bitMatrix = new MultiFormatWriter().encode(contents,
                        BarcodeFormat.QR_CODE, width, height, hints);
    
                MatrixToImageWriter
                        .writeToFile(bitMatrix, "png", new File(imgPath));
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            String imgPath = "d:/1.png";
            String contents = "Hello Word!";
            int width = 300, height = 300;
            ZxingEncoderHandler handler = new ZxingEncoderHandler();
            handler.encode(contents, width, height, imgPath);
        }
    }

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

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

    解码示例:

    package michael.zxing;
    
    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.util.Hashtable;
    
    import javax.imageio.ImageIO;
    
    import com.google.zxing.BinaryBitmap;
    import com.google.zxing.DecodeHintType;
    import com.google.zxing.LuminanceSource;
    import com.google.zxing.MultiFormatReader;
    import com.google.zxing.Result;
    import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
    import com.google.zxing.common.HybridBinarizer;
    
    /**
     * @blog http://sjsky.iteye.com
     * @author Michael
     */
    public class ZxingDecoderHandler {
    
        /**
         * @param imgPath
         * @return String
         */
        public String decode(String imgPath) {
            BufferedImage image = null;
            Result result = null;
            try {
                image = ImageIO.read(new File(imgPath));
                if (image == null) {
                    System.out.println("the decode image may be not exit.");
                }
                LuminanceSource source = new BufferedImageLuminanceSource(image);
                BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
    
                Hashtable<Object, Object> hints = new Hashtable<Object, Object>();
                hints.put(DecodeHintType.CHARACTER_SET, "utf-8");
    
                result = new MultiFormatReader().decode(bitmap, hints);
                return result.getText();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            String imgPath = "d:/1.png";
            ZxingDecoderHandler handler = new ZxingDecoderHandler();
            String decodeContent = handler.decode(imgPath);
            System.out.println("解码内容如下:");
            System.out.println(decodeContent);
        }
    }

    解码内容如下:
    Hello Word!

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

    编码示例:

    package michael.zxing;
    
    import java.io.File;
    
    import com.google.zxing.BarcodeFormat;
    import com.google.zxing.MultiFormatWriter;
    import com.google.zxing.client.j2se.MatrixToImageWriter;
    import com.google.zxing.common.BitMatrix;
    
    /**
     * @blog http://sjsky.iteye.com
     * @author Michael
     */
    public class ZxingEAN13EncoderHandler {
    
        /**
         * 编码
         * @param contents
         * @param width
         * @param height
         * @param imgPath
         */
        public void encode(String contents, int width, int height, String imgPath) {
            int codeWidth = 3 + // start guard
                    (7 * 6) + // left bars
                    5 + // middle guard
                    (7 * 6) + // right bars
                    3; // end guard
            codeWidth = Math.max(codeWidth, width);
            try {
                BitMatrix bitMatrix = new MultiFormatWriter().encode(contents,
                        BarcodeFormat.EAN_13, codeWidth, height, null);
    
                MatrixToImageWriter
                        .writeToFile(bitMatrix, "png", new File(imgPath));
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            String imgPath = "d:/2.png";
            // 益达无糖口香糖的条形码
            String contents = "6923450657713";
    
            int width = 105, height = 50;
            ZxingEAN13EncoderHandler handler = new ZxingEAN13EncoderHandler();
            handler.encode(contents, width, height, imgPath);
        }
    }

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

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

    解码示例:

    package michael.zxing;
    
    import java.awt.image.BufferedImage;
    import java.io.File;
    
    import javax.imageio.ImageIO;
    
    import com.google.zxing.BinaryBitmap;
    import com.google.zxing.LuminanceSource;
    import com.google.zxing.MultiFormatReader;
    import com.google.zxing.Result;
    import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
    import com.google.zxing.common.HybridBinarizer;
    
    /**
     * @blog http://sjsky.iteye.com
     * @author Michael
     */
    public class ZxingEAN13DecoderHandler {
    
        /**
         * @param imgPath
         * @return String
         */
        public String decode(String imgPath) {
            BufferedImage image = null;
            Result result = null;
            try {
                image = ImageIO.read(new File(imgPath));
                if (image == null) {
                    System.out.println("the decode image may be not exit.");
                }
                LuminanceSource source = new BufferedImageLuminanceSource(image);
                BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
    
                result = new MultiFormatReader().decode(bitmap, null);
                return result.getText();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            String imgPath = "d:/2.png";
            ZxingEAN13DecoderHandler handler = new ZxingEAN13DecoderHandler();
            String decodeContent = handler.decode(imgPath);
            System.out.println("解码内容如下:");
            System.out.println(decodeContent);
        }
    }

    解码内容如下:
    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

  • 抱歉!评论已关闭.