Serge's World

Blogging about software development, astronomy, genealogy and more.

Barcodes in C#: UPC-E

The UPC-E barcode format is a compressed form of the UPC-A format and is used where space is at a premium. The UPC-E format also require that there are at least 5 0’s in a group in the barcode, so that it can be compressed.

UPC-E

Before we shorten the barcode, we need to enter a full 11 digit UPC-A barcode (excluding the parity digit), and then calculate the parity digit as per the UPC-A barcode.

We first need add up the 11 digits of the barcode with the weighting applied. The weighting is the same as the EAN-13 and UPC-A weighting, where the weighting of each digit which is in an odd-numbered position is 1 and for even-numbered positions, the weighting is 3. To find the sum, we need to multiply each digit by its weighting before adding it together.

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).

Now that we have an 12 digit number, we need to shorten it to an 8 digit number.

The rules for this are quite simple.

The manufacturer portion of the number is the first 5 digits excluding the first digit of the barcode. The product portion is the subsequent 5 digits.

If the last 3 manufacturer digits are 100, 200 or 000, then the shortened for is made up of the first digit, the first two digits of the manufacturer, the last 3 digits of the product, the third digit of the manufacturer and finally the parity.

Otherwise, if the last two digits of the manufacturer is 00, then the barcode is made up of first digit, the first three digits of the manufacturer, the last 2 digits of the product, the number 3, and finally the parity.

Then, if the last digit of the manufacturer is 0, the barcode is made up of first digit, the first four digits of the manufacturer, the last digit of the product, the number 4, and finally the parity.

We can now use this number for the rest of the calculation

We do not split up this format, and only have with a guard bar at the beginning and end of the barcode. The left guard bars are encoded as 101, while the right guard bar is 010101.

The first digit of the barcode determines the parity set to use. The encodings are split up by odd and even encodings, which is determined by the parity bit. This is found by choosing the correct parity set encodings, and then finding the parity bit string for the parity we calculated earlier, and then returning the bit value at the position in the string for the digit we wish to encode.

</tr> </table> Once we have the parity bit, we then choose the odd or even encoding accordingly, for each digit. Only 6 digits are explicitly encoded, since the first and last digits are used to calculate the parity bit, so are not needed to be encoded directly.
Digit</stromg></td> Set 0 Set 1
0 000111 111000
1 001011 110100
2 001101 110010
3 001110 110001
4 010011 101100
5 011001 100110
6 011100 100011
7 010101 101010
8 010110 101001
9 011010 100101
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 BarcodeUPCE
    {
        private string gLeftGuard = "101";
        private string gRightGuard = "010101";
        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 int[] gWeighting = { 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3 };
        private string gLongBars = "111000000000000000000000000000000000000000000111111";
        private string[] gParity0 = { "000111", "001011", "001101", "001110", "010011", "011001", "011100", "010101", "010110", "011010"};
        private string[] gParity1 = { "111000", "110100", "110010", "110001", "101100", "100110", "100011", "101010", "101001", "100101"};

        public Bitmap Encode(string message)
        {
            string encodedMessage;
            string fullMessage;
            string shortMessage;

            Bitmap barcodeImage = new Bitmap(250, 100);
            Graphics g = Graphics.FromImage(barcodeImage);


            Validate(message);
            fullMessage = message + CalcParity(message).ToString().Trim();
            shortMessage = ConvertToShort(fullMessage);
            encodedMessage = EncodeBarcode(shortMessage, fullMessage);

            PrintBarcode(g, encodedMessage, shortMessage, fullMessage, 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 != 11)
            {
                throw new Exception("Encode string must be 11 digits long");
            }
        }

        private void PrintBarcode(Graphics g, string encodedMessage, string message, string fullMessage, 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 = 10;
            int barHeight = 50;
            int barGuardHeight = 7;

            for (int i = 0; i < encodedMessage.Length; i++)
            {
                if (encodedMessage[i] == '1')
                {
                    if (gLongBars[i] == '1')
                    {
                        g.FillRectangle(blackBrush, xPos, yTop, 1, barHeight + barGuardHeight);
                    }
                    else
                    {
                        g.FillRectangle(blackBrush, xPos, yTop, 1, barHeight);
                    }
                }
                xPos += 1;
            }

            xPos = 20;
            yTop += barHeight - 2;
            g.DrawString(fullMessage[0].ToString().Trim(), textFont, blackBrush, xPos - 10, yTop);

            xPos += 1;
            for (int i = 0; i < 6; i++)
            {
                g.DrawString(message[i].ToString().Trim(), textFont, blackBrush, xPos, yTop);
                xPos += 7;
            }
            xPos += 7;
            g.DrawString(message[6].ToString().Trim(), textFont, blackBrush, xPos, yTop);

        }

        private string EncodeBarcode(string message, string fullMessage)
        {
            int i;
            string encodedString = gLeftGuard;
            int parityCode = Convert.ToInt32(fullMessage[11].ToString());
            int paritySet = Convert.ToInt32(fullMessage[0].ToString());
            char parity;

            for (i = 0; i < 6; i++)
            {
                if (paritySet == 0)
                {
                    parity = gParity0[parityCode][i];
                }
                else
                {
                    parity = gParity1[parityCode][i];
                }
                if (parity == '1')
                {
                    encodedString += gOdd[Convert.ToInt32(message[i].ToString())];
                }
                else
                {
                    encodedString += gEven[Convert.ToInt32(message[i].ToString())];
                }
            }
            encodedString += gRightGuard;

            return encodedString;
        }
    
        private int CalcParity(string message)
        {
            int sum = 0;
            int parity = 0;

            for (int i = 0; i < message.Length; i++)
            {
                sum += Convert.ToInt32(message[i].ToString()) * gWeighting[i];
            }

            parity = 10 - (sum % 10);
            if (parity == 10)
            {
                parity = 0;
            }
            return parity;
        }

        private string ConvertToShort(string message)
        {
            string tmp = "";
            string manufacturer = message.Substring(1, 5);
            string product = message.Substring(6, 5);
            string digits = "";
            if ((manufacturer.Substring(2) == "000") || (manufacturer.Substring(2) == "100") || (manufacturer.Substring(2) == "200"))
            {
                digits = manufacturer.Substring(0, 2) + product.Substring(2, 3) + manufacturer.Substring(2, 1);
            }
            else if (manufacturer.Substring(3) == "00")
            {
                digits = manufacturer.Substring(0, 3) + product.Substring(3) + "3";
            }
            else if (manufacturer.Substring(4) == "0")
            {
                digits = manufacturer.Substring(0, 4) + product.Substring(4) + "4";

            }
            else
            {
                digits = manufacturer.Substring(0, 5) + product.Substring(4);
            }
            tmp = digits + message.Substring(11, 1);
            return tmp;
        }
            
    }
}
_Originally posted on my old blog, Smoky Cogs, on 27 Oct 2009_

Tag Cloud

Algorithms (3) Android (10) Astronomy (25) Audio (1) Audiobooks (1) Barcodes (9) C# (69) Css (1) Deep sky (6) Esoteric languages (3) Family (3) Fractals (10) Gaming (1) Genealogy (14) General (2) Geodesy (3) Google (1) Graphics (3) Hubble (2) Humour (1) Image processing (23) Java (8) Javascript (5) jQuery (3) Jupiter (3) Maths (22) Moon (5) Music (4) Pets (5) Programming (88) Saturn (1) Science (1) Spitzer (4) Sun (4) Tutorials (68) Unity (3) Web (9) Whisky (13) Windows (1) Xamarin (2)