QRCode 二维码
1 、简介
二维条形码最早发明于日本,它是用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息
的,在代码编制上巧妙地利用构成计算机内部逻辑基础的“0 ”、“1 ”比特流的概念,使用若干个与二进制相对应的几何形体来表示文字
数值信息,通过图象输入设备或光电扫描设备自动识读以实现信息自动处理。它具有条码技术的一些共性:每种码制有其特定的字符集;
每个字符占有一定的宽度;具有一定的校验功能等。同时还具有对不同行的信息自动识别功能、及处理图形旋转变化等特点。
条形码(bar code)是将宽度不等的多个黑条和空白,按照一定的编码规则排列,用以表达一组信息的图形标识符。常见的条形码是由反
射率相差很大的黑条(简称条)和白条(简称空)排成的平行线图案。条形码可以标出物品的生产国、制造厂家、商品名称、生产日期、
图书分类号、邮件起止地点、类别、日期等许多信息,因而在商品流通、图书管理、邮政管理、银行系统等许多领域都得到广泛的应用。
2 、ZX ing基本介绍
ZX ing是一个开源Jav a类库用于解析多种格式的条形码和二维码. 官
网:ht t p: //code. google. com /p/zx ing/(ht t ps : //git hub. com /zx ing/zx ing)
截止目前为止最新版本提供以下编码格式的支持:
U PC -A and U PC - E
EAN -8 and EAN -1 3
C ode 3 9
C ode 9 3
C ode 1 2 8
Q R C ode
I T F
C odabar
R S S -1 4 (all v ar iant s )
Dat a Mat r ix
PDF 4 1 7 ('alpha' qualit y )
Azt ec ('alpha' qualit y )
同时G it Hub提供了 Andr oid、cpp、C #、iPhone、j2 m e、j2 s e、jr uby 、objc、r im 、s y m bian等多种应用的类库,具体详情可以参
考下载的源码包中。
QR码符号共有40种规格,分别为版本1、版本2„„版本40。版本1的规格为21模块×21模块,版本2为25模块×25模块,以此类推,每一版本符
号比前一版本每边增加4个模块,直到版本40,规格为177模块×177模块。其中最高版本40可容纳多达1850个大写字母或2710个数字或1108
个字节,或500多个汉字,比普通条码信息容量约高几十倍。由于其高密度编码,信息容量大,所以被广泛采用。
下图1为版本2的示意图(共25模块×25模块):
二维码的结构。
3 、Andr oid端编码演示
这里使用的ZX ing是经过简化版的,去除了一些一般使用不必要的文件,项目工程和效果截图如下:
其中enc odi ng包是在原基础上加上去的,功能是根据传入的字符串来生成二维码图片,返回一个B i tmap,其余的包是Z Xi ng项目自带的。另
外对扫描界面的布局也进行了修改,官方的扫描界面是横向的,改成了纵向的,并加入了顶部的Tab和取消按钮(c amera. xml ),另外还需
要的一些文件是c ol ors. xml 、i ds. xml ,这些都是原本Z Xi ng项目中自带的,最后就是l i bs下面的j ar包。
接下来看如何使用,首先是把Z Xi ng项目中的一些文件拷贝到我们自己的项目中,然后在Mai ni fest文件中进行配置权限:
1. <uses-permission android:name="android.permission.VIBRATE"/>
2. <uses-permission android:name="android.permission.CAMERA"/>
3. <uses-feature android:name="android.hardware.camera"/>
4. <uses-feature android:name="android.hardware.camera.autofocus"/>
还有就是扫描界面Ac t iv it y 的配置:
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>
下面是主Ac t iv it y 的代码,主要功能是打开扫描框、显示扫描结果、根据输入的字符串生成二维码图片:
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. }
60. }
其中生成二维码图片的代码在EncodingHandler . jav a中:
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. }
25. }
26.
最后是在哪里对扫描结果进行解码,进入C apt ur eAc t iv it y . jav a找到下面这个方法便可以对自己对结果进行操作:
1. /**
2. * Handler scan result
3. * @param result
4. * @param barcode
5. */
6. public 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. }
21. CaptureActivity.this.finish();
4. Java端编码演示
在Java端上实现条形码(E A N-13)和二维码(QRCode) 的编码和解码的示例,以供大家参考,用到了源码中c ore和j avase下面的相关源代
码,附件提供自己编译之后的l i b包:
zxi ng. j ar
zxi ng-j 2se. j ar
有关各种手机系统的应用,有兴趣的朋友可以下载官方源码包,包下有具体详细的应用介绍。
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. }
54. }
运行后生成的二维码图片如下:
用手机的二维码扫描软件(本人用的:androi d 快拍二维码 )来测试下,识别成功的截图如下:
解码示例:
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. }
59. }
解码内容如下: Hello W or d!
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. }
54. }
运行后生成条形码图片如下:
用手机的条形码扫描软件(本人用的:androi d 快拍二维码 )来测试下,识别成功的截图如下:
解码示例:
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. }
54. }
解码内容如下: 6 9 2 3 4 5 0 6 5 7 7 1 3
5.源码说明和下载
官方例子:
BarcodeScanner (Barcode Scanner 4.31 for Androi d Feat ured 必须先将此apk安装才可以运行ZXi ngTes t 项目)
ZXi ngTes t (androi d端调用BarcodeScanner测试例子)
简化例子:
BarCodeTes t (androi d端扫描和解码精简例子)
QRcode (java端扫描和解码例子)