Free Online Courses for Software Developers - MrBool
× Please, log in to give us a feedback. Click here to login
×

You must be logged to download. Click here to login

×

MrBool is totally free and you can help us to help the Developers Community around the world

Yes, I'd like to help the MrBool and the Developers Community before download

No, I'd like to download without make the donation

×

MrBool is totally free and you can help us to help the Developers Community around the world

Yes, I'd like to help the MrBool and the Developers Community before download

No, I'd like to download without make the donation

Generating QR Codes with ZXing Java Library

In this article we will see how to implement QR Code generation using ZXing Java library and save it as an image file.

QR Codes are the new way to process information along with social media, mobile apps and electronic applications that run in all kinds of devices. When we talk about Java, specifically embedded environments, there are no famous options we can use to implement this type of feature.

ZXing is an open-source, multi-format 1D/2D barcode image processing library implemented in Java, with ports to other languages like Android, C++, Objective C, Runy, Python and .NET. It offers a whole suite of APIs and classes that will allow you to develop code to generate and decode QR codes

Starting the project

In this project, we will use the ZXing library (see Links section) to perform text conversion to image, more specifically in QRcode. This can be found in the downloads section of this article.

The entire project will be simple and will aim to show the conversion quickly without using design patterns,etc.. We will create only a form that will have two fields: A text field for the user to type the text to be converted and a button to generate the image in the directory as the user wishes.

In Figure 1 we see how our form will be.

Figure 1. Form to generate QRCODE

As we explained just above, the form is simple and has a logic only on the "Generate QRCode" button that we will see forward. If you are using NetBeans to create the form, you may enjoy the listing below, because it shows a ".form" file to create the form in NetBeans.

Listing 1. FQrCodeGenerator.form in NetBeans

<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
    <Properties>
        <Property name="defaultCloseOperation" type="int" value="3"/>
    </Properties>
    <SyntheticProperties>
        <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
        <SyntheticProperty name="generateCenter" type="boolean" value="false"/>
    </SyntheticProperties>
    <AuxValues>
        <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
        <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
        <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
        <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
        <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
        <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
        <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
        <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
        <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
    </AuxValues>
    <Layout>
        <DimensionLayout dim="0">
            <Group type="103" groupAlignment="0" attributes="0">
                <Group type="102" attributes="0">
                    <EmptySpace max="-2" attributes="0"/>
                    <Group type="103" groupAlignment="0" attributes="0">
                        <Component id="jButtonGerar" alignment="0" min="-2" max="-2" attributes="0"/>
                        <Component id="jLabel1" alignment="0" min="-2" max="-2" attributes="0"/>
                        <Component id="jTextTexto" alignment="0" min="-2" pref="338" max="-2" attributes="0"/>
                    </Group>
                    <EmptySpace pref="50" max="32767" attributes="0"/>
                </Group>
            </Group>
        </DimensionLayout>
        <DimensionLayout dim="1">
            <Group type="103" groupAlignment="0" attributes="0">
                <Group type="102" alignment="1" attributes="0">
                    <EmptySpace min="-2" pref="34" max="-2" attributes="0"/>
                    <Component id="jLabel1" min="-2" max="-2" attributes="0"/>
                    <EmptySpace max="-2" attributes="0"/>
                    <Component id="jTextTexto" min="-2" max="-2" attributes="0"/>
                    <EmptySpace pref="175" max="32767" attributes="0"/>
                    <Component id="jButtonGerar" min="-2" max="-2" attributes="0"/>
                    <EmptySpace max="-2" attributes="0"/>
                </Group>
            </Group>
        </DimensionLayout>
    </Layout>
    <SubComponents>
        <Component class="javax.swing.JButton" name="jButtonGerar">
            <Properties>
                <Property name="text" type="java.lang.String" value="Generate QRCode"/>
            </Properties>
            <Events>
                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonGerarActionPerformed"/>
            </Events>
        </Component>
        <Component class="javax.swing.JLabel" name="jLabel1">
            <Properties>
                <Property name="text" type="java.lang.String" value="Text to be encoded"/>
            </Properties>
        </Component>
        <Component class="javax.swing.JTextField" name="jTextTexto"></Component>
    </SubComponents>
</Form>

So far, we have our structured form, but we need to start adding content to it. First, let's see Listing 2, which contains the complete code of FQrCodeGenerator.java class.

Listing 2. FQrCodeGenerator.java class

package com.mrbool.zxing;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Hashtable;

import javax.imageio.ImageIO;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

/**
 * @author MrBool
 */
public class FQrCodeGenerator extends javax.swing.JFrame {
    
	private static final long serialVersionUID = 1L;
	private static final String nomeQrCodeGerado = "qrcodeimage";
	private static final String formatoQrCodeGerado = "png";

	/**
	 * Creates new form FQrCodeGenerator
	 */
	public FQrCodeGenerator() {
		initComponents();
	}

	/**
	 * This method is called from within the constructor to initialize the form.
	 * WARNING: Do NOT modify this code. The content of this method is always
	 * regenerated by the Form Editor.
	 */
	private void initComponents() {
		jButtonGerar = new javax.swing.JButton();
		jLabel1 = new javax.swing.JLabel();
		jTextTexto = new javax.swing.JTextField();

		setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

		jButtonGerar.setText("Generate QRCode");
		jButtonGerar.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				jButtonGerarActionPerformed(evt);
			}
		});

		jLabel1.setText("Text to be encoded:");

		javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
		getContentPane().setLayout(layout);
		layout.setHorizontalGroup(
		layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
			.addGroup(layout.createSequentialGroup()
			.addContainerGap()
			.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
			.addComponent(jButtonGerar)
			.addComponent(jLabel1)
			.addComponent(jTextTexto, javax.swing.GroupLayout.PREFERRED_SIZE, 338, javax.swing.GroupLayout.PREFERRED_SIZE))
			.addContainerGap(50, Short.MAX_VALUE)));
		layout.setVerticalGroup(
		layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
			.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
			.addGap(34, 34, 34)
			.addComponent(jLabel1)
			.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
			.addComponent(jTextTexto, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
			.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 175, Short.MAX_VALUE)
			.addComponent(jButtonGerar)
			.addContainerGap()));
		pack();
	} // </editor-fold>//GEN-END:initComponents

	private void jButtonGerarActionPerformed(java.awt.event.ActionEvent evt) { //GEN-FIRST:event_jButtonGerarActionPerformed
		gerarQrCode();
	} //GEN-LAST:event_jButtonGerarActionPerformed

	public void gerarQrCode() {
		if (jTextTexto.getText() == null || jTextTexto.getText().isEmpty()) {
			JOptionPane.showMessageDialog(this, "The text to be encoded is required");
		} else {
			JFileChooser chooser = new JFileChooser();
			chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
			if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
				String path = chooser.getSelectedFile().getAbsolutePath();
				gerarComZXing(path, jTextTexto.getText());
			}
		}
	}

	private void gerarComZXing(String path, String texto) {
		try {
			File myFile = new File(path + "/" + nomeQrCodeGerado + "." + formatoQrCodeGerado);
			Hashtable < EncodeHintType, ErrorCorrectionLevel > hintMap = new Hashtable < EncodeHintType, ErrorCorrectionLevel > ();
			hintMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
			QRCodeWriter qrCodeWriter = new QRCodeWriter();
			BitMatrix byteMatrix = qrCodeWriter.encode(texto, BarcodeFormat.QR_CODE, 100, 100, hintMap);
			int CrunchifyWidth = byteMatrix.getWidth();
			BufferedImage image = new BufferedImage(CrunchifyWidth, CrunchifyWidth,
			BufferedImage.TYPE_INT_RGB);
			image.createGraphics();

			Graphics2D graphics = (Graphics2D) image.getGraphics();
			graphics.setColor(Color.WHITE);
			graphics.fillRect(0, 0, CrunchifyWidth, CrunchifyWidth);
			graphics.setColor(Color.BLACK);

			for (int i = 0; i < CrunchifyWidth; i++) {
				for (int j = 0; j < CrunchifyWidth; j++) {
					if (byteMatrix.get(i, j)) {
						graphics.fillRect(i, j, 1, 1);
					}
				}
			}
			ImageIO.write(image, formatoQrCodeGerado, myFile);
			JOptionPane.showMessageDialog(this, "QRCode generated in: " + myFile.getAbsolutePath());
		} catch (WriterException e) {
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * @param args the command line arguments
	 */
	public static void main(String args[]) {
		/* Set the Nimbus look and feel */
		//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
		/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
		 * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
		 */
		try {
			for (javax.swing.UIManager.LookAndFeelInfo info: javax.swing.UIManager.getInstalledLookAndFeels()) {
				if ("Nimbus".equals(info.getName())) {
					javax.swing.UIManager.setLookAndFeel(info.getClassName());
					break;
				}
			}
		} catch (ClassNotFoundException ex) {
			java.util.logging.Logger.getLogger(FQrCodeGenerator.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
		} catch (InstantiationException ex) {
			java.util.logging.Logger.getLogger(FQrCodeGenerator.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
		} catch (IllegalAccessException ex) {
			java.util.logging.Logger.getLogger(FQrCodeGenerator.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
		} catch (javax.swing.UnsupportedLookAndFeelException ex) {
			java.util.logging.Logger.getLogger(FQrCodeGenerator.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
		}
		//</editor-fold>

		/* Create and display the form */
		java.awt.EventQueue.invokeLater(new Runnable() {
			public void run() {
				new FQrCodeGenerator().setVisible(true);
			}
		});
	}

	// Variables declaration - do not modify//GEN-BEGIN:variables
	private javax.swing.JButton jButtonGerar;
	private javax.swing.JLabel jLabel1;
	private javax.swing.JTextField jTextTexto;
	// End of variables declaration//GEN-END:variables
}

Early in the declaration, we have two important variables. With these two variables we can identify which will be the name and format of the generated image. In our case, it will always be "qrcodeimage.png", but we can leave that dynamic information available to the user, which would add more logic and complexity to our form.

Next, we have the class constructor that calls the initComponents() method. This method performs the initialization of all the graphic components in addition to the provision of these on the screen.

The "jButtonGenerate" has a method called jButtonGerarActionPerformed() button, which is called every time a click is made. Therefore, clicking this button makes the call to our generateQrCode() method, which is what we really want.

The generateQrCode() method handles all logic necessary to create the QRcode from the text sent as parameter. We could put this method in a utility class for it not stay in the form, so we would leave our system with less engagement and more reusability, but this is not the focus of our article.

The generateQrCode() method first checks if the text entered is valid, i.e., if it is not empty or null. If it is valid, we use theJFileChooser class to show a window where the user can choose the place the image will be saved:

if (jTextTexto.getText() == null || jTextTexto.getText().isEmpty()) {
	JOptionPane.showMessageDialog(this, "The text to be enconded is required");
} else {
	JFileChooser chooser = new JFileChooser();
	chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
}

The JFileChooser has a method called "setFileSelectionMode()", where we define that the user can choose only directories, which is what we need. There is no reason to make a choiceonce no files will be open.

When we call the showOpenDialog() method of JFileChooser(), it returns an integer indicating what was done in the window, and what matters to us is that "Open" button has been clicked. For that, we use the constant JFileChooser.APPROVE_OPTION:

if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
	String path = chooser.getSelectedFile().getAbsolutePath();
	gerarComZXing(path, jTextTexto.getText());
}

By clicking the "Open" button, the condition is satisfied and we capture the path he selected, storing this in the "path" variable. The generateWithZXing() method works directly with the ZXing library receiving the information "path" (path where the image will be saved) and "text" (value that contains the image).

Let us understand generateWithZXingmethod in parts:

File myFile = new File(path + "/" + QrCodeGeneratedName + "." + formatoQrCodeGerado);
Hashtable < EncodeHintType, ErrorCorrectionLevel > hintMap = new Hashtable < EncodeHintType, ErrorCorrectionLevel > ;
();
hintMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
QRCodeWriter qrCodeWriter = new QRCodeWriter();

At this time, we only did the variables initialization for subsequent generation of QRCode. We need the File that will point to the exact location where the image will be recorded and for this we use two variables that soon we mentioned at the article.

The variable "hintMap" describes a Map of parameters that QRCodeWriter gets to encode our text to image. In our case, we only pass value one, which is referred to by "ERROR_CONNECTION" constant.

We created the qrCodeWriter variable and then immediately started coding the text:

BitMatrix byteMatrix = qrCodeWriter.encode(texto,BarcodeFormat.QR_CODE, 100, 100, hintMap);

The encode() method gets the text we want to code with the format we want (QR_CODE in our case), the size X, Y (in this case 100, 100) and Map parameters. The return is an object of type BitMatrix that can be used for conversion into BufferedImage and later recording on user-selected directory.

int CrunchifyWidth = byteMatrix.getWidth();
BufferedImage image = new BufferedImage(CrunchifyWidth, CrunchifyWidth, BufferedImage.TYPE_INT_RGB);
image.createGraphics();

Graphics2D graphics = (Graphics2D) image.getGraphics();
graphics.setColor(Color.WHITE);
graphics.fillRect(0, 0, CrunchifyWidth, CrunchifyWidth);
graphics.setColor(Color.BLACK);

for (int i = 0; i < CrunchifyWidth; i++) {
	for (int j = 0; j < CrunchifyWidth; j++) {
		if (byteMatrix.get(i, j)) {
			graphics.fillRect(i, j, 1, 1);
		}
	}
}
ImageIO.write(image, formatoQrCodeGerado, myFile);
} catch (WriterException e) {
	e.printStackTrace();
} catch (IOException e) {
	// TODO Auto-generated catch block
	e.printStackTrace();
}

We used the ImageIO.write() with the desired image and the path where it will be saved. You must enclose the try-catch block with WriterException exceptions due to the ZXing, and IOException for the disk image writing.

Thus, we have the image in QRcode generated through the text described by the user (Figure 2), which may be read by any QRCode reader software, redirecting to a predefined URL or just showing a static text.

Figure 2 . QRcode generated via example

Conclusion

The idea of this article was to show a quick and good way to generate QRcode through any information entered by the user with a simple form. You can adapt this logic for a utility or Helper from your system, thus making its recycling at various points.

Links

Official ZXing GitHub page

https://github.com/zxing/zxing



Julio is a System analyst and enthusiast of Information Technology. He is currently a developer at iFactory Solutions company, working in the development of strategic systems, is also a JAVA instructor. He has knowledge and experi...

What did you think of this post?
Services
[Close]
To have full access to this post (or download the associated files) you must have MrBool Credits.

  See the prices for this post in Mr.Bool Credits System below:

Individually – in this case the price for this post is US$ 0,00 (Buy it now)
in this case you will buy only this video by paying the full price with no discount.

Package of 10 credits - in this case the price for this post is US$ 0,00
This subscription is ideal if you want to download few videos. In this plan you will receive a discount of 50% in each video. Subscribe for this package!

Package of 50 credits – in this case the price for this post is US$ 0,00
This subscription is ideal if you want to download several videos. In this plan you will receive a discount of 83% in each video. Subscribe for this package!


> More info about MrBool Credits
[Close]
You must be logged to download.

Click here to login