Create QR-Code in vector image
You can use Apache Batik
instead of JFreeSVG
if you want a more liberate license. That makes especially sense when you use Apache FOP
that includes Apache Batik
as a transient dependency.
Here a tweaked version. Credits for the idea and the original code goes to David Gilbert.
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import org.apache.batik.anim.dom.SVGDOMImplementation;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.svg.SVGDocument;
import java.awt.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
public class QRCodesBatik {
public static void main(String[] args) throws WriterException, IOException {
QRCodeWriter qrCodeWriter = new QRCodeWriter();
BitMatrix bitMatrix = qrCodeWriter.encode("https://xmlgraphics.apache.org/batik/",
BarcodeFormat.QR_CODE, 800, 800);
// Create a document with the appropriate namespace
DOMImplementation domImpl = SVGDOMImplementation.getDOMImplementation();
SVGDocument document = (SVGDocument) domImpl.createDocument(SVGDOMImplementation.SVG_NAMESPACE_URI, "svg", null);
// Create an instance of the SVG Generator
org.apache.batik.svggen.SVGGraphics2D g2 = new org.apache.batik.svggen.SVGGraphics2D(document);
// draw onto the SVG Graphics object
g2.setColor(Color.BLACK);
for (int xIndex = 0; xIndex < bitMatrix.getWidth(); xIndex = xIndex + bitMatrix.getRowSize()) {
for (int yIndex = 0; yIndex < bitMatrix.getWidth(); yIndex = yIndex + bitMatrix.getRowSize()) {
if (bitMatrix.get(xIndex, yIndex)) {
g2.fillRect(xIndex, yIndex, bitMatrix.getRowSize(), bitMatrix.getRowSize());
}
}
}
try (Writer out = new OutputStreamWriter(new FileOutputStream(new File("qrtest.svg")), "UTF-8")) {
g2.stream(out, true);
}
}
}
The easiest way I found was to create a PDF with iText and then convert the resulting PDF to EPS or SVG. Here is the code to create the PDF:
@Test
public void testQRtoPDF() throws WriterException, FileNotFoundException, DocumentException, UnsupportedEncodingException {
final int s = 600;
int r = 1;
Charset charset = Charset.forName( "UTF-8" );
CharsetEncoder encoder = charset.newEncoder();
byte[] b = null;
try {
// Convert a string to UTF-8 bytes in a ByteBuffer
ByteBuffer bbuf = encoder.encode( CharBuffer.wrap(
"1éöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùò1" +
"2éöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùò2" +
"3éöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùò3" +
"4éöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùò4" +
"5éöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùò5" +
"6éöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùòïëéöà äèüùò6" ) );
b = bbuf.array();
} catch ( CharacterCodingException e ) {
System.out.println( e.getMessage() );
}
String content = new String( b, "UTF-8" );
QRCodeWriter qrCodeWriter = new QRCodeWriter();
Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>( 2 );
hints.put( EncodeHintType.CHARACTER_SET, "UTF-8" );
BitMatrix qrCode = qrCodeWriter.encode( content, BarcodeFormat.QR_CODE, s, s, hints );
Document doc = new Document( new Rectangle( s, s ) );
PdfWriter pdfWriter = PdfWriter.getInstance( doc, new FileOutputStream( "qr-code.pdf" ) );
doc.open();
PdfContentByte contentByte = pdfWriter.getDirectContent();
contentByte.setColorFill( BaseColor.BLACK );
boolean d = false;
for ( int x = 0; x < qrCode.getWidth(); x += r ) {
for ( int y = 0; y < qrCode.getHeight(); y += r ) {
if ( qrCode.get( x, y ) ) {
contentByte.rectangle( x, s - y, r, r );
contentByte.fill();
contentByte.stroke();
}
}
}
doc.close();
}
I then use image magic for the conversion. Like so:
convert qr-code.pdf qr-code.eps
the same can NOT be done for svg
convert qr-code.pdf qr-code.svg
this does not work
I tested this code with some long content and it worked with up to 600 characters. This is probably down to the precision of either camera on the phone or screen.
I hope this helps someone
You can even do it only with zxing withou additional libraries:
QRCodeWriter qrCodeWriter = new QRCodeWriter();
Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
hints.put(EncodeHintType.CHARACTER_SET, StandardCharsets.UTF_8.name());
BitMatrix bitMatrix = qrCodeWriter.encode(payload, BarcodeFormat.QR_CODE, 543, 543, hints);
StringBuilder sbPath = new StringBuilder();
int width = bitMatrix.getWidth();
int height = bitMatrix.getHeight();
int rowSize = bitMatrix.getRowSize();
BitArray row = new BitArray(width);
for(int y = 0; y < height; ++y) {
row = bitMatrix.getRow(y, row);
for(int x = 0; x < width; ++x) {
if (row.get(x)) {
sbPath.append(" M"+x+","+y+"h1v1h-1z");
}
}
}
StringBuilder sb = new StringBuilder();
sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
sb.append("<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 ").append(width).append(" ").append(height).append("\" stroke=\"none\">\n");
sb.append("<style type=\"text/css\">\n");
sb.append(".black {fill:#000000;}\n");
sb.append("</style>\n");
sb.append("<path class=\"black\" d=\"").append(sbPath.toString()).append("\"/>\n");
sb.append("</svg>\n");
Please note that the solution above is much more efficient in terms of memory consumption than the one using Batik's DOM.
Old question I know, but for anyone that comes along looking for how to do this...it's pretty easy to connect ZXing
to JFreeSVG
(http://www.jfree.org/jfreesvg), for example:
package org.jfree.demo;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import java.awt.Color;
import java.io.File;
import java.io.IOException;
import org.jfree.graphics2d.svg.SVGGraphics2D;
import org.jfree.graphics2d.svg.SVGUtils;
public class QRCodes {
public static void main(String[] args) throws WriterException, IOException {
QRCodeWriter qrCodeWriter = new QRCodeWriter();
BitMatrix bitMatrix = qrCodeWriter.encode("http://www.jfree.org/jfreesvg",
BarcodeFormat.QR_CODE, 160, 160);
int w = bitMatrix.getWidth();
SVGGraphics2D g2 = new SVGGraphics2D(w, w);
g2.setColor(Color.BLACK);
for (int xIndex = 0; xIndex < w; xIndex = xIndex + bitMatrix.getRowSize()) {
for (int yIndex = 0; yIndex < w; yIndex = yIndex + bitMatrix.getRowSize()) {
if (bitMatrix.get(xIndex, yIndex)) {
g2.fillRect(xIndex, yIndex, bitMatrix.getRowSize(), bitMatrix.getRowSize());
}
}
}
SVGUtils.writeToSVG(new File("qrtest.svg"), g2.getSVGElement());
}
}