Email:
Password:
Email:
JLION.COM
12/26/2007 ASP.NET, Charting, VB.NET

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:

  1. Use javascript to open a new page with the contents of the current report minus the menus.
  2. 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.
  3. 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:

  1. T is the text to be encoded.
  2. H is the height of the bars in the bar code
  3. 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

 

Created by Joe Lynds 2002-2008. Contact Joe
http://www.jlion.com