Two-dimensional code scanning analysis has now become a comprehensive APP indispensable a function, there are a lot of entry-level developers may be distressed two-dimensional code recognition must be image analysis technology ah, do you have to learn OpencV? Zxing is an open source Java class library for parsing 1D/2D barcodes in a variety of formats. The goal is to be able to decode THE 1D barcode of QR code, Data Matrix and UPC. It provides clients on a variety of platforms including J2ME, J2SE and Android.

The official github:https://github.com/zxing/zxing/tree/zxing-3.0.0

As Android developers, we cannot rely on all codes. Therefore, in this blog post, I only introduce the scanning and recognition of two-dimensional code. Since two-dimensional code is only part of the function, I found a Module in moOCs. All you just need to download down on lot depends on: https://github.com/weizainiunai/libzxing, as to how to rely on I’ll explain in the next post.

So do a TWO-DIMENSIONAL code scanning APP, must first understand what two-dimensional code is?Two-dimensional barcode/two-dimensional code (2-dimensional bar code) is used to record data symbol information by using a certain geometric pattern distributed in the plane (two-dimensional direction) in black and white. On the compiled code clever use of which form the basis of computer internal logic “0”, the concept of “1” bit stream, using a number of corresponding to the binary numerical information, geometric shapes to represent text automatically recognized by image input device or photoelectric scanning equipment in order to realize the automatic information processing: some common: it has a barcode for each code system has its particular character set; Each character occupies a certain width; Has a certain calibration function. At the same time, it also has the function of automatic recognition of different lines of information, and processing of graph rotation change point. More specific you can go to Baidu encyclopedia to understand.



Let’s start with a new project






Open and select the lib Project you downloaded previously to rely on:










After that, we wrote our interface: acitivity_main.xml:
The XML version = "1.0" encoding = "utf-8"? > xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> android:id="@+id/btn_scan" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="scan" /> android:id="@+id/tv_result" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="result" />


After the interface is written, what methods do we need to call to achieve two-dimensional code recognition function? The previous project we relied on had a captureActivity. Java file, and this activity was the implementation and callback of the QR code recognition function:
/**
 * This activity opens the camera and does the actual scanning on a background
 * thread. It draws a viewfinder to help the user place the barcode correctly,
 * shows feedback as the image processing is happening, and then overlays the
 * results when a scan is successful.
 *
 * @author [email protected] (Daniel Switkin)
 * @author Sean Owen
 */
public final class CaptureActivity extends Activity implements SurfaceHolder.Callback {

    private static final String TAG = CaptureActivity.class.getSimpleName();

    private CameraManager cameraManager;
    private CaptureActivityHandler handler;
    private InactivityTimer inactivityTimer;
    private BeepManager beepManager;

    private SurfaceView scanPreview = null;
    private RelativeLayout scanContainer;
    private RelativeLayout scanCropView;
    private ImageView scanLine;

    private Rect mCropRect = null;
    private boolean isHasSurface = false;

    public Handler getHandler() {
        return handler;
    }

    public CameraManager getCameraManager() {
        return cameraManager;
    }

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);

        Window window = getWindow();
        window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        setContentView(R.layout.activity_capture);

        scanPreview = (SurfaceView) findViewById(R.id.capture_preview);
        scanContainer = (RelativeLayout) findViewById(R.id.capture_container);
        scanCropView = (RelativeLayout) findViewById(R.id.capture_crop_view);
        scanLine = (ImageView) findViewById(R.id.capture_scan_line);

        inactivityTimer = new InactivityTimer(this);
        beepManager = new BeepManager(this);

        TranslateAnimation animation = new TranslateAnimation(Animation.RELATIVE_TO_PARENT, 0.0f, Animation
                .RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT,
                0.9f);
        animation.setDuration(4500);
        animation.setRepeatCount(-1);
        animation.setRepeatMode(Animation.RESTART);
        scanLine.startAnimation(animation);
    }

    @Override
    protected void onResume() {
        super.onResume();

        // CameraManager must be initialized here, not in onCreate(). This is
        // necessary because we don't
        // want to open the camera driver and measure the screen size if we're
        // going to show the help on
        // first launch. That led to bugs where the scanning rectangle was the
        // wrong size and partially
        // off screen.
        cameraManager = new CameraManager(getApplication());

        handler = null;

        if (isHasSurface) {
            // The activity was paused but not stopped, so the surface still
            // exists. Therefore
            // surfaceCreated() won't be called, so init the camera here.
            initCamera(scanPreview.getHolder());
        } else {
            // Install the callback and wait for surfaceCreated() to init the
            // camera.
            scanPreview.getHolder().addCallback(this);
        }

        inactivityTimer.onResume();
    }

    @Override
    protected void onPause() {
        if (handler != null) {
            handler.quitSynchronously();
            handler = null;
        }
        inactivityTimer.onPause();
        beepManager.close();
        cameraManager.closeDriver();
        if (!isHasSurface) {
            scanPreview.getHolder().removeCallback(this);
        }
        super.onPause();
    }

    @Override
    protected void onDestroy() {
        inactivityTimer.shutdown();
        super.onDestroy();
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        if (holder == null) {
            Log.e(TAG, "*** WARNING *** surfaceCreated() gave us a null surface!");
        }
        if (!isHasSurface) {
            isHasSurface = true;
            initCamera(holder);
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        isHasSurface = false;
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    /**
     * A valid barcode has been found, so give an indication of success and show
     * the results.
     *
     * @param rawResult The contents of the barcode.
     * @param bundle    The extras
     */
    public void handleDecode(Result rawResult, Bundle bundle) {
        inactivityTimer.onActivity();
        beepManager.playBeepSoundAndVibrate();

        Intent resultIntent = new Intent();
        bundle.putInt("width", mCropRect.width());
        bundle.putInt("height", mCropRect.height());
        bundle.putString("result", rawResult.getText());
        resultIntent.putExtras(bundle);
        this.setResult(RESULT_OK, resultIntent);
        CaptureActivity.this.finish();
    }

    private void initCamera(SurfaceHolder surfaceHolder) {
        if (surfaceHolder == null) {
            throw new IllegalStateException("No SurfaceHolder provided");
        }
        if (cameraManager.isOpen()) {
            Log.w(TAG, "initCamera() while already open -- late SurfaceView callback?");
            return;
        }
        try {
            cameraManager.openDriver(surfaceHolder);
            // Creating the handler starts the preview, which can also throw a
            // RuntimeException.
            if (handler == null) {
                handler = new CaptureActivityHandler(this, cameraManager, DecodeThread.ALL_MODE);
            }

            initCrop();
        } catch (IOException ioe) {
            Log.w(TAG, ioe);
            displayFrameworkBugMessageAndExit();
        } catch (RuntimeException e) {
            // Barcode Scanner has seen crashes in the wild of this variety:
            // java.?lang.?RuntimeException: Fail to connect to camera service
            Log.w(TAG, "Unexpected error initializing camera", e);
            displayFrameworkBugMessageAndExit();
        }
    }

    private void displayFrameworkBugMessageAndExit() {
        // camera error
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(getString(R.string.app_name));
        builder.setMessage("Camera error");
        builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                finish();
            }

        });
        builder.setOnCancelListener(new DialogInterface.OnCancelListener() {

            @Override
            public void onCancel(DialogInterface dialog) {
                finish();
            }
        });
        builder.show();
    }

    public void restartPreviewAfterDelay(long delayMS) {
        if (handler != null) {
            handler.sendEmptyMessageDelayed(R.id.restart_preview, delayMS);
        }
    }

    public Rect getCropRect() {
        return mCropRect;
    }

    /**
     * 初始化截取的矩形区域
     */
    private void initCrop() {
        int cameraWidth = cameraManager.getCameraResolution().y;
        int cameraHeight = cameraManager.getCameraResolution().x;

        /** 获取布局中扫描框的位置信息 */
        int[] location = new int[2];
        scanCropView.getLocationInWindow(location);

        int cropLeft = location[0];
        int cropTop = location[1] - getStatusBarHeight();

        int cropWidth = scanCropView.getWidth();
        int cropHeight = scanCropView.getHeight();

        /** 获取布局容器的宽高 */
        int containerWidth = scanContainer.getWidth();
        int containerHeight = scanContainer.getHeight();

        /** 计算最终截取的矩形的左上角顶点x坐标 */
        int x = cropLeft * cameraWidth / containerWidth;
        /** 计算最终截取的矩形的左上角顶点y坐标 */
        int y = cropTop * cameraHeight / containerHeight;

        /** 计算最终截取的矩形的宽度 */
        int width = cropWidth * cameraWidth / containerWidth;
        /** 计算最终截取的矩形的高度 */
        int height = cropHeight * cameraHeight / containerHeight;

        /** 生成最终的截取的矩形 */
        mCropRect = new Rect(x, y, width + x, height + y);
    }

    private int getStatusBarHeight() {
        try {
            Class c = Class.forName("com.android.internal.R$dimen");
            Object obj = c.newInstance();
            Field field = c.getField("status_bar_height");
            int x = Integer.parseInt(field.get(obj).toString());
            return getResources().getDimensionPixelSize(x);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }
}


If you need to learn the code to identify the lower level of the code, there are a lot of things, that for us users, we just need to understand the class callback method, what parameter is returned to us? What’s the key?
/**
 * A valid barcode has been found, so give an indication of success and show
 * the results.
 *
 * @param rawResult The contents of the barcode.
 * @param bundle    The extras
 */
public void handleDecode(Result rawResult, Bundle bundle) {
    inactivityTimer.onActivity();
    beepManager.playBeepSoundAndVibrate();

    Intent resultIntent = new Intent();
    bundle.putInt("width", mCropRect.width());
    bundle.putInt("height", mCropRect.height());
    bundle.putString("result", rawResult.getText());
    resultIntent.putExtras(bundle);
    this.setResult(RESULT_OK, resultIntent);
    CaptureActivity.this.finish();
}


As you can see, it calls back three parameters: width, height, and string (the recognized content). We only need the result parameter, so knowing this, the main code is written: entrenceActivity.java
public class EntrenceActivity extends AppCompatActivity { private Button mBtnScanner; private TextView mTvResult; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_entrence); initview(); } private void initview() { mBtnScanner = (Button) findViewById(R.id.btn_scan); mTvResult = (TextView) findViewById(R.id.tv_result); mBtnScanner.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { startActivityForResult(new Intent(EntrenceActivity.this , CaptureActivity.class) , 0); }}); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK){ Bundle bundle = data.getExtras(); String result = bundle.getString("result"); mTvResult.setText(result); }}}


After knowing these, we probably also know how to use Zxing to achieve a simple TWO-DIMENSIONAL code recognition app, of course, we do not need to add relevant camera and other permissions in our main project, because it has been added in the Module provided to us by Google, so we can rest assured to use, See if it is really 5 minutes to realize the TWO-DIMENSIONAL code scan ~~, if you think it is ok, please give the blogger like oh!!