Include dynamic bar codes in your web pages and reports
Almost all of the reports that I create nowadays are ASPX pages. In today's
web-centric times, users have come to expect to be able to drill down at will
and such reports lend themselves easily to being linked to, or to being
linked from.
In many cases, creating a web report is actually easier than using a reporting
tool such as Crystal Reports. It's easy to rough out a query in SQL Query Analyzer,
pop the query into the appropriate data layer object and then copy and slightly modify
existing reporting code into a new web page. Presto: New web report. ASPX provides
handy menuing and security functions so the new report can quickly be made available
to users.
If there is one challenge with web reports, it's that they don't lend themselves
to printing. Thus the success of products like Acrobat Reader. Recently I've been
addressing printing using some combination of these three approaches:
- Use javascript to open a new page with the contents of the current report minus the menus.
- Provide an option for the user to export data shown in the report as a CSV file. This is convenient
as the exported data opens up automatically in Excel.
- Provide for generation of word or excel documents via an off-line batch process. The
reports are generated on a batch server separate from the web server, and a link to
the completed report is emailed to the user when the report is finished.
Recently I've come up against something that none of these three options easily addresses:
A need to include dynamic bar codes as part of the web page.
Workers on using this particular application have bar code scanners that they
use to communicate with a robotic packing system. I wanted to use web reports as they
are quick to develop and easy to support, and the workers are familier with the present
set of web reports. An additional web report is the easiest for them.
After thinking about the problem for a little while, I realized that a bar code is very much
like a chart. I've created quite a number of different kinds of web charts, and decided to create
a bar code using the same approach.
There are a number of different bar code standards. Code 3of9 is one of the easiest to
implement. Information encoded in 3of9 takes more space than other formats such as code 128
but in my particular application I did not need to encode much information and so space
limitations were not a factor. Wikipedia very usefully supplies all the information one
needs to create a 3of9 bar code, so the actual
bar code algorithm was only a few minutes work.
I used the same technique here that I used for my sparkline and
thermometer charts. The chart is created and streamed out by an ASPX
page. Charting options are controlled by querystring parameters.
For this bar code chart the options are as follows:
- T is the text to be encoded.
- H is the height of the bars in the bar code
- W is the width of a narrow bar in the bar code
The chart is displayed in a web page by including an image tag referencing the chart page, as shown below. Since
the text of the bar code is being passed as a URL parameter, it's a good idea to url encode it so that such characters
as spaces and plus signs are correctly passed to the chart.
<img src="BarCode.aspx?T=B101&H=20&W=20" />
The source code for BarCode.aspx can be downloaded here: Download source code
Below is the core code for generating the bar code. This code simply draws the bar code. See the above
download for the code for creating the final bar code image and streaming it out to the browser.
Public Class jBarCode_3of9
'http://en.wikipedia.org/wiki/3_of_9
Public Enum FormatType As Integer
FORMAT1 = 1
FORMAT2 = 2
End Enum
Private moCharSet As Collection
Public Sub New()
moCharSet = New Collection
AddToCharSet("*", "NwNnWnWnN", "bWbwBwBwb")
AddToCharSet("-", "NwNnNnWnW", "bWbwbwBwB")
AddToCharSet("$", "NwNwNwNnN", "bWbWbWbwb")
AddToCharSet("%", "NnNwNwNwN", "bwbWbWbWb")
AddToCharSet("_", "NwWnNnWnN", "bWBwbwBwb")
AddToCharSet(".", "WwNnNnWnN", "BWbwbwBwb")
AddToCharSet("/", "NwNwNnNwN", "bWbWbwbWb")
AddToCharSet("+", "NwNnNwNwN", "bWbwbWbWb")
AddToCharSet("0", "NnNwWnWnN", "bwbWBwBwb")
AddToCharSet("1", "WnNwNnNnW", "BwbWbwbwB")
AddToCharSet("2", "NnWwNnNnW", "bwBWbwbwB")
AddToCharSet("3", "WnWwNnNnN", "BwBWbwbwb")
AddToCharSet("4", "NnNwWnNnW", "bwbWBwbwB")
AddToCharSet("5", "WnNwWnNnN", "BwbWBwbwb")
AddToCharSet("6", "NnWwWnNnN", "bwBWBwbwb")
AddToCharSet("7", "NnNwNnWnW", "bwbWbwBwB")
AddToCharSet("8", "WnNwNnWnN", "BwbWbwBwb")
AddToCharSet("9", "NnWwNnWnN", "bwBWbwBwb")
AddToCharSet("A", "WnNnNwNnW", "BwbwbWbwB")
AddToCharSet("B", "NnWnNwNnW", "bwBwbWbwB")
AddToCharSet("C", "WnWnNwNnN", "BwBwbWbwb")
AddToCharSet("D", "NnNnWwNnW", "bwbwBWbwB")
AddToCharSet("E", "WnNnWwNnN", "BwbwBWbwb")
AddToCharSet("F", "NnWnWwNnN", "bwBwBWbwb")
AddToCharSet("G", "NnNnNwWnW", "bwbwbWBwB")
AddToCharSet("H", "WnNnNwWnN", "BwbwbWBwb")
AddToCharSet("I", "NnWnNwWnN", "bwBwbWBwb")
AddToCharSet("J", "NnNnWwWnN", "bwbwBWBwb")
AddToCharSet("K", "WnNnNnNwW", "BwbwbwbWB")
AddToCharSet("L", "NnWnNnNwW", "bwBwbwbWB")
AddToCharSet("M", "WnWnNnNwN", "BwBwbwbWb")
AddToCharSet("N", "NnNnWnNwW", "bwbwBwbWB")
AddToCharSet("O", "WnNnWnNwN", "BwbwBwbWb")
AddToCharSet("P", "NnWnWnNwN", "bwBwBwbWb")
AddToCharSet("Q", "NnNnNnWwW", "bwbwbwBWB")
AddToCharSet("R", "WnNnNnWwN", "BwbwbwBWb")
AddToCharSet("S", "NnWnNnWwN", "bwBwbwBWb")
AddToCharSet("T", "NnNnWnWwN", "bwbwBwBWb")
AddToCharSet("U", "WwNnNnNnW", "BWbwbwbwB")
AddToCharSet("V", "NwWnNnNnW", "bWBwbwbwB")
AddToCharSet("W", "WwWnNnNnN", "BWBwbwbwb")
AddToCharSet("X", "NwNnWnNnW", "bWbwBwbwB")
AddToCharSet("Y", "WwNnWnNnN", "BWbwBwbwb")
AddToCharSet("Z", "NwWnWnNnN", "bWBwBwbwb")
End Sub
Private Sub AddToCharSet( _
ByVal sChar As String, _
ByVal sFormat1 As String, _
ByVal sFormat2 As String)
moCharSet.Add(New CharacterEncoding(sChar, sFormat1, sFormat2), sChar)
End Sub
Public Sub DrawBarCode( _
ByRef g As Graphics, _
ByVal sText As String, _
ByVal iX As Integer, _
ByVal iY As Integer, _
ByVal iBarWidth As Integer, _
ByVal iBarHeight As Integer, _
ByRef iBarCodeWidth As Integer, _
ByVal iFormat As FormatType)
Dim iCurX As Integer = iX
DrawSingleCharacter(g, "*", iCurX, iY, iBarWidth, iBarHeight, iFormat)
For i As Integer = 0 To sText.Length - 1
DrawSingleCharacter(g, sText.Substring(i, 1), iCurX, iY, iBarWidth, iBarHeight, iFormat)
Next
DrawSingleCharacter(g, "*", iCurX, iY, iBarWidth, iBarHeight, iFormat)
iBarCodeWidth = iCurX
End Sub
Private Sub DrawSingleCharacter( _
ByRef g As Graphics, _
ByVal sChar As String, _
ByRef iX As Integer, _
ByVal iY As Integer, _
ByVal iBarWidth As Integer, _
ByVal iBarHeight As Integer, _
ByVal iFormat As FormatType)
If sChar = " " Then sChar = "_"
Dim oEncoding As CharacterEncoding = moCharSet(sChar)
oEncoding.DrawChar(g, iX, iY, iBarWidth, iBarHeight, iFormat)
End Sub
Protected Class CharacterEncoding
Public Const F1_Wide_Black As String = "W"
Public Const F1_Narrow_Black As String = "N"
Public Const F1_Wide_White As String = "w"
Public Const F1_Narrow_White As String = "n"
Public Const F2_Wide_Black As String = "B"
Public Const F2_Narrow_Black As String = "b"
Public Const F2_Wide_White As String = "W"
Public Const F2_Narrow_White As String = "w"
Public Const NARROW_MULTIPLIER As Integer = 1
Public Const WIDE_MULTIPLIER As Integer = 2
Private msChar As String
Private msFormat1 As String
Private msFormat2 As String
Public Sub New( _
ByVal sChar As String, _
ByVal sFormat1 As String, _
ByVal sFormat2 As String)
msChar = sChar
msFormat1 = sFormat1
msFormat2 = sFormat2
End Sub
Public Property [Char]() As String
Get
Return msChar
End Get
Set(ByVal value As String)
msChar = value
End Set
End Property
Public Property Format1() As String
Get
Return msFormat1
End Get
Set(ByVal value As String)
msFormat1 = value
End Set
End Property
Public Property Format2() As String
Get
Return msFormat2
End Get
Set(ByVal value As String)
msFormat2 = value
End Set
End Property
Public Sub DrawChar( _
ByVal g As Graphics, _
ByRef iX As Integer, _
ByVal iY As Integer, _
ByVal iBarWidth As Integer, _
ByVal iBarHeight As Integer, _
ByVal iFormatID As FormatType)
Dim sFormat As String = ""
Select Case iFormatID
Case FormatType.FORMAT1
sFormat = msFormat1
Case FormatType.FORMAT2
sFormat = msFormat2
End Select
For i As Integer = 0 To sFormat.Length - 1
Dim sCharAtPos As String = sFormat.Substring(i, 1)
Dim oColor As Color = Color.Red
Dim iWidthMultiplier As Integer = 0
Select Case sCharAtPos
Case F1_Wide_Black
oColor = Color.Black
iWidthMultiplier = WIDE_MULTIPLIER
Case F1_Narrow_Black
oColor = Color.Black
iWidthMultiplier = NARROW_MULTIPLIER
Case F1_Wide_White
oColor = Color.White
iWidthMultiplier = WIDE_MULTIPLIER
Case F1_Narrow_White
oColor = Color.White
iWidthMultiplier = NARROW_MULTIPLIER
End Select
DrawSingleBar(g, iX, iY, iBarWidth * iWidthMultiplier, iBarHeight, oColor)
Next
DrawSingleBar(g, iX, iY, iBarWidth * NARROW_MULTIPLIER, iBarHeight, Color.White)
End Sub
Private Sub DrawSingleBar( _
ByRef g As Graphics, _
ByRef iX As Integer, _
ByVal iY As Integer, _
ByVal iBarWidth As Integer, _
ByVal iBarHeight As Integer, _
ByVal oColor As Color)
Dim rRect As New RectangleF(iX, iY, iBarWidth, iBarHeight)
g.FillRectangle(New SolidBrush(oColor), rRect)
iX = iX + rRect.Width
End Sub
End Class
End Class