Monday, September 18, 2006 12:08 AM bart

Code 39 barcodes in C#

Introduction

Code 39 is a specification for barcodes that allows coding of the following symbols: A-Z 0-9 - . $ / + % * space. The goal of this small project is to allow generation of barcodes using System.Drawing in .NET, with C#.

Some principles

Every character of a code is translated into a sequence of white and black bars, each of which can be narrow or wide. A code is typically wrapped between a trailing and ending * character because the encoding of the * character allows to detect the orientation of the barcode based on asymmetry. Encoding of the characters is done on a one-per-one basis and an intercharacter gap (white) is inserted between two consecutive character encodings. For more info, see the Code 39 specification.

Mission goal

In the end we want to be able to write the following;

class Program
{
   static void Main(string
[] args)
   {
      Code39 code = new Code39("BART DE SMET"
);
      code.Paint().Save(
"c:\\temp\\demo.bmp"
);
   }
}

The code skeleton

The basic code skeleton looks as follows, including the constructors and two private members:

class Code39
{
   private string
code;
   private Code39Settings
settings;

   public Code39(string code) : this(code, new Code39Settings
())
   {
   }

   public Code39(string code, Code39Settings
settings)
   {
      foreach (char c in
code)
         if
(!codes.ContainsKey(c))
            throw new ArgumentException("Invalid character encountered in specified code."
);

      if (!code.StartsWith("*"
))
         code =
"*"
+ code;
      if (!code.EndsWith("*"
))
         code = code +
"*"
;

      this
.code = code;
     
this
.settings = settings;
   }
}

The Code39Settings class isn't rocket science at all and is a container for a series of properties ('property type' 'property name' = 'default value'):

  • int BarCodeHeight = 80
  • int LeftMargin = 10
  • int RightMargin = 10
  • int TopMargin = 10
  • int BottomMargin = 10
  • int WideWidth = 6
  • int NarrowWidth = 2
  • int InterCharacterGap = 2
  • bool DrawText = true
  • int CodeToTextGapHeight = 10
  • Font Font = new Font(FontFamily.GenericSansSerif, 12)

Coding the character codes

Another requirement is an encoding table that maps a character on a encoding. Basically, every character is encoded as a BWBWBWBWB pattern (B=black, W=white) each of which can be either n(arrow) or w(ide). Therefore we have the following code table:

static Dictionary<char, Pattern> codes;

static
Code39()
{
   object[][] chars = new object
[][]
   {
      new object[] {'0', "n n n w w n w n n"
},
      new object[] {'1', "w n n w n n n n w"
},
      new object[] {'2', "n n w w n n n n w"
},
      new object[] {'3', "w n w w n n n n n"
},
      new object[] {'4', "n n n w w n n n w"
},
      new object[] {'5', "w n n w w n n n n"
},
      new object[] {'6', "n n w w w n n n n"
},
      new object[] {'7', "n n n w n n w n w"
},
      new object[] {'8', "w n n w n n w n n"
},
      new object[] {'9', "n n w w n n w n n"
},
      new object[] {'A', "w n n n n w n n w"
},
      new object[] {'B', "n n w n n w n n w"
},
      new object[] {'C', "w n w n n w n n n"
},
      new object[] {'D', "n n n n w w n n w"
},
      new object[] {'E', "w n n n w w n n n"
},
      new object[] {'F', "n n w n w w n n n"
},
      new object[] {'G', "n n n n n w w n w"
},
      new object[] {'H', "w n n n n w w n n"
},
      new object[] {'I', "n n w n n w w n n"
},
      new object[] {'J', "n n n n w w w n n"
},
      new object[] {'K', "w n n n n n n w w"
},
      new object[] {'L', "n n w n n n n w w"
},
      new object[] {'M', "w n w n n n n w n"
},
      new object[] {'N', "n n n n w n n w w"
},
      new object[] {'O', "w n n n w n n w n"
},
      new object[] {'P', "n n w n w n n w n"
},
      new object[] {'Q', "n n n n n n w w w"
},
      new object[] {'R', "w n n n n n w w n"
},
      new object[] {'S', "n n w n n n w w n"
},
      new object[] {'T', "n n n n w n w w n"
},
      new object[] {'U', "w w n n n n n n w"
},
      new object[] {'V', "n w w n n n n n w"
},
      new object[] {'W', "w w w n n n n n n"
},
      new object[] {'X', "n w n n w n n n w"
},
      new object[] {'Y', "w w n n w n n n n"
},
      new object[] {'Z', "n w w n w n n n n"
},
      new object[] {'-', "n w n n n n w n w"
},
      new object[] {'.', "w w n n n n w n n"
},
      new object[] {' ', "n w w n n n w n n"
},
      new object[] {'*', "n w n n w n w n n"
},
      new object[] {'$', "n w n w n w n n n"
},
      new object[] {'/', "n w n w n n n w n"
},
      new object[] {'+', "n w n n n w n w n"
},
      new object[] {'%', "n n n w n w n w n"
}
   };

   codes =
new Dictionary<char, Pattern
>();
   foreach (object[] c in
chars)
      codes.Add((
char)c[0], Pattern.Parse((string
)c[1]));
}

private static Pen pen = new Pen(Color.Black);
private static Brush brush = Brushes.Black;

The two last lines are System.Drawing support for what comes next.

Representing and painting patterns

As you've seen in the initialization code above, we need some Pattern class to represent a single character pattern and - see later - that's also able to paint itself in some given "context". Therefore we define a private class Pattern.

private class Pattern
{
   private bool[] nw = new bool[9];
}

First we define the static Parse method:

public static Pattern Parse(string s)
{
   Debug.Assert(s != null);

   s = s.Replace(
" ", "").ToLower();

   Debug.Assert(s.Length == 9);
   Debug.Assert(s.Replace("n", "").Replace("w", "").Length == 0);

   Pattern p = new Pattern
();

   int
i = 0;
   foreach (char c in
s)
      p.nw[i++] = c ==
'w'
;

   return
p;
}

Nothing special going on in here, just parsing the narrow-wide code string (from the static initialization stuff) to a boolean array, of which each element tells whether the corresponding position (B/W) in the graphical code is wide (true) or not (false).

Example:

For {'0', "n n n w w n w n n"} the encoding will become { false, false, false, true, true, false, true, false, false } meaning: narrow black + narrow white + narrow black + wide white + wide black + narrow white + wide black + narrow white + narrow black or:

Time to get the thing painted: the Paint method. Notice this requires System.Drawing.dll to be referenced and the System.Drawing namespace to be imported:

public int Paint(Code39Settings settings, Graphics g, int left)
{
   #if
DEBUG
   Rectangle gray = new Rectangle
(left, 0, GetWidth(settings), settings.BarCodeHeight + settings.TopMargin + settings.BottomMargin);
   g.FillRectangle(
Brushes
.Gray, gray);
   #endif

   int
x = left;
   int
w = 0;

   for (int
i = 0; i < 9; i++)
   {
      int
width = (nw[i] ? settings.WideWidth : settings.NarrowWidth);
      if
(i % 2 == 0)
      {
         Rectangle r = new Rectangle
(x, settings.TopMargin, width, settings.BarCodeHeight);
         g.FillRectangle(brush, r);
      }
      x += width;
      w += width;
   }

   return
w;
}

This piece of code is given a Graphics graphical context, the Code39Settings object as well as the left position to start painting on (on the "canvas" of the Graphics context). It returns the horizontal space taken while painting the character.

In the core loop of the method, the width of the current "code part" (i.e. the white or black bar) is examined by looking at the nw array. This determines the width of the "code part" based on the settings (WideWidth or NarrowWidth). For every even position (i.e. 0, 2, 4, 6, 8) we'll draw a black bar with the determined width. Otherwise, we'll just skip drawing and continue, while bookkeeping the total drawing width.

To assist in debugging we paint a gray background when the debugging flag is turned on (Debug build). This allows for visual inspection without having your eyes hurt on the tiny bars with a screen flicker rate of 60 to 75 Hz :-). Example:

(Notice the 6 characters needed to encode BART, because of the trailing * characters.)

An additional supporting method is available to calculate the width of a character pattern without drawing it:

public int GetWidth(Code39Settings settings)
{
   int
width = 0;

   for (int
i = 0; i < 9; i++)
      width += (nw[i] ? settings.WideWidth : settings.NarrowWidth);

   return
width;
}

Painting the code

On to the Code39 class's Paint method. Quite a bit of code but rather easy to understand:

public Bitmap Paint()
{
   string code = this.code.Trim('*'
);

   SizeF sizeCodeText = Graphics.FromImage(new Bitmap
(1, 1)).MeasureString(code, settings.Font);

   int
w = settings.LeftMargin + settings.RightMargin;
   foreach (char c in this
.code)
      w += codes[c].GetWidth(settings) + settings.InterCharacterGap;
   w -= settings.InterCharacterGap;

   int
h = settings.TopMargin + settings.BottomMargin + settings.BarCodeHeight;
   if
(settings.DrawText)
      h += settings.BarCodeToTextGapHeight + (
int
) sizeCodeText.Height;

   Bitmap bmp = new Bitmap(w, h, PixelFormat
.Format32bppArgb);
   Graphics g = Graphics
.FromImage(bmp);

   int
left = settings.LeftMargin;
   foreach (char c in this
.code)
      left += codes[c].Paint(settings, g, left) + settings.InterCharacterGap;

   if
(settings.DrawText)
   {
      int tX = settings.LeftMargin + (w - settings.LeftMargin - settings.RightMargin - (int
) sizeCodeText.Width) / 2;

      if
(tX < 0)
         tX = 0;

      int
tY = settings.TopMargin + settings.BarCodeHeight + settings.BarCodeToTextGapHeight;
      g.DrawString(code, settings.Font, brush, tX, tY);
   }

   return
bmp;
}

Apart from some string measurement tricks, the code is rather straightforward. The core of the method is the following piece of code:

   foreach (char c in this.code)
      left += codes[c].Paint(settings, g, left) + settings.InterCharacterGap;

This piece of code is responsible to extract the code patterns from the codes encoding dictionary and ask these objects to paint themselves (Pattern.Paint) on the given left position, every time leaving some intercharacter gap spacing.

The result

Have fun,

Code39 code = new Code39("BART DE SMET");
code.Paint().Save(
"c:\\temp\\bart.png", ImageFormat.Png);

Download the code here.

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Filed under:

Comments

# Code 39 barcodes in C#

Monday, September 18, 2006 7:34 AM by It's Way Too Early For This

Another great post from Bart. Reproduced here in all it's glory. Thanks for your contributions, Bart!

# Tim Van Wassenhove &raquo; Blog Archive &raquo; Code 39 barcodes recognizer

# An ASP.NET .ashx HTTP handler for Code-39 barcode generation

Tuesday, September 19, 2006 3:22 AM by B# .NET Blog

Introduction
In my previous blog post on Code-39 barcodes, I've shown you guys how to generate Code-39...

# An ASP.NET .ashx HTTP handler for Code 39 barcode generation

Tuesday, September 19, 2006 7:31 AM by It's Way Too Early For This

I dig Bart's contributions. Here's yet another one. A follow on to his previous post on the Code 39 Barcode

# EAN-13 barcodes in C#

Tuesday, September 19, 2006 6:11 PM by B# .NET Blog

Introduction
A couple of days ago I posted about Code 39 barcode generation in C#&amp;nbsp;(and here). Today...

# Creating Barcodes On The Fly With C#

Monday, October 02, 2006 7:06 PM by Tom's corner

# Creating Barcodes On The Fly With C#

Friday, October 06, 2006 6:04 AM by It's Way Too Early For This

I had a couple of pointers to two of these articles, but here is the whole catalog of barcode code from

# Tim Van Wassenhove &raquo; Blog Archive &raquo; Code 39 barcodes recognizer

# Code 39 in C# &laquo; .NET i takie tam

Monday, June 18, 2007 8:47 AM by Code 39 in C# « .NET i takie tam

Pingback from  Code 39 in C# &laquo; .NET i takie tam

# http://community.bartdesmet.net/blogs/bart/archive/2006/09/18/4432.aspx

# http://blog.bartdesmet.net/blogs/bart/archive/2006/09/18/4432.aspx

# http://bartdesmet.net/blogs/bart/archive/2006/09/18/4432.aspx

# http://blogs.bartdesmet.net/blogs/bart/archive/2006/09/18/4432.aspx

# RBM Binary Image now displays barcode using Code39 : Ramy Mostafa

Pingback from  RBM Binary Image now displays barcode using Code39 : Ramy Mostafa