Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / VB

Barcode Scanner

4.90/5 (9 votes)
15 Jan 2019CPOL 14.8K   1.2K  
This Windows application lets you scan image in a given folder and generate CSV file to show barcodes for each image file.

Image 1

Introduction

This Windows application lets you scan image in a given folder (and subfolders) and generate CSV file based on the output. This article uses the BarcodeImaging.dll library developed by Berend Engelbrecht to scan barcodes: Reading Barcodes from an Image - III.

Background

I found that BarcodeImaging.dll library does a pretty decent job, but for some cases I needed to use Byte Scout (Bytescout.BarCodeReader.dll) library (which costs $20 and is slow). I tried Byte Scout library for comparison but left it unchecked in the application, in case someone will still want to try it.

Using the Code

To use this program, simply select a folder and click Process. The program will create a CSV file within target folder.

Here is the code:

VB.NET
Dim oAppSetting As New AppSetting()
Dim oLogFile As System.IO.StreamWriter
Dim bStartFile As Boolean = True

Private Sub Form1_FormClosing(sender As Object, _
        e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
    oAppSetting.SetValue("FromPath", txtFrom.Text)
    oAppSetting.SetValue("RegName", txtRegName.Text)
    oAppSetting.SetValue("RegKey", txtRegKey.Text)
    oAppSetting.SetValue("StartFile", txtStartFile.Text)

    oAppSetting.SetValue("BarcodeType", cbBarcodeType.SelectedIndex)
    oAppSetting.SetValue("Direction", cbDirection.SelectedIndex)

    oAppSetting.SetValue("UseBarcodeZones", IIf(chkUseBarcodeZones.Checked, "1", "0"))
    oAppSetting.SetValue("Log", IIf(chkLog.Checked, "1", "0"))
    oAppSetting.SetValue("ShowTime", IIf(chkShowTime.Checked, "1", "0"))
    oAppSetting.SetValue("CSV", IIf(chkCSV.Checked, "1", "0"))

    oAppSetting.SetValue("Bytescout", IIf(chkBytescout.Checked, "1", "0"))
    oAppSetting.SetValue("Fast", IIf(chkFast.Checked, "1", "0"))

    oAppSetting.SaveData()
End Sub

Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load

    oAppSetting.LoadData()

    txtFrom.Text = oAppSetting.GetValue("FromPath")
    txtRegName.Text = oAppSetting.GetValueDef("RegName", txtRegName.Text)
    txtRegKey.Text = oAppSetting.GetValueDef("RegKey", txtRegKey.Text)
    txtStartFile.Text = oAppSetting.GetValue("StartFile")

    Dim sBarcodeType As String = oAppSetting.GetValue("BarcodeType")
    If sBarcodeType <> "" Then
        cbBarcodeType.SelectedIndex = CInt(sBarcodeType)
    Else
        cbBarcodeType.SelectedIndex = 0
    End If

    Dim sDirection As String = oAppSetting.GetValue("Direction")
    If sDirection <> "" Then
        cbDirection.SelectedIndex = CInt(sDirection)
    Else
        cbDirection.SelectedIndex = 0
    End If

    chkUseBarcodeZones.Checked = oAppSetting.GetValue("UseBarcodeZones") = "1"
    chkLog.Checked = oAppSetting.GetValue("Log") <> "0"
    chkShowTime.Checked = oAppSetting.GetValue("ShowTime") <> "0"
    chkCSV.Checked = oAppSetting.GetValue("CSV") <> "0"

    chkBytescout.Checked = oAppSetting.GetValue("Bytescout") = "1"
    chkFast.Checked = oAppSetting.GetValue("Fast") = "1"

    BytescoutChecked()
End Sub

Public Shared Function GetShortName(ByVal sLongFileName As String) As String

    If sLongFileName.Length < 250 Then
        Return sLongFileName
    End If

    Dim lRetVal As Long
    Dim iLen As Integer = 1024
    Dim sShortPathName As System.Text.StringBuilder = New System.Text.StringBuilder(iLen)
    lRetVal = GetShortPathName(sLongFileName, sShortPathName, iLen)
    Dim sRet As String = sShortPathName.ToString()

    If sRet <> "" Then
        Return sRet
    Else
        Return sLongFileName
    End If

End Function

Private Sub btnFrom_Click(sender As System.Object, e As System.EventArgs) Handles btnFrom.Click
    fldFrom.SelectedPath = txtFrom.Text
    fldFrom.ShowDialog()
    txtFrom.Text = fldFrom.SelectedPath
End Sub

Private Sub btnProcess_Click(sender As System.Object, e As System.EventArgs) _
           Handles btnProcess.Click
    btnProcess.Enabled = False

    Dim sFromPath As String = txtFrom.Text
    If Not Directory.Exists(sFromPath) Then
        btnProcess.Enabled = True
        MsgBox("Folder does not exist")
        Exit Sub
    End If

    If chkCSV.Checked Then
        Dim sLogFileName As String = Now.Month.ToString() & "-" & _
         Now.Day.ToString() & "-" & _
         Now.Year.ToString() & "_" & _
         Now.Hour.ToString() & "-" & _
         Now.Minute.ToString() & "-" & _
         Now.Second.ToString() & ".csv"
        Dim sLogFilePath As String = IO.Path.Combine(sFromPath, sLogFileName)
        oLogFile = New System.IO.StreamWriter(sLogFilePath)
    End If

    If txtStartFile.Text <> "" Then
        bStartFile = False
    End If

    txtOutput.Text = ""
    txtOutput.AppendText("Starting..." & vbCrLf)
    ProccessFolder(sFromPath)
    txtOutput.AppendText("Done!")

    btnProcess.Enabled = True

    If chkCSV.Checked Then
        oLogFile.Close()
    End If

End Sub

Sub ProccessFolder(ByVal sFolderPath As String)
    Dim sFromPath As String = txtFrom.Text
    Dim oFiles As String() = Directory.GetFiles(sFolderPath)
    ProgressBar1.Maximum = oFiles.Length
    For i As Integer = 0 To oFiles.Length - 1
        Dim sFromFilePath As String = oFiles(i)

        If txtStartFile.Text <> "" Then
            If Trim(LCase(txtStartFile.Text)) = LCase(sFromFilePath) Then
                bStartFile = True
            End If
        End If

        If bStartFile Then
            Dim oFileInfo As New FileInfo(GetShortName(sFromFilePath))
            Dim sExt As String = PadExt(oFileInfo.Extension)

            If sExt = "JPG" Or sExt = "GIF" Or sExt = "PNG" Or sExt = "BMP" Or sExt = "TIF" Then

                If chkBytescout.Checked Then
                    Bytescout_ReadBarcode(sFromFilePath)
                Else
                    ReadBarcode(sFromFilePath)
                End If

            End If
        End If

        ProgressBar1.Value = i
        Application.DoEvents()
    Next

    ProgressBar1.Value = 0

    Dim oFolders As String() = Directory.GetDirectories(sFolderPath)
    For i As Integer = 0 To oFolders.Length - 1
        Dim sChildFolder As String = oFolders(i)
        Dim iPos As Integer = sChildFolder.LastIndexOf("\")
        Dim sFolderName As String = sChildFolder.Substring(iPos + 1)
        ProccessFolder(sChildFolder)
    Next

End Sub

Private Sub ReadBarcode(sFromFilePath As String)

    Dim sFromPath As String = txtFrom.Text
    Dim sFileName As String = sFromFilePath.Replace(sFromPath & "\", "")

    Dim oImage As System.Drawing.Image = Nothing

    Try
        oImage = System.Drawing.Image.FromFile(sFromFilePath)
    Catch ex As Exception
        If chkLog.Checked Then
            txtOutput.AppendText(sFileName & vbTab & "Could not open" & vbCrLf)
        End If

        WriteLog(sFileName & "," & "Could not open")
        Exit Sub
    End Try

    Dim barcodes As New System.Collections.ArrayList
    Dim iScans As Integer = 100
    Dim dtStart As DateTime = DateTime.Now

    BarcodeImaging.UseBarcodeZones = chkUseBarcodeZones.Checked

    Dim oBarcodeType As BarcodeImaging.BarcodeType = BarcodeImaging.BarcodeType.All
    Select Case cbBarcodeType.Text
        Case "Code39"
            oBarcodeType = BarcodeImaging.BarcodeType.Code39
        Case "Code128"
            oBarcodeType = BarcodeImaging.BarcodeType.Code128
        Case "EAN"
            oBarcodeType = BarcodeImaging.BarcodeType.EAN
    End Select

    Select Case cbDirection.Text
        Case "All"
            BarcodeImaging.FullScanBarcodeTypes = oBarcodeType
            BarcodeImaging.FullScanPage(barcodes, oImage, iScans)
        Case "Vertical"
            BarcodeImaging.ScanPage(barcodes, oImage, iScans, _
                                    BarcodeImaging.ScanDirection.Horizontal, oBarcodeType)
        Case "Horizontal"
            BarcodeImaging.ScanPage(barcodes, oImage, iScans, _
                                    BarcodeImaging.ScanDirection.Vertical, oBarcodeType)
    End Select

    Dim sSec As String = ""
    If chkShowTime.Checked Then
        sSec = vbTab & DateTime.Now.Subtract(dtStart).TotalSeconds.ToString("#0.00")
    End If

    If barcodes.Count = 0 Then

        If chkLog.Checked Then
            txtOutput.AppendText(sFileName & vbTab & "Failed" & sSec & vbCrLf)
        End If

        WriteLog(sFileName & "," & "Failed")
    Else
        For Each bc As Object In barcodes

            If chkLog.Checked Then
                txtOutput.AppendText(sFileName & vbTab & bc & sSec & vbCrLf)
            End If

            WriteLog(sFileName & "," & bc)
        Next
    End If

    oImage.Dispose()
End Sub

Here is the code for AppSetting.vb to persist user settings:

VB.NET
Public Class AppSetting

	Private oDS As New Data.DataSet
	Private oTable As New Data.DataTable
	Private sFilePath As String = ""

	Public Sub New()
		Dim sAssPath As String = System.Reflection.Assembly.GetExecutingAssembly().Location
		Dim sPath As String = System.IO.Path.GetDirectoryName(sAssPath)
		sFilePath = System.IO.Path.Combine(sPath, "Settings.xml")
	End Sub

	Public Sub LoadData()
		oDS = New Data.DataSet()

		If System.IO.File.Exists(sFilePath) Then
			oDS.ReadXml(sFilePath)
			If oDS.Tables.Count > 0 Then
				oTable = oDS.Tables(0)
				Exit Sub
			End If
		End If

		'setup New
		oTable = New Data.DataTable()
		oTable.Columns.Add(New Data.DataColumn("key"))
		oTable.Columns.Add(New Data.DataColumn("value"))
		oDS.Tables.Add(oTable)
	End Sub

	Public Sub SaveData()
		'If System.IO.File.Exists(sFilePath) Then
		'	System.IO.File.Delete(sFilePath)
		'End If

		oTable.DataSet.WriteXml(sFilePath, XmlWriteMode.WriteSchema)
	End Sub

	Public Sub SetValue(ByVal sKey As String, ByVal sValue As String)

		Dim oDataRow As DataRow
		Dim oDataRows As DataRow() = oTable.Select("key = '" & Replace(sKey, "'", "''") & "'")
		If oDataRows.Length > 0 Then
			oDataRows(0)("value") = sValue
		Else
			oDataRow = oTable.NewRow()
			oDataRow("key") = sKey
			oDataRow("value") = sValue
			oTable.Rows.Add(oDataRow)
		End If

	End Sub

	Public Function GetValue(ByVal sKey As String) As String
		Dim oDataRows As DataRow() = oTable.Select("key = '" & Replace(sKey, "'", "''") & "'")
		If oDataRows.Length > 0 Then
			Return oDataRows(0)("value") & ""
		End If
		Return ""
	End Function

	Public Function GetValueDef(ByVal sKey As String, ByVal sDefVal As String) As String
		Dim sValue As String = GetValue(sKey)
		If sValue <> "" Then
			Return sValue
		End If

		Return sDefVal
	End Function
End Class

History

  • 16th January, 2019: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)