Android之zxing二維碼生成與識別


轉:http://blog.csdn.net/bear_huangzhen/article/details/46053327

二維碼:

是用某種特定的幾何圖形按一定規律在平面(二維方向上)分布的黑白相間的圖形記錄數據符號信息的;

在代碼編制上巧妙的利用構成計算機內部邏輯基礎的0和1比特流的概念,使用若干個與二進制相對應的幾何形體來表示文字數值信息,通過圖像輸入設備或光電掃描設備自動識讀以實現信息自動處理;

二維碼能夠在橫向和縱向兩個方位同時表達信息,因此能在很小的面積內表達大量的信息;

二維碼相對於條形碼的優勢就是省空間;

 

zxing簡介:

zxing是一個開放源碼的,用java實現的多種格式的1D/2D條碼圖像處理庫,它包含了聯系到其他語言的接口。

zxing可以實現使用手機的內置的攝像頭完成條形碼和二維碼的掃描與解碼。

zxing可以實現條形碼和二維碼的編碼與解碼。

zxing目前支持的的格式如下:

UPC-A,UPC-E

EAN-8,EAN-13

39碼

93碼

代碼128

QR碼

 

Android上zxing的使用:

這里使用的時候可以有兩種形式:

1.將zxing的jar包放到工程的lib庫中,然后還要拷貝相應的類源碼到工程中去,整個文件夾拷貝過去也是很快的;

2.將已經弄好zxing的工程作為當前工程的依賴庫,然后直接使用就可以了;

如圖:

 

 

下面來通過一個實例來完成以下三個功能:

1.生成二維碼;

2.解析二維碼圖片;

3.掃描二維碼並解析;

 

最終效果是這樣的:

 

在我們新建工程之前,我們必須將依賴庫導入到Eclipse中,依賴庫的原工程文件夾我已經打包,文章最后面有鏈接可以下載。

 

識別二維碼(識別圖片)這個功能需要用到一個名叫RGBLuminanceSource的類,這個類的內容如下:

 

[java]  view plain copy
 
  1. import java.io.FileNotFoundException;  
  2.   
  3. import android.graphics.Bitmap;  
  4. import android.graphics.BitmapFactory;  
  5.   
  6. import com.google.zxing.LuminanceSource;  
  7.   
  8. public class RGBLuminanceSource extends LuminanceSource {  
  9.     private final byte[] luminances;  
  10.       
  11.     public RGBLuminanceSource(Bitmap bitmap) {  
  12.         super(bitmap.getWidth(), bitmap.getHeight());  
  13.         //得到圖片的寬高  
  14.         int width = bitmap.getWidth();  
  15.         int height = bitmap.getHeight();  
  16.         //得到圖片的像素  
  17.         int[] pixels = new int[width * height];  
  18.         //  
  19.         bitmap.getPixels(pixels, 0, width, 0, 0, width, height);  
  20.         //為了測量純解碼速度,我們將整個圖像灰度陣列前面,這是一樣的通道  
  21.         // YUVLuminanceSource在現實應用。  
  22.         //得到像素大小的字節數  
  23.         luminances = new byte[width * height];  
  24.         //得到圖片每點像素顏色  
  25.         for (int y = 0; y < height; y++) {  
  26.             int offset = y * width;  
  27.             for (int x = 0; x < width; x++) {  
  28.                 int pixel = pixels[offset + x];  
  29.                 int r = (pixel >> 16) & 0xff;  
  30.                 int g = (pixel >> 8) & 0xff;  
  31.                 int b = pixel & 0xff;  
  32.                 //當某一點三種顏色值相同時,相應字節對應空間賦值為其值  
  33.                 if (r == g && g == b) {  
  34.                     luminances[offset + x] = (byte) r;  
  35.                 }   
  36.                 //其它情況字節空間對應賦值為:  
  37.                 else {    
  38.                     luminances[offset + x] = (byte) ((r + g + g + b) >> 2);  
  39.                 }  
  40.             }  
  41.         }  
  42.     }  
  43.   
  44.     public RGBLuminanceSource(String path) throws FileNotFoundException {  
  45.         this(loadBitmap(path));  
  46.     }  
  47.       
  48.   
  49.     @Override  
  50.     public byte[] getMatrix() {  
  51.         return luminances;  
  52.     }  
  53.   
  54.     @Override  
  55.     public byte[] getRow(int arg0, byte[] arg1) {  
  56.         if (arg0 < 0 || arg0 >= getHeight()) {  
  57.             throw new IllegalArgumentException(  
  58.                     "Requested row is outside the image: " + arg0);  
  59.         }  
  60.         int width = getWidth();  
  61.         if (arg1 == null || arg1.length < width) {  
  62.             arg1 = new byte[width];  
  63.         }  
  64.         System.arraycopy(luminances, arg0 * width, arg1, 0, width);  
  65.         return arg1;  
  66.     }  
  67.   
  68.     private static Bitmap loadBitmap(String path) throws FileNotFoundException {  
  69.         Bitmap bitmap = BitmapFactory.decodeFile(path);  
  70.         if (bitmap == null) {  
  71.             throw new FileNotFoundException("Couldn't open " + path);  
  72.         }  
  73.         return bitmap;  
  74.     }  
  75. }  


接下來,還有一個特別要注意的地方就是manifest的配置部分,需要加入權限,和依賴庫中的一個Activity的聲明:

 

 

[html]  view plain copy 在CODE上查看代碼片 派生到我的代碼片
 
  1. <uses-permission android:name="android.permission.CAMERA" />  
  2. <uses-permission android:name="android.permission.VIBRATE" />  
  3. <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />  
  4. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  
  5. <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />  
  6.   
  7. <application  
  8.     android:allowBackup="true"  
  9.     android:icon="@drawable/ic_launcher"  
  10.     android:label="@string/app_name"  
  11.     android:theme="@style/AppTheme" >  
  12.     <activity  
  13.         android:name=".MainActivity"  
  14.         android:label="@string/app_name" >  
  15.         <intent-filter>  
  16.             <action android:name="android.intent.action.MAIN" />  
  17.   
  18.             <category android:name="android.intent.category.LAUNCHER" />  
  19.         </intent-filter>  
  20.     </activity>  
  21.     <activity android:name="com.zxing.activity.CaptureActivity"></activity>  
  22. </application>  


好,現在我們來看看自己編寫的Activity類如何實現以上所說的三個功能:

 

 

[java]  view plain copy 在CODE上查看代碼片 派生到我的代碼片
 
  1. import java.util.Hashtable;  
  2.   
  3. import com.google.zxing.BinaryBitmap;  
  4. import com.google.zxing.DecodeHintType;  
  5. import com.google.zxing.Result;  
  6. import com.google.zxing.common.HybridBinarizer;  
  7. import com.google.zxing.qrcode.QRCodeReader;  
  8. import com.zxing.activity.CaptureActivity;  
  9. import com.zxing.encoding.EncodingHandler;  
  10.   
  11. import android.annotation.SuppressLint;  
  12. import android.app.Activity;  
  13. import android.content.Intent;  
  14. import android.database.Cursor;  
  15. import android.graphics.Bitmap;  
  16. import android.graphics.BitmapFactory;  
  17. import android.os.Bundle;  
  18. import android.provider.MediaStore;  
  19. import android.view.View;  
  20. import android.view.View.OnClickListener;  
  21. import android.widget.EditText;  
  22. import android.widget.ImageView;  
  23. import android.widget.Toast;  
  24.   
  25. public class MainActivity extends Activity implements OnClickListener {  
  26.       
  27.     private static final int CHOOSE_PIC = 0;  
  28.     private static final int PHOTO_PIC = 1;  
  29.   
  30.     private EditText contentEditText = null;  
  31.     private ImageView qrcodeImageView = null;  
  32.     private String  imgPath = null;  
  33.   
  34.     @Override  
  35.     protected void onCreate(Bundle savedInstanceState) {  
  36.         super.onCreate(savedInstanceState);  
  37.         setContentView(R.layout.activity_main);  
  38.         setupViews();  
  39.     }  
  40.   
  41.     private void setupViews() {  
  42.         contentEditText = (EditText) findViewById(R.id.editText1);  
  43.         findViewById(R.id.button1).setOnClickListener(this);  
  44.         findViewById(R.id.button2).setOnClickListener(this);  
  45.         findViewById(R.id.button3).setOnClickListener(this);  
  46.         qrcodeImageView = (ImageView) findViewById(R.id.img1);  
  47.     }  
  48.       
  49.     //解析二維碼圖片,返回結果封裝在Result對象中  
  50.     private com.google.zxing.Result  parseQRcodeBitmap(String bitmapPath){  
  51.         //解析轉換類型UTF-8  
  52.         Hashtable<DecodeHintType, String> hints = new Hashtable<DecodeHintType, String>();  
  53.         hints.put(DecodeHintType.CHARACTER_SET, "utf-8");  
  54.         //獲取到待解析的圖片  
  55.         BitmapFactory.Options options = new BitmapFactory.Options();   
  56.         //如果我們把inJustDecodeBounds設為true,那么BitmapFactory.decodeFile(String path, Options opt)  
  57.         //並不會真的返回一個Bitmap給你,它僅僅會把它的寬,高取回來給你  
  58.         options.inJustDecodeBounds = true;  
  59.         //此時的bitmap是null,這段代碼之后,options.outWidth 和 options.outHeight就是我們想要的寬和高了  
  60.         Bitmap bitmap = BitmapFactory.decodeFile(bitmapPath,options);  
  61.         //我們現在想取出來的圖片的邊長(二維碼圖片是正方形的)設置為400像素  
  62.         /** 
  63.             options.outHeight = 400; 
  64.             options.outWidth = 400; 
  65.             options.inJustDecodeBounds = false; 
  66.             bitmap = BitmapFactory.decodeFile(bitmapPath, options); 
  67.         */  
  68.         //以上這種做法,雖然把bitmap限定到了我們要的大小,但是並沒有節約內存,如果要節約內存,我們還需要使用inSimpleSize這個屬性  
  69.         options.inSampleSize = options.outHeight / 400;  
  70.         if(options.inSampleSize <= 0){  
  71.             options.inSampleSize = 1; //防止其值小於或等於0  
  72.         }  
  73.         /** 
  74.          * 輔助節約內存設置 
  75.          *  
  76.          * options.inPreferredConfig = Bitmap.Config.ARGB_4444;    // 默認是Bitmap.Config.ARGB_8888 
  77.          * options.inPurgeable = true;  
  78.          * options.inInputShareable = true;  
  79.          */  
  80.         options.inJustDecodeBounds = false;  
  81.         bitmap = BitmapFactory.decodeFile(bitmapPath, options);   
  82.         //新建一個RGBLuminanceSource對象,將bitmap圖片傳給此對象  
  83.         RGBLuminanceSource rgbLuminanceSource = new RGBLuminanceSource(bitmap);  
  84.         //將圖片轉換成二進制圖片  
  85.         BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(rgbLuminanceSource));  
  86.         //初始化解析對象  
  87.         QRCodeReader reader = new QRCodeReader();  
  88.         //開始解析  
  89.         Result result = null;  
  90.         try {  
  91.             result = reader.decode(binaryBitmap, hints);  
  92.         } catch (Exception e) {  
  93.             // TODO: handle exception  
  94.         }  
  95.           
  96.         return result;  
  97.     }  
  98.       
  99.     @Override  
  100.     protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
  101.         super.onActivityResult(requestCode, resultCode, data);  
  102.         imgPath = null;  
  103.         if(resultCode == RESULT_OK){  
  104.             switch (requestCode) {  
  105.             case CHOOSE_PIC:  
  106.                 String[] proj = new String[]{MediaStore.Images.Media.DATA};  
  107.                 Cursor cursor = MainActivity.this.getContentResolver().query(data.getData(), proj, null, null, null);  
  108.                   
  109.                 if(cursor.moveToFirst()){  
  110.                     int columnIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA);  
  111.                     System.out.println(columnIndex);  
  112.                     //獲取到用戶選擇的二維碼圖片的絕對路徑  
  113.                     imgPath = cursor.getString(columnIndex);  
  114.                 }  
  115.                 cursor.close();  
  116.                   
  117.                 //獲取解析結果  
  118.                 Result ret = parseQRcodeBitmap(imgPath);  
  119.                 Toast.makeText(MainActivity.this,"解析結果:" + ret.toString(), Toast.LENGTH_LONG).show();  
  120.                 break;  
  121.             case PHOTO_PIC:  
  122.                 String result = data.getExtras().getString("result");  
  123.                 Toast.makeText(MainActivity.this,"解析結果:" + result, Toast.LENGTH_LONG).show();  
  124.                 break;  
  125.   
  126.             default:  
  127.                 break;  
  128.             }  
  129.         }  
  130.           
  131.     }  
  132.       
  133.     @SuppressLint("InlinedApi")  
  134.     @Override  
  135.     public void onClick(View v) {  
  136.         switch (v.getId()) {  
  137.         case R.id.button1:  
  138.             //獲取界面輸入的內容  
  139.             String content = contentEditText.getText().toString();  
  140.             //判斷內容是否為空  
  141.             if (null == content || "".equals(content)) {  
  142.                 Toast.makeText(MainActivity.this, "請輸入要寫入二維碼的內容...",  
  143.                         Toast.LENGTH_SHORT).show();  
  144.                 return;  
  145.             }  
  146.               
  147.             try {  
  148.                 //生成二維碼圖片,第一個參數是二維碼的內容,第二個參數是正方形圖片的邊長,單位是像素  
  149.                 Bitmap qrcodeBitmap = EncodingHandler.createQRCode(content, 400);  
  150.                 qrcodeImageView.setImageBitmap(qrcodeBitmap);  
  151.             } catch (Exception e) {  
  152.                 // TODO Auto-generated catch block  
  153.                 e.printStackTrace();  
  154.             }  
  155.             break;  
  156.         case R.id.button2:  
  157.             //跳轉到圖片選擇界面去選擇一張二維碼圖片  
  158.             Intent intent1 = new Intent();  
  159. //          if(android.os.Build.VERSION.SDK_INT < 19){  
  160. //              intent1.setAction(Intent.ACTION_GET_CONTENT);  
  161. //          }else{  
  162. //              intent1.setAction(Intent.ACTION_OPEN_DOCUMENT);  
  163. //          }  
  164.             intent1.setAction(Intent.ACTION_PICK);  
  165.               
  166.             intent1.setType("image/*");  
  167.               
  168.             Intent intent2 =  Intent.createChooser(intent1, "選擇二維碼圖片");  
  169.             startActivityForResult(intent2, CHOOSE_PIC);  
  170.             break;  
  171.         case R.id.button3:  
  172.             //跳轉到拍照界面掃描二維碼  
  173.             Intent intent3 = new Intent(MainActivity.this, CaptureActivity.class);  
  174.             startActivityForResult(intent3, PHOTO_PIC);  
  175.             break;  
  176.   
  177.         default:  
  178.             break;  
  179.         }  
  180.   
  181.     }  
  182. }  


最后附上所有代碼打包的鏈接,有需要的同學可以下載,導入到自己的Eclipse中去:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM