Java uses IO stream and file stream to generate and download QR code

Posted by shapiro125 on Wed, 09 Mar 2022 06:48:11 +0100

scene

A QR code is generated in the system, and users save it and share it. After scanning, others jump to one of our activity details pages to view the content of this activity.

From the above requirements, we can extract the following points:

  • When the user clicks generate QR code, we need to get which activity the user generated QR code is about;
  • Request to come to the background, get the activity ID, as the parameter of our activity details page, generate a url, as the jump address after scanning, and generate a QR code;
  • Return the generated QR code to the front end and display it to the user;
  • The user saves the QR code and downloads it.

The requirement is to set the content of the QR code and display it at the front end. The content of QR code can be a clear text or an http or https link, which will be accessed automatically when scanning.

realization

Focus on the third and fourth steps, that is, the generation of QR code and the user downloading QR code.

How to generate a QR code? There are many dependent packages on the market. Just use them. The focus is how to return them gracefully to users and download them. In fact, it is not necessary for users to download this action. After all, most young people know that long press to save, but they still need to take care of other users and give obvious download buttons.

First, the third step, how to return the QR code to the front end? Maybe many people will think that it's OK to save the generated QR code to the server and then return the image path? Of course, this is OK, but there are many unnecessary operations:

For the QR code, we only need to return it to the user and do not need to store it on our server, which is meaningless and takes up disk space;

If you write the QR code to the server, you need to deal with disk IO, which is a high price;

Each user generated QR code corresponds to a URL, which is very messy

We can directly return the generated QR code image to the requestor through the response response body in the form of IO stream. First, there is no need to fall on our disk. All operations are completed in memory, which is more efficient; Second, all requests to generate QR codes can be accessed here. src with img tag directly at the front end can be accessed. You can also get a picture by directly entering this path in the browser, which reduces a lot of interaction and logical processing.

In the fourth step, we implement it directly on the front end, because the front end has a mechanism to download the image of an img tag without wasting our server.

Step 1 - introduce dependencies

Two dependent packages need to be introduced:

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

Writing tool classes

package com.dosion.utils;
 
 
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
 
 
import java.io.File;
import java.io.IOException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
 
/**
 *  <p>
 *      Tool class for generating QR code
 *  </p>
 * */
public class QRCodeUtils {
 
    /**
     *  Generate QR code and return it to the front end for display in the form of IO stream
     * @param content Content of QR code
     * @param width Width of QR code
     * @param height Height of QR code
     * @return BitMatrix object
     * */
    public static BitMatrix createCode(String content,int width,int height) throws IOException {

        //Other parameters, such as character set encoding
        Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        //Fault tolerance level is H
        hints.put(EncodeHintType.ERROR_CORRECTION , ErrorCorrectionLevel.H);
        //The width of the white edge can be taken as 0 ~ 4
        hints.put(EncodeHintType.MARGIN , 0);

        BitMatrix bitMatrix = null;
        try {
            //Generate the matrix, because the encoded URL is transmitted from my business scenario, so decode it first
            bitMatrix = new MultiFormatWriter().encode(content,
                    BarcodeFormat.QR_CODE, width, height, hints);

            //bitMatrix = deleteWhite(bitMatrix);
        } catch (WriterException e) {
            e.printStackTrace();
        }

        return bitMatrix;
    }
 
    /**
     *  Delete the white edge around the generated QR code and decide whether to delete it according to aesthetics
     * @param matrix BitMatrix object
     * @return BitMatrix object
     * */
    private static BitMatrix deleteWhite(BitMatrix matrix) {
        int[] rec = matrix.getEnclosingRectangle();
        int resWidth = rec[2] + 1;
        int resHeight = rec[3] + 1;
 
        BitMatrix resMatrix = new BitMatrix(resWidth, resHeight);
        resMatrix.clear();
        for (int i = 0; i < resWidth; i++) {
            for (int j = 0; j < resHeight; j++) {
                if (matrix.get(i + rec[0], j + rec[1]))
                    resMatrix.set(i, j);
            }
        }
        return resMatrix;
    }


    /**
     *  Download QR code
     * @param content Content of QR code
     * @param width Width of QR code
     * @param height Height of QR code
     * @return BitMatrix object
     * */
    public static BitMatrix dowanload(String content,int width,int height) throws Exception {

        Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
        // Specify encoding format
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        // Specify error correction level (L--7%,M--15%,Q--25%,H--30%)
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        // Coding content, coding type (designated as QR code here), generated picture width, generated picture height, and set parameters
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
        return bitMatrix;
    }

}

Write API interface

    /**
     *  Generate QR code
     * */
    @GetMapping(value = "/qrcode/create")
    public void getCode(@RequestParam("content") String content , HttpServletResponse response) throws IOException {
        // Set response flow information
        response.setContentType("image/jpg");
        response.setHeader("Pragma", "no-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);

        OutputStream stream = response.getOutputStream();

        //Width and height of QR code
        int width = 200;
        int height = 200;

        //Get a QR code picture
        BitMatrix bitMatrix = QRCodeUtils.createCode(content,width,height);
        //Output to the front end in the form of stream
        MatrixToImageWriter.writeToStream(bitMatrix , "jpg" , stream);
    }

    @GetMapping("/qrcode/dowanload")
    public void dowanload(@RequestParam("content") String content ,
                          HttpServletRequest request, HttpServletResponse response) throws Exception {
        //Width and height of QR code
        int width = 200;
        int height = 200;

        BitMatrix bitMatrix = QRCodeUtils.dowanload(content,width,height);
        //Set request header
        response.setHeader("Content-Type","application/octet-stream");
        response.setHeader("Content-Disposition", "attachment;filename=" + "QR code.png");
        OutputStream outputStream = response.getOutputStream();
        MatrixToImageWriter.writeToStream(bitMatrix, "png", outputStream);
        outputStream.flush();
        outputStream.close();
    }

Access test

Scanning the above QR code will display the content

Download pictures

The usage is also very simple. imgSrc is the address of the picture. Just point to our API above here, because our API responds to a picture. Name is the file name after downloading.

function downloadImage(imgsrc, name) {//Download picture address and picture name
                let image = new Image();
                // Solve the problem of cross domain Canvas pollution
                image.setAttribute("crossOrigin", "anonymous");
                image.onload = function() {
                    let canvas = document.createElement("canvas");
                    canvas.width = image.width;
                    canvas.height = image.height;
                    let context = canvas.getContext("2d");
                    context.drawImage(image, 0, 0, image.width, image.height);
                    let url = canvas.toDataURL("image/jpg"); //Get the base64 encoded data of the picture
                    let a = document.createElement("a"); // Generate an a element
                    let event = new MouseEvent("click"); // Create a click event
                    a.download = name || "photo"; // Set picture name
                    a.href = url; // Set the generated URL to the a.href attribute
                    a.dispatchEvent(event); // Click event triggering a
                };
                image.src = imgsrc;
            }

Generate and parse QR codes, support images and output streams, and add logo images

import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Shape;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.OutputStream;
import java.util.Hashtable;
import java.util.Random;

import javax.imageio.ImageIO;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.Result;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

public class QRCodeUtils {
    private static final String CHARSET = "utf-8";
    private static final String FORMAT_NAME = "JPG";
    // QR code size    
    private static final int QRCODE_SIZE = 300;
    // LOGO width    
    private static final int WIDTH = 60;
    // LOGO height    
    private static final int HEIGHT = 60;

    private static BufferedImage createImage(String content, String imgPath,
                                             boolean needCompress) throws Exception {
        Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content,
                BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, hints);
        int width = bitMatrix.getWidth();
        int height = bitMatrix.getHeight();
        BufferedImage image = new BufferedImage(width, height,
                BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000
                        : 0xFFFFFFFF);
            }
        }
        if (imgPath == null || "".equals(imgPath)) {
            return image;
        }
        // Insert picture    
        QRCodeUtils.insertImage(image, imgPath, needCompress);
        return image;
    }

    /**
     * Insert LOGO  
     *
     * @param source
     *            QR code picture  
     * @param imgPath
     *            LOGO Picture address  
     * @param needCompress
     *            Whether to compress  
     * @throws Exception
     */
    private static void insertImage(BufferedImage source, String imgPath,
                                    boolean needCompress) throws Exception {
        File file = new File(imgPath);
        if (!file.exists()) {
            System.err.println(""+imgPath+"   The file does not exist!");
            return;
        }
        Image src = ImageIO.read(new File(imgPath));
        int width = src.getWidth(null);
        int height = src.getHeight(null);
        if (needCompress) { // Compressed LOGO    
            if (width > WIDTH) {
                width = WIDTH;
            }
            if (height > HEIGHT) {
                height = HEIGHT;
            }
            Image image = src.getScaledInstance(width, height,
                    Image.SCALE_SMOOTH);
            BufferedImage tag = new BufferedImage(width, height,
                    BufferedImage.TYPE_INT_RGB);
            Graphics g = tag.getGraphics();
            g.drawImage(image, 0, 0, null); // Draw a reduced map    
            g.dispose();
            src = image;
        }
        // Insert LOGO    
        Graphics2D graph = source.createGraphics();
        int x = (QRCODE_SIZE - width) / 2;
        int y = (QRCODE_SIZE - height) / 2;
        graph.drawImage(src, x, y, width, height, null);
        Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);
        graph.setStroke(new BasicStroke(3f));
        graph.draw(shape);
        graph.dispose();
    }

    /**
     * Generate QR code (embedded LOGO)  
     *
     * @param content
     *            content  
     * @param imgPath
     *            LOGO address  
     * @param destPath
     *            Storage directory  
     * @param needCompress
     *            Compress LOGO  
     * @throws Exception
     */
    public static String encode(String content, String imgPath, String destPath,
                              boolean needCompress) throws Exception {
        BufferedImage image = QRCodeUtils.createImage(content, imgPath,
                needCompress);
        mkdirs(destPath);
        String file = new Random().nextInt(99999999)+".jpg";
        ImageIO.write(image, FORMAT_NAME, new File(destPath+"/"+file));
        return file;
    }

    /**
     * When the folder does not exist, mkdirs will automatically create multi-level directories, which is different from mkdir. (mkdir will throw an exception if the parent directory does not exist)  
     * @date 2013-12-11 10:16:36 am  
     * @param destPath Storage directory  
     */
    public static void mkdirs(String destPath) {
        File file =new File(destPath);
        //When the folder does not exist, mkdirs will automatically create multi-level directories, which is different from mkdir. (mkdir will throw an exception if the parent directory does not exist)    
        if (!file.exists() && !file.isDirectory()) {
            file.mkdirs();
        }
    }

    /**
     * Generate QR code (embedded LOGO)  
     *
     * @param content
     *            content  
     * @param imgPath
     *            LOGO address  
     * @param destPath
     *            Storage address  
     * @throws Exception
     */
    public static void encode(String content, String imgPath, String destPath)
            throws Exception {
        QRCodeUtils.encode(content, imgPath, destPath, false);
    }

    /**
     * Generate QR code  
     *
     * @param content
     *            content  
     * @param destPath
     *            Storage address  
     * @param needCompress
     *            Compress LOGO  
     * @throws Exception
     */
    public static void encode(String content, String destPath,
                              boolean needCompress) throws Exception {
        QRCodeUtils.encode(content, null, destPath, needCompress);
    }

    /**
     * Generate QR code  
     *
     * @param content
     *            content  
     * @param destPath
     *            Storage address  
     * @throws Exception
     */
    public static void encode(String content, String destPath) throws Exception {
        QRCodeUtils.encode(content, null, destPath, false);
    }

    /**
     * Generate QR code (embedded LOGO)  
     *
     * @param content
     *            content  
     * @param imgPath
     *            LOGO address  
     * @param output
     *            Output stream  
     * @param needCompress
     *            Compress LOGO  
     * @throws Exception
     */
    public static void encode(String content, String imgPath,
                              OutputStream output, boolean needCompress) throws Exception {
        BufferedImage image = QRCodeUtils.createImage(content, imgPath,
                needCompress);
        ImageIO.write(image, FORMAT_NAME, output);
    }

    /**
     * Generate QR code  
     *
     * @param content
     *            content  
     * @param output
     *            Output stream  
     * @throws Exception
     */
    public static void encode(String content, OutputStream output)
            throws Exception {
        QRCodeUtils.encode(content, null, output, false);
    }

    /**
     * Parse QR code  
     *
     * @param file
     *            QR code picture  
     * @return
     * @throws Exception
     */
    public static String decode(File file) throws Exception {
        BufferedImage image;
        image = ImageIO.read(file);
        if (image == null) {
            return null;
        }
        BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(
                image);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
        Result result;
        Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>();
        hints.put(DecodeHintType.CHARACTER_SET, CHARSET);
        result = new MultiFormatReader().decode(bitmap, hints);
        String resultStr = result.getText();
        return resultStr;
    }

    /**
     * Parse QR code  
     *
     * @param path
     *            QR code picture address  
     * @return
     * @throws Exception
     */
    public static String decode(String path) throws Exception {
        return QRCodeUtils.decode(new File(path));
    }

    public static void main(String[] args) throws Exception {
        String text = "http://www.baidu.com "; / / set custom website url here
        String logoPath = "C:\\Users\\admin\\Desktop\\test\\test.jpg";
        String destPath = "C:\\Users\\admin\\Desktop\\test\\";
        System.out.println(QRCodeUtils.encode(text, logoPath, destPath, true));
    }
}  

reference resources:

Java generates QR code and returns it to the front-end display in the form of IO stream (without writing to the server), and downloads QR code pictures: https://blog.csdn.net/wzy18210825916/article/details/100037429

java generates two-dimensional code and outputs it to the page in stream form: http://www.manongjc.com/article/18411.html

Implementation of java generated QR code technology: https://www.jianshu.com/p/bb76ded47d64

Use java to generate two-dimensional code tool class example code: https://www.jb51.net/article/123311.htm

Java generates and parses QR codes, supports images and output streams, and supports the addition of logo images: https://blog.csdn.net/jinqilin721/article/details/88894682