Rendering 1-Dimensional Barcodes With Zxing And ColdFusion
At PAI, we deal with manufacturing; and, manufacturing workflows run on barcodes. As such, I need to learn about rendering barcodes in ColdFusion; which, it turns out, is relatively easy thanks to the Zxing "Zebra Crossing" Java library from Sean Owen (currently in maintenance mode). Today, I wanted to look at various approaches to rendering 1-Dimensional barcodes (specifically the CODE_39
format) in ColdFusion since these are what I need to print in the immediate future.
In the ColdFusion community, there's a bunch of prior art on the matter. In fact, I'm like 15-years late to the conversation about using Zxing to render barcodes:
- CFSearching's blog post from 2010.
- Alan Quinlan's ColdFusion wrapper, CFZxing.
- AJ Mercer's ColdFusion wrapper, QR Code Generator
That said, I wanted to roll-up my sleeves and get my hands dirty as I start to build up the possible use-cases in my mind. First, I went to Maven Repository and downloaded two JAR files:
Then, since I'm using Lucee CFML, I created a utility function that proxies the Java class creation through fromJars()
. This allows me to create an isolated Class Loader by providing a collection of JAR files with each call to the underlying createObject()
function.
<cfscript>
/**
* I create a Java class from the given JAR files using an isolated classloader.
*/
private any function fromJars( required string classname ) {
var jarPaths = [
expandPath( "./vendor/com.google.zxing/3.5.3/core-3.5.3.jar" ),
expandPath( "./vendor/com.google.zxing/3.5.3/javase-3.5.3.jar" )
];
return createObject( "java", classname, jarPaths );
}
</cfscript>
Once I had this utility function, I was able to start playing around with the ZXing library. This library can do a lot. But, for the scope of these experiments, I'm only dealing with two classes: a "barcode writer", which take my input value and encodes it into a data structure that represents the barcode; and, an "image writer", which takes said data structure and serializes it into an image.
Rendering Barcodes With CSS Flexbox
But, we don't even need the image writer right away - we can do a good deal with just the barcode writer. Once of the encode()
method signatures returns an array of Boolean values that define the on/off sequence of the barcode pixels. We can take those pixels and render them right to the browser using something like CSS Flexbox:
<cfscript>
include "./utils.cfm";
// ------------------------------------------------------------------------------- //
// ------------------------------------------------------------------------------- //
// When encoding a string as the sole argument, the writer returns an array of Boolean
// flags in which True indicates a filled segment and False indicates a blank segment.
// These segments make up the vertical lines of a rendered barcode.
pixels = fromJars( "com.google.zxing.oned.Code39Writer" )
.encode( "https://www.bennadel.com/" )
;
</cfscript>
<cfoutput>
<h1>
Render 1D Barcode Using ColdFusion, Zxing, And CSS Flexbox
</h1>
<style type="text/css">
.barcode {
background-color: white ;
display: flex ;
height: 100px ;
/**
* We don't want to allow the Flexbox container to shrink smaller than the
* number of segments or we run the risk of losing data fidelity. As such,
* we're setting the min-width the number of pixels.
*/
min-width: #arrayLen( pixels )#px ;
max-width: 1000px ;
& > * {
flex: 1 1 auto ;
&[data-on="true"] {
background-color: deeppink ;
}
}
}
</style>
<div class="barcode">
<cfloop array="#pixels#" item="pixel">
<span data-on="#pixel#"></span>
</cfloop>
</div>
</cfoutput>
In this example, my rendered barcode is a Flexbox container in which each on/off pixel is represented by a flex-child, one per barcode pixel. And when we run this ColdFusion code, we get the following output:

One thing that I learned from the CSS Flexbox approach is that the barcode still works even when it streeeeeeetches. I have the min-width
set to the number of pixels so that we don't lose data fidelity as the browser shrinks; but, I allow the barcode to grow up to 1,000 pixels wide. And, if I do that, take a screenshot of it, and then upload it to a barcode reader, it still reads it properly.
Rendering Barcodes With SVG
After getting the CSS Flexbox approach to work, I wanted to try encoding the pixels as SVG rectangles. This is, essentially, the same exact approach using a different type of HTML container:
<cfscript>
include "./utils.cfm";
pixels = fromJars( "com.google.zxing.oned.Code39Writer" )
.encode( "https://www.bennadel.com/" )
;
</cfscript>
<cfoutput>
<h1>
Render 1D Barcode Using ColdFusion, Zxing, And SVG
</h1>
<style type="text/css">
.barcode {
color: cornflowerblue ;
}
</style>
<!--- Note: the Viewbox width is +1 pixels to give the last Rect room to render. --->
<svg viewBox="0 0 #( arrayLen( pixels ) + 1 )# 100" class="barcode">
<cfloop array="#pixels#" item="pixel" index="i">
<cfif pixel>
<rect x="#i#" y="0" width="1" height="100" fill="currentColor" />
</cfif>
</cfloop>
</svg>
</cfoutput>
Notice that the viewBox
encodes the dimensions of the barcode. This allows my rect
element to be relative to the viewBox
without caring about how big the actual <svg>
element is. Which, in turn, allows this element to scale up and down based on its parent container.
If we run this ColdFusion code, we get the following output:

This barcode only needs about 650 pixels to render. But, on my monitor, it will render at about 2,590 pixels wide. And, as I mentioned in the CSS Flexbox approach, even as the barcode stretches, it retains its fidelity.
Rendering Barcodes With SVG Data URI
Rendering the 1D barcode as an SVG element is nice; but, it's still not an "image". Meaning, I can't right-click and save the <svg>
element as a file. But, if we can generate SVG markup in ColdFusion, then we should be able to serialize that markup into a Data URI and render it as an actual <img>
element.
<cfscript>
include "./utils.cfm";
pixels = fromJars( "com.google.zxing.oned.Code39Writer" )
.encode( "https://www.bennadel.com/" )
;
</cfscript>
<cfoutput>
<h1>
Render 1D Barcode Using ColdFusion, Zxing, And SVG Data URI
</h1>
<!--- Store SVG to an output buffer. --->
<cfsavecontent variable="data">
<!--- NOTE: xmlns attribute is required for data URI to work. --->
<svg viewBox="0 0 #( arrayLen( pixels ) + 1 )# 50" xmlns="http://www.w3.org/2000/svg">
<defs>
<rect id="true" y="0" width="1" height="50" fill="black" />
<rect id="false" y="0" width="1" height="50" fill="white" />
</defs>
<cfloop array="#pixels#" item="flag" index="i">
<use href="###flag#" x="#i#" />
</cfloop>
</svg>
</cfsavecontent>
<!--- Remove all extra space. --->
<cfset trimmedData = data
.reReplace( "\s+", " ", "all" )
.reReplace( "\s+<", "<", "all" )
.trim()
/>
<!--- Encode for the URL (spaces must be encoded as %20). --->
<cfset encodedImage = encodeForUrl( trimmedData )
.replace( "+", "%20", "all" )
/>
<img src="data:image/svg+xml,#encodedImage#" height="50" />
</cfoutput>
This time, instead of rendering the <svg>
element directly to the browser, I'm rendering it to to a CFSaveContent
output buffer. Then, I'm stripping out the rendered white space, encoding it as a URL, and putting in the src
attribute of an image tag. And, when we run this ColdFusion code, we get the following output:

In the above example, you can see that after I call encodeForUrl()
, I have to manually convert the +
character to %20
in order to get the data URI to work. To be honest, I'm not sure why that's the case. But, we should be able to work around this issue by Base64-encoding the SVG string:
<cfscript>
include "./utils.cfm";
pixels = fromJars( "com.google.zxing.oned.Code39Writer" )
.encode( "https://www.bennadel.com/" )
;
</cfscript>
<cfoutput>
<h1>
Render 1D Barcode Using ColdFusion, Zxing, And SVG Data URI
</h1>
<!--- Store SVG to an output buffer. --->
<cfsavecontent variable="data">
<!--- NOTE: xmlns attribute is required for data URI to work. --->
<svg viewBox="0 0 #( arrayLen( pixels ) + 1 )# 50" xmlns="http://www.w3.org/2000/svg">
<defs>
<rect id="true" y="0" width="1" height="50" fill="black" />
<rect id="false" y="0" width="1" height="50" fill="white" />
</defs>
<cfloop array="#pixels#" item="flag" index="i">
<use href="###flag#" x="#i#" />
</cfloop>
</svg>
</cfsavecontent>
<!--- Remove all extra space. --->
<cfset trimmedData = data
.reReplace( "\s+", " ", "all" )
.reReplace( "\s+<", "<", "all" )
.trim()
/>
<!--- Encode for the URL as Base64. --->
<cfset encodedImage = binaryEncode( charsetDecode( trimmedData, "utf-8" ), "base64" ) />
<img src="data:image/svg+xml;base64,#encodedImage#" height="50" />
</cfoutput>
This does the exact same thing; only, instead of embedded the SVG data directly into the src
attribute, we're encoding it as Base64 first. And, by doing so, we don't have to worry about which characters are or are not valid.
Rendering Barcodes With PNG Data URI
Rendering barcodes as an SVG data URI is relatively simple! But, unfortunately, it doesn't seem to work in the PDF extension in Lucee CFML. But, you know what does work in a PDF? A PNG data URI!
Rendering a PNG is more complicated because it's a more complicated data format. But, the ZXing library has us covered. Instead of having the "barcode writer" return an array of pixels, we need to have it return a "bit matrix" that encodes those pixels into a 2D format. Then, we need to pull in the "image writer" to encode that bit matrix into a PNG value.
In this demo, I'm having it write the PNG value to a ByteArrayOutputStream
so that I can capture the binary value and encode it into Base64, the same way we were doing with the SVG approach above. Then, I can consume this value directly in the <img[src]>
attribute.
<cfscript>
include "./utils.cfm";
// ------------------------------------------------------------------------------- //
// ------------------------------------------------------------------------------- //
// Instead of getting an array of on/off pixels, this time we're going to render the
// barcode to a pixel matrix (this is essentially the same thing, but uses a width and
// height to represent the pixels in 2D space).
bitMatrix = fromJars( "com.google.zxing.oned.Code39Writer" ).encode(
"https://www.bennadel.com/",
fromJars( "com.google.zxing.BarcodeFormat" ).valueOf( "CODE_39" ),
0, // width - setting to 0 to generate minimum size.
100 // height.
);
// The width / height that we passed-in above are the "preferred" dimensions (with "0"
// indicating a desire for the minimum possible values). If the bit matrix needs to
// use more than the preferred space, it will. As such, the rendered dimensions may
// not match what we passed-in. But, we can read the rendered dimensions.
barcodeWidth = bitMatrix.getWidth();
barcodeHight = bitMatrix.getHeight();
// Write the bit matrix data to a PNG. But, instead of writing to a file, we're going
// to write it to a binary buffer so that we can simply generate a data URI instead of
// having to clean-up a temporary, physical file.
byteStream = createObject( "java", "java.io.ByteArrayOutputStream" ).init();
// Translate to the PNG image format.
fromJars( "com.google.zxing.client.j2se.MatrixToImageWriter" )
.writeToStream( bitMatrix, "png", byteStream )
;
// Encode the PNG image data as base64 for our data URI.
encodedImage = binaryEncode( byteStream.toByteArray(), "base64" );
</cfscript>
<cfoutput>
<h1>
Render 1D Barcode Using ColdFusion, Zxing, And PNG Data URI
</h1>
<img
src="data:image/png;base64,#encodedImage#"
width="#barcodeWidth#"
height="#barcodeHight#"
/>
</cfoutput>
When we run this ColdFusion code, we render a PNG-based image without creating an intermediary PNG file:

This inline PNG approach works in Lucee CFML PDF extension, but, I haven't tested in Adobe ColdFusion version. I'm assuming it works there as well since data URIs are a relatively old concept.
Rendering Barcodes With PNG Image APIs
The inline PNG image approach is nice because it's wholly self-contained. But, for the sake of exploration, let's create an image API that takes a url.value
and encodes it into a PNG image that gets returned in the HTTP response. This way, our calling page doesn't have to go through the machinations of encoding the image data.
In this example, we'll use two different approaches: one that renders the PNG image from a byte-array, just as we did above; and, one that renders the PNG image to an intermediary, temporary file.
First, our calling page:
<cfoutput>
<h1>
Render 1D Barcode Using ColdFusion, Zxing, And PNG
</h1>
<p> Rendered to response stream: </p>
<img src="png-file-stream.cfm?value=#encodeForUrl( 'https://www.bennadel.com/' )#" />
<p> Rendered to temp file: </p>
<img src="png-file.cfm?value=#encodeForUrl( 'https://www.bennadel.com/' )#" />
</cfoutput>
Both of the <img>
tags are using a CFML API as the src
. The first ColdFUsion API will render the image by streaming the byte-array data back in the response:
<cfscript>
include "./utils.cfm";
// ------------------------------------------------------------------------------- //
// ------------------------------------------------------------------------------- //
// The value to encode into a 1D (Code 39) barcode.
param name="url.value" type="string";
// The preferred dimensions.
param name="url.width" type="numeric" default=0;
param name="url.height" type="numeric" default=50;
bitMatrix = fromJars( "com.google.zxing.oned.Code39Writer" ).encode(
url.value,
fromJars( "com.google.zxing.BarcodeFormat" ).valueOf( "CODE_39" ),
val( url.width ),
val( url.height )
);
byteStream = createObject( "java", "java.io.ByteArrayOutputStream" ).init();
fromJars( "com.google.zxing.client.j2se.MatrixToImageWriter" )
.writeToStream( bitMatrix, "png", byteStream )
;
header
name = "X-Barcode-Width"
value = bitMatrix.getWidth()
;
header
name = "X-Barcode-Height"
value = bitMatrix.getHeight()
;
content
type = "image/png"
variable = byteStream.toByteArray()
;
</cfscript>
As you can see, this approach mirrors the previous one. Only instead of encoding the binary data into a data URI, it's streaming it back using the CFContet
tag.
In the second CFML API, we're going to have the "image writer" write to a temporary PNG file:
<cfscript>
include "./utils.cfm";
// ------------------------------------------------------------------------------- //
// ------------------------------------------------------------------------------- //
// The value to encode into a 1D (Code 39) barcode.
param name="url.value" type="string";
// Instead of getting an array of on/off pixels, this time we're going to render the
// barcode to a pixel matrix (this is essentially the same thing, but uses a width and
// height to represent the pixels in 2D space).
bitMatrix = fromJars( "com.google.zxing.oned.Code39Writer" ).encode(
url.value,
fromJars( "com.google.zxing.BarcodeFormat" ).valueOf( "CODE_39" ),
0, // width - setting to 0 to generate minimum size.
100 // height.
);
// Write the bit matrix to a temporary PNG file on disk.
file = createObject( "java", "java.io.File" )
.init( getTempFile( prefix = "barcode", extension = "png" ) )
;
fromJars( "com.google.zxing.client.j2se.MatrixToImageWriter" )
.writeToPath( bitMatrix, "png", file.toPath() )
;
// Serve up (and then delete) the temporary PNG file.
content
type = "image/png"
file = file.getAbsolutePath()
deleteFile = true
;
</cfscript>
This time instead of calling .writeToStream()
on the image writer, we're using .writeToPath()
and having it render the barcode to a PNG file in our temp directory. Then, I'm having the CFContent
tag server and delete the temporary file.
Now, if we run the calling page, we get the following ColdFusion output:

As you can see, both remote ColdFusion calls rendered the same PNG file (at different height
values).
When I found out that I had to start rendering barcodes in ColdFusion, I thought it was going to be a relatively "big ask". But, the fact that ColdFusion is built on top of Java continues to make my life hella easy! Thank goodness the ZXing barcode library exists.
Want to use code from this post? Check out the license.
Reader Comments
Generating barcodes caught my eye. I'm in a similar boat. 😅
As always thanks for the selfless act of kindness!
@Ray,
I love how relatively easy this Zxing library is to use! Barcodes have always seemed like some very mysterious thing to me (especially QR codes). But, it's all just data to "bitmatrix" and then bitmatrix to "image" calls.
I mean, don't get me wrong, I have no idea what this library is doing under the hood. I tried to look, but it seems to be all math and bit-shifting. Over my head. I just love that they've created such a nice abstraction.
I just started playing around with QR codes. Was surprising to find that the whole "logo in the middle" thing isn't part of the QR code specification - it's just taking advantage of the fact that the QR code can do error correction. So, as long as the logo doesn't cover too much of the data, it "just works". Bonkers! 😮
Also, for anyone that comes across this code, I realize now that I didn't need to do this full hoop-jumping in this line of code:
I used the
.valueOf()
call because the JavaDocs seem to imply that this is the way to do it. And, this is the way a lot of the public demos do it. But, at least with ColdFusion, this kind of reflection is unnecessary. I could have just done:Easier to read this way.
A quick follow-up to render QR Codes with the Zxing library and ColdFusion:
www.bennadel.com/blog/4808-rendering-qr-codes-with-zxing-and-coldfusion.htm
Post A Comment — ❤️ I'd Love To Hear From You! ❤️
Post a Comment →