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
- QR Code generator
- Okapi Barcode generator
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.
QR Code generator is an open-source library that aims to be the clearest QR code generator with flexible options and absolute correctness. It was originally written in Java and ported to some other programming languages.
Okapi Barcode generator is a pure Java library for generating various barcodes, including QR codes. It’s actively maintained, with regular updates to ensure reliability. It supports over 50 symbologies.
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:
<dependency>
<groupId>net.sourceforge.barbecue</groupId>
<artifactId>barbecue</artifactId>
<version>1.5-beta1</version>
</dependency>
Let’s create a generator for an EAN13 barcode:
public static BufferedImage generateEAN13BarcodeImage(String barcodeText) throws Exception {
Barcode barcode = BarcodeFactory.createEAN13(barcodeText);
barcode.setFont(BARCODE_TEXT_FONT);
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:
<dependency>
<groupId>net.sf.barcode4j</groupId>
<artifactId>barcode4j</artifactId>
<version>2.1</version>
</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:
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.3.0</version>
</dependency>
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:
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.github.kenglxn.qrgen</groupId>
<artifactId>javase</artifactId>
<version>2.6.0</version>
</dependency>
</dependencies>
Let’s create a method that generates a QR Code:
public static BufferedImage generateQRCodeImage(String barcodeText) throws Exception {
ByteArrayOutputStream stream = QRCode
.from(barcodeText)
.withSize(250, 250)
.stream();
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.
5.3. Using QR Code Generator
First, let’s add the QR Code generator dependency to the pom:
<dependency>
<groupId>io.nayuki</groupId>
<artifactId>qrcodegen</artifactId>
<version>1.8.0</version>
</dependency>
Next, let’s define a method that accepts a QR code message as an argument and generates a QR code image:
public static BufferedImage generateQrcode(String barcodeText) throws Exception {
QrCode qrCode = QrCode.encodeText(barcodeText, QrCode.Ecc.MEDIUM);
BufferedImage img = toImage(qrCode, 4, 10);
return img;
}
In the method above, we create a QrCode object by encoding the barcodeText with medium-level error correction capability. Then, we convert the QR code object to a BufferedImage by invoking the toImage() method. The toImage() method generates an image representation of the QR code with a defined scale and border dimensions.
The toImage() method is an overloaded method that allows us to specify the default value of the light and dark colors to represent the QR code:
public static BufferedImage toImage(QrCode qr, int scale, int border) {
return toImage(qr, scale, border, 0xFFFFFF, 0x000000);
}
Let’s see the second toImage() method:
public static BufferedImage toImage(QrCode qr, int scale, int border, int lightColor, int darkColor) {
Objects.requireNonNull(qr);
if (scale <= 0 || border < 0) {
throw new IllegalArgumentException("Value out of range");
}
if (border > Integer.MAX_VALUE / 2 || qr.size + border * 2L > Integer.MAX_VALUE / scale) {
throw new IllegalArgumentException("Scale or border too large");
}
BufferedImage result = new BufferedImage(
(qr.size + border * 2) * scale,
(qr.size + border * 2) * scale,
BufferedImage.TYPE_INT_RGB
);
for (int y = 0; y < result.getHeight(); y++) {
for (int x = 0; x < result.getWidth(); x++) {
boolean color = qr.getModule(x / scale - border, y / scale - border);
result.setRGB(x, y, color ? darkColor : lightColor);
}
}
return result;
}
The method above helps create a BufferedImage object with a set scale, border, and colors. It iterates over each pixel in the QR code and sets the color based on the corresponding module, using the lightColor and darkColor values.
5.4. Using Okapi Barcode Generator
To begin, let’s add the Okapi barcode generator dependency to the pom.xml:
<dependency>
<groupId>uk.org.okapibarcode</groupId>
<artifactId>okapibarcode</artifactId>
<version>0.4.6</version>
</dependency>
Let’s create a simple 2D barcode:
public static BufferedImage generateOkapiBarcode(String barcodeText) throws Exception {
Code128 barcode = new Code128();
barcode.setFontName("Monospaced");
barcode.setFontSize(16);
barcode.setModuleWidth(2);
barcode.setBarHeight(50);
barcode.setHumanReadableLocation(HumanReadableLocation.BOTTOM);
barcode.setContent(barcodeText);
int width = barcode.getWidth();
int height = barcode.getHeight();
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
Graphics2D g2d = image.createGraphics();
Java2DRenderer renderer = new Java2DRenderer(g2d, 1, Color.WHITE, Color.BLACK);
renderer.render(barcode);
g2d.dispose();
return image;
}
Here, we create a Code128 object representing the Code 128 barcode format. Then, we set various properties such as the font name, font size, module width, bar height, location of the human-readable text, and the barcode content.
Furthermore, we calculate the width and height of the barcode and create a BufferedImage object to hold the barcode image.
Finally, we create a Java2DRenderer object to render the barcode.
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.setColor(Color.WHITE);
graphics.fillRect(0, 0, matrixWidth, matrixHeight);
graphics.setColor(Color.BLACK);
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.setColor(Color.WHITE);
finalGraphics.fillRect(0, 0, finalWidth, finalHeight);
finalGraphics.setColor(Color.BLACK);
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:
@RestController
@RequestMapping("/barcodes")
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:
@Bean
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:
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:
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:
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:
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.