首頁 Java java教程 Android基於google Zxing實現二維碼的生成

Android基於google Zxing實現二維碼的生成

Jan 07, 2017 am 10:42 AM

最近專案用到了二維碼的生成與識別,之前沒有接觸這塊,然後就上網搜了搜,發現有很多這方面的資源,特別是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); 
} 
}; 
  
  
}
登入後複製

下面是主詳細圖

了解的請下載demo自己看,Demo中解決了在豎拍解碼時二維碼被拉伸的現象。

不過我遇到了一個問題是二維碼的掃描框調大後,掃描的靈敏度降低了,希望知道的朋友給指導下

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持PHP中文網。

更多Android基於google Zxing實現二維碼的生成相關文章請關注PHP中文網!


本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1658
14
CakePHP 教程
1415
52
Laravel 教程
1309
25
PHP教程
1257
29
C# 教程
1231
24
公司安全軟件導致應用無法運行?如何排查和解決? 公司安全軟件導致應用無法運行?如何排查和解決? Apr 19, 2025 pm 04:51 PM

公司安全軟件導致部分應用無法正常運行的排查與解決方法許多公司為了保障內部網絡安全,會部署安全軟件。 ...

如何將姓名轉換為數字以實現排序並保持群組中的一致性? 如何將姓名轉換為數字以實現排序並保持群組中的一致性? Apr 19, 2025 pm 11:30 PM

將姓名轉換為數字以實現排序的解決方案在許多應用場景中,用戶可能需要在群組中進行排序,尤其是在一個用...

IntelliJ IDEA是如何在不輸出日誌的情況下識別Spring Boot項目的端口號的? IntelliJ IDEA是如何在不輸出日誌的情況下識別Spring Boot項目的端口號的? Apr 19, 2025 pm 11:45 PM

在使用IntelliJIDEAUltimate版本啟動Spring...

如何使用MapStruct簡化系統對接中的字段映射問題? 如何使用MapStruct簡化系統對接中的字段映射問題? Apr 19, 2025 pm 06:21 PM

系統對接中的字段映射處理在進行系統對接時,常常會遇到一個棘手的問題:如何將A系統的接口字段有效地映�...

Java對像如何安全地轉換為數組? Java對像如何安全地轉換為數組? Apr 19, 2025 pm 11:33 PM

Java對象與數組的轉換:深入探討強制類型轉換的風險與正確方法很多Java初學者會遇到將一個對象轉換成數組的�...

如何優雅地獲取實體類變量名構建數據庫查詢條件? 如何優雅地獲取實體類變量名構建數據庫查詢條件? Apr 19, 2025 pm 11:42 PM

在使用MyBatis-Plus或其他ORM框架進行數據庫操作時,經常需要根據實體類的屬性名構造查詢條件。如果每次都手動...

如何利用Redis緩存方案高效實現產品排行榜列表的需求? 如何利用Redis緩存方案高效實現產品排行榜列表的需求? Apr 19, 2025 pm 11:36 PM

Redis緩存方案如何實現產品排行榜列表的需求?在開發過程中,我們常常需要處理排行榜的需求,例如展示一個�...

電商平台SKU和SPU數據庫設計:如何兼顧用戶自定義屬性和無屬性商品? 電商平台SKU和SPU數據庫設計:如何兼顧用戶自定義屬性和無屬性商品? Apr 19, 2025 pm 11:27 PM

電商平台SKU和SPU表設計詳解本文將探討電商平台中SKU和SPU的數據庫設計問題,特別是如何處理用戶自定義銷售屬...

See all articles