今天老大出差,没人给任务,闲来无事就玩玩与公司相关的一些小Demo。
二维码生成简单,固定不变的代码,玩来玩去还是这些代码
代码如下:
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String s=editText.getText().toString();//s的长度约长,生成的二维码越密集,空白越少, 4个基点不能遮挡
if(!TextUtils.isEmpty(s)){
QRCodeWriter writer=new QRCodeWriter();
try {
Map<EncodeHintType,Object> map=new HashMap<EncodeHintType, Object>();
map.put(EncodeHintType.CHARACTER_SET,"UTF_8");//字符集
map.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);//H最高容错等级,但输入的字符不能太短
BitMatrix encode= writer.encode(s, BarcodeFormat.QR_CODE,500,500,map);
Bitmap bitmap=Bitmap.createBitmap(500,500, Bitmap.Config.RGB_565);
for (int i = 0; i < encode.getWidth(); i++) {
for (int i1 = 0; i1 < encode.getHeight(); i1++) {
if(encode.get(i,i1)){//每个像素点
bitmap.setPixel(i,i1, Color.BLACK);
}else{
bitmap.setPixel(i,i1,Color.WHITE);
}
}
}
Bitmap icon= BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher);//二维码的LOGO
new Canvas(bitmap).drawBitmap(icon,new Rect(0,0,icon.getWidth(),icon.getHeight()), new RectF(200,200,300,300),new Paint());
imageView.setImageBitmap(bitmap);
} catch (WriterException e) {
e.printStackTrace();
}
}
}
});
}
至于二维码的扫描解码,开始我是百度了很多Demo,但都是对Zxing的简化,但我还是想弄懂原理,可百度的结果总是不尽人意。先上一张图,代表二维码的解码流程
一、初始化相机
相机使用的是android.hardware.Camera这个类,在Android 5.0之后,推荐使用更强大的android.hardware.Camera2这个类,为了兼容更低版本Android系统,我们在这里仍然使用Camera类来实现。
Camera可以通过setDisplayOrientation()方法设置预览图像的方向,旋转度数只能是0、90、180、270中的一个,根据需求,本例中设置为90度。
Camera还可以通过Camera.Parameters类设置预览图像的分辨率,但是只能在气可支持的分辨率中选择一个,不能随便设置,我们需要根据屏幕大小,在其中选出一个最佳的预览图像分辨率,太大浪费资源,太小会显示不清楚,具体选择方法,在代码中有,这里就不细述了。
Camera可以通过setPreviewFormat()方法来设置预览图像的数据格式,推荐选择的有ImageFormat.NV21和ImageFormat.YV12,默认是NV21。NV21属于YUV图像,和RGB图像有所不同。
注意在使用Camera时,需要在AndroidManifest.xml里声明一些权限:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature android:name="android.hardware.camera.flash" />
二、绑定SurfaceView
在SurfaceView创建好后,通过Camera类的setPreviewDisplay()方法,将SurfaceHolder传入Camera。
调用Camera的startPreview()方法,Camera捕捉到的图像就会显示到SurfaceView上了。
三、获取一帧图像
调用Camera的setOneShotPreviewCallback(PreviewCallback cb)方法,可以请求获取一帧图像,获取到图像后,会调用PreviewCallback的onPreviewFrame(byte[] data, Camera camera)方法,其中的data参数就是图像的YUV数据了。
四、图像预处理
根据二维码的原理,我们只需要图像的亮度信息来进行二维码解析,所以我们要把获取到的彩色图像转换为灰度图像。YUV图像转换为灰度图像的方法,以及RGB图像转换为灰度图像的方法这里有个坑,待会详细介绍。
五、二维码解析
在这里,二维码解析使用的是google的zxing开源框架,把上一步处理后的灰度图像,封装为zxing的LuminanceSource,再封装为zxing的BinaryBitmap,然后就可以进行二维码解析了。
值得一提的是,利用zxing解析二维码是耗时操作,为避免ANR,需要写到子线程中来处理,我这里只是玩,就不写到子线程了。
六、解析结果
解析成功后可以调用result.getText();来获得解码后的字符串,怎么进行处理就是你们自己的事了。
开始就是初始化Camera和在SurfaceView上显示,做过Camera开发的都知道流程,我就不写了。
camera.setOneShotPreviewCallback()之后进入onPreviewFrame(byte[] bytes,Camera camera){}
关键的地方来了,我的解码操作也是在里面进行。(切记玩玩可以放在主线程,正规的时候还是利用Handle来进行解码的操作,否则小心出现ANR)
上代码
public void onPreviewFrame(byte[] bytes, Camera camera) {
/*开始我的想法也是利用BitmapFactory来直接利用bytes生成一个bitmap,但总是得到个空的Bitmap
*后来查了下,原来是因为格式的问题,这里我们要对bytes做下处理
*/
Camera.Size previewSize = camera.getParameters().getPreviewSize();
BitmapFactory.Options options=new BitmapFactory.Options();
options.inJustDecodeBounds=true;
YuvImage yuvImage=new YuvImage(bytes, ImageFormat.NV21,previewSize.width,previewSize.height,null);
ByteArrayOutputStream baos=new ByteArrayOutputStream();
yuvImage.compressToJpeg(new Rect(0,0,previewSize.width,previewSize.height),80,baos);
byte[] data = baos.toByteArray();
Bitmap bitmap= BitmapFactory.decodeByteArray(data,0,data.length);
int[] pixels=new int[bitmap.getWidth()*bitmap.getHeight()];
bitmap.getPixels(pixels,0,bitmap.getWidth(),0,0,bitmap.getWidth(),bitmap.getHeight());
RGBLuminanceSource source = new RGBLuminanceSource(bitmap.getWidth(),bitmap.getHeight(),pixels);
BinaryBitmap binaryBitmap=new BinaryBitmap(new HybridBinarizer(source));
QRCodeReader reader=new QRCodeReader();
try {
Result result = reader.decode(binaryBitmap);
Toast.makeText(this,result.getText(),Toast.LENGTH_SHORT).show();
decodeSucess=true;
Intent intent=new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(result.getText()));
startActivity(intent);
} catch (NotFoundException e) {
e.printStackTrace();
} catch (ChecksumException e) {
e.printStackTrace();
} catch (FormatException e) {
e.printStackTrace();
}
if(!decodeSucess){
camera.autoFocus(this);
}
菜鸟一枚,不喜勿喷,也欢迎你的宝贵意见