Android基于google Zxing实现二维码的生成
程序员文章站
2024-03-02 09:41:22
最近项目用到了二维码的生成与识别,之前没有接触这块,然后就上网搜了搜,发现有好多这方面的资源,特别是google zxing对二维码的封装,实现的已经不错了,可以直接拿过来...
最近项目用到了二维码的生成与识别,之前没有接触这块,然后就上网搜了搜,发现有好多这方面的资源,特别是google zxing对二维码的封装,实现的已经不错了,可以直接拿过来引用,下载了他们的源码后,只做了少少的改动,就是在demo中增加了长按识别的功能,网上虽然也有长按识别的demo,但好多下载下来却无法运行,然后总结了一下,加在了下面的demo中。
下面来介绍这个demo的主类
public class barcodetestactivity extends activity { private textview resulttextview; private edittext qrstredittext; private imageview qrimgimageview; private string time; private file file = null; @override public void oncreate(bundle savedinstancestate) { 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); button scanbarcodebutton = (button) this.findviewbyid(r.id.btn_scan_barcode); scanbarcodebutton.setonclicklistener(new onclicklistener() { @override public void onclick(view v) { //打开扫描界面扫描条形码或二维码 intent opencameraintent = new intent(barcodetestactivity.this,captureactivity.class); startactivityforresult(opencameraintent, 0); } }); qrimgimageview.setonlongclicklistener(new onlongclicklistener() { @override public boolean onlongclick(view v) { // 长按识别二维码 savecurrentimage(); return true; } }); button generateqrcodebutton = (button) this.findviewbyid(r.id.btn_add_qrcode); generateqrcodebutton.setonclicklistener(new onclicklistener() { @override public void onclick(view v) { try { string contentstring = qrstredittext.gettext().tostring(); if (!contentstring.equals("")) { //根据字符串生成二维码图片并显示在界面上,第二个参数为图片的大小(350*350) bitmap qrcodebitmap = encodinghandler.createqrcode(contentstring, 350); qrimgimageview.setimagebitmap(qrcodebitmap); }else { //提示文本不能是空的 toast.maketext(barcodetestactivity.this, "text can not be empty", toast.length_short).show(); } } catch (writerexception e) { // todo auto-generated catch block e.printstacktrace(); } } }); } //这种方法状态栏是空白,显示不了状态栏的信息 private void savecurrentimage() { //获取当前屏幕的大小 int width = getwindow().getdecorview().getrootview().getwidth(); int height = getwindow().getdecorview().getrootview().getheight(); //生成相同大小的图片 bitmap tembitmap = bitmap.createbitmap( width, height, bitmap.config.argb_8888 ); //找到当前页面的根布局 view view = getwindow().getdecorview().getrootview(); //设置缓存 view.setdrawingcacheenabled(true); view.builddrawingcache(); //从缓存中获取当前屏幕的图片,创建一个drawingcache的拷贝,因为drawingcache得到的位图在禁用后会被回收 tembitmap = view.getdrawingcache(); simpledateformat df = new simpledateformat("yyyymmddhhmmss"); time = df.format(new date()); if(environment.media_mounted.equals(environment.getexternalstoragestate())){ file = new file(environment.getexternalstoragedirectory().getabsolutepath() + "/screen",time + ".png"); if(!file.exists()){ file.getparentfile().mkdirs(); try { file.createnewfile(); } catch (ioexception e) { // todo auto-generated catch block e.printstacktrace(); } } fileoutputstream fos = null; try { fos = new fileoutputstream(file); tembitmap.compress(bitmap.compressformat.png, 100, fos); fos.flush(); fos.close(); } catch (filenotfoundexception e) { e.printstacktrace(); } catch (ioexception e) { // todo auto-generated catch block e.printstacktrace(); } new thread(new runnable() { @override public void run() { string path = environment.getexternalstoragedirectory().getabsolutepath() + "/screen/" + time + ".png"; final result result = parseqrcodebitmap(path); runonuithread(new runnable() { public void run() { if(null!=result){ resulttextview.settext(result.tostring()); }else{ toast.maketext(barcodetestactivity.this, "无法识别", toast.length_long).show(); } } }); } }).start(); //禁用drawingcahce否则会影响性能 ,而且不禁止会导致每次截图到保存的是缓存的位图 view.setdrawingcacheenabled(false); } } //解析二维码图片,返回结果封装在result对象中 private com.google.zxing.result parseqrcodebitmap(string bitmappath){ //解析转换类型utf-8 hashtable<decodehinttype, string> hints = new hashtable<decodehinttype, string>(); hints.put(decodehinttype.character_set, "utf-8"); //获取到待解析的图片 bitmapfactory.options options = new bitmapfactory.options(); //如果我们把injustdecodebounds设为true,那么bitmapfactory.decodefile(string path, options opt) //并不会真的返回一个bitmap给你,它仅仅会把它的宽,高取回来给你 options.injustdecodebounds = true; //此时的bitmap是null,这段代码之后,options.outwidth 和 options.outheight就是我们想要的宽和高了 bitmap bitmap = 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图片传给此对象 rgbluminancesource rgbluminancesource = new rgbluminancesource(bitmap); //将图片转换成二进制图片 binarybitmap binarybitmap = new binarybitmap(new hybridbinarizer(rgbluminancesource)); //初始化解析对象 qrcodereader reader = new qrcodereader(); //开始解析 result result = null; try { result = reader.decode(binarybitmap, hints); } catch (exception e) { // todo: handle exception } return result; } @override protected void onactivityresult(int requestcode, int resultcode, intent data) { super.onactivityresult(requestcode, resultcode, data); //处理扫描结果(在界面上显示) if (resultcode == result_ok) { bundle bundle = data.getextras(); string scanresult = bundle.getstring("result"); resulttextview.settext(scanresult); } } }
然后长按识别二维码调用了rgbluminancesource这个类
public class rgbluminancesource extends luminancesource { private byte bitmappixels[]; protected rgbluminancesource(bitmap bitmap) { super(bitmap.getwidth(), bitmap.getheight()); // 首先,要取得该图片的像素数组内容 int[] data = new int[bitmap.getwidth() * bitmap.getheight()]; this.bitmappixels = new byte[bitmap.getwidth() * bitmap.getheight()]; bitmap.getpixels(data, 0, getwidth(), 0, 0, getwidth(), getheight()); // 将int数组转换为byte数组,也就是取像素值中蓝色值部分作为辨析内容 for (int i = 0; i < data.length; i++) { this.bitmappixels[i] = (byte) data[i]; } } @override public byte[] getmatrix() { // 返回我们生成好的像素数据 return bitmappixels; } @override public byte[] getrow(int y, byte[] row) { // 这里要得到指定行的像素数据 system.arraycopy(bitmappixels, y * getwidth(), row, 0, getwidth()); return row; } }
相机识别二维码调用了captureactivity这个类
public class captureactivity extends activity implements callback { private captureactivityhandler handler; private viewfinderview viewfinderview; private boolean hassurface; private vector<barcodeformat> decodeformats; private string characterset; private inactivitytimer inactivitytimer; private mediaplayer mediaplayer; private boolean playbeep; private static final float beep_volume = 0.10f; private boolean vibrate; private button cancelscanbutton; /** called when the activity is first created. */ @override public void oncreate(bundle savedinstancestate) { 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 = new inactivitytimer(this); } @override protected void onresume() { super.onresume(); surfaceview surfaceview = (surfaceview) findviewbyid(r.id.preview_view); surfaceholder surfaceholder = surfaceview.getholder(); if (hassurface) { initcamera(surfaceholder); } else { surfaceholder.addcallback(this); surfaceholder.settype(surfaceholder.surface_type_push_buffers); } decodeformats = null; characterset = null; playbeep = true; audiomanager audioservice = (audiomanager) getsystemservice(audio_service); if (audioservice.getringermode() != audiomanager.ringer_mode_normal) { playbeep = false; } initbeepsound(); vibrate = true; //quit the scan view cancelscanbutton.setonclicklistener(new onclicklistener() { @override public void onclick(view v) { captureactivity.this.finish(); } }); } @override protected void onpause() { super.onpause(); if (handler != null) { handler.quitsynchronously(); handler = null; } cameramanager.get().closedriver(); } @override protected void ondestroy() { inactivitytimer.shutdown(); super.ondestroy(); } /** * handler scan result * @param result * @param barcode */ public void handledecode(result result, bitmap barcode) { inactivitytimer.onactivity(); playbeepsoundandvibrate(); string resultstring = result.gettext(); //fixme if (resultstring.equals("")) { //扫描失败 toast.maketext(captureactivity.this, "scan failed!", toast.length_short).show(); }else { // system.out.println("result:"+resultstring); intent resultintent = new intent(); bundle bundle = new bundle(); bundle.putstring("result", resultstring); resultintent.putextras(bundle); this.setresult(result_ok, resultintent); } captureactivity.this.finish(); } private void initcamera(surfaceholder surfaceholder) { try { cameramanager.get().opendriver(surfaceholder); } catch (ioexception ioe) { return; } catch (runtimeexception e) { return; } if (handler == null) { handler = new captureactivityhandler(this, decodeformats, characterset); } } @override public void surfacechanged(surfaceholder holder, int format, int width, int height) { } @override public void surfacecreated(surfaceholder holder) { if (!hassurface) { hassurface = true; initcamera(holder); } } @override public void surfacedestroyed(surfaceholder holder) { hassurface = false; } public viewfinderview getviewfinderview() { return viewfinderview; } public handler gethandler() { return handler; } public void drawviewfinder() { viewfinderview.drawviewfinder(); } private void initbeepsound() { if (playbeep && mediaplayer == null) { // the volume on stream_system is not adjustable, and users found it // too loud, // so we now play on the music stream. setvolumecontrolstream(audiomanager.stream_music); mediaplayer = new mediaplayer(); mediaplayer.setaudiostreamtype(audiomanager.stream_music); mediaplayer.setoncompletionlistener(beeplistener); assetfiledescriptor file = 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 (ioexception e) { mediaplayer = null; } } } private static final long vibrate_duration = 200l; private void playbeepsoundandvibrate() { if (playbeep && mediaplayer != null) { mediaplayer.start(); } if (vibrate) { vibrator vibrator = (vibrator) getsystemservice(vibrator_service); vibrator.vibrate(vibrate_duration); } } /** * when the beep has finished playing, rewind to queue up another one. */ private final oncompletionlistener beeplistener = new oncompletionlistener() { public void oncompletion(mediaplayer mediaplayer) { mediaplayer.seekto(0); } }; }
下面是主布局mian文件
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns: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="open camera" /> <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="scan result:" /> <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="input the text"/> <button android:id="@+id/btn_add_qrcode" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="generate qrcode" /> <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看一看:google zxing实现二维码的生成
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
推荐阅读
-
Android基于google Zxing实现二维码的生成
-
Python基于QRCode实现生成二维码的方法【下载,安装,调用等】
-
基于Android实现个性彩色好看的二维码
-
Android 基于google Zxing实现二维码、条形码扫描,仿微信二维码扫描效果(推荐)
-
Android基于google Zxing实现各类二维码扫描效果
-
基于Android实现个性彩色好看的二维码
-
Android 基于google Zxing实现二维码、条形码扫描,仿微信二维码扫描效果(推荐)
-
Android基于google Zxing实现各类二维码扫描效果
-
Android基于google Zxing实现各类二维码扫描效果
-
Android基于google Zxing实现二维码的生成