Android基于google Zxing实现二维码的生成
最近项目用到了二维码的生成与识别,之前没有接触这块,然后就上网搜了搜,发现有好多这方面的资源,特别是googleZxing对二维码的封装,实现的已经不错了,可以直接拿过来引用,下载了他们的源码后,只做了少少的改动,就是在Demo中增加了长按识别的功能,网上虽然也有长按识别的Demo,但好多下载下来却无法运行,然后总结了一下,加在了下面的Demo中。
下面来介绍这个Demo的主类
publicclassBarCodeTestActivityextendsActivity{
privateTextViewresultTextView;
privateEditTextqrStrEditText;
privateImageViewqrImgImageView;
privateStringtime;
privateFilefile=null;
@Override
publicvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
resultTextView=(TextView)this.findViewById(R.id.tv_scan_result);
qrStrEditText=(EditText)this.findViewById(R.id.et_qr_string);
qrImgImageView=(ImageView)this.findViewById(R.id.iv_qr_image);
ButtonscanBarCodeButton=(Button)this.findViewById(R.id.btn_scan_barcode);
scanBarCodeButton.setOnClickListener(newOnClickListener(){
@Override
publicvoidonClick(Viewv){
//打开扫描界面扫描条形码或二维码
IntentopenCameraIntent=newIntent(BarCodeTestActivity.this,CaptureActivity.class);
startActivityForResult(openCameraIntent,0);
}
});
qrImgImageView.setOnLongClickListener(newOnLongClickListener(){
@Override
publicbooleanonLongClick(Viewv){
//长按识别二维码
saveCurrentImage();
returntrue;
}
});
ButtongenerateQRCodeButton=(Button)this.findViewById(R.id.btn_add_qrcode);
generateQRCodeButton.setOnClickListener(newOnClickListener(){
@Override
publicvoidonClick(Viewv){
try{
StringcontentString=qrStrEditText.getText().toString();
if(!contentString.equals("")){
//根据字符串生成二维码图片并显示在界面上,第二个参数为图片的大小(350*350)
BitmapqrCodeBitmap=EncodingHandler.createQRCode(contentString,350);
qrImgImageView.setImageBitmap(qrCodeBitmap);
}else{
//提示文本不能是空的
Toast.makeText(BarCodeTestActivity.this,"Textcannotbeempty",Toast.LENGTH_SHORT).show();
}
}catch(WriterExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
});
}
//这种方法状态栏是空白,显示不了状态栏的信息
privatevoidsaveCurrentImage()
{
//获取当前屏幕的大小
intwidth=getWindow().getDecorView().getRootView().getWidth();
intheight=getWindow().getDecorView().getRootView().getHeight();
//生成相同大小的图片
BitmaptemBitmap=Bitmap.createBitmap(width,height,Bitmap.Config.ARGB_8888);
//找到当前页面的根布局
Viewview=getWindow().getDecorView().getRootView();
//设置缓存
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
//从缓存中获取当前屏幕的图片,创建一个DrawingCache的拷贝,因为DrawingCache得到的位图在禁用后会被回收
temBitmap=view.getDrawingCache();
SimpleDateFormatdf=newSimpleDateFormat("yyyymmddhhmmss");
time=df.format(newDate());
if(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())){
file=newFile(Environment.getExternalStorageDirectory().getAbsolutePath()+"/screen",time+".png");
if(!file.exists()){
file.getParentFile().mkdirs();
try{
file.createNewFile();
}catch(IOExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
FileOutputStreamfos=null;
try{
fos=newFileOutputStream(file);
temBitmap.compress(Bitmap.CompressFormat.PNG,100,fos);
fos.flush();
fos.close();
}catch(FileNotFoundExceptione){
e.printStackTrace();
}catch(IOExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
newThread(newRunnable(){
@Override
publicvoidrun(){
Stringpath=Environment.getExternalStorageDirectory().getAbsolutePath()+"/screen/"+time+".png";
finalResultresult=parseQRcodeBitmap(path);
runOnUiThread(newRunnable(){
publicvoidrun(){
if(null!=result){
resultTextView.setText(result.toString());
}else{
Toast.makeText(BarCodeTestActivity.this,"无法识别",Toast.LENGTH_LONG).show();
}
}
});
}
}).start();
//禁用DrawingCahce否则会影响性能,而且不禁止会导致每次截图到保存的是缓存的位图
view.setDrawingCacheEnabled(false);
}
}
//解析二维码图片,返回结果封装在Result对象中
privatecom.google.zxing.ResultparseQRcodeBitmap(StringbitmapPath){
//解析转换类型UTF-8
Hashtable<DecodeHintType,String>hints=newHashtable<DecodeHintType,String>();
hints.put(DecodeHintType.CHARACTER_SET,"utf-8");
//获取到待解析的图片
BitmapFactory.Optionsoptions=newBitmapFactory.Options();
//如果我们把inJustDecodeBounds设为true,那么BitmapFactory.decodeFile(Stringpath,Optionsopt)
//并不会真的返回一个Bitmap给你,它仅仅会把它的宽,高取回来给你
options.inJustDecodeBounds=true;
//此时的bitmap是null,这段代码之后,options.outWidth和options.outHeight就是我们想要的宽和高了
Bitmapbitmap=BitmapFactory.decodeFile(bitmapPath,options);
//我们现在想取出来的图片的边长(二维码图片是正方形的)设置为400像素
/**
options.outHeight=400;
options.outWidth=400;
options.inJustDecodeBounds=false;
bitmap=BitmapFactory.decodeFile(bitmapPath,options);
*/
//以上这种做法,虽然把bitmap限定到了我们要的大小,但是并没有节约内存,如果要节约内存,我们还需要使用inSimpleSize这个属性
options.inSampleSize=options.outHeight/400;
if(options.inSampleSize<=0){
options.inSampleSize=1;//防止其值小于或等于0
}
/**
*辅助节约内存设置
*
*options.inPreferredConfig=Bitmap.Config.ARGB_4444;//默认是Bitmap.Config.ARGB_8888
*options.inPurgeable=true;
*options.inInputShareable=true;
*/
options.inJustDecodeBounds=false;
bitmap=BitmapFactory.decodeFile(bitmapPath,options);
//新建一个RGBLuminanceSource对象,将bitmap图片传给此对象
RGBLuminanceSourcergbLuminanceSource=newRGBLuminanceSource(bitmap);
//将图片转换成二进制图片
BinaryBitmapbinaryBitmap=newBinaryBitmap(newHybridBinarizer(rgbLuminanceSource));
//初始化解析对象
QRCodeReaderreader=newQRCodeReader();
//开始解析
Resultresult=null;
try{
result=reader.decode(binaryBitmap,hints);
}catch(Exceptione){
//TODO:handleexception
}
returnresult;
}
@Override
protectedvoidonActivityResult(intrequestCode,intresultCode,Intentdata){
super.onActivityResult(requestCode,resultCode,data);
//处理扫描结果(在界面上显示)
if(resultCode==RESULT_OK){
Bundlebundle=data.getExtras();
StringscanResult=bundle.getString("result");
resultTextView.setText(scanResult);
}
}
}
然后长按识别二维码调用了RGBLuminanceSource这个类
publicclassRGBLuminanceSourceextendsLuminanceSource{
privatebytebitmapPixels[];
protectedRGBLuminanceSource(Bitmapbitmap){
super(bitmap.getWidth(),bitmap.getHeight());
//首先,要取得该图片的像素数组内容
int[]data=newint[bitmap.getWidth()*bitmap.getHeight()];
this.bitmapPixels=newbyte[bitmap.getWidth()*bitmap.getHeight()];
bitmap.getPixels(data,0,getWidth(),0,0,getWidth(),getHeight());
//将int数组转换为byte数组,也就是取像素值中蓝色值部分作为辨析内容
for(inti=0;i<data.length;i++){
this.bitmapPixels[i]=(byte)data[i];
}
}
@Override
publicbyte[]getMatrix(){
//返回我们生成好的像素数据
returnbitmapPixels;
}
@Override
publicbyte[]getRow(inty,byte[]row){
//这里要得到指定行的像素数据
System.arraycopy(bitmapPixels,y*getWidth(),row,0,getWidth());
returnrow;
}
}
相机识别二维码调用了CaptureActivity这个类
publicclassCaptureActivityextendsActivityimplementsCallback{
privateCaptureActivityHandlerhandler;
privateViewfinderViewviewfinderView;
privatebooleanhasSurface;
privateVector<BarcodeFormat>decodeFormats;
privateStringcharacterSet;
privateInactivityTimerinactivityTimer;
privateMediaPlayermediaPlayer;
privatebooleanplayBeep;
privatestaticfinalfloatBEEP_VOLUME=0.10f;
privatebooleanvibrate;
privateButtoncancelScanButton;
/**Calledwhentheactivityisfirstcreated.*/
@Override
publicvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.camera);
CameraManager.init(getApplication());
viewfinderView=(ViewfinderView)findViewById(R.id.viewfinder_view);
cancelScanButton=(Button)this.findViewById(R.id.btn_cancel_scan);
hasSurface=false;
inactivityTimer=newInactivityTimer(this);
}
@Override
protectedvoidonResume(){
super.onResume();
SurfaceViewsurfaceView=(SurfaceView)findViewById(R.id.preview_view);
SurfaceHoldersurfaceHolder=surfaceView.getHolder();
if(hasSurface){
initCamera(surfaceHolder);
}else{
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
decodeFormats=null;
characterSet=null;
playBeep=true;
AudioManageraudioService=(AudioManager)getSystemService(AUDIO_SERVICE);
if(audioService.getRingerMode()!=AudioManager.RINGER_MODE_NORMAL){
playBeep=false;
}
initBeepSound();
vibrate=true;
//quitthescanview
cancelScanButton.setOnClickListener(newOnClickListener(){
@Override
publicvoidonClick(Viewv){
CaptureActivity.this.finish();
}
});
}
@Override
protectedvoidonPause(){
super.onPause();
if(handler!=null){
handler.quitSynchronously();
handler=null;
}
CameraManager.get().closeDriver();
}
@Override
protectedvoidonDestroy(){
inactivityTimer.shutdown();
super.onDestroy();
}
/**
*Handlerscanresult
*@paramresult
*@parambarcode
*/
publicvoidhandleDecode(Resultresult,Bitmapbarcode){
inactivityTimer.onActivity();
playBeepSoundAndVibrate();
StringresultString=result.getText();
//FIXME
if(resultString.equals("")){
//扫描失败
Toast.makeText(CaptureActivity.this,"Scanfailed!",Toast.LENGTH_SHORT).show();
}else{
//System.out.println("Result:"+resultString);
IntentresultIntent=newIntent();
Bundlebundle=newBundle();
bundle.putString("result",resultString);
resultIntent.putExtras(bundle);
this.setResult(RESULT_OK,resultIntent);
}
CaptureActivity.this.finish();
}
privatevoidinitCamera(SurfaceHoldersurfaceHolder){
try{
CameraManager.get().openDriver(surfaceHolder);
}catch(IOExceptionioe){
return;
}catch(RuntimeExceptione){
return;
}
if(handler==null){
handler=newCaptureActivityHandler(this,decodeFormats,
characterSet);
}
}
@Override
publicvoidsurfaceChanged(SurfaceHolderholder,intformat,intwidth,
intheight){
}
@Override
publicvoidsurfaceCreated(SurfaceHolderholder){
if(!hasSurface){
hasSurface=true;
initCamera(holder);
}
}
@Override
publicvoidsurfaceDestroyed(SurfaceHolderholder){
hasSurface=false;
}
publicViewfinderViewgetViewfinderView(){
returnviewfinderView;
}
publicHandlergetHandler(){
returnhandler;
}
publicvoiddrawViewfinder(){
viewfinderView.drawViewfinder();
}
privatevoidinitBeepSound(){
if(playBeep&&mediaPlayer==null){
//ThevolumeonSTREAM_SYSTEMisnotadjustable,andusersfoundit
//tooloud,
//sowenowplayonthemusicstream.
setVolumeControlStream(AudioManager.STREAM_MUSIC);
mediaPlayer=newMediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setOnCompletionListener(beepListener);
AssetFileDescriptorfile=getResources().openRawResourceFd(
R.raw.beep);
try{
mediaPlayer.setDataSource(file.getFileDescriptor(),
file.getStartOffset(),file.getLength());
file.close();
mediaPlayer.setVolume(BEEP_VOLUME,BEEP_VOLUME);
mediaPlayer.prepare();
}catch(IOExceptione){
mediaPlayer=null;
}
}
}
privatestaticfinallongVIBRATE_DURATION=200L;
privatevoidplayBeepSoundAndVibrate(){
if(playBeep&&mediaPlayer!=null){
mediaPlayer.start();
}
if(vibrate){
Vibratorvibrator=(Vibrator)getSystemService(VIBRATOR_SERVICE);
vibrator.vibrate(VIBRATE_DURATION);
}
}
/**
*Whenthebeephasfinishedplaying,rewindtoqueueupanotherone.
*/
privatefinalOnCompletionListenerbeepListener=newOnCompletionListener(){
publicvoidonCompletion(MediaPlayermediaPlayer){
mediaPlayer.seekTo(0);
}
};
}
下面是主布局mian文件
<?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@android:color/white" android:orientation="vertical"> <Button android:id="@+id/btn_scan_barcode" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="30dp" android:text="Opencamera"/> <LinearLayout android:orientation="horizontal" android:layout_marginTop="10dp" android:layout_width="fill_parent" android:layout_height="wrap_content"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@android:color/black" android:textSize="18sp" android:text="Scanresult:"/> <TextView android:id="@+id/tv_scan_result" android:layout_width="fill_parent" android:textSize="18sp" android:textColor="@android:color/black" android:layout_height="wrap_content"/> </LinearLayout> <EditText android:id="@+id/et_qr_string" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="30dp" android:hint="Inputthetext"/> <Button android:id="@+id/btn_add_qrcode" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="GenerateQRcode"/> <ImageView android:id="@+id/iv_qr_image" android:layout_width="250dp" android:layout_height="250dp" android:scaleType="fitXY" android:layout_marginTop="10dp" android:layout_gravity="center"/> </LinearLayout>
详细了解的请下载demo自己看,Demo中解决了在竖拍解码时二维码被拉伸的现象。
不过我遇到了一个问题是二维码的扫描框调大后,扫描的灵敏度降低了,希望知道的朋友给指导下
有兴趣的可以下载Demo看一看:googleZxing实现二维码的生成
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。