Barcodes in C#: UPC-5
UPC-5 is a variation on the UPC-A barcode](/programming/2009/10/barcodes-in-csharp-upca) designed to contain 5 digits of data.
The checksum (or parity) for the UPC-5 format is used only to encode the barcode, and therefore is not coded directly.
Calculating the parity uses the same modulo 10 method as the UPC-A, except that the weightings are different. Odd-numbered positions are weighted 3, while even-numbered positions are weighted 9.
Once we have the weighted sum, we apply a modulo 10 to the weighted sum, which gets the remainder after applying a modulo of 10 to the weighted sum.
The parity is then 10 - (modulo 10 of the weighted sum).
UPC-5 only has a left guard and centre guard (which is places after the third digit), which are encoded as 1011 and 01 respectively.
The 5 digits are then encoded using either odd or even encoding, which is determined by the parity string.
0 | 00111 |
1 | 01011 |
2 | 01101 |
3 | 01110 |
4 | 10011 |
5 | 11001 |
6 | 11100 |
7 | 10101 |
8 | 10110 |
9 | 11010 |
The odd and even encodings are the same as the ones for the UPC-E format</p>
Digit | Odd | Even |
0 | 0001101 | 0100111 |
1 | 0011001 | 0110011 |
2 | 0010011 | 0011011 |
3 | 0111101 | 0100001 |
4 | 0100011 | 0011101 |
5 | 0110001 | 0111001 |
6 | 0101111 | 0000101 |
7 | 0111011 | 0010001 |
8 | 0110111 | 0001001 |
9 | 0001011 | 0010111 |
The full source code is available at [https://github.com/sjmeunier/barcoder](https://github.com/sjmeunier/barcoder).
namespace BarcoderLib
{
public class BarcodeUPC5
{
private string gLeftGuard = "1011";
private string gCentreGuard = "01";
private string[] gOdd = { "0001101", "0011001", "0010011", "0111101", "0100011", "0110001", "0101111", "0111011", "0110111", "0001011" };
private string[] gEven = { "0100111", "0110011", "0011011", "0100001", "0011101", "0111001", "0000101", "0010001", "0001001", "0010111" };
private string[] gParity = {"00111", "01011", "01101", "01110", "10011", "11001", "11100", "10101", "10110", "11010"};
private int[] gWeighting = { 3, 9, 3, 9, 3};
public Bitmap Encode(string message)
{
string encodedMessage;
Bitmap barcodeImage = new Bitmap(250, 100);
Graphics g = Graphics.FromImage(barcodeImage);
Validate(message);
encodedMessage = EncodeBarcode(message);
PrintBarcode(g, encodedMessage, message, 250, 100);
return barcodeImage;
}
private void Validate(string message)
{
Regex reNum = new Regex(@"^\d+$");
if (reNum.Match(message).Success == false)
{
throw new Exception("Encode string must be numeric");
}
if (message.Length != 5)
{
throw new Exception("Encode string must be 5 digits long");
}
}
private void PrintBarcode(Graphics g, string encodedMessage, string message, int width, int height)
{
SolidBrush whiteBrush = new SolidBrush(Color.White);
SolidBrush blackBrush = new SolidBrush(Color.Black);
Font textFont = new Font(FontFamily.GenericMonospace, 10, FontStyle.Regular);
g.FillRectangle(whiteBrush, 0, 0, width, height);
int xPos = 20;
int yTop = 20;
int barHeight = 50;
for (int i = 0; i < encodedMessage.Length; i++)
{
if (encodedMessage[i] == '1')
{
g.FillRectangle(blackBrush, xPos, yTop, 1, barHeight);
}
xPos += 1;
}
xPos = 20;
yTop -= 17;
for (int i = 0; i < message.Length; i++)
{
g.DrawString(message[i].ToString(), textFont, blackBrush, xPos, yTop);
xPos += 7;
}
}
private string EncodeBarcode(string message)
{
int i;
int parityCode = CalcParity(message);
char parity;
string encodedString = gLeftGuard;
for (i = 0; i < 5; i++)
{
parity = gParity[parityCode][i];
if (parity == '1')
{
encodedString += gOdd[Convert.ToInt32(message[i].ToString())];
}
else{
encodedString += gEven[Convert.ToInt32(message[i].ToString())];
}
if (i < 4)
{
encodedString += gCentreGuard;
}
}
return encodedString;
}
private int CalcParity(string message)
{
int sum = 0;
int parity = 0;
for (int i = 0; i < 5; i++)
{
sum += Convert.ToInt32(message[i].ToString()) * gWeighting[i];
}
parity = 10 - (sum % 10);
if (parity == 10)
{
parity = 0;
}
return parity;
}
}
}