Android基于google Zxing實(shí)現(xiàn)二維碼的生成
最近項(xiàng)目用到了二維碼的生成與識(shí)別,之前沒(méi)有接觸這塊,然后就上網(wǎng)搜了搜,發(fā)現(xiàn)有好多這方面的資源,特別是google Zxing對(duì)二維碼的封裝,實(shí)現(xiàn)的已經(jīng)不錯(cuò)了,可以直接拿過(guò)來(lái)引用,下載了他們的源碼后,只做了少少的改動(dòng),就是在Demo中增加了長(zhǎng)按識(shí)別的功能,網(wǎng)上雖然也有長(zhǎng)按識(shí)別的Demo,但好多下載下來(lái)卻無(wú)法運(yùn)行,然后總結(jié)了一下,加在了下面的Demo中。
下面來(lái)介紹這個(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) { //打開(kāi)掃描界面掃描條形碼或二維碼 Intent openCameraIntent = new Intent(BarCodeTestActivity.this,CaptureActivity.class); startActivityForResult(openCameraIntent, 0); } }); qrImgImageView.setOnLongClickListener(new OnLongClickListener() { @Override public boolean onLongClick(View v) { // 長(zhǎng)按識(shí)別二維碼 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)前頁(yè)面的根布局 View view = getWindow().getDecorView().getRootView(); //設(shè)置緩存 view.setDrawingCacheEnabled(true); view.buildDrawingCache(); //從緩存中獲取當(dāng)前屏幕的圖片,創(chuàng)建一個(gè)DrawingCache的拷貝,因?yàn)镈rawingCache得到的位圖在禁用后會(huì)被回收 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, "無(wú)法識(shí)別", Toast.LENGTH_LONG).show(); } } }); } }).start(); //禁用DrawingCahce否則會(huì)影響性能 ,而且不禁止會(huì)導(dǎo)致每次截圖到保存的是緩存的位圖 view.setDrawingCacheEnabled(false); } } //解析二維碼圖片,返回結(jié)果封裝在Result對(duì)象中 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) //并不會(huì)真的返回一個(gè)Bitmap給你,它僅僅會(huì)把它的寬,高取回來(lái)給你 options.inJustDecodeBounds = true; //此時(shí)的bitmap是null,這段代碼之后,options.outWidth 和 options.outHeight就是我們想要的寬和高了 Bitmap bitmap = BitmapFactory.decodeFile(bitmapPath,options); //我們現(xiàn)在想取出來(lái)的圖片的邊長(zhǎng)(二維碼圖片是正方形的)設(shè)置為400像素 /** options.outHeight = 400; options.outWidth = 400; options.inJustDecodeBounds = false; bitmap = BitmapFactory.decodeFile(bitmapPath, options); */ //以上這種做法,雖然把bitmap限定到了我們要的大小,但是并沒(méi)有節(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對(duì)象,將bitmap圖片傳給此對(duì)象 RGBLuminanceSource rgbLuminanceSource = new RGBLuminanceSource(bitmap); //將圖片轉(zhuǎn)換成二進(jìn)制圖片 BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(rgbLuminanceSource)); //初始化解析對(duì)象 QRCodeReader reader = new QRCodeReader(); //開(kāi)始解析 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); } } }
然后長(zhǎng)按識(shí)別二維碼調(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ī)識(shí)別二維碼調(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ì)了解的請(qǐng)下載demo自己看,Demo中解決了在豎拍解碼時(shí)二維碼被拉伸的現(xiàn)象。
不過(guò)我遇到了一個(gè)問(wèn)題是 二維碼的掃描框調(diào)大后,掃描的靈敏度降低了,希望知道的朋友給指導(dǎo)下
有興趣的可以下載Demo看一看:google Zxing實(shí)現(xiàn)二維碼的生成
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android實(shí)現(xiàn)二維碼掃描和生成的簡(jiǎn)單方法
- Android 超簡(jiǎn)易Zxing框架 生成二維碼+掃碼功能
- Android 二維碼掃描和生成二維碼功能
- Android平臺(tái)生成二維碼并實(shí)現(xiàn)掃描 & 識(shí)別功能
- Android中使用ZXing生成二維碼(支持添加Logo圖案)
- Android 二維碼 生成和識(shí)別二維碼 附源碼下載
- Android編程實(shí)現(xiàn)二維碼的生成與解析
- Android生成條形碼和二維碼功能
- Android 點(diǎn)擊生成二維碼功能實(shí)現(xiàn)代碼
- Android中二維碼的掃描和生成(使用zxing庫(kù))
相關(guān)文章
Android 使用Vitamio打造自己的萬(wàn)能播放器(3)——本地播放(主界面、播放列表)
本文主要介紹 Android Vitamio本地播放功能,這里提供實(shí)例代碼和效果圖以便大家參考,有需要的小伙伴可以參考下2016-07-07Android通過(guò)實(shí)現(xiàn)GridView的橫向滾動(dòng)實(shí)現(xiàn)仿京東秒殺效果
這篇文章主要介紹了Android通過(guò)實(shí)現(xiàn)GridView的橫向滾動(dòng)實(shí)現(xiàn)仿京東秒殺效果,實(shí)現(xiàn)代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-07-07Android 5.0最應(yīng)該實(shí)現(xiàn)的8個(gè)期望
毫無(wú)疑問(wèn),Android 5 將是令人興奮的操作系統(tǒng),因?yàn)?Android4.0 至 4.4 版本之間并沒(méi)有顯著的差異,顯然谷歌會(huì)在 5.0 版本中進(jìn)行一些較大幅度的革新2016-01-01Android編程判斷手機(jī)上是否安裝了某個(gè)程序的方法
這篇文章主要介紹了Android編程判斷手機(jī)上是否安裝了某個(gè)程序的方法,涉及Android針對(duì)程序包的操作及進(jìn)程判斷的相關(guān)技巧,需要的朋友可以參考下2015-11-11Android權(quán)限HaloPermission詳細(xì)使用
這篇文章主要介紹了Android權(quán)限HaloPermission詳細(xì)使用,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-04-045分鐘學(xué)會(huì)Android設(shè)計(jì)模式之策略模式Strategy Pattern教程
這篇文章主要為大家介紹了5分鐘學(xué)會(huì)Android設(shè)計(jì)模式之策略模式Strategy Pattern教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03Android實(shí)現(xiàn)多點(diǎn)觸摸操作
這篇文章主要介紹了Android實(shí)現(xiàn)多點(diǎn)觸摸操作,實(shí)現(xiàn)圖片的放大、縮小和旋轉(zhuǎn)等處理,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05Android編程中FileOutputStream與openFileOutput()的區(qū)別分析
這篇文章主要介紹了Android編程中FileOutputStream與openFileOutput()的區(qū)別,結(jié)合實(shí)例形式分析了FileOutputStream與openFileOutput()的功能,使用技巧與用法區(qū)別,需要的朋友可以參考下2016-02-02