今天研究了一下Zxing的用法,感谢广大网友的技术分享!~
ZXing是一个开放源码的,用Java实现的多种格式的1D/2D条码图像处理库,它包含了联系到其他语言的端口。Zxing可以实现使用手机的内置的摄像头完成条形码的扫描及解码。该项目可实现的条形码编码和解码。总得来说就一句话,这玩意是google老大给出来的,用来生成二维码和条形码的
我找了很久前前后后下载了十几个demo都没什么让我满意的,要不就是没有生成条形码的,要不就是没有自定义扫描样式的。下面分享一个网友制作的demo:下载地址:http://download.csdn.net/detail/liaoinstan/9258087,感谢分享!~
可以选择手机本地图片进行扫描
这个demo包含了动态扫描线以及,生成二维码与条形码,
生成二维码演示
//该demo存在一些小问题
在原demo生成的二维码当生成的文字为中文时,用微信扫描会出现乱码问题
我的修改方法是在MainActivity 对二维码生成按钮点击事件中做了修改
原来是:
case R.id.btn_create_qr:
{
String contentString = edit_qr.getText().toString();
if (!contentString.equals("")) {
//根据字符串生成二维码图片并显示在界面上,第二个参数为图片的大小(350*350)
Bitmap qrCodeBitmap = EncodingHandler.createQRCode(contentString, 350);
if(qrCodeBitmap!=null) mImageView.setImageBitmap(qrCodeBitmap);
else Toast.makeText(this, "解析错误", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(this, "Text can not be empty", Toast.LENGTH_SHORT).show();
}
break;
}
修改后
case R.id.btn_create_qr:
{
String contentString = edit_qr.getText().toString();
if (!contentString.equals("")) {
//根据字符串生成二维码图片并显示在界面上,第二个参数为图片的大小(350*350)
Bitmap qrCodeBitmap=null;
try {
qrCodeBitmap = EncodingHandler.createQRCode(new String(contentString.getBytes(),"iso-8859-1"), 350);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(qrCodeBitmap!=null) mImageView.setImageBitmap(qrCodeBitmap);
else Toast.makeText(this, "解析错误", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(this, "Text can not be empty", Toast.LENGTH_SHORT).show();
}
break;
}
我也尝试了修改EncodingHandler类里面的createQRCode方法,然而并没有什么用
Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
编码格式我换了gbk,iso-8859-1,等一些编码格式都没用,所以只能用我的蠢方法啦~~
下面我讲讲扫描框的绘制原理
首先在com.mining.app.zxing.camera包下的CameraManager类中,是调用getFramingRect()方法获取扫描框区域,扫描框越大,所占内存就越大
/**
注释的中文意思大致是:计算解码窗体矩形的控件大小,目的是帮助用户保持足够远以确保图片能被对焦
兄弟别纠结,我知道我的翻译烂
* Calculates the framing rect which the UI should draw to show the user where to place the
* barcode. This target helps with alignment as well as forces the user to hold the device
* far enough away to ensure the image will be in focus.
*
* @return The rectangle to draw on screen in window coordinates.
*/
public Rect getFramingRect() {
//获取当前屏幕分辨率
Point screenResolution = configManager.getScreenResolution();
if (framingRect == null) {
if (camera == null) {
return null;
}
//计算出扫描框的大小
// //int width = screenResolution.x * 3 / 4; 为屏幕宽的3/4
//if (width < MIN_FRAME_WIDTH) { 要注意这里的判断条件,这个MIN_Frame_Width是demo中写死
//width = MIN_FRAME_WIDTH; 的常量,默认屏幕高度为480*360
// } else if (width > MAX_FRAME_WIDTH) {
// width = MAX_FRAME_WIDTH;
// }
// int height = screenResolution.y * 3 / 4;
// if (height < MIN_FRAME_HEIGHT) { 为屏幕的高的3/4
// height = MIN_FRAME_HEIGHT;
// } else if (height > MAX_FRAME_HEIGHT) {
// height = MAX_FRAME_HEIGHT;
// }
// int leftOffset = (screenResolution.x - width) / 2;//起始位置
// int topOffset = (screenResolution.y - height) / 2;
// int width = screenResolution.x/2; //关键是这里才是实际算屏幕高度和宽度的,以便更好的屏 幕适配
// int height = screenResolution.x/2;
// int leftOffset = (screenResolution.x - width) / 2;
// int topOffset = (screenResolution.y - height) / 2;
framingRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height);
Log.d(TAG, "Calculated framing rect: " + framingRect);
}
return framingRect;
}
到这里你可能就明白扫描框大小是怎么定义的了,但是绘制阴影部分的呢?
CameraManager类没有写出来在哪里绘制啊,
其实自定义扫描框是在com.mining.app.zxing.view包下的ViewfinderView类中,这是一个自定义控件,继承自View的
学android的大概都知道,绘制样式是在onDraw方法中完成的,以下代码就是绘制边角样式和动态扫描线的地方
@Override
public void onDraw(Canvas canvas) {
//中间的扫描框,你要修改扫描框的大小,去CameraManager里面修改
Rect frame = CameraManager.get().getFramingRect();
if (frame == null) {
return;
}
//初始化中间线滑动的最上边和最下边
if(!isFirst){
isFirst = true;
slideTop = frame.top;
slideBottom = frame.bottom;
}
//获取屏幕的宽和高
int width = canvas.getWidth();
int height = canvas.getHeight();
paint.setColor(resultBitmap != null ? resultColor : maskColor);
//画出扫描框外面的阴影部分,共四个部分,扫描框的上面到屏幕上面,扫描框的下面到屏幕下面
//扫描框的左边面到屏幕左边,扫描框的右边到屏幕右边
canvas.drawRect(0, 0, width, frame.top, paint);
canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint);
canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1,
paint);
canvas.drawRect(0, frame.bottom + 1, width, height, paint);
if (resultBitmap != null) {
// Draw the opaque result bitmap over the scanning rectangle
paint.setAlpha(OPAQUE);
canvas.drawBitmap(resultBitmap, frame.left, frame.top, paint);
} else {
//画扫描框边上的角,总共8个部分,
paint.setColor(Color.GREEN);//设置画笔颜色
canvas.drawRect(frame.left, frame.top, frame.left + ScreenRate,
frame.top + CORNER_WIDTH, paint);
canvas.drawRect(frame.left, frame.top, frame.left + CORNER_WIDTH, frame.top
+ ScreenRate, paint);
canvas.drawRect(frame.right - ScreenRate, frame.top, frame.right,
frame.top + CORNER_WIDTH, paint);
canvas.drawRect(frame.right - CORNER_WIDTH, frame.top, frame.right, frame.top
+ ScreenRate, paint);
canvas.drawRect(frame.left, frame.bottom - CORNER_WIDTH, frame.left
+ ScreenRate, frame.bottom, paint);
canvas.drawRect(frame.left, frame.bottom - ScreenRate,
frame.left + CORNER_WIDTH, frame.bottom, paint);
canvas.drawRect(frame.right - ScreenRate, frame.bottom - CORNER_WIDTH,
frame.right, frame.bottom, paint);
canvas.drawRect(frame.right - CORNER_WIDTH, frame.bottom - ScreenRate,
frame.right, frame.bottom, paint);
//绘制中间的线,每次刷新界面,中间的线往下移动SPEEN_DISTANCE
slideTop += SPEEN_DISTANCE; /** 绘制动态扫描线的位置*/
if(slideTop >= frame.bottom){
slideTop = frame.top;
}
Rect lineRect = new Rect();
lineRect.left = frame.left;
lineRect.right = frame.right;
lineRect.top = slideTop;
lineRect.bottom = slideTop + 18;
canvas.drawBitmap(((BitmapDrawable)(getResources().getDrawable(R.drawable.qrcode_scan_line))).getBitmap(), null, lineRect, paint);
//画扫描框下面的字
paint.setColor(Color.WHITE);
paint.setTextSize(TEXT_SIZE * density);
paint.setAlpha(0x40);
paint.setTypeface(Typeface.create("System", Typeface.BOLD));
String text = getResources().getString(R.string.scan_text);
float textWidth = paint.measureText(text);
canvas.drawText(text, (width - textWidth)/2, (float) (frame.bottom + (float)TEXT_PADDING_TOP *density), paint);
Collection<ResultPoint> currentPossible = possibleResultPoints;
Collection<ResultPoint> currentLast = lastPossibleResultPoints;
if (currentPossible.isEmpty()) {
lastPossibleResultPoints = null;
} else {
possibleResultPoints = new HashSet<ResultPoint>(5);
lastPossibleResultPoints = currentPossible;
paint.setAlpha(OPAQUE);
paint.setColor(resultPointColor);
for (ResultPoint point : currentPossible) {
canvas.drawCircle(frame.left + point.getX(), frame.top
+ point.getY(), 6.0f, paint);
}
}
if (currentLast != null) {
paint.setAlpha(OPAQUE / 2);
paint.setColor(resultPointColor);
for (ResultPoint point : currentLast) {
canvas.drawCircle(frame.left + point.getX(), frame.top
+ point.getY(), 3.0f, paint);
}
}
//只刷新扫描框的内容,其他地方不刷新
postInvalidateDelayed(ANIMATION_DELAY, frame.left, frame.top,
frame.right, frame.bottom);
}
}
这篇文章主要是我个人的学习记录,也可以方便一下想初步了解Zxing的朋友,因为在网上找的一些分享出来的demo要不就是一运行就崩,要么就是
条形码演示功能没有,要么就是选择图片解析二维码没有。这是我找到的篇较为完整的demo,有很多地方都可以实际应用到项目中,而且注释很全,省得自己再去用蹩脚的英语翻译,再一次感谢作者的分享!