Créer des QR Codes avec Zxing et Java 2D, en 5 minutes

Thierry Leriche-Dessirier

Ce petit article s'intéresse à la génération de QR codes en Java. Nous allons voir qu'il est relativement simple de créer une matrice de modules à l'aide de Zxing puis d'en faire une jolie image avec Java 2D. Commentez ♪

- Titre : Créer des QR Codes avec Zxing et Java 2D, en 5 minutes

- Auteur : Thierry Leriche-Dessirier

- Parution : 3 septembre 2012

- Mise à jour : 27 février 2013

- Public visé :

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2011 Thierry Leriche-Dessirier. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- I-A. À propos

- I-B. Avant de commencer

- I-C. Mises à jour

- II. Découverte du projet d'exemple

- II-A. Télécharger, installer et importer le projet d'exemple

- II-B. Ce que fait déjà le projet d'exemple

- III. Action

- III-A. Maven

- III-B. Création des QR codes

- III-C. Un code en couleur

- III-D. un code avec redondance

- III-E. Voir la grille

- III-F. Des modules ronds

- III-G. Avec un dégradé de couleur

- III-H. Autres types de messages

- III-I. Réduction d'adresse

- IV. Conclusions

- V. Remerciements

- VI. Annexes

- VI-A. Des exemples de beaux QR codes

- VI-B. Liens

- VI-C. Liens personnels

- VI-D. Les fichiers importants en entier

I - Introduction

Un QR code est la représentation graphique d'un message. C'est une sorte de code-barre en deux dimensions. Ledit message peut contenir une URL, un e-mail, un numéro de téléphone, une vCard, etc. Dans la suite, nous nous intéresserons aux messages simples, les messages plus complexes n'étant que des extensions avec une syntaxe particulière.

La plupart des développeurs sont à l'aise avec les QR codes. Ils savent comment les scanner depuis leurs smartphones. De nombreuses « app » sont dédiées à cette fonctionnalité et on en possède souvent plusieurs. Les développeurs savent aussi comment créer des QR codes à l'aide des mêmes « app », des plugins Chrome ou Firefox, ou encore des sites web comme Unitag et SoQR.

QR code vers le site de Developpez.com

En revanche, quand il s'agit de générer soit même un QR code, c'est tout de suite moins drôle, car les algorithmes de calcul sont loin d'être triviaux et la génération d'images, un minimum jolies, n'est pas une compétence très répandue. On pourrait donc penser que la tâche est complexe, voire impossible sans une étude approfondie.

Dans cet article, nous allons d'abord voir comment générer une matrice de modules à l'aide de la bibliothèque Zxing. Dans un second temps, nous verrons comment dessiner des images (belles) à l'aide de Java 2D.

En première approche, un QR code simple ressemble à un carré rempli de gros pixels blancs et noirs. Ces « pixels noirs » sont les « modules » dont je parle plus haut.

I-A - À propos

Découvrir une technologie n'est pas chose facile. En aborder plusieurs d'un coup l'est encore moins. Partant de ce constat, cet article a été écrit pour aller à l'essentiel. Les points importants sont présentés dans le corps de l'article et les éléments secondaires, comme la gestion des exceptions, sont expliqués en annexes.

I-B - Avant de commencer

Pour écrire ce tutoriel, j'ai utilisé les éléments suivants :

- Java JDK 1.6.0_24-b07 ;

- Eclipse Indigo 3.7 JEE 64b ;

- Maven 3.0.3 ;

- Zxing 2.0.

I-C - Mises à jour

1er novembre : ajout du chapitre « Réduction d'adresse », qui propose une piste pour créer des QR codes plus simples à scanner.

27 février 2013 : ajout d'un lien dans les annexes vers l'article « Usages des codes à barres 2D, QR Codes et flashcodes », par Eric POMMEREAU.

II - Découverte du projet d'exemple

II-A - Télécharger, installer et importer le projet d'exemple

Pour commencer, je vous propose de télécharger le fichier Zip « qr-code-01.zip », contenant un projet Java-Maven d'exemple (vide) qui va nous servir de support pour les fonctionnalités présentées dans la suite de cet article.

Compilez le projet d'exemple et importez-le dans Eclipse (comme expliqué dans le tutoriel « Importer un projet Maven dans Eclipse en 5 minutes ») ou dans l'IDE de votre choix.

Pour suivre ce tutoriel, vous pouvez vous contenter de lire les codes proposés ci-dessous (codes complets en annexes) et de faire confiance aux captures d'écran.

II-B - Ce que fait déjà le projet d'exemple

Pour une fois, je vous propose un projet d'exemple qui ne fait rien. C'est un projet Maven vide qui va seulement servir d'enveloppe pour la suite.

III - Action

III-A - Maven

Durée estimée : 1 minute.

Pour utiliser Zxing, il faut ajouter une dépendance dans le fichier « pom.xml ».

Dépendance dans le pom.xml

<!-- zxing -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>2.0</version>
</dependency>

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

Puis relancer une installation Maven.

Commande Maven

mvn clean install eclipse:eclipse

En fonction des éléments déjà présents sur le disque dur, le résultat de l'installation Maven devrait ressembler à la trace suivante :

Commande Maven

C:\...\qr-code>mvn clean install eclipse:eclipse

[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building qr-code 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 11.025s
[INFO] Finished at: Thu Apr 30 20:59:22 CEST 2012
[INFO] Final Memory: 10M/53M
[INFO] ------------------------------------------------------------------------

On doit ensuite faire un refresh (touche F5) dans Eclipse pour faire apparaitre Zxing dans la liste des bibliothèques référencées.

III-B - Création des QR codes

Durée estimée : 2 minutes.

La génération d'un QR code commence toujours par le calcul de sa matrice, qu'on peut assimiler à un tableau de « 1 » et de « 0 » correspondant aux modules noirs et blancs.

Calcul de la matrice

public class SimpleQrcodeGenerator {

public static void main(String[] args) {
String data = "Je suis Thierry et je suis gentil.";
int size = 400;

// encode
BitMatrix bitMatrix = generateMatrix(data, size);
}

private static BitMatrix generateMatrix(String data, int size) {
BitMatrix bitMatrix = new QRCodeWriter().encode(data, BarcodeFormat.QR_CODE, size, size);
return bitMatrix;
}

...

Quand c'est fait, il suffit de dessiner les modules.

Dessin

public class SimpleQrcodeGenerator {

public static void main(String[] args) {

...
BitMatrix bitMatrix = generateMatrix(data, size);

String imageFormat = "png";
String outputFileName = "c:/code/qrcode-01." + imageFormat;

// write in a file
writeImage(outputFileName, imageFormat, bitMatrix);
}

private static void writeImage(String outputFileName, String imageFormat, BitMatrix bitMatrix)  {
FileOutputStream fileOutputStream = new FileOutputStream(new File(outputFileName));
MatrixToImageWriter.writeToStream(bitMatrix, imageFormat, fileOutputStream);
fileOutputStream.close();
}

...

Le code complet, avec la gestion des exceptions est donné en annexe.

Cela va donc générer l'image « qrcode-01.png » contenant le message « Je suis Thierry et je suis gentil ».

QR code : Je suis Thierry et je suis gentil.

Voici ce que ça donne lorsque je scanne ce code depuis mon iPhone :

Scan en cours sur l'iPhone

Après le scan

III-C - Un code en couleur

Durée estimée : 2 minutes.

C'est bien beau de savoir générer un code, mais ça n'est pas très sexy de se contenter de noir et de blanc. J'ai donc demandé aux développeurs d'Unitag de m'envoyer quelques morceaux de code pour ajouter un peu de couleur.

Je vais donc devoir un peu changer mon code, mais le principe reste le même, avec un peu de contrôles supplémentaires.

Calcul de la matrice

public class ColoredQrcodeGenerator {

public static void main(String[] args) {
String data = "Je suis Thierry et je suis gentil.";

// encode
ByteMatrix matrix = generateMatrix(data);
}

private static ByteMatrix generateMatrix(final String data) {
QRCode qr = new QRCode();
Encoder.encode(data, ErrorCorrectionLevel.L, qr);
ByteMatrix matrix = qr.getMatrix();
return matrix;
}

...

De nouveau, quand j'ai ma matrice, je peux lancer la génération de l'image. Cette fois nous allons procéder par étapes.

Dessin

public class ColoredQrcodeGenerator {

public static void main(String[] args) {

...
ByteMatrix matrix = generateMatrix(data);

int size = 400;
String imageFormat = "png";
String outputFileName = "c:/code/qrcode-01." + imageFormat;

// write in a file
writeImage(outputFileName, imageFormat, matrix, size);
}

private static void writeImage(String outputFileName, String imageFormat, ByteMatrix matrix, final int size) {
...
}

...

La suite de ce chapitre n'est pas simple : elle utilise les fonctionnalités de Java 2D (qui nécessitent un peu de concentration), alors qu'on utilisait la génération automatisée (mais aux options réduites) de Zxing dans le chapitre précédent.

On commence par générer la « forme » du QR code (à l'aide de Java 2D) : modules, quietzone, etc.

Area

public class ColoredQrcodeGenerator {

private static void writeImage(String outputFileName, String imageFormat, ByteMatrix matrix, final int size) {

// Java 2D Traitement de Area
// Futurs modules
Area a = new Area();
Area module = new Area(new Rectangle.Float(0, 0, 1, 1));

// Deplacement du module
AffineTransform at = new AffineTransform();
int width = matrix.getWidth();
for (int i = 0; i < width; i++) {
for (int j = 0; j < width; j++) {
if (matrix.get(j, i) == 1) {
// Ajout du module
a.add(module);
}
// Decalage a droite
at.setToTranslation(1, 0);
module.transform(at);
}

// Ligne suivante
at.setToTranslation(-width, 1);
module.transform(at);
}

// Agrandissement de l'Area pour le remplissage de l'image
double ratio = size / (double) width;

// Quietzone : 4 modules de bordures autour du QR Code (zone vide pour bien identifier le code dans la page imprimee)
double adjustment = width / (double) (width + 8);
ratio = ratio * adjustment;
at.setToTranslation(4, 4);
a.transform(at);

// On agrandit le tour a la taille souhaitee.
at.setToScale(ratio, ratio);
a.transform(at);
}

...

Puis on peut passer à l'étape de « coloriage » des modules ajoutés dans la boucle (cf. code source précédent).

Dessin

public class ColoredQrcodeGenerator {

private static void writeImage(String outputFileName, String imageFormat, ByteMatrix matrix, final int size) {

// Java 2D Traitement de Area
...

// Java 2D Traitement l'image
BufferedImage im = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB);
Graphics2D g = (Graphics2D) im.getGraphics();

// Modules verts
Color vert = new Color(0xAFC828);
g.setPaint(vert);

g.setBackground(new Color(0xFFFFFF));

// Fond blanc
g.clearRect(0, 0, size, size);

// Remplissage des modules
g.fill(a);
}

...

Enfin, on peut écrire le fichier sur le disque.

Ecriture sur le disque

public class ColoredQrcodeGenerator {

private static void writeImage(String outputFileName, String imageFormat, ByteMatrix matrix, final int size) {

// Java 2D Traitement de Area
...

// Java 2D Traitement l'image
...

// Ecriture sur le disque
File f = new File(outputFileName);
f.setWritable(true);
ImageIO.write(im, imageFormat, f);
f.createNewFile();
}

...

Ça me donne une belle image verte. Je vous laisse trouver la couleur qui vous convient le mieux…

QR code vert

III-D - un code avec redondance

Durée estimée : 30 secondes.

Une des particularités des QR codes est qu'ils restent lisibles même lorsqu'ils sont déchirés ou abîmés, un peu comme un CD qui reste utilisable lorsqu'il est rayé. Pour cela, la « norme » des QR codes implique que les données soient répliquées. Elle définit quatre niveaux de réplication : L (7 %), M (15 %), Q (25 %) et H (30 %).

Bien entendu, plus le niveau de réplication est élevé et plus gros devra être le QR code généré pour tout contenir.

Ici, une simple adaptation du code proposé au chapitre précédent devrait suffire.

Calcul de la matrice

public class LevelColoredQrcodeGenerator {

public static void main(String[] args) {
String data = "Je suis Thierry et je suis gentil.";
ErrorCorrectionLevel level = ErrorCorrectionLevel.Q;

// encode
ByteMatrix matrix = generateMatrix(data, level);

...
}

private static ByteMatrix generateMatrix(String data, ErrorCorrectionLevel level) {
final QRCode qr = new QRCode();
Encoder.encode(data, level, qr);
final ByteMatrix matrix = qr.getMatrix();
return matrix;
}

...

Par défaut, Zxing génère des QR codes avec le niveau « L » (low). Dans l'exemple j'ai utilisé le niveau « Q » (quality) et on constate donc une plus grande densité des modules. Pour que ça saute aux yeux, j'ai utilisé du « bleu mauve » pour cette version.

QR code vert avec le niveau L

QR code bleu mauve avec le niveau Q

Si on avait utilisé le niveau « H » (high), la différence aurait été encore plus flagrante.

III-E - Voir la grille

Durée estimée : 30 secondes.

Pour continuer, disons qu'on souhaite voir le maillage des modules. C'est relativement simple : il suffit de dessiner des modules qui n'occupent pas toute la place disponible dans la « case ».

Modules plus petits laissant voir la grille

public class GridQrcodeGenerator {

private static void writeImage(String outputFileName, String imageFormat, ByteMatrix matrix, int size) {

...
// Area module = new Area(new Rectangle.Float(0, 0, 1, 1));
Area module = new Area(new Rectangle2D.Float(0.05f, 0.05f, 0.9f, 0.9f));

...
}

...

QR code bleu mauve

QR code rouge avec grille

III-F - Des modules ronds

Durée estimée : 30 secondes.

Continuons sur notre lancée. Cette fois, disons que nous voulons des modules ronds.

Modules ronds

public class RoundedQrcodeGenerator {

private static void writeImage(String outputFileName, String imageFormat, ByteMatrix matrix, int size) {

...
//Area module = new Area(new Rectangle2D.Float(0.05f, 0.05f, 0.9f, 0.9f));
Area module = new Area(new RoundRectangle2D.Float(0, 0, 0.9f, 0.9f, 1f, 1f));

...
}

...

Juste pour rigoler, j'ai fait des modules ronds et blancs sur fond bleu. On a aussi le droit de changer la couleur du fond puisque c'est la différence de contraste qui compte. Toutefois tous les scanners ne savent pas forcément lire les QR codes inversés.

QR code rouge avec grille

QR code avec des modules ronds

Avec le fond bleu, on voit bien la « quietzone » de quatre modules autour du QR code.

III-G - Avec un dégradé de couleur

Durée estimée : 30 secondes.

Pour finir avec un dernier effet sympa et simple, je vous propose d'utiliser un dégradé de couleur.

Dégradé de couleurs

public class TransColoredQrcodeGenerator {

private static void writeImage(String outputFileName, String imageFormat, ByteMatrix matrix, int size) {

...

// Color couleur1 = new Color(0xFFFFFF);
// g.setPaint(couleur1);
Color couleur1 = new Color(0xAFC828);
Color couleur2 = new Color(0x606640);
// Debut et fin du gradient
float[] fractions = { 0.0f, 1.0f };
Color[] colors = { couleur1, couleur2 };
g.setPaint(new RadialGradientPaint(size / 2, size / 2, size / 2, fractions, colors));

...
}

...

QR code avec un dégradé de couleurs

III-H - Autres types de messages

La plupart du temps, on va générer des QR codes pour les faire « pointer » vers des sites Web. Pour cela, il suffit d'encoder un message contenant l'URL du-dit site.

Dégradé de couleurs

public static void main(String[] args) {
// String data = "Je suis Thierry et je suis gentil.";
String data = "http://www.developpez.com";

...

QR code vers le site www.developpez.com

Pour générer des QR codes permettant d'envoyer des SMS, des e-mails, d'appeler un numéro de téléphone, d'enregistrer des vCards (etc.), il y a une syntaxe particulière que je vous laisse découvrir sur le site d'Unitag ou sur la page dédiée aux contenus chez Zxing. Voici néanmoins quelques exemples simples :

Dégradé de couleurs

public static void main(String[] args) {
// String data = "Je suis Thierry et je suis gentil.";
// String data = "http://www.developpez.com";

// Envoie de SMS
String data = "sms:+33312345678:bonjour...";

// Envoie d'email
String data = "mail:jean.dupond@google.com?subject=Coucou&body=Bonjour...";

...

III-I - Réduction d'adresse

Il y a un point auquel on ne pense jamais, c'est de réduire la taille du message contenu dans le QR code. En effet, plus le message est long et plus il faudra de modules pour le représenter. Sur une surface d'impression donnée, cela se traduit par des modules plus petits et donc plus difficiles à scanner.

C'est difficile lorsqu'il s'agit d'une phrase, car on ne va pas enlever des mots. Par contre il existe des techniques pour les URL. Mais avant ça, partons d'un constat. Il faut 95 caractères pour représenter l'adresse de cet article en ligne : https://thierry-leriche-dessirier.developpez.com/tutoriels/java/creer-qrcode-zxing-java2d-5-min/

En utilisant les programmes présentés ci-dessus, cela nous donne le QR code orange suivant :

QR code orange : 95 caractères

Plusieurs sites, dont bit.ly, proposent des services de réduction de la taille des adresses. Cela permet d'arriver sur cet article grâce à l'URL http://bit.ly/V2AtCZ qui ne comporte que 19 caractères. Le gain est incontestable.

Cette seconde URL nous permet de créer le QR code rose suivant :

QR code rose : 19 caractères

En mettant les deux QR codes à côté, on devine que le second sera bien plus facile à scanner.

QR code orange : 95 caractères

QR code rose : 19 caractères

Et voilà…

IV - Conclusions

Comme on vient de le voir, on peut générer des QR codes très facilement à l'aide de la bibliothèque Zxing et un peu de dessin à l'aide de Java 2D. Les possibilités sont nombreuses, mais réclament un talent de graphiste qui me manque. Vous trouverez des outils sympas sur le Web et j'espère qu'ils vous donneront des idées.

Dans un prochain article, je m'attarderai sur les algorithmes liés aux QR codes, notamment pour le calcul de la matrice, des masques, des mécanismes de correction d'erreur, etc. Mais pour le moment, je vous laisse déjà vous amuser avec tout ça.

Le code final de ce tutoriel est disponible dans le fichier ZIP qr-code-02.zip.

Vos retours nous aident à améliorer nos publications. N'hésitez donc pas à commenter cet article sur le forum : Commentez

Retrouvez mes autres tutoriels rapides sur developpez.com à l'adresse https://thierry-leriche-dessirier.developpez.com/#page_articles

V - Remerciements

J'adresse des remerciements particuliers aux équipes d'Unitag, sans qui cet article n'aurait jamais vu le jour. Unitag est une société française, basée à Toulouse et leader dans le domaine de la génération et la personnalisation des QR Codes. Leur site Web propose de nombreux outils gratuits (et performants) que viennent compléter des offres professionnelles intéressantes (et pas chères).

Et en plus, je tiens à remercier, en tant qu'auteur du tutoriel, toutes les personnes qui m'ont aidé et soutenu. Je pense tout d'abord à mes collègues qui subissent mes questions au quotidien, mais aussi à mes contacts et amis du Web, dans le domaine de l'informatique ou non, qui m'ont fait part de leurs remarques et critiques. Bien entendu, je n'oublie pas l'équipe de developpez.com qui m'a guidé dans la rédaction de cet article et m'a aidé à le corriger et le faire évoluer, principalement sur le forum.

Plus particulièrement j'adresse mes remerciements à Mickael Baron (keulkeul), Sébastien Germez (FirePrawn), Marc (Gueritarish) et mlny84.

VI - Annexes

VI-A - Des exemples de beaux QR codes

Voici une petite sélection de QR codes design que j'ai simplement cherché sur Google.. Je les trouve beaux, mais ça n'engage que moi.

Quand on scanne des QR codes (à l'aide d'un iPhone par exemple) directement sur l'écran et de trop près, on voit apparaitre des lignes correspondant à la matrice des pixels du LCD. Il est donc possible que ces QR codes ne soient pas lisibles sur tous les écrans. En revanche ils devraient être lisibles facilement une fois imprimés, même sur des mauvaises imprimantes, même en noir et blanc.

Ces images sont la propriété de leurs auteurs. Je les propose ici dans le cadre du « fair use ». Contactez-moi pour les supprimer ou ajouter des références.

VI-B - Liens

Unitag : http://www.unitag.fr

QR Code vers Unitag

QR Code design vers Unitag

QR Dress Code : http://www.qrdresscode.com

QR Code vers QR Dress Code

Zxing : http://code.google.com/p/zxing/

Je vous conseille aussi la lecture du très bon article de Eric POMMEREAU, intitulé « Usages des codes à barres 2D, QR Codes et flashcodes », dans lequel il explique les différents usages intéressants.
https://eric-pommereau.developpez.com/tutoriels/general/usages-codes-barres-2d/

VI-C - Liens personnels

Retrouvez ma page et mes autres articles sur developpez.com à l'adresse https://thierry-leriche-dessirier.developpez.com/#page_articles

QR Code vers mes articles

Ajoutez-moi à vos contacts à l'aide du QR Code suivant :

QR Code contenant ma vCard

Suivez-moi sur Twitter : @thierryleriche

@thierryleriche

VI-D - Les fichiers importants en entier

SimpleQrcodeGenerator.java

package com.dvp.tutoriel.qrcode;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;

public class SimpleQrcodeGenerator {

private static BitMatrix generateMatrix(final String data, final int size) throws WriterException {
final BitMatrix bitMatrix = new QRCodeWriter().encode(data, BarcodeFormat.QR_CODE, size, size);
return bitMatrix;
}

private static void writeImage(final String outputFileName, final String imageFormat, final BitMatrix bitMatrix) throws FileNotFoundException,
IOException {
final FileOutputStream fileOutputStream = new FileOutputStream(new File(outputFileName));
MatrixToImageWriter.writeToStream(bitMatrix, imageFormat, fileOutputStream);
fileOutputStream.close();
}

/**
* @param args
*/
public static void main(String[] args) {
System.out.println("SimpleQrcodeGenerator DEBUT");

try {
final String data = "Je suis Thierry et je suis gentil.";
final String imageFormat = "png";
final String outputFileName = "c:/code/qrcode-01." + imageFormat;
final int size = 400;

// encode
final BitMatrix bitMatrix = generateMatrix(data, size);

// write in a file
writeImage(outputFileName, imageFormat, bitMatrix);

System.out.println("SimpleQrcodeGenerator FIN");

} catch (Exception e) {
e.printStackTrace();
}
}
}

GridQrcodeGenerator.java

package com.dvp.tutoriel.qrcode;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

import javax.imageio.ImageIO;

import com.google.zxing.WriterException;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.google.zxing.qrcode.encoder.ByteMatrix;
import com.google.zxing.qrcode.encoder.Encoder;
import com.google.zxing.qrcode.encoder.QRCode;

public class GridQrcodeGenerator {
private static ByteMatrix generateMatrix(final String data, final ErrorCorrectionLevel level) throws WriterException {
final QRCode qr = new QRCode();
Encoder.encode(data, level, qr);
final ByteMatrix matrix = qr.getMatrix();
return matrix;
}

private static void writeImage(final String outputFileName, final String imageFormat, final ByteMatrix matrix, final int size)
throws FileNotFoundException, IOException {

/**
* Java 2D Traitement de Area
*/
Area a = new Area(); // les futurs modules
Area module = new Area(new Rectangle2D.Float(0.05f, 0.05f, 0.9f, 0.9f));

AffineTransform at = new AffineTransform(); // pour déplacer le module
int width = matrix.getWidth();
for (int i = 0; i < width; i++) {
for (int j = 0; j < width; j++) {
if (matrix.get(j, i) == 1) {
a.add(module); // on ajoute le module
}
at.setToTranslation(1, 0); // on décale vers la droite
module.transform(at);
}
at.setToTranslation(-width, 1); // on saute une ligne on revient au
// début
module.transform(at);
}

// agrandissement de l'Area pour le remplissage de l'image
double ratio = size / (double) width;
// il faut respecter la Quietzone : 4 modules de bordures autour du QR
// Code
double adjustment = width / (double) (width + 8);
ratio = ratio * adjustment;

at.setToTranslation(4, 4); // à cause de la quietzone
a.transform(at);

at.setToScale(ratio, ratio); // on agrandit
a.transform(at);

/**
* Java 2D Traitement l'image
*/
BufferedImage im = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB);
Graphics2D g = (Graphics2D) im.getGraphics();
Color couleur1 = new Color(0xFF0000);
g.setPaint(couleur1);

g.setBackground(new Color(0xFFFFFF));
g.clearRect(0, 0, size, size); // pour le fond blanc
g.fill(a); // remplissage des modules

// Ecriture sur le disque
File f = new File(outputFileName);
f.setWritable(true);
try {
ImageIO.write(im, imageFormat, f);
f.createNewFile();
} catch (Exception e) {
}

}

/**
* @param args
*/
public static void main(String[] args) {
System.out.println("GridQrcodeGenerator DEBUT");

try {
final String data = "Je suis Thierry et je suis gentil.";
final String imageFormat = "png";
final String outputFileName = "c:/code/qrcode-04." + imageFormat;
final int size = 400;
final ErrorCorrectionLevel level = ErrorCorrectionLevel.Q;

// encode
final ByteMatrix matrix = generateMatrix(data, level);

// write in a file
writeImage(outputFileName, imageFormat, matrix, size);

System.out.println("GridQrcodeGenerator FIN");

} catch (Exception e) {
e.printStackTrace();
}
}
}

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.tle.qrcodegen</groupId>
<artifactId>qrcode-generator</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>

<name>qrcode-generator</name>
<description>TODO</description>
<url>http://www.icauda.com</url>

<licenses>
<license>
<name>Copyright ©1995-2012 icauda.com et Copyright ©2011 Developpez.com</name>
<comments>Les sources présentés sur cette page sont libres de droits, et vous pouvez les utiliser à votre [..]</comments>
</license>
</licenses>

<developers>
<!-- Thierry -->
<developer>
<name>Thierry Leriche-Dessirier</name>
<roles>
<role>Developper</role>
</roles>
<organization>ICAUDA</organization>
</developer>

</developers>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.6</java.version>
<maven-compiler-plugin.version>2.3.1</maven-compiler-plugin.version>
<junit.version>4.8.2</junit.version>

<log4j.version>1.2.13</log4j.version>
<guava.version>12.0</guava.version>
<zxing-core.version>2.0</zxing-core.version>

</properties>

<dependencyManagement>
<dependencies>
<!-- JUnit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>

<!-- log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>

<!-- Guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>

<!-- zxing -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>${zxing-core.version}</version>
</dependency>

<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>${zxing-core.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>

<!-- Guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>

<!-- zxing -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
</dependency>

<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
</dependency>
</dependencies>

<build>
<finalName>qrcode-generator</finalName>

<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>