ZXing實現二維碼的生成與解析
大概一年前的掃碼風潮徹底把二維碼推向大眾,現在什麼下載,加好友,關注,都要掃一掃,這裡道長絮叨一下google旗下的ZXing,用ZXing實現二維碼的生成和解析。
一、二維碼的生成
這裡道長用的是3.1.0版本的ZXing,如果要使用可以自己下載,也可以使用道長Demo中的。和以前一樣,Demo道長放在文章最後。如果想看一下ZXing的原始碼可以點選傳送門。
1.帶邊界的二維碼
- 傳遞要生成二維碼的資料
private void initData() {
String filePath = Environment.getDataDirectory().getPath() + File.separator + "data" + File.separator;
String fileName = "zxing.png";
json = new JSONObject();
try {
json.put("url", "https://github.com/zxing/zxing");
json.put("author", "yushan");
json.put("filepath", filePath);
json.put("filename", fileName);
} catch (JSONException e) {
e.printStackTrace();
}
}
- 建立工具類,並傳遞引數
EncodingHelper encodingHelper = new EncodingHelper(HomeActivity.this, json, 350);
Bitmap bitmap = encodingHelper.getBitmap(true);
tv_show.setVisibility(View.GONE);
iv_client_ewm.setVisibility(View.VISIBLE);
iv_client_ewm.setBackgroundDrawable(new BitmapDrawable(bitmap));
- 生成二維碼的程式碼
/**
* 獲取帶邊界的二維碼
*
* @param hasBK
* @return
*/
public Bitmap getBitmap(Boolean hasBK) {
BitMatrix bitMatrix = null;
try {
bitMatrix = dealData();
} catch (WriterException e) {
e.printStackTrace();
}
int width = bitMatrix.getWidth();
int height = bitMatrix.getHeight();
int[] pixels = new int[width * height];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
if (bitMatrix.get(x, y)) {
pixels[y * width + x] = BLACK;
} else {
pixels[y * width + x] = WHITE;
}
}
}
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444);
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
// 畫邊框
if (hasBK != null && hasBK == true) {
Paint paint = new Paint();
Canvas canvas = new Canvas(bitmap);
drawBK(paint, canvas);
}
return bitmap;
}
/**
* 生成二維碼矩陣
*
* @return
* @throws WriterException
*/
private BitMatrix dealData() throws WriterException {
String content = json.toString();
Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); // 字元編碼
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M); // 糾錯等級
hints.put(EncodeHintType.MARGIN, 1);
BitMatrix bitMatrix = new MultiFormatWriter().encode(content,
BarcodeFormat.QR_CODE, width, height, hints); // 生成矩陣
return bitMatrix;
}
- 效果圖
2.帶圖示的二維碼
- 呼叫方法
EncodingHelper encodingHelper = new EncodingHelper(HomeActivity.this, json, 350);
Bitmap bitmap = encodingHelper.getBitmapWithSingOrBK(R.drawable.ewm_hulu, true);
tv_show.setVisibility(View.GONE);
iv_client_ewm.setVisibility(View.VISIBLE);
iv_client_ewm.setBackgroundDrawable(new BitmapDrawable(bitmap));
- 生成二維碼的程式碼
/**
* 獲取帶圖示或邊界的二維碼
*
* @param drawableId
* @param hasBK
* @return
*/
public Bitmap getBitmapWithSingOrBK(int drawableId, Boolean hasBK) {
mBitmap = toRoundCorner(((BitmapDrawable) mContext.getResources().getDrawable(drawableId)).getBitmap(), 10);
if (mBitmap != null) {
Bitmap bitmapWithSign = bitmapWithSign(getBitmap(hasBK));
return bitmapWithSign;
} else {
return getBitmap(hasBK);
}
}
/**
* 生成帶圖示的二維碼
*
* @param bitmap
* @return
*/
private Bitmap bitmapWithSign(Bitmap bitmap) {
Paint paint = new Paint();
Canvas canvas = new Canvas(bitmap);
canvas.drawARGB(0, 0, 0, 0);// 透明色
Rect outDst = new Rect();
outDst.left = width * 2 / 5 - 6;
outDst.top = height * 2 / 5 - 6;
outDst.right = width * 3 / 5 + 6;
outDst.bottom = height * 3 / 5 + 6;
canvas.drawBitmap(((BitmapDrawable) mContext.getResources().getDrawable(
R.drawable.ewm_bg)).getBitmap(), null, outDst, paint);
Rect inDst = new Rect();
inDst.left = width * 2 / 5;
inDst.top = height * 2 / 5;
inDst.right = width * 3 / 5;
inDst.bottom = height * 3 / 5;
canvas.drawBitmap(mBitmap, null, inDst, paint);
inDst = null;
outDst = null;
paint = null;
canvas = null;
return bitmap;
}
- 效果圖
到這裡道長已經把二維碼的生成已經說完了,至於傳參啊什麼的這裡道長就不說了,然後我們們說一下二維碼的解析。
二、二維碼的解析
這裡我們麼不止要初始化相機,還要自定義掃碼介面。
效果圖如下:
這裡的自定義View是用畫筆和畫布實現的,這裡道長就不貼程式碼了。
- 新增許可權
記得在AndroidManifest.xml新增許可權:
<uses-permission android:name="android.permission.CAMERA" />
- 初始化相機
viewfinderView.setShowInfoType(ViewfinderView.TEXTCONTENTTYPE_SCAN);
CameraManager.frameSize = 2;
CameraManager.init(getApplication());
- 開啟掃描
@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;
}
private void initCamera(SurfaceHolder surfaceHolder) {
try {
CameraManager.get().openDriver(surfaceHolder);
} catch (IOException ioe) {
Toast.makeText(this, "請授予相應許可權,再使用掃一掃!", Toast.LENGTH_SHORT).show();
finish();// 獲取系統相機事件被拒絕後,直接finish()掉本activity
} catch (RuntimeException e) {
Toast.makeText(this, "請授予相應許可權,再使用掃一掃!", Toast.LENGTH_SHORT).show();
finish();// 獲取系統相機事件被拒絕後,直接finish()掉本activity
}
if (handler == null) {
handler = new CaptureActivityHandler(this, decodeFormats, characterSet);
}
}
- 開啟一個執行緒decodeThread,用來掃描解析圖片
public CaptureActivityHandler(ScanActivity activity, Vector<BarcodeFormat> decodeFormats,
String characterSet) {
this.activity = activity;
decodeThread = new DecodeThread(activity, decodeFormats, characterSet,
new ViewfinderResultPointCallback(activity.getViewfinderView()));
decodeThread.start();
state = State.SUCCESS;
manager = CameraManager.get();
// Start ourselves capturing previews and decoding.
manager.startPreview();
restartPreviewAndDecode();
}
- decodeThread執行緒在Handler中處理資料
/**
* Decode the data within the viewfinder rectangle, and time how long it took. For efficiency,
* reuse the same reader objects from one decode to the next.
*
* @param data The YUV preview frame.
* @param width The width of the preview frame.
* @param height The height of the preview frame.
*/
private void decode(byte[] data, int width, int height) {
if ((data == null) || (data.length <= 0)) {
return;
} // 判斷以防null指標異常
long start = System.currentTimeMillis();
Result rawResult = null;
// modify here
byte[] rotatedData = new byte[data.length];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++)
rotatedData[x * height + height - y - 1] = data[x + y * width];
}
int tmp = width; // Here we are swapping, that's the difference to #11
width = height;
height = tmp;
PlanarYUVLuminanceSource source = CameraManager.get().buildLuminanceSource(rotatedData, width, height);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
try {
rawResult = multiFormatReader.decodeWithState(bitmap);
} catch (ReaderException re) {
// continue
} finally {
multiFormatReader.reset();
}
if (rawResult != null) {
long end = System.currentTimeMillis();
Log.e("yushan", "Found barcode (" + (end - start) + " ms):\n" + rawResult.toString());
Message message = Message.obtain(activity.getHandler(), R.id.decode_succeeded, rawResult);
Bundle bundle = new Bundle();
bundle.putParcelable(DecodeThread.BARCODE_BITMAP, source.renderCroppedGreyscaleBitmap());
message.setData(bundle);
// Log.d(TAG, "Sending decode succeeded message...");
message.sendToTarget();
} else {
Message message = Message.obtain(activity.getHandler(), R.id.decode_failed);
message.sendToTarget();
}
}
- 處理完成的資料通過message傳送到另一個Handler
@Override
public void handleMessage(Message message) {
switch (message.what) {
case R.id.auto_focus:
//Log.d(TAG, "Got auto-focus message");
// When one auto focus pass finishes, start another. This is the closest thing to
// continuous AF. It does seem to hunt a bit, but I'm not sure what else to do.
if (state == State.PREVIEW) {
manager.requestAutoFocus(this, R.id.auto_focus);
}
break;
case R.id.restart_preview:
Log.d(TAG, "Got restart preview message");
restartPreviewAndDecode();
break;
case R.id.decode_succeeded:
Log.d(TAG, "Got decode succeeded message");
state = State.SUCCESS;
Bundle bundle = message.getData();
/***********************************************************************/
// Bitmap barcode = bundle == null ? null : (Bitmap) bundle.getParcelable(DecodeThread.BARCODE_BITMAP);
// activity.handleDecode((Result) message.obj, barcode);
String resultString = ((Result) message.obj).getText() + "";
activity.handleDecode(resultString);// 返回資料
/***********************************************************************/
break;
case R.id.decode_failed:
// We're decoding as fast as possible, so when one decode fails, start another.
state = State.PREVIEW;
manager.requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
break;
case R.id.return_scan_result:
Log.d(TAG, "Got return scan result message");
activity.setResult(Activity.RESULT_OK, (Intent) message.obj);
activity.finish();
break;
case R.id.launch_product_query:
Log.d(TAG, "Got product query message");
String url = (String) message.obj;
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
activity.startActivity(intent);
break;
}
}
- 把解析資料返回到主介面
/**
* 掃描返回資料
*
* @param resultString
*/
public void handleDecode(String resultString) {
inactivityTimer.onActivity();
Log.e("yushan", resultString);
Intent intent = this.getIntent();
intent.putExtra("resultString", resultString);
this.setResult(RESULT_OK, intent);
this.finish();
}
- 展示解析結果
好了,到了這裡ZXing實現二維碼的生成與解析都已經實現了,希望這篇部落格能夠為你提供一些幫助。
原始碼下載
相關文章
- google zxing作為二維碼生成工具Go
- zxing第三方框架實現二維碼掃描以及生成框架
- java實現二維碼生成Java
- 基於ZXing Android實現生成二維碼圖片和相機掃描二維碼圖片即時解碼的功能Android
- Google zxing實現二維碼掃描完美解決方案Go
- Java 中使用 google.zxing 快捷生成二維碼(附工具類原始碼)JavaGo原始碼
- Flutter - 生成二維碼與識別二維碼Flutter
- Java實現將文字內容、網址連結url,生成二維碼與反解析Java
- Android 基於Zxing掃碼實現(三)、從相簿選取二維碼Android
- C++用zxing識別二維碼C++
- ZXing原始碼解析二:掌握解碼步驟原始碼
- 用zxing 識別二維碼的main函式AI函式
- Android 基於zxing的二維碼掃描功能的簡單實現及優化Android優化
- 幾行程式碼搞定java生成解析二維碼功能行程Java
- 【MISC】一道假的二維碼題目學習zxing庫[python解讀二維碼]Python
- 二維碼管理平臺 生成二維碼
- Android二維碼生成與掃描Android
- 二維碼解析
- XQRCode 一個非常方便實用的二維碼掃描、解析、生成庫
- jquery生成二維碼jQuery
- 二維碼線上生成
- 利用php生成二維碼,非常實用PHP
- QRCode-二維碼識別與生成
- 實現彩色二維碼程式碼實
- 直播系統搭建,java二維碼 生成二維碼Java
- iOS 花式二維碼生成和二維碼識別iOS
- Android 二維碼掃描和生成二維碼Android
- 易易二維碼,多功能線上檔案預覽與二維碼生成器
- C#中輕鬆實現二維碼和條形碼識別:OpenCvSharp和ZXing詳細教程C#OpenCV
- Tp框架 生成二維碼框架
- ios--二維碼生成iOS
- 二維碼生成工具類
- 二維碼生成-PythonPython
- c++生成二維碼C++
- JS線上生成二維碼JS
- 二維碼線上生成工具
- 從普通二維碼到檔案生成二維碼的轉變
- 線上生成二維碼的API介面API