QR code generation

Making QR code requires introducing google jar

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

QR code generation:

	 /**
     * @param text  QR code storage information
     * @param width The width of the generated picture
     * @param height Height of generated picture
     * @param filePath Storage path of generated pictures
     * @throws WriterException 
     * @throws IOException
     */
    public static void generateQRCodeImage(String text, int width, int height, String filePath)
            throws WriterException, IOException {
        QRCodeWriter qrCodeWriter = new QRCodeWriter();
        BitMatrix matrix = qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, width, height);
        Path path = FileSystems.getDefault().getPath(filePath);
        MatrixToImageWriter.writeToPath(matrix,"png", path);

    }


test

//You can scan directly with your mobile phone. Chinese characters may be garbled on your mobile phone, so you should pay attention to the character set coding of your mobile phone
        generateQRCodeImage(new String("Germany is very rich 3".getBytes("gbk"),"ISO-8859-1"),500,500,"./test.png");

Picture:

Two dimensional code principle

QR code principle: QR code principle link , this article is relatively clear

In the matrix 21 * 21 in the figure above, the black-and-white area is designated as a fixed position in the QR code specification, which is called finder pattern and timing pattern. Image seeking graphics and positioning graphics are used to help the decoding program determine the coordinates of specific symbols in the graphics.

The yellow area is used to store the encoded data content and error correction information code.

The blue area is used to identify the error correction level (i.e. Level L to Level H) and the so-called "Mask pattern". This area is called "format information".

  • level L: maximum 7% of errors can be corrected;
  • level M: up to 15% of errors can be corrected;
  • level Q: maximum 25% of errors can be corrected;
  • level H: up to 30% of errors can be corrected;

QR code color modification

I'm more interested in how the QR code changes color? Now I want to change the black-and-white QR code into other colors. How can I change its color?
There is a premise here, that is, you must know how the pictures are stored on the computer?
We all know the concept of pixel. A picture is composed of pixels. Each pixel stores an RGB value; For example, it is easy to understand: for example, a picture of 500 * 600; In fact, it is: width: 500 pixels, height: 600 pixels;

In order to more intuitively show what pixels are, I cut a picture, each small grid above is a pixel; When you see this picture, you have a deeper understanding of how the picture is stored. The picture is actually a pile of pixels; Back to the above question, how can we change the color? Just change the black pixels in the picture to the color we need;

Get the rgb value of the picture and modify it:

        QRCodeWriter qrCodeWriter = new QRCodeWriter();
        BitMatrix matrix = qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, width, height);
        int w = matrix.getWidth();
        int h = matrix.getHeight();
        int[] data = new int[w * h];
        Color color = new Color(50 , 165 , 162 );
        int colorInt = color.getRGB();
        for (int y = 0; y < h; y++) {
            for (int x = 0; x < w; x++) {
                if(matrix.get(x, y)){//Judge whether the pixel of coordinates (x,y) is black
                     data[y * w + x] = colorInt;
                    }
                }else{                   
                    data[y * w + x] = -1;//white
                }
            }
        }
        BufferedImage image = new BufferedImage(width, height,
                BufferedImage.TYPE_INT_RGB);//Create a BufferedImage 
        image.getRaster().setDataElements(0, 0, width, height, data);//Render pixel values into BufferedImage to generate images   
        ImageIO.write(image,"png", new File(filePath));

Seeing the above code, we know that rgb values are stored in a one-dimensional array rather than a two-dimensional array. Why should we use two-dimensional arrays? In addition, when storing rgb values, the subscript calculation formula is: index = y * w + x; What's going on?

Let's first look at why we use binary arrays?
If we use a two-dimensional array to store the pixels of the picture, it is more intuitive and easier to understand; Because the coordinates of the binary array just correspond to the position of the pixel;

Why use one-dimensional array instead of two-dimensional array?
May be: efficiency and memory consumption;
In fact, the essence of Java's two-dimensional array is one-dimensional array
for instance:

        int[][] a = new int[4][];
        a[0] = new int[4];
        a[1] = new int[3];
        a[2] = new int[3];
        a[3] = new int[2];

In memory:

Efficiency issues

As can be seen from the above figure, the data of the two-dimensional array is actually stored in the secondary array. To find the data, you will query twice; For example, a[2][2]; First find a[2], and then find a[2][2] through a[2]; If it is a one-dimensional array, you only need to find it once;

Occupation of memory

The layout of objects in memory can be divided into three areas: object header, instance data, alignment and filling;
A two-dimensional array: a[n] []; Create n more objects than a one-dimensional array storing the same elements, so it will also take up more space;

index of one-dimensional array

Now we use one-dimensional array to store pixel information. There is a problem. How to convert the pixel coordinates in the picture into the subscript index of one-dimensional array?

Just use a simple formula: index = y * width + x; Where (x,y) is the pixel subscript and width is the picture width; through this formula, the information of two-dimensional array can be stored in one-dimensional array in order;

About RGB values

In fact, there is another interesting section in the above code, that is, the RGB value is stored in an int variable; We know that RGB represents three colors: R: red, G: green, B: blue; By mixing these three colors, we can get any color; The value range of these three colors is 0 ~ 255; This range can be covered by 8 bits. Only three values account for 24 bits, while an int variable accounts for 32 bits (4 bytes). Is there still 4 bits left?
Color source code:

    public Color(int r, int g, int b) {
        this(r, g, b, 255);
    }
    
    @ConstructorProperties({"red", "green", "blue", "alpha"})
    public Color(int r, int g, int b, int a) {
        value = ((a & 0xFF) << 24) |
                ((r & 0xFF) << 16) |
                ((g & 0xFF) << 8)  |
                ((b & 0xFF) << 0);
        testColorValueRange(r,g,b,a);
    }


We are in new color (123123); In fact, there is a default value: alpha (transparency); the default value is 255 (opacity); each value of these four values accounts for 8bit, just the length of an int variable; according to the calculation process of value, we can know the order of these four values in the int variable:

==========================================================================================
follow-up:
There is something wrong with the way Color calculates rgb values:

	
   public Color(int r, int g, int b, int a) {
        value = ((a & 0xFF) << 24) |
                ((r & 0xFF) << 16) |
                ((g & 0xFF) << 8)  |
                ((b & 0xFF) << 0);
        testColorValueRange(r,g,b,a);//Check whether the values of r,g,b,a are between 0 and 255; An error is reported when the range is exceeded;
        
    }
    

The calculation result of a & 0xff only retains the lower 8 bits of a, and the binary range of 8 bits is exactly 0-255, which is the value range of color;


(X: indicates 0 or 1, 0xFF: hexadecimal: 255)

The source code calculates the RGB value first and then checks whether there is a problem with the value, which is in the wrong order; Normal logic should first check whether the value is correct, and then calculate the RGB value, which can reduce unnecessary calculation;

   public Color(int r, int g, int b, int a) {
   		testColorValueRange(r,g,b,a);//First check whether the values of R, G, B and a are in the range of 0-255; Throw exceptions outside this range
        value = (a << 24) | (r << 16) | (g << 8)  | b;//At this step, the range of 4 values has been guaranteed to be 0-255; No bit operation with 0xff;
        }

Keywords: JavaSE

Added by aftabn10 on Thu, 23 Dec 2021 07:50:16 +0200