ZXing开发详解

博客转载自:https://blog.csdn.net/skillcollege/article/details/38852183

什么是Z*?

在Android平台做过二维码相关模块的肯定都熟知ZXing开源项目,Z*是一个开源Java类库用于解析多种格式的1D/2D条形码。目标是能够对QR编码、Data Matrix、UPC的1D条形码进行解码。 其提供了多种平台下的客户端包括:J2ME、J2SE和Android。其GitHub地址是:传送门

Z*项目里面代码很多,实现的功能也很多,我们的应用只需要剥离其中的扫描模块即可,再多一点也就是生成二维码的功能;接下来我们就一起来精简ZXing项目,最终形成一个小的Demo案例,当然江湖上已经有过N多种版本的ZXing精简项目,什么横屏改竖屏,绘制扫描界面,开启闪光灯等等,并且许多都是基于ZXing2.3.0来做精简的,后续有许多更新的版本,包括自动对焦,Camera管理,bug修复等等新功能;笔者使用的是ZXing3.1.0版本,这里需要说明的就是我的这版Demo绝对是江湖上面还没有出现的,也算是一点点小小的创新把,那就是去除ZXing项目中恼人的ViewFinderView的绘制,使用XML布局扫描界面,添加扫描动画,精确计算扫描区域

克隆Z*项目到本地

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

整理ZXing代码

打开ZXing项目的文件夹,可以看到如下文件目录:

其中我们主要关注2个文件夹里的内容: 

1. core : Z*项目的核心代码,可以新建一个Java工程,然后export成jar来调用。如下图所示:

免打包即可获得的zxing-3.1.0.jar  猛戳下载 

2. android : Android示例工程代码,成功运行之后就是一个专业的扫码应用了。如下图所示:

免引入免整理的zxing原始工程 ZXingRawProject  猛戳下载

但是这样就让你满足了,那怎么可以说是极致二维码扫描呢,有木有感觉ZXing的扫描框的绘制很不爽啊?自定义的View绘制的很丑,多屏幕适配的时候还经常不兼容,原始项目还是横屏模式的,目前大家都习惯竖屏扫描呢。怎么办?别怕,我来告诉你,我要将ViewFinderView砍掉,使用xml界面布局,添加扫描动画,最终一样准确无误的扫描到二维码数据,只需要对准,是的,毫厘不差的对准就可以了。

精简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

猜你喜欢

转载自www.cnblogs.com/Alex80/p/11624585.html