
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:
- Go through digits 1-12, if the digit is even add the value, if not add the value * 3.
- Calculate the modulus 10 of the sum calculated below.
- Subtract the value from 10.
- 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; 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)));
}
int remainder = 10-(csumTotal % 10);
remainder = remainder % 10;
return remainder.ToString();
}
The EAN - Class
private int[] Pool01i; private char[] Pool01s; private int[] Pool2i; private int[][] Additions = new int[10][];
private const int p = 112; private const int P = 80; private Color backcolor; private Bitmap tmpCode;
private Graphics Renderer;
private int wdth; private int hght; private Font font private int[] ALengths;
private string CodeVal = ""; private string eancode = ""; private bool valid = true;
private int Seperators = 51; private float brushwidth = 1; 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;
Pool01i = new int[]{243,963,783,4083,3087,3843,3327,4047,3903,207,
3135,3855,975,3075,1011,4035,51,771,195,831};
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};
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++)
{
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
{
eancode = value.Trim();
if (eancode.Length == 12)
{
eancode += CreateChecksum(eancode);
}
if (eancode.Length == 13)
{
valid = true;
if (CreateChecksum(eancode.Substring(0,12)) != eancode[12].ToString())
{
valid = false;
}
CodeVal = CreateCode(eancode);
}
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 = "";
RetVal = Dec2Bin(Seperators);
int Spos = int.Parse(ean.Substring(0,1));
for (int i=1; i<=ean.Length;i++)
{
if (i <= 6)
{
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)
{
RetVal += "00" + Dec2Bin(Seperators);
}
else
{
int nm = int.Parse(ean.Substring(i-1,1));
RetVal += "00" + Dec2Bin(Pool2i[nm]).PadLeft(12,'0');
}
}
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()
{
tmpCode = new Bitmap(wdth,hght);
Renderer = Graphics.FromImage(tmpCode);
Renderer.Clear(backcolor);
WriteEAN(10,0,Renderer,hght*2/3);
}
private void WriteEAN(int x, int y, Graphics g, int Height)
{
Brush B1 = (Brush)System.Drawing.Brushes.Black.Clone();
if (!valid)
{
B1 = (Brush)Brushes.Red.Clone();
}
Brush B0 = (Brush)Brushes.Transparent.Clone();
Font PFont = font;
if (eancode.Length == 13)
{
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;
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;
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.