Generating QR Code In SpringBoot Application

In this blog we will look at the generating QR Code in Spring Boot Application.

 QR code (short for “quick-response code“) typically contains data for a location, contact information , and website. 

Let’s try to generate QR code for Wifi network so that you can share the Wifi details with your guests with out revealing the password.

QR code for Wifi network contains following string format.

“WIFI:S:<SSID>;T:<Network-Type>;P:<Password>;;”

In our API, we will accept ssid, networkType and Password details and generate the QR code.

Set up a new Spring Boot Project:

Go to start.spring.io project and create new spring boot projects

Add Dependencies for QR Code Generation

Add zxing QRCode Generator library to your project.


<dependency>
   <groupId>com.google.zxing</groupId>
   <artifactId>core</artifactId>
   <version>3.5.2</version>
</dependency>
Code language: Java (java)

Create a Service class that generates the QR code

From zxing library you can use either of the following 2 classes to generate QR code.

  • QRWriter
  • MultiFormatWriter

For the following first example let’s use the QRWriter class.

@SpringBootApplication
public class Application {

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}

	@Bean
	public QRCodeWriter getQrCodeWriter(){
		return new QRCodeWriter();
	}

	@Bean
	public MultiFormatWriter getMultiFormatWriter(){
		return new MultiFormatWriter();
	}

}Code language: Java (java)
@Service
public class QRCodeGeneratorService {

  @Autowired QRCodeWriter qrCodeWriter;

  @Autowired MultiFormatWriter multiFormatWriter;

  public byte[] generateQRCode(WifiNetwork wifiNetwork,int width,int height) throws WriterException {

    Map<EncodeHintType, Object> hints = new HashMap<>();
    hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
    hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);

    BitMatrix bitMatrix = qrCodeWriter.encode(wifiNetwork.getWifiNetworkString(),
            BarcodeFormat.QR_CODE, 200, 200,
            hints);

    BufferedImage qrCodeImage = getBufferedImage(width, height, bitMatrix);

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    try {
      ImageIO.write(qrCodeImage, "png", outputStream);
    } catch (IOException e) {
      throw new RuntimeException("Failed to write QR code image to output stream.", e);
    }

    return outputStream.toByteArray();
  }

  private static BufferedImage getBufferedImage(int width, int height, BitMatrix bitMatrix) {
    BufferedImage qrCodeImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    qrCodeImage.createGraphics();

    Graphics2D graphics = (Graphics2D) qrCodeImage.getGraphics();
    graphics.setColor(Color.WHITE);
    graphics.fillRect(0, 0, width, height);
    graphics.setColor(Color.BLACK);

    for (int i = 0; i < width; i++) {
      for (int j = 0; j < height; j++) {
        if (bitMatrix.get(i, j)) {
          graphics.fillRect(i, j, 1, 1);
        }
      }
    }
    return qrCodeImage;
  }
}Code language: Java (java)

QRCodeWriter -> encode method generates BitMatrix which contains one’s and zeros.

The data from BitMatrix is used to generate an Image containing the QR Code.

The getBufferedImage() method first creates a new BufferedImage object with the specified width, height, and image type. It then creates a Graphics2D object from the BufferedImage object.

The method then sets the color of the Graphics2D object to white and fills the entire image with white. This will create a blank white canvas for the QR code.

Next, the method sets the color of the Graphics2D object to black. It then iterates over the BitMatrix object, drawing a black pixel at each coordinate where the BitMatrix object is set to true.

Finally, the method returns the BufferedImage object.

Now let’s test the generation of QRCode

Note: I have used, Thunder Client for VS Code Rest Client for testing.

Error Correction

QR Code has error correction capability to restore data if the code is dirty or damaged. Four error correction levels are available for users to choose according to the operating environment. Raising this level improves error correction capability but also increases the amount of data QR Code size.
To select error correction level, various factors such as the operating environment and QR Code size need to be considered

QR Error Code Correction Capability
LEVEL LApprox. 7%
LEVEL MApprox. 15%
LEVEL QApprox. 25%
LEVEL HApprox. 30%

QRCodeWriter class can be replaced with MultiFormatWriter. Internally MultiFormatWriter class uses QRCodeWriter when we pass QRCode as barcode format.

In your application, if you are dealing with more than one barcode format, using MultiFormatWriter class is preferred.

public byte[] generateQRCode2(WifiNetwork wifiNetwork,int width,int height) throws WriterException {

    Map<EncodeHintType, Object> hints = new HashMap<>();
    hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
    hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);

    BitMatrix bitMatrix = multiFormatWriter.encode(wifiNetwork.getWifiNetworkString(),
            BarcodeFormat.QR_CODE, 200, 200,
            hints);

    BufferedImage qrCodeImage = getBufferedImage(width, height, bitMatrix);

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    try {
      ImageIO.write(qrCodeImage, "png", outputStream);
    } catch (IOException e) {
      throw new RuntimeException("Failed to write QR code image to output stream.", e);
    }

    return outputStream.toByteArray();
  }Code language: Java (java)

In above examples we have written our own code to generate QRCode BufferedImage.

If we include following library ,we can use utility methods which simplifies the generating QRCode.

<dependency>
   <groupId>com.google.zxing</groupId>
   <artifactId>javase</artifactId>
   <version>3.5.2</version>
</dependency>Code language: Java (java)

The library provides MatrixToImageWriter class which contains utility functions to convert BitMatrix to Image or Stream of Image or write Image to path.

public byte[] generateQRCode4(WifiNetwork wifiNetwork, int width, int height)
          throws WriterException, IOException {


    Map<EncodeHintType, Object> hints = new HashMap<>();
    hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
    hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);

    BitMatrix bitMatrix = qrCodeWriter.encode(wifiNetwork.getWifiNetworkString(),
            BarcodeFormat.QR_CODE, 200, 200,
            hints);

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    MatrixToImageWriter.writeToStream(bitMatrix,"PNG",outputStream);


    return outputStream.toByteArray();
  }
Code language: Java (java)

Fun with QR Codes

Generating Colorful QR Codes

Generally QRCodes comes in black and white format. But we can make them colorful replacing black color with another color.

 Graphics2D graphics = (Graphics2D) qrCodeImage.getGraphics();
    graphics.setColor(Color.WHITE);
    graphics.fillRect(0, 0, width, height);
    graphics.setColor(Color.GREEN);
Code language: Java (java)

By setting the fill color to green instead of black, we can generate QRCode with green color that looks different from usual.

Make sure that the selected color stands out and QR code scanner can scan it.

Overlaying Logos in Background

Another idea is, you can generate black and white QR code but you can overlay QR code with company logo or image. This idea and code is taken from another blog

First thing you need to do when overlaying images is, change the error correction level to H which has highest level of correction.

Next you need to experiment with different alpha values so that your QR code can be scanned by scanner.

 public byte[] generateQRCode6(WifiNetwork wifiNetwork, int width, int height)
          throws WriterException, IOException {


    Map<EncodeHintType, Object> hints = new HashMap<>();
    hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
    hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);

    BitMatrix bitMatrix = qrCodeWriter.encode(wifiNetwork.getWifiNetworkString(),
            BarcodeFormat.QR_CODE, 500, 500,
            hints);

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    BufferedImage qrImage = MatrixToImageWriter.toBufferedImage(bitMatrix,new MatrixToImageConfig(
            0xFF000000,
            0xFFFFFFFF));

    BufferedImage combined = new BufferedImage(qrImage.getHeight(), qrImage.getWidth(),
            BufferedImage.TYPE_INT_ARGB);
    Graphics2D g = (Graphics2D) combined.getGraphics();

    // Write QR code to new image at position 0/0
    g.drawImage(qrImage, 0, 0, null);

    g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));

    addOverlayImage(g, qrImage);


    try {
      ImageIO.write(combined, "png", outputStream);
    } catch (IOException e) {
      throw new RuntimeException("Failed to write QR code image to output stream.", e);
    }

    return outputStream.toByteArray();


  }

  private  BufferedImage addOverlayImage(Graphics2D g, BufferedImage qrImage
                                              ) throws IOException {

    Resource resource = resourceLoader.getResource("classpath:wifi-logo.png");
    BufferedImage overlay = ImageIO.read(resource.getInputStream());

    // Calculate the delta height and width between QR code and the logo
    // Note that we don't do any scaling, so the sizes need to kind of
    // work together without obscuring too much logo
    int deltaHeight = qrImage.getHeight() - overlay.getHeight();
    int deltaWidth = qrImage.getWidth() - overlay.getWidth();

    int woffset = Math.round(deltaWidth / 2);
    int hoffset = Math.round(deltaHeight / 2);

    // Write the logo into the combined image at position (deltaWidth / 2) and
    // (deltaHeight / 2), so that it's centered
    g.drawImage(overlay, woffset, hoffset, null);
    return overlay;
  }
Code language: Java (java)

Here are few QR codes overlayed by other images.

You can download source code for this blog post from GitHub

Similar Posts