Click here to Skip to main content
Click here to Skip to main content
Go to top

An EAN13 Code Control

, 24 May 2005
Rate this:
Please Sign up or sign in to vote.
A Windows control that draws EAN13 Codes.

Introduction

EAN-13 is a Standard - Barcode - format. This code is used to scan articles in stores and other places. For a project I'm working on, I need to print EAN - Codes on a Laser printer and display them on the screen for the user. The printing task is quite easy since most printers support EAN - Codes, if you pass them an escape sequence. The trouble is, that you can pass the escape sequences only if you open the port manually and print the whole page with print-commands, which means, you can not use the System.Drawing.Printing objects. So, if you want to print EAN - Codes and use the Print objects of .NET, you need to draw the EAN - Codes yourself.

The EAN - Format

To draw an EAN - 13 formatted Barcode you need three tables which tell you how to format each digit. The first and the second are used for the digits 1 - 7 and the third table is used for the digits 8 - 13. Each digit is 12 bits long; if you count the 2 bits separators they are 14 bits long.

These are the three tables with the digits and their decimal value in the barcode:

Digit Table 1 Table 2 Table 3
0 243 3135 4035
1 963 3855 3855
2 783 975 3900
3 4083 3075 3075
4 3087 1011 3324
5 3843 4035 3135
6 3327 51 3264
7 4047 771 3084
8 3903 195 3120
9 207 831 4044

Now the question is: Why do we use two tables for the first 7 digits? Answer: Because the first digit is not really printed, if you look at the code you only see the digits 2-13. First digit is decoded by the variations of the usage for the drawing of digits 2-7.

These are the combinations we use to decode the first digit:

Value: Digit1 Tab for Digit2 Digit3 Digit4 Digit5 Digit6 Digit7
0 1 1 1 1 1 1
1 1 1 2 1 2 2
2 1 1 2 2 1 2
3 1 1 2 2 2 1
4 1 2 1 1 2 2
5 1 2 2 1 1 2
6 1 2 2 2 1 1
7 1 2 1 2 1 2
8 1 2 1 2 2 1
9 1 2 2 1 2 1

Now, the last important thing is the 13th digit. You can't choose it freely. It's a checksum. It's calculated in the following way:

  1. Go through digits 1-12, if the digit is even add the value, if not add the value * 3.
  2. Calculate the modulus 10 of the sum calculated below.
  3. Subtract the value from 10.
  4. Calculate once again the Modulus 10 of the value.

If you code it, it looks like this:

private string CreateChecksum(string EAN)
{
    int csumTotal = 0; // The checksum working variable starts at zero
    // Calculate the checksum value for the message
    for( int charPos = EAN.Length - 1; charPos >= 0; charPos--) 
    {
        if( charPos % 2 == 0 )
            csumTotal = csumTotal + int.Parse(EAN.Substring(charPos,1));
        else
            csumTotal = csumTotal + (3 * int.Parse(EAN.Substring(charPos,1)));
    }
    // Calculate the checksum digit
    int remainder = 10-(csumTotal % 10);
    remainder = remainder % 10;
    return remainder.ToString();
}

The EAN - Class

private int[] Pool01i; // the Integer Representation of the Tables 1 and 2
private char[] Pool01s; // the char Representation of the tables 1 and 2
private int[] Pool2i; // the Integer Representation of the Table 3
// the Offsets for each digit depending on the first
private int[][] Additions = new int[10][]; 
private const int p = 112; //ASCII - Value of p
private const int P = 80; // ASCII - Value of P
private Color backcolor; // Backcolor of EAN - Code
// Bitmap, that holds the graphic representation of the Code
private Bitmap tmpCode; 
// Graphics - Object to draw the EAN - Code into the Bitmap
private Graphics Renderer; 
private int wdth; //Width of EAN - Code
private int hght; //Height of EAN
private Font font //Used font to draw the EAN - String
//Marks the bars which must be longer than the others
private int[] ALengths; 
private string CodeVal = ""; // Binary Representation of the EAN - Code
private string eancode = ""; //Decimal Representation of the EAN - Code
// Marks the Code as Valid or invalid depending on the Checksum
private bool valid = true; 
private int Seperators = 51; // Decimal Value of the Seperator - Bars
private float brushwidth = 1; // Width of a bar
// Event is fired after the EAN - Code has changed
internal event EventHandler CodeChanged;

In the constructor of my EAN class, I initialize these values:

internal EAN13Code(int width, int height, Font fnt, Color BC)
{
    backcolor = BC;
    tmpCode = new Bitmap(width,height);
    Renderer = Graphics.FromImage(tmpCode);
    wdth = width;
    hght = height;
    font = fnt;
    // Pool1i holds the Values of Table 1 and 2
    Pool01i = new int[]{243,963,783,4083,3087,3843,3327,4047,3903,207,
                                3135,3855,975,3075,1011,4035,51,771,195,831};
    // The Values in Pool01i are Associated with char Values from p-y and P-Y
    Pool01s = new char[]{'p','q','r','s','t','u','v','w','x','y','P','Q',
                                             'R','S','T','U','V','W','X','Y'};
    Pool2i = new int[]{4035,3855,3900,3075,3324,3135,3264,3084,3120,4044};
    // in the Additions we set the Offsets for each digit 
    // depending on the value of the first Digit.
    Additions[0] = new int[]{p,p,p,p,p,p};
    Additions[1] = new int[]{p,p,P,p,P,P};
    Additions[2] = new int[]{p,p,P,P,p,P};
    Additions[3] = new int[]{p,p,P,P,P,p};
    Additions[4] = new int[]{p,P,p,p,P,P};
    Additions[5] = new int[]{p,P,P,p,p,P};
    Additions[6] = new int[]{p,P,P,P,p,p};
    Additions[7] = new int[]{p,P,p,P,p,P};
    Additions[8] = new int[]{p,P,p,P,P,p};
    Additions[9] = new int[]{p,P,P,p,P,p};
    ALengths = new int[190];
    for (int i= 0; i< ALengths.Length;i++)
    {
        //We want the Leading bars, the seperator - Bars and the Ending 
        // Bars to be longer than the others.
        ALengths[i] = 0;
        if (i == 0 |i == 1 |i == 4 |i == 5 | i==92 | i == 93 |i == 96 | 
                     i == 97 | i == 189 | i == 188 | i == 185 | i == 184)
        {
            ALengths[i] = 10;
        }
    }
}

With the property EANCode, I aggregate the variable eancode and do all the steps to make sure that the EAN - Code can be painted.

internal string EANCode
{
    get
    {
       return eancode;
    }
    set
    {
       // assign the Code no matter if it's valid or not.
       eancode = value.Trim();
       // if the Length is 12 we calculate the Checksum
       if (eancode.Length == 12)
       {
           eancode += CreateChecksum(eancode);
       }
       // if the EAN - Code is 13 digits long we check if the code is valid and
       // create the binary representation of it.
       if (eancode.Length == 13)
       {
         valid = true;
         if (CreateChecksum(eancode.Substring(0,12)) != eancode[12].ToString())
         {
             valid = false;
         }
         CodeVal = CreateCode(eancode);
       }
       // we draw the Code into a bitmap and inform the client that the code is
       // now ready for Painting somewhere.
       PrepareCode();
       if (CodeChanged != null)
       {
          CodeChanged(this,EventArgs.Empty);
       }
    }
}

The creation of the binary representation of the EAN - Code is quite simple:

private string CreateCode(string ean)
{
     string RetVal = "";
    // First thing in the code are the 2 leading Seperator - Bars.
    RetVal = Dec2Bin(Seperators);
    // Get the first Digit of the code. we use 
    // this number for the Selection of the
    // Table we're going to use for the 2nd to the 7th digit.
    int Spos = int.Parse(ean.Substring(0,1));
    for (int i=1; i<=ean.Length;i++)
    {
       if (i <= 6)
       {
           //Each Digit is leaded by 2 empty Bars. 
           // for the first 6 Digits we use Pool01i with an 
           // offset depending on the first Digit
           int nm = int.Parse(ean.Substring(i,1));
           RetVal += "00" + Dec2Bin(Pool01i[IndexOf(nm+Additions[Spos][i-1],
                                                     Pool01s)]).PadLeft(12,'0');
       }
       else if (i == 7)
       {
           // in the Middle we draw the Seperator
           RetVal += "00" + Dec2Bin(Seperators);
       }
       else
       {
           // the rest of the digits are defined with Pool2i
           int nm = int.Parse(ean.Substring(i-1,1));
           RetVal += "00" + Dec2Bin(Pool2i[nm]).PadLeft(12,'0');
       }
    }
    // The Code is finished with the Ending Seperator.
    RetVal += "00" + Dec2Bin(Seperators);
    return RetVal;
}

After we know what the binary appearance of the code is, we can create a bitmap of it.

private void PrepareCode()
{
    //Create a Bitmap with the Measurements of the EAN - Code
    tmpCode = new Bitmap(wdth,hght);
    // Initialize the Graphics object for the Bitmap.
    Renderer = Graphics.FromImage(tmpCode);
    // Set the Backcolor of the Control.
    Renderer.Clear(backcolor);
    //Print the EAN into the Bitmap.
    WriteEAN(10,0,Renderer,hght*2/3);
}
private void WriteEAN(int x, int y, Graphics g, int Height)
{
    // Set the Color of the Bars with 1 depending on if 
    // the code is valid (black) or invalid (red)
    Brush B1 = (Brush)System.Drawing.Brushes.Black.Clone();
    if (!valid)
    {
        B1 = (Brush)Brushes.Red.Clone();
    }
    // the Bars with 0 are not painted.
    Brush B0 = (Brush)Brushes.Transparent.Clone();
    Font PFont = font;
    // the Barcode is only painted if its length is 13
    if (eancode.Length == 13)
    {
        // First draw the leading Digit.
        g.DrawString(eancode.Substring(0,1),PFont, System.Drawing.Brushes.Black, 
            x-g.MeasureString(eancode.Substring(0,1),PFont).Width-3,y+Height+3);
        float F = 0;
        // Now Draw all the Bars in black or transparent.
        for (int i= 0; i< CodeVal.Length; i++, F+=brushwidth)
        {
            if (CodeVal.Substring(i,1) == "1")
            {
                 g.FillRectangle(B1,x+F,y,brushwidth,Height+ALengths[i]);
            }
            else
            {
                 g.FillRectangle(B0,x+F,y,brushwidth,Height+ALengths[i]);
            }
        }
        F = brushwidth;
        // Write the decimal Representations of 
        // each digit on the Position the bars
        // were painted before.
        for (int i = 1; i<=6; i++, F+=brushwidth)
        {
            g.DrawString(eancode.Substring(i,1),PFont,
                     System.Drawing.Brushes.Black,x+(14*(F-1))+8,y+Height+3);
        }
        F = brushwidth*7;
        for (int i = 7; i<13; i++,F+=brushwidth)
        {
            g.DrawString(eancode.Substring(i,1),PFont,
                    System.Drawing.Brushes.Black,x+(14*(F-7))+99,y+Height+3);
        }
    }
}

After I created the EAN13 class, I added an object of it as a member to a control and that's now my EAN13CodeControl.

Usage of the Code

Add EAN13CodeControl on a form and type in your code something like this:

eaN13CodeCtl1.Text = "012345678901";

So, that's all

If you're interested in EAN13 backgrounds, there's a great article from rainman_63 about that.

The code looks a bit strange (naming conventions and things like that), sorry about that.

License

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

Share

About the Author

m@u
Software Developer
Switzerland Switzerland
No Biography provided

Comments and Discussions

 
QuestionEAN-13 Control PinmemberZacbr13-May-12 14:01 
GeneralMy vote of 5 Pinmembercseq20-Nov-11 4:08 
GeneralMy vote of 5 PinmemberGabriel_7513-Oct-11 3:57 
GeneralHelp me to generate EAN-8 code PinmemberMathiyazhagan17-Aug-09 20:43 
GeneralThis stuff doesnt work! PinmemberP98Ft5622-Oct-08 8:19 
Always nice to find out that when you download something it doesnt work at all. Something with conversion to 2008 Visual Basic.
QuestionLicense? PinmemberTomas Brennan3-Sep-07 3:14 
AnswerRe: License? PinmemberThe Dogcow Farmer1-Oct-08 6:51 
GeneralGood Article on EAN13 PinmemberBashiiui22-Jun-06 21:17 
GeneralCutted image PinmemberPablo Robert17-Jun-05 10:43 
GeneralDownload Misspelled PinmemberASerfes18-Apr-05 2:02 
GeneralRe: Download Misspelled Pinmemberm@u18-Apr-05 2:26 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140916.1 | Last Updated 24 May 2005
Article Copyright 2005 by m@u
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid