ZXing開發詳解

博客轉載自:https://blog.csdn.net/skillcollege/article/details/38852183android

什麼是Z*?

在Android平臺作過二維碼相關模塊的確定都熟知ZXing開源項目,Z*是一個開源Java類庫用於解析多種格式的1D/2D條形碼。目標是可以對QR編碼、Data Matrix、UPC的1D條形碼進行解碼。 其提供了多種平臺下的客戶端包括:J2ME、J2SE和Android。其GitHub地址是:傳送門git

Z*項目裏面代碼不少,實現的功能也不少,咱們的應用只須要剝離其中的掃描模塊便可,再多一點也就是生成二維碼的功能;接下來咱們就一塊兒來精簡ZXing項目,最終造成一個小的Demo案例,固然江湖上已經有過N多種版本的ZXing精簡項目,什麼橫屏改豎屏,繪製掃描界面,開啓閃光燈等等,而且許多都是基於ZXing2.3.0來作精簡的,後續有許多更新的版本,包括自動對焦,Camera管理,bug修復等等新功能;筆者使用的是ZXing3.1.0版本,這裏須要說明的就是個人這版Demo絕對是江湖上面尚未出現的,也算是一點點小小的創新把,那就是去除ZXing項目中惱人的ViewFinderView的繪製,使用XML佈局掃描界面,添加掃描動畫,精確計算掃描區域github

克隆Z*項目到本地

1
git clone https: //github.com/zxing/zxing.git

整理ZXing代碼

打開ZXing項目的文件夾,能夠看到以下文件目錄:算法

其中咱們主要關注2個文件夾裏的內容: canvas

1. core : Z*項目的核心代碼,能夠新建一個Java工程,而後export成jar來調用。以下圖所示:maven

免打包便可得到的zxing-3.1.0.jar  猛戳下載 工具

2. android : Android示例工程代碼,成功運行以後就是一個專業的掃碼應用了。以下圖所示:佈局

免引入免整理的zxing原始工程 ZXingRawProject  猛戳下載動畫

可是這樣就讓你知足了,那怎麼能夠說是極致二維碼掃描呢,有木有感受ZXing的掃描框的繪製很不爽啊?自定義的View繪製的很醜,多屏幕適配的時候還常常不兼容,原始項目仍是橫屏模式的,目前你們都習慣豎屏掃描呢。怎麼辦?別怕,我來告訴你,我要將ViewFinderView砍掉,使用xml界面佈局,添加掃描動畫,最終同樣準確無誤的掃描到二維碼數據,只須要對準,是的,毫釐不差的對準就能夠了。ui

精簡Z*代碼,打造極致掃描

1. 去掉Z*中一些和掃描無關的代碼,最終留下的代碼結構以下圖所示,最關鍵的是你看不到ViewFinderView 了

2. 佈局掃描界面,xml代碼以下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<?xml version= "1.0"  encoding= "utf-8" ?> 
<RelativeLayout xmlns:android= "http://schemas.android.com/apk/res/android" 
     android:layout_width= "match_parent" 
     android:layout_height= "match_parent" 
     android:background= "@android:color/transparent" 
     android:orientation= "vertical" 
   
     <SurfaceView 
         android:id= "@+id/capture_preview" 
         android:layout_width= "match_parent" 
         android:layout_height= "match_parent"  /> 
   
     <RelativeLayout 
         android:id= "@+id/capture_container" 
         android:layout_width= "match_parent" 
         android:layout_height= "match_parent" 
   
         <ImageView 
             android:id= "@+id/capture_mask_top" 
             android:layout_width= "match_parent" 
             android:layout_height= "120dp" 
             android:layout_alignParentTop= "true" 
             android:background= "@drawable/shadow"  /> 
   
         <RelativeLayout 
             android:id= "@+id/capture_crop_view" 
             android:layout_width= "200dp" 
             android:layout_height= "200dp" 
             android:layout_below= "@id/capture_mask_top" 
             android:layout_centerHorizontal= "true" 
             android:background= "@drawable/qr_code_bg" 
   
             <ImageView 
                 android:id= "@+id/capture_scan_line" 
                 android:layout_width= "match_parent" 
                 android:layout_height= "wrap_content" 
                 android:layout_alignParentTop= "true" 
                 android:layout_marginBottom= "5dp" 
                 android:layout_marginTop= "5dp" 
                 android:src= "@drawable/scan_line"  /> 
         </RelativeLayout> 
   
         <ImageView 
             android:id= "@+id/capture_mask_bottom" 
             android:layout_width= "match_parent" 
             android:layout_height= "wrap_content" 
             android:layout_alignParentBottom= "true" 
             android:layout_below= "@id/capture_crop_view" 
             android:background= "@drawable/shadow"  /> 
   
         <ImageView 
             android:id= "@+id/capture_mask_left" 
             android:layout_width= "wrap_content" 
             android:layout_height= "match_parent" 
             android:layout_above= "@id/capture_mask_bottom" 
             android:layout_alignParentLeft= "true" 
             android:layout_below= "@id/capture_mask_top" 
             android:layout_toLeftOf= "@id/capture_crop_view" 
             android:background= "@drawable/shadow"  /> 
   
         <ImageView 
             android:id= "@+id/capture_mask_right" 
             android:layout_width= "wrap_content" 
             android:layout_height= "match_parent" 
             android:layout_above= "@id/capture_mask_bottom" 
             android:layout_alignParentRight= "true" 
             android:layout_below= "@id/capture_mask_top" 
             android:layout_toRightOf= "@id/capture_crop_view" 
             android:background= "@drawable/shadow"  /> 
     </RelativeLayout> 
   
</RelativeLayout>

3. 計算截取區域 貼心註解: 若是你沒有看上一篇ZBar掃描中關於掃描區域計算的解釋,那趕忙回去,咱不能急,看完再來接上,不然你會不理解的!傳送門

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
private  void  initCrop() { 
     int  cameraWidth = cameraManager.getCameraResolution().y; 
     int  cameraHeight = cameraManager.getCameraResolution().x; 
   
     /** 獲取佈局中掃描框的位置信息 */ 
     int [] location =  new  int [2]; 
     scanCropView.getLocationInWindow(location); 
   
     int  cropLeft = location[0]; 
     int  cropTop = location[1] - getStatusBarHeight(); 
   
     int  cropWidth = scanCropView.getWidth(); 
     int  cropHeight = scanCropView.getHeight(); 
   
     /** 獲取佈局容器的寬高 */ 
     int  containerWidth = scanContainer.getWidth(); 
     int  containerHeight = scanContainer.getHeight(); 
   
     /** 計算最終截取的矩形的左上角頂點x座標 */ 
     int  x = cropLeft * cameraWidth / containerWidth; 
     /** 計算最終截取的矩形的左上角頂點y座標 */ 
     int  y = cropTop * cameraHeight / containerHeight; 
   
     /** 計算最終截取的矩形的寬度 */ 
     int  width = cropWidth * cameraWidth / containerWidth; 
     /** 計算最終截取的矩形的高度 */ 
     int  height = cropHeight * cameraHeight / containerHeight; 
   
     /** 生成最終的截取的矩形 */ 
     mCropRect =  new  Rect(x, y, width + x, height + y); 

5. 完整項目代碼: 猛戳下載

 

 

android URL轉換二維碼

添加依賴
compile 'com.google.zxing:core:3.3.0'
建立工具類:ZXingUtils
public class ZXingUtils {
/**
* 生成二維碼 要轉換的地址或字符串,能夠是中文
* 不須要logo最後一個參數傳null
* @param url
* @param width
* @param height
* @return
*/
public static Bitmap createQRImage(String url, final int width, final int height, Bitmap logoBitmap) {
try {
// 判斷URL合法性
if (url == null || "".equals(url) || url.length() < 1) {
return null;
}
Hashtable hints = new Hashtable();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
// 圖像數據轉換,使用了矩陣轉換
BitMatrix bitMatrix = new QRCodeWriter().encode(url,
BarcodeFormat.QR_CODE, width, height, hints);
int[] pixels = new int[width * height];
// 下面這裏按照二維碼的算法,逐個生成二維碼的圖片,
// 兩個for循環是圖片橫列掃描的結果
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
if (bitMatrix.get(x, y)) {
pixels[y * width + x] = 0xff000000;
} else {
pixels[y * width + x] = 0xffffffff;
}
}
}
// 生成二維碼圖片的格式,使用ARGB_8888
Bitmap bitmap = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
if (logoBitmap != null) {
bitmap = addLogo(bitmap, logoBitmap);
}
return bitmap;
} catch (WriterException e) {
e.printStackTrace();
}
return null;
}

/**
* 在二維碼中間添加Logo圖案
*/
private static Bitmap addLogo(Bitmap src, Bitmap logo) {
if (src == null) {
return null;
}

if (logo == null) {
return src;
}

//獲取圖片的寬高
int srcWidth = src.getWidth();
int srcHeight = src.getHeight();
int logoWidth = logo.getWidth();
int logoHeight = logo.getHeight();

if (srcWidth == 0 || srcHeight == 0) {
return null;
}

if (logoWidth == 0 || logoHeight == 0) {
return src;
}

//logo大小爲二維碼總體大小的1/5
float scaleFactor = srcWidth * 1.0f / 5 / logoWidth;
Bitmap bitmap = Bitmap.createBitmap(srcWidth, srcHeight, Bitmap.Config.ARGB_8888);
try {
Canvas canvas = new Canvas(bitmap);
canvas.drawBitmap(src, 0, 0, null);
canvas.scale(scaleFactor, scaleFactor, srcWidth / 2, srcHeight / 2);
canvas.drawBitmap(logo, (srcWidth - logoWidth) / 2, (srcHeight - logoHeight) / 2, null);

canvas.save(Canvas.ALL_SAVE_FLAG);
canvas.restore();
} catch (Exception e) {
bitmap = null;
e.getStackTrace();
}

return bitmap;
}
}
activity代碼
Bitmap bitmap = ZXingUtils.createQRImage(url, 600, 600,BitmapFactory.decodeResource(getResources(), R.drawable.call));
imageView.setImageBitmap(bitmap);
下面的是網上找到的一個工具類
/**
*
* 生成條形碼和二維碼的工具
*/
public class ZXingUtils {
/**
* 生成二維碼 要轉換的地址或字符串,能夠是中文
*
* @param url
* @param width
* @param height
* @return
*/
public static Bitmap createQRImage(String url, final int width, final int height) {
try {
// 判斷URL合法性
if (url == null || "".equals(url) || url.length() < 1) {
return null;
}
Hashtable hints = new Hashtable();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
// 圖像數據轉換,使用了矩陣轉換
BitMatrix bitMatrix = new QRCodeWriter().encode(url,
BarcodeFormat.QR_CODE, width, height, hints);
int[] pixels = new int[width * height];
// 下面這裏按照二維碼的算法,逐個生成二維碼的圖片,
// 兩個for循環是圖片橫列掃描的結果
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
if (bitMatrix.get(x, y)) {
pixels[y * width + x] = 0xff000000;
} else {
pixels[y * width + x] = 0xffffffff;
}
}
}
// 生成二維碼圖片的格式,使用ARGB_8888
Bitmap bitmap = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
return bitmap;
} catch (WriterException e) {
e.printStackTrace();
}
return null;
}

/**
* 生成條形碼
*
* @param context
* @param contents
* 須要生成的內容
* @param desiredWidth
* 生成條形碼的寬帶
* @param desiredHeight
* 生成條形碼的高度
* @param displayCode
* 是否在條形碼下方顯示內容
* @return
*/
public static Bitmap creatBarcode(Context context, String contents,
int desiredWidth, int desiredHeight, boolean displayCode) {
Bitmap ruseltBitmap = null;
/**
* 圖片兩端所保留的空白的寬度
*/
int marginW = 20;
/**
* 條形碼的編碼類型
*/
BarcodeFormat barcodeFormat = BarcodeFormat.CODE_128;

if (displayCode) {
Bitmap barcodeBitmap = encodeAsBitmap(contents, barcodeFormat,
desiredWidth, desiredHeight);
Bitmap codeBitmap = creatCodeBitmap(contents, desiredWidth + 2
* marginW, desiredHeight, context);
ruseltBitmap = mixtureBitmap(barcodeBitmap, codeBitmap, new PointF(
0, desiredHeight));
} else {
ruseltBitmap = encodeAsBitmap(contents, barcodeFormat,
desiredWidth, desiredHeight);
}

return ruseltBitmap;
}

/**
* 生成條形碼的Bitmap
*
* @param contents
* 須要生成的內容
* @param format
* 編碼格式
* @param desiredWidth
* @param desiredHeight
* @return
* @throws WriterException
*/
protected static Bitmap encodeAsBitmap(String contents,
BarcodeFormat format, int desiredWidth, int desiredHeight) {
final int WHITE = 0xFFFFFFFF;
final int BLACK = 0xFF000000;

MultiFormatWriter writer = new MultiFormatWriter();
BitMatrix result = null;
try {
result = writer.encode(contents, format, desiredWidth,
desiredHeight, null);
} catch (WriterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

int width = result.getWidth();
int height = result.getHeight();
int[] pixels = new int[width * height];
// All are 0, or black, by default
for (int y = 0; y < height; y++) {
int offset = y * width;
for (int x = 0; x < width; x++) {
pixels[offset + x] = result.get(x, y) ? BLACK : WHITE;
}
}

Bitmap bitmap = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
return bitmap;
}

/**
* 生成顯示編碼的Bitmap
*
* @param contents
* @param width
* @param height
* @param context
* @return
*/
protected static Bitmap creatCodeBitmap(String contents, int width,
int height, Context context) {
TextView tv = new TextView(context);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
tv.setLayoutParams(layoutParams);
tv.setText(contents);
tv.setHeight(height);
tv.setGravity(Gravity.CENTER_HORIZONTAL);
tv.setWidth(width);
tv.setDrawingCacheEnabled(true);
tv.setTextColor(Color.BLACK);
tv.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
tv.layout(0, 0, tv.getMeasuredWidth(), tv.getMeasuredHeight());

tv.buildDrawingCache();
Bitmap bitmapCode = tv.getDrawingCache();
return bitmapCode;
}

/**
* 將兩個Bitmap合併成一個
*
* @param first
* @param second
* @param fromPoint
* 第二個Bitmap開始繪製的起始位置(相對於第一個Bitmap)
* @return
*/
protected static Bitmap mixtureBitmap(Bitmap first, Bitmap second,
PointF fromPoint) {
if (first == null || second == null || fromPoint == null) {
return null;
}
int marginW = 20;
Bitmap newBitmap = Bitmap.createBitmap(
first.getWidth() + second.getWidth() + marginW,
first.getHeight() + second.getHeight(), Config.ARGB_4444);
Canvas cv = new Canvas(newBitmap);
cv.drawBitmap(first, marginW, 0, null);
cv.drawBitmap(second, fromPoint.x, fromPoint.y, null);
cv.save(Canvas.ALL_SAVE_FLAG);
cv.restore();

return newBitmap;
}

}

 

 

http://repo1.maven.org/maven2/com/google/zxing

相關文章
相關標籤/搜索