1. Overview

Barcodes are used to convey information visually. We’ll most likely provide an appropriate barcode image in a web page, email, or a printable document.

In this tutorial, we’re going to look at how to generate the most common types of barcodes in Java.

First, we’ll learn about the internals of several types of barcodes. Next, we’ll explore the most popular Java libraries for generating barcodes. Finally, we’ll see how to integrate barcodes into our application by serving them from a web service using Spring Boot.

2. Types of Barcodes

Barcodes encode information such as product numbers, serial numbers, and batch numbers. Also, they enable parties like retailers, manufacturers, and transport providers to track assets through the entire supply chain.

We can group the many different barcode symbologies into two primary categories:

  • linear barcodes
  • 2D barcodes

2.1. UPC (Universal Product Code) Codes

UPC Codes are some of the most commonly used 1D barcodes, and we mostly find them in the United States.

The UPC-A is a numeric-only code that contains 12 digits: a manufacturer identification number (6 digits), an item number (5 digits), and a check digit. There is also a UPC-E code that has only 8 digits and is used for small packages.

2.2. EAN Codes

EAN Codes are known worldwide as both European Article Number and International Article Number. They’re designed for Point-of-Sale scanning. There are also a few different variations of the EAN code, including EAN-13, EAN-8, JAN-13, and ISBN.

The EAN-13 code is the most commonly used EAN standard and is similar to the UPC code. It’s made of 13 digits — a leading “0” followed by the UPC-A code.

2.3. Code 128

The Code 128 barcode is a compact, high-density linear code used in the logistics and transportation industries for ordering and distribution. It can encode all 128 characters of ASCII, and its length is variable.

2.4. PDF417

PDF417 is a stacked linear barcode comprised of multiple 1D barcodes stacked one on top of another. Hence, it can use a traditional linear scanner.

We might expect to find it on a variety of applications such as travel (boarding passes), identification cards, and inventory management.

PDF417 uses Reed-Solomon error correction instead of check digits. This error correction allows the symbol to endure some damage without causing loss of data. However, it can be expansive in size – 4 times larger than other 2D barcodes such as Datamatrix and QR Codes.

2.5. QR Codes

QR Codes are becoming the most widely recognized 2D barcodes worldwide. The big benefit of the QR code is that we can store large amounts of data in a limited space.

They use four standardized encoding modes to store data efficiently:

  • numeric
  • alphanumeric
  • byte/binary
  • kanji

Moreover, they are flexible in size and are easily scanned using a smartphone. Similar to PDF417, a QR code can withstand some damage without causing loss of data.

3. Barcode Libraries

We’re going to explore several libraries:

  • Barbecue
  • Barcode4j
  • ZXing
  • QRGen

Barbecue is an open-source Java library that supports an extensive set of 1D barcode formats. Also, the barcodes can be output to PNG, GIF, JPEG, and SVG.

Barcode4j is also an open-source library. In addition, it offers 2D barcode formats – like DataMatrix and PDF417 – and more output formats. The PDF417 format is available in both libraries. But, unlike Barcode4j, Barbecue considers it a linear barcode.

ZXing (“zebra crossing”) is an open-source, multi-format 1D/2D barcode image processing library implemented in Java, with ports to other languages. This is the main library that supports QR codes in Java.

QRGen library offers a simple QRCode generation API built on top of ZXing. It provides separate modules for Java and Android.

4. Generating Linear Barcodes

Let’s create a barcode image generator for each library and barcode pair. We’ll retrieve the image in the PNG format, but we could also use other formats like GIF or JPEG.

4.1. Using the Barbecue Library

As we’ll see, Barbecue provides the simplest API for generating barcodes. We only need to provide the barcode text as minimal input. But we could optionally set a font and a resolution (dots per inch). Regarding the font, we can use it to display the barcode text under the image.

First, we need to add the Barbecue Maven dependency:


Let’s create a generator for an EAN13 barcode:

public static BufferedImage generateEAN13BarcodeImage(String barcodeText) throws Exception {
    Barcode barcode = BarcodeFactory.createEAN13(barcodeText);

    return BarcodeImageHandler.getImage(barcode);

We can generate images for the rest of the linear barcode types in a similar manner.

We should note that we do not need to provide the checksum digit for EAN/UPC barcodes, as it is automatically added by the library.

4.2. Using the Barcode4j Library

Let’s start by adding the Barcode4j Maven Dependency:


Likewise, let’s build a generator for an EAN13 barcode:

public static BufferedImage generateEAN13BarcodeImage(String barcodeText) {
    EAN13Bean barcodeGenerator = new EAN13Bean();
    BitmapCanvasProvider canvas = 
      new BitmapCanvasProvider(160, BufferedImage.TYPE_BYTE_BINARY, false, 0);

    barcodeGenerator.generateBarcode(canvas, barcodeText);
    return canvas.getBufferedImage();

The BitmapCanvasProvider constructor takes several parameters: resolution, image type, whether to enable anti-aliasing, and image orientation. Also, we don’t need to set a font because the text under the image is displayed by default.

4.3. Using the ZXing Library

Here, we need to add two Maven dependencies: the core image library and the Java client:


Let’s create an EAN13 generator:

public static BufferedImage generateEAN13BarcodeImage(String barcodeText) throws Exception {
    EAN13Writer barcodeWriter = new EAN13Writer();
    BitMatrix bitMatrix = barcodeWriter.encode(barcodeText, BarcodeFormat.EAN_13, 300, 150);

    return MatrixToImageWriter.toBufferedImage(bitMatrix);

Here, we need to provide several parameters as input, such as a barcode text, a barcode format, and barcode dimensions. Unlike the other two libraries, we must also add the checksum digit for EAN barcodes. But, for UPC-A barcodes, the checksum is optional.

Moreover, this library will not display barcode text under the image.

5. Generating 2D Barcodes

5.1. Using the ZXing Library

We’re going to use this library to generate a QR Code. The API is similar to that of the linear barcodes:

public static BufferedImage generateQRCodeImage(String barcodeText) throws Exception {
    QRCodeWriter barcodeWriter = new QRCodeWriter();
    BitMatrix bitMatrix = 
      barcodeWriter.encode(barcodeText, BarcodeFormat.QR_CODE, 200, 200);

    return MatrixToImageWriter.toBufferedImage(bitMatrix);

5.2. Using the QRGen Library

The library is no longer deployed to Maven Central, but we can find it on jitpack.io.

First, we need to add the jitpack repository and the QRGen dependency to our pom.xml:



Let’s create a method that generates a QR Code:

public static BufferedImage generateQRCodeImage(String barcodeText) throws Exception {
    ByteArrayOutputStream stream = QRCode
      .withSize(250, 250)
    ByteArrayInputStream bis = new ByteArrayInputStream(stream.toByteArray());

    return ImageIO.read(bis);

As we can see, the API is based on the Builder pattern and it provides two types of output: File and OutputStream. We can use the ImageIO library to convert it to a BufferedImage.

6. Generating QR Code with Text

Adding text to a QR code provides additional context that increases the likelihood of user interaction.

We can add text to the upper or lower part of a QR code generated with the ZXing library or any other library that can generate a QR barcode.

In the last section, we saw how to generate a QR code using the ZXing library. However, the library doesn’t have a method to add text to the boundaries of the QR code. Hence, we need to implement a method to achieve this purpose.

First, let’s create a method to generate a QR code that accepts data we intend to encode, the top text, and bottom text as parameters:

public static BufferedImage createQRwithText(String data, String topText, String bottomText) throws WriterException, IOException {
    QRCodeWriter barcodeWriter = new QRCodeWriter();
    BitMatrix matrix = barcodeWriter.encode(data, BarcodeFormat.QR_CODE, 200, 200);
    return modifiedQRCode(matrix, topText, bottomText);

The method above generates a QR code with some data. Next, we pass the QR code to the modifiedQRcode() method to add text to the top and bottom of the generated QR code.

The modifiedQRcode() method replicates the QR code and modifies it:

int matrixWidth = matrix.getWidth();
int matrixHeight = matrix.getHeight();

BufferedImage image = new BufferedImage(matrixWidth, matrixHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = image.createGraphics();
graphics.fillRect(0, 0, matrixWidth, matrixHeight);

for (int i = 0; i < matrixWidth; i++) {
    for (int j = 0; j < matrixHeight; j++) {
        if (matrix.get(i, j)) {
            graphics.fillRect(i, j, 1, 1);

Here, we create a BufferedImage instance that temporarily holds the QR code by drawing its pixels on a Graphics2D object.

Next, let’s calculate the dimensions required to accommodate the text and QR code:

FontMetrics fontMetrics = graphics.getFontMetrics();
int topTextWidth = fontMetrics.stringWidth(topText);
int bottomTextWidth = fontMetrics.stringWidth(bottomText);
int finalWidth = Math.max(matrixWidth, Math.max(topTextWidth, bottomTextWidth)) + 1;
int finalHeight = matrixHeight + fontMetrics.getHeight() + fontMetrics.getAscent() + 1;

Finally, let’s create a new BufferedImage instance to hold the final image:

BufferedImage finalImage = new BufferedImage(finalWidth, finalHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D finalGraphics = finalImage.createGraphics();
finalGraphics.fillRect(0, 0, finalWidth, finalHeight);

finalGraphics.drawImage(image, (finalWidth - matrixWidth) / 2, fontMetrics.getAscent() + 2, null);
finalGraphics.drawString(topText, (finalWidth - topTextWidth) / 2, fontMetrics.getAscent() + 2);
finalGraphics.drawString(bottomText, (finalWidth - bottomTextWidth) / 2, finalHeight - fontMetrics.getDescent() - 5);

In the code above, we define a new instance of BufferedImage and pass it to the Graphics2D instance. Finally, we draw the QR code and the text on the final image.

7. Building a REST Service

Now we have a choice of barcode library to use, let’s look at how to serve barcodes from a Spring Boot web service.

We’ll start with a RestController:

public class BarcodesController {

    @GetMapping(value = "/barbecue/ean13/{barcode}", produces = MediaType.IMAGE_PNG_VALUE)
    public ResponseEntity<BufferedImage> barbecueEAN13Barcode(@PathVariable("barcode") String barcode)
    throws Exception {
        return okResponse(BarbecueBarcodeGenerator.generateEAN13BarcodeImage(barcode));

Also, we need to manually register a message converter for BufferedImage HTTP Responses because there is no default:

public HttpMessageConverter<BufferedImage> createImageHttpMessageConverter() {
    return new BufferedImageHttpMessageConverter();

Finally, we can use Postman or a browser to view the generated barcodes.

7.1. Generating a UPC-A Barcode

Let’s call the UPC-A web service using the Barbecue library:

[GET] http://localhost:8080/barcodes/barbecue/upca/12345678901

Here’s the result:


7.2. Generating an EAN13 Barcode

Similarly, we’re going to call the EAN13 web service:

[GET] http://localhost:8080/barcodes/barbecue/ean13/012345678901

And here’s our barcode:


7.3. Generating a Code128 Barcode

In this case, we’re going to use the POST method. Let’s call the Code128 web service using the Barbecue library:

[POST] http://localhost:8080/barcodes/barbecue/code128

We’ll provide the request body, containing the data:

Lorem ipsum dolor sit amet, consectetur adipiscing elit,
 sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Let’s see the result:

code128 barbecue2

7.4. Generating a PDF417 Barcode

Here, we’re going to call the PDF417 web service, which is similar to Code128:

[POST] http://localhost:8080/barcodes/barbecue/pdf417

We’ll provide the request body, containing the data:

Lorem ipsum dolor sit amet, consectetur adipiscing elit,
 sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

And here’s the resulting barcode:

pdf417 barbecue 3

7.5. Generating a QR Code Barcode

Let’s call the QR Code web service using the ZXing library:

[POST] http://localhost:8080/barcodes/zxing/qrcode

We’ll provide the request body, containing the data:

Lorem ipsum dolor sit amet, consectetur adipiscing elit,
 sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
 quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

Here’s our QR code:

qrcode zxing3

Here, we can see the power of QR codes to store large amounts of data in a limited space.

7.6. Generating a QR Code Barcode with Text

Let’s invoke the QR Code web service that adds texts to the generated QR code using the ZXing library:

[GET] http://localhost:8080/barcodes/zxing/qrcode/text?barcode=https://baeldung.com&toptext=Baeldung&bottomtext=Baeldung%20Home%20Page

The request parameters contain the data to be encoded — the top and bottom text, respectively.

Here’s the QR code:

qr code generated with zxing library with text.

The texts describe the data embedded in the QR code

8. Conclusion

In this article, we learned how to generate the most common types of barcodes in Java.

First, we studied the formats of several types of linear and 2D barcodes. Next, we explored the most popular Java libraries for generating them. Though we tried some simple examples, we can study the libraries further for more customized implementations.

Finally, we saw how to integrate the barcode generators into a REST service, and how to test them.

As always, the example code from this tutorial is available over on GitHub.

Course – LS (cat=Java)

Get started with Spring and Spring Boot, through the Learn Spring course:

res – REST with Spring (eBook) (everywhere)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.