JAVA obtains the A, B, C interfaces of the QR code of the applet, and then parses the pit encountered

1. Problem description


Recently, the company has a requirement to obtain the QR code from the applet, then parse the URL from the QR code, and customize the QR code by itself. . . I think the code generated by WeChat is too ugly. . . The documentation for obtaining the QR code of WeChat Mini Program is as follows: https://developers.weixin.qq.com/miniprogram/dev/api/qrcode.html  Look at this document. . . Just want to rant. . It's too vague.



It didn't even write what the return value was. . Finally learned that it is returned in the form of a stream. . . There are three types of interfaces A, B, and C in the document. I don't know what WeChat thinks. . . There are so many interfaces, what to do. . The A and B interfaces have a limit on the number of times they are generated, and the B interface has no limit. .


The test code is as follows:

public class Test {
    public static void main(String[] args) {
        try {
            URL url = new URL("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=你的access_token");
            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
            httpURLConnection.setRequestMethod("POST");// Submit mode
            // conn.setConnectTimeout(10000);//Connection timeout in milliseconds
            // conn.setReadTimeout(2000);//Read timeout in milliseconds
            // Sending a POST request must set the following two lines
            httpURLConnection.setDoOutput(true);
            httpURLConnection.setDoInput(true);
            // Get the output stream corresponding to the URLConnection object
            PrintWriter printWriter = new PrintWriter(httpURLConnection.getOutputStream());
            // send request parameters
            JSONObject paramJson = new JSONObject();
            paramJson.put("scene", "a=1234567890");
            paramJson.put("page", "pages/index/index");
            paramJson.put("width", 430);
            paramJson.put("auto_color", true);
            /**
             * line_color takes effect
             * paramJson.put("auto_color", false);
             * JSONObject lineColor = new JSONObject();
             * lineColor.put("r", 0);
             * lineColor.put("g", 0);
             * lineColor.put("b", 0);
             * paramJson.put("line_color", lineColor);
             * */

            printWriter.write(paramJson.toString());
            // flush the buffer of the output stream
            printWriter.flush();
            //Start getting data
            BufferedInputStream bis = new BufferedInputStream(httpURLConnection.getInputStream());
            OutputStream os = new FileOutputStream(new File("/Users/Xxxx/Music/abc.png"));
            int len;
            byte[] arr = new byte[1024];
            while ((len = bis.read(arr)) != -1) {
                os.write(arr, 0, len);
                os.flush();
            }
            os.close();
        } catch (Exception e) {
            e.printStackTrace ();
        }
    }
}

The generated QR code is as follows:



But no matter how I do this kind of QR code, I can't parse the data in the QR code. I tried QRCode.jar and Zxing, but I couldn't parse it out, and they all reported:

com.google.zxing.NotFoundException
This kind of error is said on the Internet that the QR code is complicated, or an error is reported when there is a LOGO in the middle. . But the QR code returned by the C interface



The above error is also reported through Zxing analysis, but I found a solution on the Internet, just remove the string of Chinese below the QR code.


Second, the solution


The solution is as follows, in the stream returned by WeChat, parse and intercept the image:

            ByteArrayInputStream inputStream= new ByteArrayInputStream(swapStream.toByteArray());
            BufferedImage image = ImageIO.read(inputStream);
            /**The cropped original image is currently 470*535 pixels 170620 pixels returned by accessing WeChat and WeChat*/
            BufferedImage subImage = image.getSubimage(0, 0, image.getWidth(), (int) (image.getHeight() * 0.85));

Remove the following Chinese, the effect is as follows



The corresponding URL is:

https://mp.weixin.qq.com/a/~~JtIAAAEESEGtXoPLOk~fPZXTPs0T7Y3SaxauUqasw~~


The complete code is as follows:


1. Introduce Zxing

		<dependency>
			<groupId>com.google.zxing</groupId>
			<artifactId>javase</artifactId>
			<version>3.2.1</version>
		</dependency>


2. Create the BufferedImageLuminanceSource class

package com.quna.app.pay;

import com.google.zxing.LuminanceSource;

import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;

/**
 * @version: V1.0
 * @author: crack
 * @className: BufferedImageLuminanceSource
 * @packageName: com.xxx
 * @description:
 * @data: 2018-04-17 14:23
 **/
public final class BufferedImageLuminanceSource extends LuminanceSource {

    private final BufferedImage image;
    private final int left;
    private final int top;

    public BufferedImageLuminanceSource(BufferedImage image) {
        this(image, 0, 0, image.getWidth(), image.getHeight());
    }

    public BufferedImageLuminanceSource(BufferedImage image, int left, int top, int width, int height) {
        super(width, height);

        int sourceWidth = image.getWidth();
        int sourceHeight = image.getHeight();
        if (left + width > sourceWidth || top + height > sourceHeight) {
            throw new IllegalArgumentException("Crop rectangle does not fit within image data.");
        }

        for (int y = top; y < top + height; y++) {
            for (int x = left; x < left + width; x++) {
                if ((image.getRGB(x, y) & 0xFF000000) == 0) {
                    image.setRGB(x, y, 0xFFFFFFFF); // = white
                }
            }
        }

        this.image = new BufferedImage(sourceWidth, sourceHeight, BufferedImage.TYPE_BYTE_GRAY);
        this.image.getGraphics().drawImage(image, 0, 0, null);
        this.left = left;
        this.top = top;
    }

    @Override
    public byte[] getRow(int y, byte[] row) {
        if (y < 0 || y >= getHeight()) {
            throw new IllegalArgumentException("Requested row is outside the image: " + y);
        }
        int width = getWidth();
        if (row == null || row.length < width) {
            row = new byte[width];
        }
        image.getRaster().getDataElements(left, top + y, width, 1, row);
        return row;
    }

    @Override
    public byte[] getMatrix() {
        int width = getWidth();
        int height = getHeight();
        int area = width * height;
        byte[] matrix = new byte[area];
        image.getRaster().getDataElements(left, top, width, height, matrix);
        return matrix;
    }

    @Override
    public boolean isCropSupported() {
        return true;
    }

    @Override
    public LuminanceSource crop(int left, int top, int width, int height) {
        return new BufferedImageLuminanceSource(image, this.left + left, this.top + top, width, height);
    }

    @Override
    public boolean isRotateSupported() {
        return true;
    }

    @Override
    public LuminanceSource rotateCounterClockwise() {

        int sourceWidth = image.getWidth();
        int sourceHeight = image.getHeight();

        AffineTransform transform = new AffineTransform(0.0, -1.0, 1.0, 0.0, 0.0, sourceWidth);

        BufferedImage rotatedImage = new BufferedImage(sourceHeight, sourceWidth, BufferedImage.TYPE_BYTE_GRAY);

        Graphics2D g = rotatedImage.createGraphics();
        g.drawImage(image, transform, null);
        g.dispose();

        int width = getWidth();
        return new BufferedImageLuminanceSource(rotatedImage, top, sourceWidth - (left + width), getHeight(), width);
    }

}

3. QR code tools

package com.quna.app.pay;

import com.google.zxing.*;
import com.google.zxing.common.HybridBinarizer;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @version: V1.0
 * @author: crack
 * @className: QrCodeUtils
 * @packageName: com.xxx
 * @description: QR code tool class
 * @data: 2018-04-17 14:23
 **/
public class QrCodeUtils {

    /**
     * Parse QR Code (QRCode)
     * @param image
     * @return
     */
    public static String decodeQrcode(BufferedImage image) throws NotFoundException {

        MultiFormatReader formatReader = new MultiFormatReader();

        BinaryBitmap binaryBitmap=new BinaryBitmap(new HybridBinarizer(new BufferedImageLuminanceSource(image)));

        //Define the parameters of the QR code:
        Map<DecodeHintType, Object> hints = new HashMap<DecodeHintType, Object>();
        hints.put(DecodeHintType.CHARACTER_SET,"utf-8");//Define character set
        hints.put(DecodeHintType.PURE_BARCODE, Boolean.TRUE);
        Result result = formatReader.decode(binaryBitmap, hints);//Start parsing

        return result.getText();
    }

    /**
     * Streaming picture decoding
     * @param   input
     * @return  String
     */
    public static String decodeQrcode(InputStream input) throws NotFoundException, IOException {

        BufferedImage image = ImageIO.read(input);
        LuminanceSource source = new BufferedImageLuminanceSource(image);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));

        Map<DecodeHintType,Object> hints = new LinkedHashMap<DecodeHintType,Object>();
        // Decode setting encoding method: utf-8,
        hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
        //Optimize precision
        hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
        //Complex mode, turn on PURE_BARCODE mode
        hints.put(DecodeHintType.PURE_BARCODE, Boolean.TRUE);
        Result result = new MultiFormatReader().decode(bitmap, hints);
        return result.getText();
    }


}

4. Test class

package com.quna.app.pay;

import com.alibaba.fastjson.JSONObject;
import org.junit.Test;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io. *;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * @version: V1.0
 * @author: crack
 * @className: TestQR
 * @packageName: com.xxx
 * @description: QR code test class
 * @data: 2018-04-17 14:23
 **/
public class TestQR {

    public static void main(String[] args) {
        try {
            URL url = new URL("https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode?access_token=你的token");
            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
            httpURLConnection.setRequestMethod("POST");// Submit mode
            // conn.setConnectTimeout(10000);//Connection timeout in milliseconds
            // conn.setReadTimeout(2000);//Read timeout in milliseconds
            // Sending a POST request must set the following two lines
            httpURLConnection.setDoOutput(true);
            httpURLConnection.setDoInput(true);
            // Get the output stream corresponding to the URLConnection object
            PrintWriter printWriter = new PrintWriter(httpURLConnection.getOutputStream());
            // send request parameters
            JSONObject paramJson = new JSONObject();
            paramJson.put("path", "pages/home/index");
            paramJson.put("width", 430);
            printWriter.write(paramJson.toString());
            // flush the buffer of the output stream
            printWriter.flush();
            //Start getting data
            BufferedInputStream bis = new BufferedInputStream(httpURLConnection.getInputStream());

            ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
            //buff is used to store temporary data read cyclically
            byte[] buff = new byte[100];
            int rc = 0;
            while ((rc = bis.read(buff, 0, 100)) > 0) {
                swapStream.write(buff, 0, rc);
            }
            ByteArrayInputStream inputStream= new ByteArrayInputStream(swapStream.toByteArray());
            BufferedImage image = ImageIO.read(inputStream);
            /**The cropped original image is currently 470*535 pixels 170620 pixels returned by accessing WeChat and WeChat*/
            BufferedImage subImage = image.getSubimage(0, 0, image.getWidth(), (int) (image.getHeight() * 0.85));

            System.out.println(QrCodeUtils.decodeQrcode(subImage));

            BufferedImage inputbig = new BufferedImage(256, 256, BufferedImage.TYPE_INT_BGR);
            Graphics2D g = (Graphics2D) inputbig.getGraphics();
            g.drawImage(subImage, 0, 0,256,256,null); //draw
            g.dispose();
            inputbig.flush();
            ImageIO.write(inputbig, "jpg", new File("C:\\Users\\luojialin\\Desktop\\jar\\2018-4-20\\124567890.png"));
        } catch (Exception e) {
            e.printStackTrace ();
        }

    }

}


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324638376&siteId=291194637