65.9K
CodeProject is changing. Read more.
Home

Barcode Scanner

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.90/5 (9 votes)

Jan 16, 2019

CPOL
viewsIcon

14763

downloadIcon

1216

This Windows application lets you scan image in a given folder and generate CSV file to show barcodes for each image file.

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:

	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:

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