Using Zxing to take pictures and select pictures to recognize two-dimensional codes

Keywords: encoding

Reprinted please indicate the source
Author: AboutJoke( http://blog.csdn.net/u013200308 )
Links to the original text: http://blog.csdn.net/u013200308/article/details/68067564

Recently in the project need to achieve two-dimensional code recognition, so the first thought. zxing During the compilation, and then from the Internet to find a lot of articles to finally achieve the required functions, the following will be shared with you.

Photo Recognition

Overall, photo recognition is relatively easy. After setting the parameters that need to be modified, we can call the CatureActivity of zxing to open the page of photo recognition. After recognition is completed, the result will be returned in onActivityResult, where we can process the result.

Open the Photo Page

private void callCapture(String characterSet) {
        /**
         * Get the width of the screen and use 2/3 of the width as the width of the scan area
         */
        int width = wm.getDefaultDisplay().getWidth() * 2 / 3;
        Intent intent = new Intent();
        intent.setAction(Intents.Scan.ACTION);
        intent.putExtra(Intents.Scan.MODE, Intents.Scan.QR_CODE_MODE);
        intent.putExtra(Intents.Scan.CHARACTER_SET, characterSet);
        /**
         * WIDTH==HEIGHT Setting up square scanner scenic spot
         * The total width of the viewing area is two-thirds of the screen width -- adapted to all models
         * */
        intent.putExtra(Intents.Scan.WIDTH, width);
        intent.putExtra(Intents.Scan.HEIGHT, width);//
        intent.setClass(this, CaptureActivity.class);//Enter CaptureActivity in zxing module
        startActivityForResult(intent, CAMERA_OK);
    }

Get the scanned results

String result = data.getStringExtra(Intents.Scan.RESULT);
String recode = recode(result);

Picture Recognition from Album Selection

Picture recognition from an album is a little more complicated than photo recognition. Here we have two ways to use it. The specific choice depends on you. The concrete logic is as follows:

  • Select pictures from albums
  • bitmap is generated and parsed according to the image path
  • Processing parsing results to prevent scrambling

Next we will follow the above logic step by step to achieve:

Select pictures from albums

private void photo() {
        // Activate the system gallery and select a picture
        Intent innerIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        Intent wrapperIntent = Intent.createChooser(innerIntent, "Choose two-dimensional code picture");
        startActivityForResult(wrapperIntent, REQUEST_CODE);
    }

Get the path of the selected image in onActivityResult

                    String[] proj = {MediaStore.Images.Media.DATA};
                    // Get the path of the selected picture
                    Cursor cursor = this.getContentResolver().query(data.getData(),
                            proj, null, null, null);
                    if (cursor.moveToFirst()) {
                        int column_index = cursor
                                .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
                        photo_path = cursor.getString(column_index);
                        if (photo_path == null) {
                            photo_path = getPath(this,
                                    data.getData());
                        }
                    }
                    cursor.close();

bitmap is generated and parsed according to the image path

Here we need to get the path of the selected image and generate a bitmap.

Constructing bitmap
       if (TextUtils.isEmpty(path)) {

            return null;

        }
        // DecodeHintType and EncodeHintType
        Hashtable<DecodeHintType, String> hints = new Hashtable<DecodeHintType, String>();
        hints.put(DecodeHintType.CHARACTER_SET, "utf-8"); // Setting the encoding of two-dimensional code content
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true; // Get the original size first
        scanBitmap = BitmapFactory.decodeFile(path, options);
        options.inJustDecodeBounds = false; // Get a new size

        int sampleSize = (int) (options.outHeight / (float) 200);

        if (sampleSize <= 0)
            sampleSize = 1;
        options.inSampleSize = sampleSize;
        scanBitmap = BitmapFactory.decodeFile(path, options);

With bitmap, we can choose two different ways to parse images.

Converting bitmap to yuv parsing
        LuminanceSource source1 = new PlanarYUVLuminanceSource(
                rgb2YUV(scanBitmap), scanBitmap.getWidth(),
                scanBitmap.getHeight(), 0, 0, scanBitmap.getWidth(),
                scanBitmap.getHeight());
        BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(
                source1));
        MultiFormatReader reader1 = new MultiFormatReader();
        Result result1;
        try {
            result1 = reader1.decode(binaryBitmap);
            String content = result1.getText();
            Log.e("123content", content);
        } catch (NotFoundException e1) {
            e1.printStackTrace();
        }
Converting bitmap to rgb parsing
        RGBLuminanceSource source = new RGBLuminanceSource(scanBitmap);
        BinaryBitmap bitmap1 = new BinaryBitmap(new HybridBinarizer(source));
        QRCodeReader reader = new QRCodeReader();

        try {

            return reader.decode(bitmap1, hints);

        } catch (NotFoundException | ChecksumException | FormatException e) {

            e.printStackTrace();

        }

Most two-dimensional code recognition methods are based on binarization. In gamut processing, YUV has better binarization effect than RGB, and RGB image does not support rotation in processing. Therefore, an optimization idea is to convert all ARGB coded images into YUV codes, and then use Planar YUV Luminance Source to process the generated results, so I recommend the first analytical method. Here we need an rgb2YUV method.

public byte[] rgb2YUV(Bitmap bitmap) {
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        int[] pixels = new int[width * height];
        bitmap.getPixels(pixels, 0, width, 0, 0, width, height);

        int len = width * height;
        byte[] yuv = new byte[len * 3 / 2];
        int y, u, v;
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                int rgb = pixels[i * width + j] & 0x00FFFFFF;

                int r = rgb & 0xFF;
                int g = (rgb >> 8) & 0xFF;
                int b = (rgb >> 16) & 0xFF;

                y = ((66 * r + 129 * g + 25 * b + 128) >> 8) + 16;
                u = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
                v = ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;

                y = y < 16 ? 16 : (y > 255 ? 255 : y);
                u = u < 0 ? 0 : (u > 255 ? 255 : u);
                v = v < 0 ? 0 : (v > 255 ? 255 : v);

                yuv[i * width + j] = (byte) y;
//                yuv[len + (i >> 1) * width + (j & ~1) + 0] = (byte) u;
//                yuv[len + (i >> 1) * width + (j & ~1) + 1] = (byte) v;
            }
        }
        return yuv;
    }

Processing analytical results

In fact, we already got the result of the scan in the last step, but we still need to encode the result to prevent the final result from scrambling.

 private String recode(String str) {
        String format = "";

        try {
            boolean ISO = Charset.forName("ISO-8859-1").newEncoder()
                    .canEncode(str);
            if (ISO) {
                format = new String(str.getBytes("ISO-8859-1"), "GB2312");
                Log.i("1234      ISO8859-1", format);
            } else {
                format = str;
                Log.i("1234      stringExtra", str);
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return format;
    }

So far, our two-dimensional code recognition function has been realized. The specific effect is that you can download the source code to experience it. Recognition speed is still very fast.

Custom content

If you are not satisfied with the two-dimensional code of the photo page, you can go to the ViewfinderView class to modify the page, there are comments can be easily read. If you download my demo experience, you will find that the success of photo recognition has voice hints. This function is implemented in BeepManager. You can also choose whether or not to shake after recognition success. Specifically, you can modify it by reading the code.

I will have time to integrate a similar Wechat, when the environment is darker, prompt whether to turn on the flash function, scan the following two-dimensional code to download demo to experience it.

Posted by Twysted on Sun, 14 Jul 2019 14:11:04 -0700