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实现二维码的生成
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。