Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android的二維碼功能實現以及長按識別二維碼

Android的二維碼功能實現以及長按識別二維碼

編輯:關於Android編程

一、初步集成Zxing項目

二維碼的識別可是在生活中隨處可見的,現在基本上所有APP都有二維碼的相關操作,如果識別二維碼從頭開始開發做起來還是相當復雜和麻煩的,從零開始開發肯定不現實,最好的做法就是借助現有的開源項目,Github上名氣最大的就是Zxing了,提供了多個平台的二維碼掃碼解決方案,開源項目地址是:https://github.com/zxing/zxing,我們今天集成Zxing到我們自己的項目中去,並實現一些二維碼生成、掃描、長按識別二維碼等相關操作:   1.下載Zxing項目所依賴的jar包: 下載地址是:http://repo1.maven.org/maven2/com/google/zxing/core/3.2.1/,選擇core-3.2.1.jar下載即可,目前是最新的,原來存在將jar包導入項目無法正常運行,只有導入源碼,現在是不存在這個問題的,在開源項目的下方也有下載地址,可以隨時下載最新的jar包,還要下載一個jar包是android-core-3.2.1.jar,或者將這個jar包裡面的只有一個類復制到工程裡面也ok     2.下載Zxing項目: 下載地址在開源項目上下載即可,100多M,這個很簡單,別跟我說你不會。   下面我們就把zxing加入到我們的項目上去,首先把下載的Zxing項目中的源碼拷貝到項目工程中去,下面我以Android Studio演示集成並實現相關功能: 下載解壓過後的樣子應該是這個樣子:   \ 點擊Android下面在src看到源碼復制到工程裡面,在把資源文件拷貝進去,然後就是改一下AndroidMainfest其中的聲明Activityde shihou ,因為都是簡寫,現在包名變了,改一下就好了,然後針對工程的R文件報錯一個一個小心翼翼的改掉就OK了,針對有一個類報錯BookmarkPickerActivity,其中大概在50行左右的時候,Browser.BOOKMARKS_URI這個報錯,我把編譯版本改成22就好了,基本上這樣就算OK了,就像這樣子: \   然後基本運行你就可以開始掃碼了。  

二、獲得Zxing的核心功能

這個項目的功能多,項目很大,我們需要把最核心的功能抽取出來就好了,網上已經有很多人做出來了,大多數都是基於第一個抽取Zxing的人,但是那個是基於Zxing1.5、2.3做的,我們需要做的就是找一個舊的將這些類用最新的Zxing的代碼替換掉就可以了。下面我給出一個基於ZXing3.1封裝,包含了最新的jar包和代碼,大家可以去下載,是醫生提供的,Github中已經包含了前面所提到的所有修改(橫豎屏、扭曲變形),用3.1ZXing代碼進行了update,同時提供了編碼、解碼方法,並且將掃碼界面抽取成XML(感謝開源作者),方便拓展。  

三、實現掃描和長按讀取等功能

先看效果圖,錄制的時候沒有把鼠標錄制進入,感覺不是很好,讀取出來用的toast顯示的,大家將就看吧 \ 實現二維碼的生成,如下調用即可:
//生成二維碼圖片,第一個參數是二維碼的內容,第二個參數是正方形圖片的邊長,單位是像素  
			Bitmap bitmap = null;
			try {
				bitmap = BitmapUtil.createQRCode(msg, 400);
			} catch (WriterException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}   
			imageView.setImageBitmap(bitmap);

然後將生成的二維碼放置到相應的位置即可。

 

現在微信基本上都有長按二維碼識別,這種實現我的思路就是,既然二維碼掃描能夠識別,那麼肯定也是能夠解析圖片的,那麼我們可以長按實現對當前屏幕截屏然後調用相關的類去解析即可:

我們先看下截屏的代碼,都有注釋自己看吧:

 

	//這種方法狀態欄是空白,顯示不了狀態欄的信息
	private void saveCurrentImage()  
	{  
		//獲取當前屏幕的大小
		int width = getWindow().getDecorView().getRootView().getWidth();
		int height = getWindow().getDecorView().getRootView().getHeight();
		//生成相同大小的圖片
		Bitmap temBitmap = Bitmap.createBitmap( width, height, Config.ARGB_8888 );    
		//找到當前頁面的根布局
		View view =  getWindow().getDecorView().getRootView();
		//設置緩存
		view.setDrawingCacheEnabled(true);
		view.buildDrawingCache();
		//從緩存中獲取當前屏幕的圖片
		temBitmap = view.getDrawingCache();
		SimpleDateFormat df = new SimpleDateFormat("yyyymmddhhmmss");
		time = df.format(new Date());
		if(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())){
			file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/screen",time + ".png");
			if(!file.exists()){
				file.getParentFile().mkdirs();
				try {
					file.createNewFile();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			FileOutputStream fos = null;  
			try {  
				fos = new FileOutputStream(file);  
				temBitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
				fos.flush();  
				fos.close();
			} catch (FileNotFoundException e) {  
				e.printStackTrace();  
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} 
		}
	}

 

上面將屏幕截圖並以當前的時間為名字保存到手機上了,我們解析直接可以將路徑傳遞進入解析就好了,我把相關的類傳遞上來,都有注釋,大家看看吧:

 

//解析二維碼圖片,返回結果封裝在Result對象中  
	private com.google.zxing.Result  parseQRcodeBitmap(String bitmapPath){  
		//解析轉換類型UTF-8  
		Hashtable hints = new Hashtable();  
		hints.put(DecodeHintType.CHARACTER_SET, "utf-8");  
		//獲取到待解析的圖片  
		BitmapFactory.Options options = new BitmapFactory.Options();   
		//如果我們把inJustDecodeBounds設為true,那麼BitmapFactory.decodeFile(String path, Options opt)  
		//並不會真的返回一個Bitmap給你,它僅僅會把它的寬,高取回來給你  
		options.inJustDecodeBounds = true;  
		//此時的bitmap是null,這段代碼之後,options.outWidth 和 options.outHeight就是我們想要的寬和高了  
		Bitmap bitmap = BitmapFactory.decodeFile(bitmapPath,options);  
		//我們現在想取出來的圖片的邊長(二維碼圖片是正方形的)設置為400像素  
		//以上這種做法,雖然把bitmap限定到了我們要的大小,但是並沒有節約內存,如果要節約內存,我們還需要使用inSimpleSize這個屬性  
		options.inSampleSize = options.outHeight / 400;  
		if(options.inSampleSize <= 0){  
			options.inSampleSize = 1; //防止其值小於或等於0  
		}  
		options.inJustDecodeBounds = false;  
		bitmap = BitmapFactory.decodeFile(bitmapPath, options);   
		//新建一個RGBLuminanceSource對象,將bitmap圖片傳給此對象  
		RGBLuminanceSource rgbLuminanceSource = new RGBLuminanceSource(bitmap);  
		//將圖片轉換成二進制圖片  
		BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(rgbLuminanceSource));  
		//初始化解析對象  
		QRCodeReader reader = new QRCodeReader();  
		//開始解析  
		Result result = null;  
		try {  
			result = reader.decode(binaryBitmap, hints);  
		} catch (Exception e) {  
			// TODO: handle exception  
		}  
		return result;  
	}  

 

按照zxing的解碼規則,我們是需要一個BitmapLuminanceSource類的,也是唯一需要去實現的

BitmapLuminanceSource繼承自LuminanceSource這個抽象類,需要實現它的構造方法,其構造方法中需要傳入寬高,這兩個值指的就是圖片的寬和高。getMatrix()方法會返回一個byte數組,這個數組就是圖片的像素數組。getRow(int y, byte[] row)如字面的意義,就是得到圖片像素數組的一行。其中的y就是需要的哪一個行的像素數組。

以下是完整的BitmapLuminanceSource類

 

public class RGBLuminanceSource extends LuminanceSource {

	private byte bitmapPixels[];  

	protected RGBLuminanceSource(Bitmap bitmap) {  
		super(bitmap.getWidth(), bitmap.getHeight());  

		// 首先,要取得該圖片的像素數組內容  
		int[] data = new int[bitmap.getWidth() * bitmap.getHeight()];  
		this.bitmapPixels = new byte[bitmap.getWidth() * bitmap.getHeight()];  
		bitmap.getPixels(data, 0, getWidth(), 0, 0, getWidth(), getHeight());  

		// 將int數組轉換為byte數組,也就是取像素值中藍色值部分作為辨析內容  
		for (int i = 0; i < data.length; i++) {  
			this.bitmapPixels[i] = (byte) data[i];  
		}  
	}  

	@Override  
	public byte[] getMatrix() {  
		// 返回我們生成好的像素數據  
		return bitmapPixels;  
	}  

	@Override  
	public byte[] getRow(int y, byte[] row) {  
		// 這裡要得到指定行的像素數據  
		System.arraycopy(bitmapPixels, y * getWidth(), row, 0, getWidth());  
		return row;  
	}  
}

 

上面獲取圖片像素組內容的byte[]數組是指圖片的像素數組,而不是所謂的Bitmap轉換成byte數組

Bitmap對象的getPixels方法可以取得的像素數組,但它得到是int型數組。根據其api文檔解釋,取得的是color,也就是像素顏色值。每個像素值包含透明度,紅色,綠色,藍色。所以白色就是0xffffffff,黑色就是0xff000000。直接由int型轉成byte型,實現上相當於我們這裡只取其藍色值部分。

 

getPixels得到的像素數組是一維的,也就是按照圖片寬度逐行取像素顏色值錄入。如果想得到單行的像素數組內容,通過y*width就可以找該行的第一個像素值,拷貝後面width個就可以得到該行的像素內容。

最後一個就是getMatrix()方法,它用來返回我們的圖像轉換成的像素數組。

最後我們將長按存儲的圖片路徑傳遞進去即可,但是注意解析的時候開個線程,不然要ANR,基本上實現了我們需要的大部分生成、讀取、識別大部分功能。

稍後上傳源碼給大家,覺得有用就點個贊吧。。。。。


  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved