当前位置: 移动技术网 > 移动技术>移动开发>Android > Android基于google Zxing实现二维码的生成

Android基于google Zxing实现二维码的生成

2019年07月24日  | 移动技术网移动技术  | 我要评论

最近项目用到了二维码的生成与识别,之前没有接触这块,然后就上网搜了搜,发现有好多这方面的资源,特别是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看一看:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网