Self–Drawing Barcode

Not all the barcodes end up being printed, some of them are simply displayed in browser. There are two main ways of getting them there:

There are many libraries and frameworks for both methods, but here we offer a framework–less implementation of client–side rendering by using a self–contained self–drawing SVG file.

Yes, by embedding Javascript code into SVG file we can make it draw itself.

This method is widely used for SVG animation, but not for barcodes. Let’s fix that! We’ll end up with a single self–drawing self–contained SVG file for QR codes, like the one below:

Here is the code used to display the image above:

<object data="qr.min.svg?data=hello, world" type="image/svg+xml" width="200" height="200">
</object>

The qr.min.svg file is just about 17Kb and contains everything you need to draw QR codes. Sounds interesting? Let’s do it step by step!

Simple SVG File

Here is a very simple SVG file we’ll be using as a template:

<?xml version="1.0" standalone="yes"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 200 200">
	<g id="qrcode">
            <line x1="0" y1="0" x2="200" y2="200" width="1" stroke="red"/>
            <line x1="0" y1="200" x2="200" y2="0" width="1" stroke="red"/>
	</g>
</svg>

And here’s what it looks like:

The image is made of two red lines defined by the <line> elements in the SVG file code. Now let’s change the SVG file to include some Javascript code to generate the line elements for us:

<?xml version="1.0" standalone="yes"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 200 200">
	<g id="qrcode"/>
	
	<script type="application/javascript">//<![CDATA[

            function line(el, x1, y1, x2, y2, width, color) {
                const nl = document.createElementNS("http://www.w3.org/2000/svg","line");
                nl.setAttribute("x1", x1);
                nl.setAttribute("y1", y1);
                nl.setAttribute("x2", x2);
                nl.setAttribute("y2", y2);
                nl.setAttribute("width", width);
                nl.setAttribute("stroke", color)
                el.appendChild(nl);
            }

            const elem = document.getElementById("qrcode");
            line(elem, 0, 0, 200, 200, 1, "red");
            line(elem, 0, 200, 200, 0, 1, "red");

	//]]>
	</script>
</svg>

The code looks much longer now and although the resulting SVG looks the same:

we can now do much more with scripting. For instance if you change the last three lines to these:

const elem = document.getElementById("qrcode");
for (let i = -200; i < 200; i += 10) {
	line(elem, 0, 0 + i, 200, 200 + i, 1, "red");
	line(elem, 0, 200 + i, 200, 0 + i, 1, "red");
}

You’ll get a mesh of lines drawn by the SVG file itself:

Now let’s make it a little more interactive…

Parsing Input Parameters

The mesh image above is made like this in HTML:

<object data="qr-3.svg" type="image/svg+xml" width="200" height="200"></object>

Notice the data attribute points to the SVG file we’ve made. However, as with any other HTML resource we can pass some parameters after the file name:

<object data="qr-3.svg?color=green" type="image/svg+xml" width="200" height="200"></object>

Here we passed the color parameter with green as a value. Let’s now read it inside the SVG file. We’ll need this code:

const params = new URLSearchParams(window.location.search);
const color = params.get("color");

The first line reads all the parameters passed to the SVG file and the second line reads the color parameter out of them.

Now let’s change the last code snippet which draws a mesh to this:

const params = new URLSearchParams(window.location.search);
const color = params.get("color");
const elem = document.getElementById("qrcode");
for (let i = -200; i < 200; i += 10) {
	line(elem, 0, 0 + i, 200, 200 + i, 1, color);
	line(elem, 0, 200 + i, 200, 0 + i, 1, color);
}

and call it this way:

<object data="qr-4.svg?color=orange" type="image/svg+xml" width="200" height="200"></object>

the result is:

So we can read the input parameters and draw custom shapes with Javascript right inside the SVG file without any dependencies. Now we are ready to draw a QR code!

Drawing QR Code

We are not going to reinvent a wheel here and simply re–use the existing Javascript library for drawing QR codes by Kazuhiko Arase.

We’ll need a function for drawing filled rectangles:

function rect(el, x, y, width, height, color) {
	const rc = document.createElementNS("http://www.w3.org/2000/svg", "rect");
	rc.setAttribute("x", x);
	rc.setAttribute("y", y);
	rc.setAttribute("width", width);
	rc.setAttribute("height", height);
	rc.setAttribute("fill", color)
	el.appendChild(rc);
}

Now the main drawing code looks this way:

const elem = document.getElementById("qrcode");
const width = 200, height = 200;

const params = new URLSearchParams(window.location.search);
const data = params.get("data");

const cl = QRErrorCorrectLevel.H;
const qr = new QRCodeModel(_getTypeNumber(data, cl), cl);
qr.addData(data);
qr.make();

const count = qr.getModuleCount();
const cw = Math.floor(width / count);
const ch = Math.floor(height / count);

for (let row = 0; row < count; row++) {
	for (let col = 0; col < count; col++) {
		if (qr.isDark(row, col)) {
			rect(elem, col * cw, row * ch, cw, ch, "black");
		}
	}
}

That’s a lot of code, but it actually is pretty simple: we read the barcode contents from a parameter, then create a QR code generator from the library we used and finally loop around all the cells of the barcode checking if they need to be filled up.

The real Javascript code contains some extra checks and errors processing. You can have a look at it here: qr.svg, or if you need the minified version: qr.min.svg.

Here are some examples of what you can do with this SVG file:

// Wi-Fi access point password
// WIFI:S:$SSID;P:$PASSWORD;;
<object data="qr.min.svg?data=WIFI:S:My Network;P:My Password;;" type="image/svg+xml" width="200" height="200"></object>

// Phone number
// tel:+NNNNNNNNNNNN
<object data="qr.min.svg?data=tel:+1234567890" type="image/svg+xml" width="200" height="200"></object>

// Map coordinates
// geo:+XXX,-YYY
<object data="qr.min.svg?data=geo:48.858222,2.2945" type="image/svg+xml" width="200" height="200"></object>

So basically anything you might want to present as a QR code can be done using this SVG file with a proper parameter. No libraries, no frameworks, no maintenance, just a single SVG file that draws itself. By the way, printing is also supported.

Limitations

The obvious limitation is that Javascript needs to be enabled in browser in order for this method to work. Here you decide for yourself if you need a backup barcode solution, but if browser doesn’t support scripting, you just get a blank space instead of the QR code with this file. No errors, no incorrect data. If the code is not the main thing on the page, it can be simply left as is.

The other limitation is that the SVG file needs a browser to work. If you open it with a viewer, load it to a vector editor or any other application — it will show nothing. Without the browser the script is not executed and the content is not drawn.

Finally, as you probably already noticed you need to use the <object> tag to display the SVG file instead of the <img> one. The problem is that browsers don’t run scripts inside SVG files loaded as images, so if you load the SVG file this way, you’ll get a blank space. That’s why the <object> tag is needed.

Can I Use That SVG?

Sure, you are very welcome to use the file as is or make the modifications you need. Please keep the original copyrights to respect the others' work. Here are the links again: qr.svg, qr.min.svg.

More Barcode Tutorials

Installation

Basics

UPC Barcodes

Other Barcodes

Export

Automation

Other