0

0

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

高洛峰

高洛峰

发布时间:2017-01-07 10:42:56

|

1304人浏览过

|

来源于php中文网

原创

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

 
 
  
  
 

 详细了解的请下载demo自己看,Demo中解决了在竖拍解码时二维码被拉伸的现象。

Ex驾校预约小程序
Ex驾校预约小程序

传统驾校预约方式步骤繁琐,效率低下,随着移动互联网科技和5G的革新,驾校考试领域迫切需要更加简洁、高效的预约方式,便捷人们的生活。因此设计基于微信小程序的驾校预约系统,改进传统驾校预约方式,实现高效的驾校学校预约。 采用腾讯提供的小程序云开发解决方案,无须服务器和域名。驾校预约管理:开始/截止时间/人数均可灵活设置,可以自定义客户预约填写的数据项驾校预约凭证:支持线下到场后校验签到/核销/二维码自

下载

不过我遇到了一个问题是 二维码的扫描框调大后,扫描的灵敏度降低了,希望知道的朋友给指导下

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

更多Android基于google Zxing实现二维码的生成相关文章请关注PHP中文网!

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
java入门学习合集
java入门学习合集

本专题整合了java入门学习指南、初学者项目实战、入门到精通等等内容,阅读专题下面的文章了解更多详细学习方法。

2

2026.01.29

java配置环境变量教程合集
java配置环境变量教程合集

本专题整合了java配置环境变量设置、步骤、安装jdk、避免冲突等等相关内容,阅读专题下面的文章了解更多详细操作。

2

2026.01.29

java成品学习网站推荐大全
java成品学习网站推荐大全

本专题整合了java成品网站、在线成品网站源码、源码入口等等相关内容,阅读专题下面的文章了解更多详细推荐内容。

0

2026.01.29

Java字符串处理使用教程合集
Java字符串处理使用教程合集

本专题整合了Java字符串截取、处理、使用、实战等等教程内容,阅读专题下面的文章了解详细操作教程。

0

2026.01.29

Java空对象相关教程合集
Java空对象相关教程合集

本专题整合了Java空对象相关教程,阅读专题下面的文章了解更多详细内容。

3

2026.01.29

clawdbot ai使用教程 保姆级clawdbot部署安装手册
clawdbot ai使用教程 保姆级clawdbot部署安装手册

Clawdbot是一个“有灵魂”的AI助手,可以帮用户清空收件箱、发送电子邮件、管理日历、办理航班值机等等,并且可以接入用户常用的任何聊天APP,所有的操作均可通过WhatsApp、Telegram等平台完成,用户只需通过对话,就能操控设备自动执行各类任务。

25

2026.01.29

clawdbot龙虾机器人官网入口 clawdbot ai官方网站地址
clawdbot龙虾机器人官网入口 clawdbot ai官方网站地址

clawdbot龙虾机器人官网入口:https://clawd.bot/,clawdbot ai是一个“有灵魂”的AI助手,可以帮用户清空收件箱、发送电子邮件、管理日历、办理航班值机等等,并且可以接入用户常用的任何聊天APP,所有的操作均可通过WhatsApp、Telegram等平台完成,用户只需通过对话,就能操控设备自动执行各类任务。

16

2026.01.29

Golang 网络安全与加密实战
Golang 网络安全与加密实战

本专题系统讲解 Golang 在网络安全与加密技术中的应用,包括对称加密与非对称加密(AES、RSA)、哈希与数字签名、JWT身份认证、SSL/TLS 安全通信、常见网络攻击防范(如SQL注入、XSS、CSRF)及其防护措施。通过实战案例,帮助学习者掌握 如何使用 Go 语言保障网络通信的安全性,保护用户数据与隐私。

8

2026.01.29

俄罗斯Yandex引擎入口
俄罗斯Yandex引擎入口

2026年俄罗斯Yandex搜索引擎最新入口汇总,涵盖免登录、多语言支持、无广告视频播放及本地化服务等核心功能。阅读专题下面的文章了解更多详细内容。

622

2026.01.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号