Android基于google Zxing實(shí)現(xiàn)二維碼的生成
最近項(xiàng)目用到了二維碼的生成與識別,之前沒有接觸這塊,然后就上網(wǎng)搜了搜,發(fā)現(xiàn)有好多這方面的資源,特別是google Zxing對二維碼的封裝,實(shí)現(xiàn)的已經(jīng)不錯(cuò)了,可以直接拿過來引用,下載了他們的源碼后,只做了少少的改動,就是在Demo中增加了長按識別的功能,網(wǎng)上雖然也有長按識別的Demo,但好多下載下來卻無法運(yùn)行,然后總結(jié)了一下,加在了下面的Demo中。
下面來介紹這個(gè)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("")) {
//根據(jù)字符串生成二維碼圖片并顯示在界面上,第二個(gè)參數(shù)為圖片的大?。?50*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();
}
}
});
}
//這種方法狀態(tài)欄是空白,顯示不了狀態(tài)欄的信息
private void saveCurrentImage()
{
//獲取當(dāng)前屏幕的大小
int width = getWindow().getDecorView().getRootView().getWidth();
int height = getWindow().getDecorView().getRootView().getHeight();
//生成相同大小的圖片
Bitmap temBitmap = Bitmap.createBitmap( width, height, Bitmap.Config.ARGB_8888 );
//找到當(dāng)前頁面的根布局
View view = getWindow().getDecorView().getRootView();
//設(shè)置緩存
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
//從緩存中獲取當(dāng)前屏幕的圖片,創(chuàng)建一個(gè)DrawingCache的拷貝,因?yàn)镈rawingCache得到的位圖在禁用后會被回收
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否則會影響性能 ,而且不禁止會導(dǎo)致每次截圖到保存的是緩存的位圖
view.setDrawingCacheEnabled(false);
}
}
//解析二維碼圖片,返回結(jié)果封裝在Result對象中
private com.google.zxing.Result parseQRcodeBitmap(String bitmapPath){
//解析轉(zhuǎn)換類型UTF-8
Hashtable<DecodeHintType, String> hints = new Hashtable<DecodeHintType, String>();
hints.put(DecodeHintType.CHARACTER_SET, "utf-8");
//獲取到待解析的圖片
BitmapFactory.Options options = new BitmapFactory.Options();
//如果我們把inJustDecodeBounds設(shè)為true,那么BitmapFactory.decodeFile(String path, Options opt)
//并不會真的返回一個(gè)Bitmap給你,它僅僅會把它的寬,高取回來給你
options.inJustDecodeBounds = true;
//此時(shí)的bitmap是null,這段代碼之后,options.outWidth 和 options.outHeight就是我們想要的寬和高了
Bitmap bitmap = BitmapFactory.decodeFile(bitmapPath,options);
//我們現(xiàn)在想取出來的圖片的邊長(二維碼圖片是正方形的)設(shè)置為400像素
/**
options.outHeight = 400;
options.outWidth = 400;
options.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeFile(bitmapPath, options);
*/
//以上這種做法,雖然把bitmap限定到了我們要的大小,但是并沒有節(jié)約內(nèi)存,如果要節(jié)約內(nèi)存,我們還需要使用inSimpleSize這個(gè)屬性
options.inSampleSize = options.outHeight / 400;
if(options.inSampleSize <= 0){
options.inSampleSize = 1; //防止其值小于或等于0
}
/**
* 輔助節(jié)約內(nèi)存設(shè)置
*
* options.inPreferredConfig = Bitmap.Config.ARGB_4444; // 默認(rèn)是Bitmap.Config.ARGB_8888
* options.inPurgeable = true;
* options.inInputShareable = true;
*/
options.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeFile(bitmapPath, options);
//新建一個(gè)RGBLuminanceSource對象,將bitmap圖片傳給此對象
RGBLuminanceSource rgbLuminanceSource = new RGBLuminanceSource(bitmap);
//將圖片轉(zhuǎn)換成二進(jìn)制圖片
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);
//處理掃描結(jié)果(在界面上顯示)
if (resultCode == RESULT_OK) {
Bundle bundle = data.getExtras();
String scanResult = bundle.getString("result");
resultTextView.setText(scanResult);
}
}
} 然后長按識別二維碼調(diào)用了RGBLuminanceSource這個(gè)類
public class RGBLuminanceSource extends LuminanceSource {
private byte bitmapPixels[];
protected RGBLuminanceSource(Bitmap bitmap) {
super(bitmap.getWidth(), bitmap.getHeight());
// 首先,要取得該圖片的像素?cái)?shù)組內(nèi)容
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數(shù)組轉(zhuǎn)換為byte數(shù)組,也就是取像素值中藍(lán)色值部分作為辨析內(nèi)容
for (int i = 0; i < data.length; i++) {
this.bitmapPixels[i] = (byte) data[i];
}
}
@Override
public byte[] getMatrix() {
// 返回我們生成好的像素?cái)?shù)據(jù)
return bitmapPixels;
}
@Override
public byte[] getRow(int y, byte[] row) {
// 這里要得到指定行的像素?cái)?shù)據(jù)
System.arraycopy(bitmapPixels, y * getWidth(), row, 0, getWidth());
return row;
}
} 相機(jī)識別二維碼調(diào)用了CaptureActivity這個(gè)類
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>
詳細(xì)了解的請下載demo自己看,Demo中解決了在豎拍解碼時(shí)二維碼被拉伸的現(xiàn)象。
不過我遇到了一個(gè)問題是 二維碼的掃描框調(diào)大后,掃描的靈敏度降低了,希望知道的朋友給指導(dǎo)下
有興趣的可以下載Demo看一看:google Zxing實(shí)現(xiàn)二維碼的生成
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android基于Toolbar實(shí)現(xiàn)頂部標(biāo)題欄及后退鍵
這篇文章主要介紹了Android基于Toolbar實(shí)現(xiàn)頂部標(biāo)題欄及后退鍵,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09
詳解Android如何實(shí)現(xiàn)不同大小的圓角
在開發(fā)過程中,設(shè)計(jì)常常會有一些比較炫酷的想法,比如兩邊不一樣大小的圓角啦,甚至四角的radius各不相同,對于這種情況我們該怎么實(shí)現(xiàn)呢,本文小編就和大家來聊聊,需要的朋友可以參考下2023-08-08
Android Filterable實(shí)現(xiàn)Recyclerview篩選功能的示例代碼
這篇文章主要介紹了Android Filterable實(shí)現(xiàn)Recyclerview篩選功能的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02
Android TextView控件文字添加下劃線的實(shí)現(xiàn)方法
下面小編就為大家?guī)硪黄狝ndroid TextView控件文字添加下劃線的實(shí)現(xiàn)方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-09-09
Android Recyclerview實(shí)現(xiàn)上拉加載更多功能
在項(xiàng)目中使用列表的下拉刷新和上拉加載更多是很常見的功能。下文給大家?guī)砹薃ndroid Recyclerview上拉加載更多功能,需要的朋友參考下吧2017-05-05
Android仿微信底部實(shí)現(xiàn)Tab選項(xiàng)卡切換效果
這篇文章主要為大家介紹了Android仿微信底部實(shí)現(xiàn)Tab選項(xiàng)卡切換效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-02-02
Android中實(shí)現(xiàn)EditText密碼顯示隱藏的方法
這篇文章主要介紹了Android中實(shí)現(xiàn)EditText密碼顯示隱藏的方法,需要的朋友可以參考下2017-01-01
Android Tween動畫之RotateAnimation實(shí)現(xiàn)圖片不停旋轉(zhuǎn)效果實(shí)例介紹
Android中如何使用rotate實(shí)現(xiàn)圖片不停旋轉(zhuǎn)的效果,下面與大家共同分析下Tween動畫的rotate實(shí)現(xiàn)旋轉(zhuǎn)效果,感興趣的朋友可以參考下哈2013-05-05

