Introduction
The ITS, LLC Barcode Generation System generates C39 Barcode Labels to be printed on Avery 8167 labels. The software was developed for printing labels to be used on document boxes and documents (both actual documents and chain of custody logs) to track documents with boxes, etc.
This software allows for the following on label creation and configuration:
- Box Label Printing (80 unique labels per page)
- Document Jaclet Label Printing (40 unique labels per page, double entry for CCT)
- Automatic scanning of box barcode label to produce document labels
- Advanced configuration of drawing styles on barcodes
- Configuration of printing options for physical delivery of barcode page generation
Background
In terms of background on the software; the software was designed to print on the Avery 8167 labels, which has 80 labels per page -- however, with some configuration, you can use it to print on other style labels as well.
The software is developed on the Microsoft .NET Framework, and heavily uses the Microsoft .NET GDI+ system for drawing barcodes. It does not use a font to write the barcodes.
Using the Code
The code is fairly straightforward, and is very well commented. But as always, if you have any questions or comments, don't hesitate to contact me or leave a comment/question on the CodeProject page.
There are a few direct exerts; well actually, it's almost the complete code from the main Barcode Workspace below.
This is the main Barcode Generation System, allowing for the generation of each barcode image:
Public Class mainBarcodeWorkspace
Private _encoding As Hashtable = New Hashtable
Private Const _wideBarWidth As Short = 2
Private Const _narrowBarWidth As Short = 1
Private Const _barHeight As Short = 31
Public totalPages As Integer = 1
Public curPage As Integer = 0
Public boxScanFrm As boxScan = New boxScan
Public returnTimer As Integer = 15
Dim barcodeCanvas As Bitmap
Private WithEvents m_PrintDocument As Printing.PrintDocument
#Region "Barcode Generation System"
Sub ITS_BarcodeC39()
_encoding.Add("*", "bWbwBwBwb")
_encoding.Add("-", "bWbwbwBwB")
_encoding.Add("$", "bWbWbWbwb")
_encoding.Add("%", "bwbWbWbWb")
_encoding.Add(" ", "bWBwbwBwb")
_encoding.Add(".", "BWbwbwBwb")
_encoding.Add("/", "bWbWbwbWb")
_encoding.Add("+", "bWbwbWbWb")
_encoding.Add("0", "bwbWBwBwb")
_encoding.Add("1", "BwbWbwbwB")
_encoding.Add("2", "bwBWbwbwB")
_encoding.Add("3", "BwBWbwbwb")
_encoding.Add("4", "bwbWBwbwB")
_encoding.Add("5", "BwbWBwbwb")
_encoding.Add("6", "bwBWBwbwb")
_encoding.Add("7", "bwbWbwBwB")
_encoding.Add("8", "BwbWbwBwb")
_encoding.Add("9", "bwBWbwBwb")
_encoding.Add("A", "BwbwbWbwB")
_encoding.Add("B", "bwBwbWbwB")
_encoding.Add("C", "BwBwbWbwb")
_encoding.Add("D", "bwbwBWbwB")
_encoding.Add("E", "BwbwBWbwb")
_encoding.Add("F", "bwBwBWbwb")
_encoding.Add("G", "bwbwbWBwB")
_encoding.Add("H", "BwbwbWBwb")
_encoding.Add("I", "bwBwbWBwb")
_encoding.Add("J", "bwbwBWBwb")
_encoding.Add("K", "BwbwbwbWB")
_encoding.Add("L", "bwBwbwbWB")
_encoding.Add("M", "BwBwbwbWb")
_encoding.Add("N", "bwbwBwbWB")
_encoding.Add("O", "BwbwBwbWb")
_encoding.Add("P", "bwBwBwbWb")
_encoding.Add("Q", "bwbwbwBWB")
_encoding.Add("R", "BwbwbwBWb")
_encoding.Add("S", "bwBwbwBWb")
_encoding.Add("T", "bwbwBwBWb")
_encoding.Add("U", "BWbwbwbwB")
_encoding.Add("V", "bWBwbwbwB")
_encoding.Add("W", "BWBwbwbwb")
_encoding.Add("X", "bWbwBwbwB")
_encoding.Add("Y", "BWbwBwbwb")
_encoding.Add("Z", "bWBwBwbwb")
End Sub
Protected Function getBCSymbolColor(ByVal symbol As String) _
As System.Drawing.Brush
getBCSymbolColor = Brushes.Black
If symbol = "W" Or symbol = "w" Then
getBCSymbolColor = Brushes.White
End If
End Function
Protected Function getBCSymbolWidth(ByVal symbol As String) As Short
getBCSymbolWidth = _narrowBarWidth
If symbol = "B" Or symbol = "W" Then
getBCSymbolWidth = _wideBarWidth
End If
End Function
Protected Overridable Function GenerateBarcodeImage(ByVal imageWidth As Short, _
ByVal imageHeight As Short, ByVal Code As String) As IO.MemoryStream
Dim b As New Bitmap(imageWidth, imageHeight, _
Imaging.PixelFormat.Format32bppArgb)
Dim canvas As New Rectangle(0, 0, imageWidth, imageHeight)
Dim g As Graphics = Graphics.FromImage(b)
g.FillRectangle(Brushes.White, 0, 0, imageWidth, imageHeight)
g.FillRectangle(New Drawing2D.LinearGradientBrush(_
New Drawing.RectangleF(1, 1, 169, 30), Color.White, _
Color.LightGray, Drawing2D.LinearGradientMode.Vertical), 1, 1, 169, 30)
g.FillRectangle(New Drawing2D.LinearGradientBrush(_
New Drawing.RectangleF(1, 34, 169, 15), Color.LightGray, _
Color.White, Drawing2D.LinearGradientMode.Vertical), 1, 34, 169, 15)
g.FillRectangle(New SolidBrush(Color.Black), 1, 33, 169, 1)
g.TextRenderingHint = Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit
g.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
g.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
g.CompositingQuality = Drawing2D.CompositingQuality.HighQuality
If boxNumber.Enabled = False Then
g.DrawImage(My.Resources.Shipping, 10, 2, 23, 23)
g.DrawString("BOX", New Font("Tahoma", 10, _
FontStyle.Bold), New SolidBrush(Color.Silver), 129, 7)
g.DrawString("Box " & Code, New Font("Tahoma", _
8, FontStyle.Bold), New SolidBrush(Color.Black), 3, 34)
Else
g.DrawString(Code, New Font("Tahoma", 8, FontStyle.Bold), _
New SolidBrush(Color.Black), 3, 34)
End If
g.DrawString("ITS v2.0", New Font("Tahoma", 8, _
FontStyle.Bold), New SolidBrush(Color.Gray), 113, 34)
g.TextRenderingHint = Drawing.Text.TextRenderingHint.SystemDefault
g.SmoothingMode = Drawing2D.SmoothingMode.None
g.InterpolationMode = Drawing2D.InterpolationMode.NearestNeighbor
g.CompositingQuality = Drawing2D.CompositingQuality.Default
Dim UseCode As String = String.Format("{0}{1}{0}", "*", Code)
Dim XPosition As Short = 1
Dim YPosition As Short = 1
Dim invalidCharacter As Boolean = False
Dim CurrentSymbol As String = String.Empty
For j As Short = 0 To CShort(UseCode.Length - 1)
CurrentSymbol = UseCode.Substring(j, 1)
If Not IsNothing(_encoding(CurrentSymbol)) Then
Dim EncodedSymbol As String = _encoding(CurrentSymbol).ToString
For i As Short = 0 To CShort(EncodedSymbol.Length - 1)
Dim CurrentCode As String = EncodedSymbol.Substring(i, 1)
XPosition = XPosition + getBCSymbolWidth(CurrentCode)
Next
XPosition = XPosition + getBCSymbolWidth("w")
End If
Next
XPosition = (imageWidth / 2) - (XPosition / 2)
For j As Short = 0 To CShort(UseCode.Length - 1)
CurrentSymbol = UseCode.Substring(j, 1)
If Not IsNothing(_encoding(CurrentSymbol)) Then
Dim EncodedSymbol As String = _encoding(CurrentSymbol).ToString
For i As Short = 0 To CShort(EncodedSymbol.Length - 1)
Dim CurrentCode As String = EncodedSymbol.Substring(i, 1)
g.FillRectangle(getBCSymbolColor(CurrentCode), XPosition, _
YPosition, getBCSymbolWidth(CurrentCode), _barHeight)
XPosition = XPosition + getBCSymbolWidth(CurrentCode)
Next
g.FillRectangle(getBCSymbolColor("w"), XPosition, _
YPosition, getBCSymbolWidth("w"), _barHeight)
XPosition = XPosition + getBCSymbolWidth("w")
Else
invalidCharacter = True
End If
Next
If invalidCharacter Then
g.FillRectangle(Brushes.White, 0, 0, imageWidth, imageHeight)
g.DrawString("Invalid Charachers Detected", _
New Font("Tahoma", 8), New SolidBrush(Color.Red), 0, 0)
g.DrawString("- Barcode Not Generated -", _
New Font("Tahoma", 8), New SolidBrush(Color.Black), 0, 10)
g.DrawString(Code, New Font("Tahoma", 8, FontStyle.Italic), _
New SolidBrush(Color.Black), 0, 30)
End If
Dim ms As New IO.MemoryStream
Dim encodingParams As New EncoderParameters
encodingParams.Param(0) = New EncoderParameter(Encoder.Quality, 100)
Dim encodingInfo As ImageCodecInfo = FindCodecInfo("PNG")
b.Save(ms, encodingInfo, encodingParams)
g.Dispose()
b.Dispose()
Return ms
End Function
This is where we set the encoding for the image before we send it to the returned memory stream:
Protected Overridable Function FindCodecInfo(ByVal codec As String) As ImageCodecInfo
Dim encoders As ImageCodecInfo() = ImageCodecInfo.GetImageEncoders
For Each e As ImageCodecInfo In encoders
If e.FormatDescription.Equals(codec) Then Return e
Next
Return Nothing
End Function
#End Region
Now, we move onto actually printing the barcode, for both the physical printing and the on-screen printing...
#Region "Printing Methods (Physical Printing and On-Screen Printing)"
Public Sub doPrintActive()
m_PrintDocument = New Printing.PrintDocument
m_PrintDocument.PrinterSettings = PrintDialog1.PrinterSettings
m_PrintDocument.DefaultPageSettings.Color = False
m_PrintDocument.DefaultPageSettings.Margins = _
New System.Drawing.Printing.Margins(8.5, 8.5, 35, 35)
m_PrintDocument.Print()
End Sub
Private Sub m_PrintDocument_PrintPage(ByVal sender As Object, _
ByVal e As System.Drawing.Printing.PrintPageEventArgs) _
Handles m_PrintDocument.PrintPage
Dim x As Integer = e.MarginBounds.X
Dim y As Integer = e.MarginBounds.Y
e.Graphics.DrawImage(barcodeCanvas, x, y)
e.HasMorePages = False
End Sub
Public Sub doPrintNow()
curPage = 0
If boxNumber.Enabled = True Then
totalPages = (CInt(bcEnd.Text) - (CInt(bcStart.Text) + 1)) / 40
Else
totalPages = (CInt(bcEnd.Text) - (CInt(bcStart.Text) + 1)) / 80
End If
ToolStrip_StatusLabel.Text = "Generating barcodes..."
If NotEffecientLabel.Visible Then
Dim surePrint As MsgBoxResult = _
MsgBox("It appears this label printing session isn't effecient!" & _
Chr(13) & Chr(13) & "Are you sure you would like to continue?", _
MsgBoxStyle.Information + MsgBoxStyle.YesNo, Me.Text)
If surePrint = MsgBoxResult.No Then
Exit Sub
End If
End If
Dim barcode As String
Dim thisBarCode As Bitmap
barcodeCanvas = New Bitmap(766, 960)
Dim dc As Graphics = Graphics.FromImage(barcodeCanvas)
dc.Clear(Color.White)
Dim pgX As Integer = 0
Dim pgXc As Integer = 0
Dim pgY As Integer = 0
Dim newColCounter As Integer = 1
Dim i As Integer
If boxNumber.Enabled = True Then
For i = CInt(bcStart.Text) To CInt(bcEnd.Text)
ToolStrip_StatusLabel.Text = "Generating Barcodes " & i & _
" (" & Math.Round((i / CInt(bcEnd.Text)) * 100, 0) & "%)..."
Dim bid As String = "0"
Dim pid As String = "0"
If Len(boxNumber.Text) < 4 Then
Select Case 4 - Len(boxNumber.Text)
Case 1
bid = "0" & boxNumber.Text
Case 2
bid = "00" & boxNumber.Text
Case 3
bid = "000" & boxNumber.Text
End Select
Else
bid = boxNumber.Text
End If
If Len(CStr(i)) < 4 Then
Select Case 4 - Len(CStr(i))
Case 1
pid = "0" & CStr(i)
Case 2
pid = "00" & CStr(i)
Case 3
pid = "000" & CStr(i)
End Select
Else
pid = CStr(i)
End If
barcode = bid & "-" & pid
thisBarCode = New Bitmap(GenerateBarcodeImage(169, 48, barcode))
dc.DrawImage(thisBarCode, New PointF(pgX, pgY))
pgX = pgX + (169 + 30)
dc.DrawImage(thisBarCode, New PointF(pgX, pgY))
pgY = pgY + 48
pgX = pgXc
If newColCounter = 20 Then
pgXc = (165 * 2) + (32.5 * 2)
pgY = 0
pgX = pgXc
End If
PictureBox1.Image = barcodeCanvas
If newColCounter = 40 And CInt(bcEnd.Text) > i Then
curPage = curPage + 1
printingProgressBar.Visible = True
printingProgressBar.Maximum = totalPages
printingProgressBar.Value = curPage
Me.Refresh()
Application.DoEvents()
If printLabels.Checked Then
ToolStrip_StatusLabel.Text = "Printing Label Page " & _
curPage & " (" & _
Math.Round((curPage / totalPages)) * 100 & "%)..."
Me.Refresh()
Application.DoEvents()
doPrintActive()
End If
dc.Clear(Color.White)
pgXc = 0
pgY = 0
pgX = pgXc
newColCounter = 0
End If
newColCounter = newColCounter + 1
Next
Else
For i = CInt(bcStart.Text) To CInt(bcEnd.Text)
ToolStrip_StatusLabel.Text = "Generating Barcodes " & _
i & " (" & Math.Round((i / CInt(bcEnd.Text)) * 100, 0) & "%)..."
Dim pid As String = "0"
If Len(CStr(i)) < 4 Then
Select Case 4 - Len(CStr(i))
Case 1
pid = "0" & CStr(i)
Case 2
pid = "00" & CStr(i)
Case 3
pid = "000" & CStr(i)
End Select
Else
pid = CStr(i)
End If
barcode = pid
thisBarCode = New Bitmap(GenerateBarcodeImage(169, 48, barcode))
dc.DrawImage(thisBarCode, New PointF(pgX, pgY))
pgY = pgY + 48
pgX = pgXc
If newColCounter = 20 Then
pgXc = 165 + 32.5
pgY = 0
pgX = pgXc
End If
If newColCounter = 40 Then
pgXc = (165 * 2) + (32.5 * 2)
pgY = 0
pgX = pgXc
End If
If newColCounter = 60 Then
pgXc = (165 * 3) + (32.5 * 3)
pgY = 0
pgX = pgXc
End If
PictureBox1.Image = barcodeCanvas
If newColCounter = 80 And CInt(bcEnd.Text) > i Then
curPage = curPage + 1
printingProgressBar.Visible = True
printingProgressBar.Maximum = totalPages
printingProgressBar.Value = curPage
Me.Refresh()
Application.DoEvents()
If printLabels.Checked Then
ToolStrip_StatusLabel.Text = "Printing Label Page " & _
curPage & " (" & _
Math.Round((curPage / totalPages)) * 100 & "%)..."
Me.Refresh()
Application.DoEvents()
doPrintActive()
End If
dc.Clear(Color.White)
pgXc = 0
pgY = 0
pgX = pgXc
newColCounter = 0
End If
newColCounter = newColCounter + 1
Next
End If
If printLabels.Checked Then
ToolStrip_StatusLabel.Text = "Printing Label Page " & curPage & _
" (" & Math.Round((curPage / totalPages)) * 100 & "%)..."
Me.Refresh()
doPrintActive()
End If
ToolStrip_StatusLabel.Text = "Finished (idle)"
printingProgressBar.Visible = False
returnToBoxScanTimer.Start()
returnToBoxScanPanel.Visible = True
End Sub
#End Region
We calculate the page requirements (physical pages of labels) to print the barcodes, with the code below. We then write it out to the user for review, and warn them if need be.
#Region "Label Pages Requirement Calculation System"
Public Sub calculatePages()
If bcStart.Text.Length < 1 Or bcStart.Text.Length < 1 Or _
bcEnd.Text.IsNullOrEmpty(bcEnd.Text) = True Or _
bcStart.Text.IsNullOrEmpty(bcStart.Text) = True Then
Exit Sub
End If
Dim pageAllocation As Integer = 40
If boxNumber.Enabled = False Then
pageAllocation = 80
End If
Dim tpages As Double = Math.Round((CDbl(bcEnd.Text) - _
CDbl(bcStart.Text) + 1) / pageAllocation, 2)
pageUsageLabel.Text = tpages & " label pages"
If CStr(tpages).Contains(".") Then
Dim ovr As Double = CDbl(CStr(tpages).Split(".")(1))
If ovr > 0 Then
NotEffecientLabel.Visible = True
YesEffecientLabel.Visible = False
Dim useL As Integer = 0
For useL = CDbl(bcEnd.Text) To CDbl(bcEnd.Text) + pageAllocation
If CStr(Math.Round((CDbl(useL) - CDbl(bcStart.Text) + 1) / _
pageAllocation, 2)).Split(".").Length = 1 Then
Exit For
End If
Next
Dim useH As Integer = 0
For useH = CDbl(bcEnd.Text) - (pageAllocation - 1) To _
CDbl(bcEnd.Text) + pageAllocation
If CStr(Math.Round((CDbl(useH) - CDbl(bcStart.Text) + 1) / _
pageAllocation, 2)).Split(".").Length = 1 Then
Exit For
End If
Next
NotEffecientLabel.Text = "Not Effecient (Use " & _
useH & " or " & useL & " instead)"
Else
NotEffecientLabel.Visible = False
YesEffecientLabel.Visible = True
End If
Else
NotEffecientLabel.Visible = False
YesEffecientLabel.Visible = True
End If
End Sub
Private Sub bcStart_TextChanged(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles bcStart.TextChanged
calculatePages()
End Sub
Private Sub bcEnd_TextChanged(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles bcEnd.TextChanged
calculatePages()
End Sub
#End Region
While the main form loads, we will load the hashtable with the encoding values, among other things:
Private Sub mainBarcodeWorkspace_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
ITS_BarcodeC39()
calculatePages()
boxNumber.Focus()
mainFrm = Me
boxScanFrm.ShowDialog(Me)
End Sub
End Class
Points of Interest
This was a very fun and interesting project to tackle. I've learned a lot more about GDI+ and have an overall knowledge of the .NET framework from this project. As with every project, there are problems that arise, but all can be solved with a clear head and time to think!
History
- Initial release - 03/19/2009, 12:40 AM CST.
- Version 2.0 release - 03/20/2009, 10:49 PM CST.