欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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实现二维码的生成

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