Example #1
0
        //
        //
        /// <summary>Make bit vector of version information.</summary>
        /// <remarks>
        /// Make bit vector of version information. On success, store the result in "bits".
        /// See 8.10 of JISX0510:2004 (p.45) for details.
        /// </remarks>
        /// <param name="version">Version of the QR-code</param>
        /// <param name="bits">Vector of bits to contain the result</param>
        public static void MakeVersionInfoBits(int version, BitVector bits)
        {
            bits.AppendBits(version, 6);
            int bchCode = CalculateBCHCode(version, VERSION_INFO_POLY);

            bits.AppendBits(bchCode, 12);
            // Just in case.
            if (bits.Size() != 18)
            {
                throw new WriterException("should not happen but we got: " + bits.Size());
            }
        }
Example #2
0
        /// <summary>Make bit vector of type information.</summary>
        /// <remarks>
        /// Make bit vector of type information. On success, store the result in "bits".
        /// Encode error correction level and mask pattern. See 8.9 of JISX0510:2004 (p.45) for details.
        /// </remarks>
        /// <param name="ecLevel">error correction level of the QR code</param>
        /// <param name="maskPattern">masking pattern to use</param>
        /// <param name="bits">Vactor of bits to contain the result</param>
        public static void MakeTypeInfoBits(ErrorCorrectionLevel ecLevel, int maskPattern, BitVector bits)
        {
            if (!QRCode.IsValidMaskPattern(maskPattern))
            {
                throw new WriterException("Invalid mask pattern");
            }
            int typeInfo = (ecLevel.GetBits() << 3) | maskPattern;

            bits.AppendBits(typeInfo, 5);
            int bchCode = CalculateBCHCode(typeInfo, TYPE_INFO_POLY);

            bits.AppendBits(bchCode, 10);
            BitVector maskBits = new BitVector();

            maskBits.AppendBits(TYPE_INFO_MASK_PATTERN, 15);
            bits.Xor(maskBits);
            // Just in case.
            if (bits.Size() != 15)
            {
                throw new WriterException("should not happen but we got: " + bits.Size());
            }
        }
Example #3
0
        private void IntellgentMail()
        {
            int       index;
            int       value;
            string    zip      = String.Empty;
            string    tracker  = String.Empty;
            BitVector zipAdder = new BitVector();

            short[] accumulator = new short[112];
            short[] xRegister   = new short[112];
            short[] yRegister   = new short[112];
            byte[]  byteData    = new byte[13];
            uint    uspsCRC;

            int[]         codeword    = new int[10];
            uint[]        characters  = new uint[10];
            int[]         barMap      = new int[130];
            StringBuilder barPattern  = new StringBuilder();
            int           inputLength = barcodeData.Length;

            if (inputLength > 31)
            {
                throw new InvalidDataLengthException("USPS: Input data too long.");
            }

            if (inputLength < 20)
            {
                throw new InvalidDataLengthException("USPS: Invalid tracking code length.");
            }

            // Separate the tracking code from the routing code.
            tracker = new string(barcodeData, 0, 20);
            if (inputLength > 20)
            {
                zip = new string(barcodeData, 20, inputLength - tracker.Length);
            }

            if (zip.Length != 11 && zip.Length != 9 && zip.Length != 5 && zip.Length != 0)
            {
                throw new InvalidDataException("USPS: Invalid ZIP code.");
            }

            Array.Clear(accumulator, 0, 112);
            for (index = 0; index < zip.Length; index++)
            {
                BinaryMath.BinaryMultiply(accumulator, "10");
                BinaryMath.BinaryLoad(xRegister, "0");
                for (int i = 0; i < 4; i++)
                {
                    value = zip[index] - '0';
                    if ((value & (0x01 << i)) > 0)
                    {
                        xRegister[i] = 1;
                    }
                }

                BinaryMath.BinaryAdd(accumulator, xRegister);
            }

            // Add weight to routing code.
            Array.Copy(accumulator, xRegister, 112);
            if (zip.Length > 9)
            {
                zipAdder.AppendBits(545, 10);       // 1000100001
            }
            else
            {
                if (zip.Length > 5)
                {
                    zipAdder.AppendBits(33, 6);     // 100001
                }
                else
                {
                    if (zip.Length > 0)
                    {
                        zipAdder.AppendBit(1);      // 1
                    }
                    else
                    {
                        zipAdder.AppendBit(0);      // 0
                    }
                }
            }

            Array.Clear(accumulator, 0, 112);
            for (index = 0; index < zipAdder.SizeInBits; index++)
            {
                BinaryMath.BinaryMultiply(accumulator, "10");
                BinaryMath.BinaryLoad(yRegister, "0");
                for (int i = 0; i < 4; i++)
                {
                    value = zipAdder[index] - '0';
                    if ((value & (0x01 << i)) > 0)
                    {
                        yRegister[i] = 1;
                    }
                }

                BinaryMath.BinaryAdd(accumulator, yRegister);
            }

            BinaryMath.BinaryAdd(accumulator, xRegister);

            // Tracking code.
            // Multiply by 10.
            BinaryMath.BinaryMultiply(accumulator, "10");
            BinaryMath.BinaryLoad(yRegister, "0");
            for (int i = 0; i < 4; i++)
            {
                value = tracker[0] - '0';
                if ((value & (0x01 << i)) > 0)
                {
                    yRegister[i] = 1;
                }
            }

            BinaryMath.BinaryAdd(accumulator, yRegister);

            // Multiply by 5.
            BinaryMath.BinaryMultiply(accumulator, "5");
            BinaryMath.BinaryLoad(yRegister, "0");
            // Add second digit.
            for (int i = 0; i < 4; i++)
            {
                value = tracker[1] - '0';
                if ((value & (0x01 << i)) > 0)
                {
                    yRegister[i] = 1;
                }
            }

            BinaryMath.BinaryAdd(accumulator, yRegister);

            // And then the rest.
            for (index = 2; index < tracker.Length; index++)
            {
                BinaryMath.BinaryMultiply(accumulator, "10");
                BinaryMath.BinaryLoad(yRegister, "0");
                for (int i = 0; i < 4; i++)
                {
                    value = tracker[index] - '0';
                    if ((value & (0x01 << i)) > 0)
                    {
                        yRegister[i] = 1;
                    }
                }

                BinaryMath.BinaryAdd(accumulator, yRegister);
            }

            // Step 2 - Generation of 11-bit CRC on Binary Data.
            accumulator[103] = 0;
            accumulator[102] = 0;

            for (int i = 0; i < 13; i++)
            {
                int j = 96 - (8 * i);
                byteData[i]  = 0;
                byteData[i] += (byte)accumulator[j];
                byteData[i] += (byte)(2 * accumulator[j + 1]);
                byteData[i] += (byte)(4 * accumulator[j + 2]);
                byteData[i] += (byte)(8 * accumulator[j + 3]);
                byteData[i] += (byte)(16 * accumulator[j + 4]);
                byteData[i] += (byte)(32 * accumulator[j + 5]);
                byteData[i] += (byte)(64 * accumulator[j + 6]);
                byteData[i] += (byte)(128 * accumulator[j + 7]);
            }

            uspsCRC = CRC11GenerateFrameCheckSequence(byteData);

            // Step 3 - Conversion from Binary Data to Codewords.
            // Start with codeword J which is base 636
            Array.Clear(xRegister, 0, 112);
            Array.Clear(yRegister, 0, 112);

            xRegister[101] = 1;
            xRegister[98]  = 1;
            xRegister[97]  = 1;
            xRegister[96]  = 1;
            xRegister[95]  = 1;
            xRegister[94]  = 1;

            for (int i = 92; i >= 0; i--)
            {
                yRegister[i] = BinaryMath.IsLarger(accumulator, xRegister);
                if (yRegister[i] == 1)
                {
                    BinaryMath.BinarySubtract(accumulator, xRegister);
                }

                BinaryMath.ShiftDown(xRegister);
            }

            codeword[9] = (accumulator[9] * 512) + (accumulator[8] * 256) + (accumulator[7] * 128) + (accumulator[6] * 64) +
                          (accumulator[5] * 32) + (accumulator[4] * 16) + (accumulator[3] * 8) + (accumulator[2] * 4) +
                          (accumulator[1] * 2) + accumulator[0];

            // Then codewords I to B with base 1365.
            for (int j = 8; j > 0; j--)
            {
                for (int i = 0; i < 112; i++)
                {
                    accumulator[i] = yRegister[i];
                    yRegister[i]   = 0;
                    xRegister[i]   = 0;
                }

                xRegister[101] = 1;
                xRegister[99]  = 1;
                xRegister[97]  = 1;
                xRegister[95]  = 1;
                xRegister[93]  = 1;
                xRegister[91]  = 1;
                for (int i = 91; i >= 0; i--)
                {
                    yRegister[i] = BinaryMath.IsLarger(accumulator, xRegister);
                    if (yRegister[i] == 1)
                    {
                        BinaryMath.BinarySubtract(accumulator, xRegister);
                    }

                    BinaryMath.ShiftDown(xRegister);
                }

                codeword[j] = (accumulator[10] * 1024) + (accumulator[9] * 512) + (accumulator[8] * 256) +
                              (accumulator[7] * 128) + (accumulator[6] * 64) + (accumulator[5] * 32) +
                              (accumulator[4] * 16) + (accumulator[3] * 8) + (accumulator[2] * 4) +
                              (accumulator[1] * 2) + accumulator[0];
            }

            codeword[0] = (yRegister[10] * 1024) + (yRegister[9] * 512) + (yRegister[8] * 256) +
                          (yRegister[7] * 128) + (yRegister[6] * 64) + (yRegister[5] * 32) +
                          (yRegister[4] * 16) + (yRegister[3] * 8) + (yRegister[2] * 4) +
                          (yRegister[1] * 2) + yRegister[0];

            for (int i = 0; i < 8; i++)
            {
                if (codeword[i] == 1365)
                {
                    codeword[i] = 0;
                    codeword[i + 1]++;
                }
            }

            // Step 4 - Inserting Additional Information into Codewords.
            codeword[9] = codeword[9] * 2;
            if (uspsCRC >= 1024)
            {
                codeword[0] += 659;
            }

            // Step 5 - Conversion from Codewords to Characters.
            for (int i = 0; i < 10; i++)
            {
                if (codeword[i] < 1287)
                {
                    characters[i] = AppendixD1[codeword[i]];
                }

                else
                {
                    characters[i] = AppendixD2[codeword[i] - 1287];
                }
            }

            for (int i = 0; i < 10; i++)
            {
                if ((uspsCRC & (1 << i)) > 0)
                {
                    characters[i] = 0x1FFF - characters[i];
                }
            }

            // Step 6 - Conversion from Characters to the Intelligent Mail Barcode.
            for (int i = 0; i < 10; i++)
            {
                for (int j = 0; j < 13; j++)
                {
                    if ((characters[i] & (1 << j)) > 0)
                    {
                        barMap[AppendixD4[(13 * i) + j] - 1] = 1;
                    }

                    else
                    {
                        barMap[AppendixD4[(13 * i) + j] - 1] = 0;
                    }
                }
            }

            for (int i = 0; i < 65; i++)
            {
                int j = 0;
                if (barMap[i] == 0)
                {
                    j += 1;
                }

                if (barMap[i + 65] == 0)
                {
                    j += 2;
                }

                barPattern.Append(j);
            }

            SymbolBuilder.BuildFourStateSymbol(Symbol, barPattern);
            // Format the barcodes text.
            barcodeText = new string(barcodeData);
            if (zip.Length > 0)
            {
                if (zip.Length == 11)
                {
                    barcodeText = barcodeText.Insert(29, " ");
                }

                if (zip.Length >= 9)
                {
                    barcodeText = barcodeText.Insert(25, " ");
                }

                if (zip.Length >= 5)
                {
                    barcodeText = barcodeText.Insert(20, " ");
                }
            }

            if (tracker[5] < '9')
            {
                barcodeText = barcodeText.Insert(11, " ");
            }

            else
            {
                barcodeText = barcodeText.Insert(14, " ");
            }

            barcodeText = barcodeText.Insert(5, " ");
            barcodeText = barcodeText.Insert(2, " ");
        }
Example #4
0
        private static void CompositeC(BitVector bitStream, int dataColumns, int eccLevel)
        {
            // CC-C 2D component - byte compressed PDF417.
            int           eccCodewords;
            int           offset;
            StringBuilder codeString = new StringBuilder();
            BitVector     bitPattern = new BitVector();
            List <int>    dataStream = new List <int>();

            dataStream.Add(0);      // Reserve for length descriptor;
            dataStream.Add(920);    // CC_C identifier.
            ProcessByte(dataStream, bitStream);
            dataStream[0] = dataStream.Count;

            eccCodewords = 1;
            for (int i = 0; i <= eccLevel; i++)
            {
                eccCodewords *= 2;
            }

            // Now take care of the Reed Solomon codes.
            if (eccCodewords == 2)
            {
                offset = 0;
            }

            else
            {
                offset = eccCodewords - 2;
            }

            int total            = 0;
            int dataStreamLength = dataStream.Count;

            int[] eccStream = new int[eccCodewords];
            for (int i = 0; i < dataStreamLength; i++)
            {
                total = (dataStream[i] + eccStream[eccCodewords - 1]) % 929;
                for (int j = eccCodewords - 1; j > 0; j--)
                {
                    eccStream[j] = (eccStream[j - 1] + 929 - (total * PDF417Tables.Coefficients[offset + j]) % 929) % 929;
                }

                eccStream[0] = (929 - (total * PDF417Tables.Coefficients[offset]) % 929) % 929;
            }

            // Add the code words to the data stream.
            for (int i = eccCodewords - 1; i >= 0; i--)
            {
                dataStream.Add((eccStream[i] != 0) ? 929 - eccStream[i] : 0);
            }

            int rowCount = dataStream.Count / dataColumns;

            if (dataStream.Count % dataColumns != 0)
            {
                rowCount++;
            }

            int c1 = (rowCount - 1) / 3;
            int c2 = (eccLevel * 3) + ((rowCount - 1) % 3);
            int c3 = dataColumns - 1;

            // Encode each row.
            int[] buffer = new int[dataColumns + 2];

            for (int row = 0; row < rowCount; row++)
            {
                for (int j = 0; j < dataColumns; j++)
                {
                    buffer[j + 1] = dataStream[row * dataColumns + j];
                }

                eccCodewords = (row / 3) * 30;
                switch (row % 3)
                {
                /* Follows this codePattern from US Patent 5,243,655:
                 * Row 0: L0 (row #, # of rows)         R0 (row #, # of columns)
                 * Row 1: L1 (row #, security level)    R1 (row #, # of rows)
                 * Row 2: L2 (row #, # of columns)      R2 (row #, security level)
                 * Row 3: L3 (row #, # of rows)         R3 (row #, # of columns)
                 * etc. */
                case 0:
                    buffer[0] = eccCodewords + c1;
                    buffer[dataColumns + 1] = eccCodewords + c3;
                    break;

                case 1:
                    buffer[0] = eccCodewords + c2;
                    buffer[dataColumns + 1] = eccCodewords + c1;
                    break;

                case 2:
                    buffer[0] = eccCodewords + c3;
                    buffer[dataColumns + 1] = eccCodewords + c2;
                    break;
                }

                codeString.Append("+*"); // Start with a start char and a separator

                for (int j = 0; j <= dataColumns + 1; j++)
                {
                    switch (row % 3)
                    {
                    case 1:
                        offset = 929;
                        break;

                    case 2:
                        offset = 1858;
                        break;

                    default: offset = 0;
                        break;
                    }

                    codeString.Append(PDF417Tables.EncodingPatterns[offset + buffer[j]]);
                    codeString.Append("*");
                }

                codeString.Append("-");

                for (int i = 0; i < codeString.Length; i++)
                {
                    int position = PDF417Tables.PDFSet.IndexOf(codeString[i]);
                    if (position >= 0 && position < 32)
                    {
                        bitPattern.AppendBits(position, 5);
                    }

                    else if (position == 32)
                    {
                        bitPattern.AppendBits(1, 2);
                    }

                    else if (position == 33)
                    {
                        bitPattern.AppendBits(0xff54, 16);
                    }

                    else
                    {
                        bitPattern.AppendBits(0x1fa29, 17);
                    }
                }

                int    size    = bitPattern.SizeInBits;
                byte[] rowData = new byte[size];
                for (int i = 0; i < size; i++)
                {
                    rowData[i] = bitPattern[i];
                }

                SymbolData symbolData = new SymbolData(rowData, 3);
                encodedData.Insert(row, symbolData);

                // Clear data ready for next row.
                codeString.Clear();
                bitPattern.Clear();
            }
        }
Example #5
0
        private static void CompositeB(BitVector bitStream, int dataColumns, int compositeShiftCount)
        {
            // CC-B 2D component.
            int           variant    = 0;
            StringBuilder codeString = new StringBuilder();
            BitVector     bitPattern = new BitVector();
            List <int>    dataStream = new List <int>();

            // CC-B component requires codeword 920 in the first symbol character position (section 9a)
            dataStream.Add(920);
            ProcessByte(dataStream, bitStream);
            int dataStreamLength = dataStream.Count;

            // Calculate variant of the symbol to use and load values accordingly.
            if (dataColumns == 2)
            {
                variant = 13;
                if (dataStreamLength <= 33)
                {
                    variant = 12;
                }
                if (dataStreamLength <= 29)
                {
                    variant = 11;
                }
                if (dataStreamLength <= 24)
                {
                    variant = 10;
                }
                if (dataStreamLength <= 19)
                {
                    variant = 9;
                }
                if (dataStreamLength <= 13)
                {
                    variant = 8;
                }
                if (dataStreamLength <= 8)
                {
                    variant = 7;
                }
            }

            if (dataColumns == 3)
            {
                variant = 23;
                if (dataStreamLength <= 70)
                {
                    variant = 22;
                }
                if (dataStreamLength <= 58)
                {
                    variant = 21;
                }
                if (dataStreamLength <= 46)
                {
                    variant = 20;
                }
                if (dataStreamLength <= 34)
                {
                    variant = 19;
                }
                if (dataStreamLength <= 24)
                {
                    variant = 18;
                }
                if (dataStreamLength <= 18)
                {
                    variant = 17;
                }
                if (dataStreamLength <= 14)
                {
                    variant = 16;
                }
                if (dataStreamLength <= 10)
                {
                    variant = 15;
                }
                if (dataStreamLength <= 6)
                {
                    variant = 14;
                }
            }

            if (dataColumns == 4)
            {
                variant = 34;
                if (dataStreamLength <= 108)
                {
                    variant = 33;
                }
                if (dataStreamLength <= 90)
                {
                    variant = 32;
                }
                if (dataStreamLength <= 72)
                {
                    variant = 31;
                }
                if (dataStreamLength <= 54)
                {
                    variant = 30;
                }
                if (dataStreamLength <= 39)
                {
                    variant = 29;
                }
                if (dataStreamLength <= 30)
                {
                    variant = 28;
                }
                if (dataStreamLength <= 24)
                {
                    variant = 27;
                }
                if (dataStreamLength <= 18)
                {
                    variant = 26;
                }
                if (dataStreamLength <= 12)
                {
                    variant = 25;
                }
                if (dataStreamLength <= 8)
                {
                    variant = 24;
                }
            }

            // Now we have the variant we can load the data - from here on the same as MicroPDF417 code.
            variant--;
            int rowCount      = PDF417Tables.MicroVariants[variant + 34];
            int eccCodewords  = PDF417Tables.MicroVariants[variant + 68];
            int dataCodewords = (dataColumns * rowCount) - eccCodewords;
            int padding       = dataCodewords - dataStreamLength;
            int offset        = PDF417Tables.MicroVariants[variant + 102]; // coefficient offset.

            // Add the padding.
            while (padding > 0)
            {
                dataStream.Add(900);
                padding--;
            }

            // Reed-Solomon error correction.
            dataStreamLength = dataStream.Count;
            int[] eccStream = new int[eccCodewords];
            int   total     = 0;

            for (int i = 0; i < dataStreamLength; i++)
            {
                total = (dataStream[i] + eccStream[eccCodewords - 1]) % 929;
                for (int j = eccCodewords - 1; j > 0; j--)
                {
                    eccStream[j] = (eccStream[j - 1] + 929 - (total * PDF417Tables.MicroCoefficients[offset + j]) % 929) % 929;
                }

                eccStream[0] = (929 - (total * PDF417Tables.MicroCoefficients[offset]) % 929) % 929;
            }

            for (int j = 0; j < eccCodewords; j++)
            {
                if (eccStream[j] != 0)
                {
                    eccStream[j] = 929 - eccStream[j];
                }
            }

            // Add the codewords to the data stream.
            for (int i = eccCodewords - 1; i >= 0; i--)
            {
                dataStream.Add(eccStream[i]);
            }

            dataStreamLength = dataStream.Count;

            // Get the RAP (Row Address Pattern) start values.
            int leftRAPStart   = PDF417Tables.RowAddressTable[variant];
            int centreRAPStart = PDF417Tables.RowAddressTable[variant + 34];
            int rightRAPStart  = PDF417Tables.RowAddressTable[variant + 68];
            int startCluster   = PDF417Tables.RowAddressTable[variant + 102] / 3;

            // That's all values loaded, get on with the encoding.
            int leftRAP   = leftRAPStart;
            int centreRAP = centreRAPStart;
            int rightRAP  = rightRAPStart;
            int cluster   = startCluster; // Cluster can be 0, 1 or 2 for cluster(0), cluster(3) and cluster(6).

            int[] buffer = new int[dataColumns + 1];
            for (int row = 0; row < rowCount; row++)
            {
                offset = 929 * cluster;
                for (int i = 0; i < buffer.Length; i++)
                {
                    buffer[i] = 0;
                }

                for (int i = 0; i < dataColumns; i++)
                {
                    buffer[i + 1] = dataStream[row * dataColumns + i];
                }

                // Copy the data into code string
                codeString.Append(PDF417Tables.RowAddressPattern[leftRAP]);
                codeString.Append("1");
                codeString.Append(PDF417Tables.EncodingPatterns[offset + buffer[1]]);
                codeString.Append("1");

                if (dataColumns == 3)
                {
                    codeString.Append(PDF417Tables.CentreRowAddressPattern[centreRAP]);
                }

                if (dataColumns >= 2)
                {
                    codeString.Append("1");
                    codeString.Append(PDF417Tables.EncodingPatterns[offset + buffer[2]]);
                    codeString.Append("1");
                }

                if (dataColumns == 4)
                {
                    codeString.Append(PDF417Tables.CentreRowAddressPattern[centreRAP]);
                }

                if (dataColumns >= 3)
                {
                    codeString.Append("1");
                    codeString.Append(PDF417Tables.EncodingPatterns[offset + buffer[3]]);
                    codeString.Append("1");
                }

                if (dataColumns == 4)
                {
                    codeString.Append("1");
                    codeString.Append(PDF417Tables.EncodingPatterns[offset + buffer[4]]);
                    codeString.Append("1");
                }

                codeString.Append(PDF417Tables.RowAddressPattern[rightRAP]);
                codeString.Append("1"); // Stop.

                // Code string is a mixture of letters and numbers.
                bool latch = true;
                for (int i = 0; i < codeString.Length; i++)
                {
                    if ((codeString[i] >= '0') && (codeString[i] <= '9'))
                    {
                        int value = (int)(codeString[i] - '0');
                        bitPattern.AppendBits((latch) ? 0xffff : 0, value);
                        latch = !latch;
                    }

                    else
                    {
                        int position = PDF417Tables.PDFSet.IndexOf(codeString[i]);
                        if (position >= 0 && position < 32)
                        {
                            bitPattern.AppendBits(position, 5);
                        }
                    }
                }

                int bitPatternLength = bitPattern.SizeInBits;
                if (hostSymbol == Symbology.Code128)
                {
                    if (linearWidth > bitPatternLength)
                    {
                        compositeShiftCount = (linearWidth - bitPatternLength) / 2;
                    }

                    else
                    {
                        compositeShiftCount = 0;
                    }
                }

                byte[] rowData = new byte[bitPatternLength + compositeShiftCount];
                for (int i = 0; i < bitPatternLength; i++)
                {
                    rowData[i + compositeShiftCount] = bitPattern[i];
                }

                SymbolData symbolData = new SymbolData(rowData, 2);
                encodedData.Insert(row, symbolData);

                // Clear data and set up RAPs and Cluster for next row.
                codeString.Clear();
                bitPattern.Clear();

                leftRAP++;
                centreRAP++;
                rightRAP++;
                cluster++;

                if (leftRAP == 53)
                {
                    leftRAP = 1;
                }

                if (centreRAP == 53)
                {
                    centreRAP = 1;
                }

                if (rightRAP == 53)
                {
                    rightRAP = 1;
                }

                if (cluster == 3)
                {
                    cluster = 0;
                }
            }
        }
Example #6
0
        private static void CompositeA(BitVector bitStream, int dataColumns, int compositeShiftCount)
        {
            // CC-A 2D component.
            int           variant = 0;
            StringBuilder binaryString;
            BitVector     bitPattern;

            int[] dataStream = new int[28];

            Initialize928();
            // Encode dataStream from bit stream
            int dataCodewords = Encode928(bitStream, dataStream);

            switch (dataColumns)
            {
            case 2:
                switch (dataCodewords)
                {
                case 6: variant = 0; break;

                case 8: variant = 1; break;

                case 9: variant = 2; break;

                case 11: variant = 3; break;

                case 12: variant = 4; break;

                case 14: variant = 5; break;

                case 17: variant = 6; break;
                }
                break;

            case 3:
                switch (dataCodewords)
                {
                case 8: variant = 7; break;

                case 10: variant = 8; break;

                case 12: variant = 9; break;

                case 14: variant = 10; break;

                case 17: variant = 11; break;
                }
                break;

            case 4:
                switch (dataCodewords)
                {
                case 8: variant = 12; break;

                case 11: variant = 13; break;

                case 14: variant = 14; break;

                case 17: variant = 15; break;

                case 20: variant = 16; break;
                }
                break;
            }

            int rowCount     = PDF417Tables.CCAVariants[variant];
            int eccCodewords = PDF417Tables.CCAVariants[17 + variant];
            int offset       = PDF417Tables.CCAVariants[34 + variant];

            // Reed-Solomon error correction.
            int[] eccStream = new int[eccCodewords];
            for (int i = 0; i < dataCodewords; i++)
            {
                int total = (dataStream[i] + eccStream[eccCodewords - 1]) % 929;
                for (int j = eccCodewords - 1; j > 0; j--)
                {
                    eccStream[j] = (eccStream[j - 1] + 929 - (total * PDF417Tables.CCACoefficients[offset + j]) % 929) % 929;
                }

                eccStream[0] = (929 - (total * PDF417Tables.CCACoefficients[offset]) % 929) % 929;
            }

            for (int j = 0; j < eccCodewords; j++)
            {
                if (eccStream[j] != 0)
                {
                    eccStream[j] = 929 - eccStream[j];
                }
            }

            for (int i = eccCodewords - 1; i >= 0; i--)
            {
                dataStream[dataCodewords++] = eccStream[i];
            }

            // Place data into table.
            int leftRAPStart   = PDF417Tables.CCARAPTable[variant];
            int centreRAPStart = PDF417Tables.CCARAPTable[variant + 17];
            int rightRAPStart  = PDF417Tables.CCARAPTable[variant + 34];
            int startCluster   = PDF417Tables.CCARAPTable[variant + 51] / 3;

            int leftRAP   = leftRAPStart;
            int centreRAP = centreRAPStart;
            int rightRAP  = rightRAPStart;
            int cluster   = startCluster; // Cluster can be 0, 1 or 2 for cluster(0), cluster(3) and cluster(6).

            binaryString = new StringBuilder();
            bitPattern   = new BitVector();
            int[] buffer = new int[dataColumns + 1];

            for (int row = 0; row < rowCount; row++)
            {
                offset = 929 * cluster;
                for (int j = 0; j < buffer.Length; j++)
                {
                    buffer[j] = 0;
                }

                for (int j = 0; j < dataColumns; j++)
                {
                    buffer[j + 1] = dataStream[row * dataColumns + j];
                }

                // Copy the data into code string.
                if (dataColumns != 3)
                {
                    binaryString.Append(PDF417Tables.RowAddressPattern[leftRAP]);
                }

                binaryString.Append("1");
                binaryString.Append(PDF417Tables.EncodingPatterns[offset + buffer[1]]);
                binaryString.Append("1");

                if (dataColumns == 3)
                {
                    binaryString.Append(PDF417Tables.CentreRowAddressPattern[centreRAP]);
                }

                if (dataColumns >= 2)
                {
                    binaryString.Append("1");
                    binaryString.Append(PDF417Tables.EncodingPatterns[offset + buffer[2]]);
                    binaryString.Append("1");
                }

                if (dataColumns == 4)
                {
                    binaryString.Append(PDF417Tables.CentreRowAddressPattern[centreRAP]);
                }

                if (dataColumns >= 3)
                {
                    binaryString.Append("1");
                    binaryString.Append(PDF417Tables.EncodingPatterns[offset + buffer[3]]);
                    binaryString.Append("1");
                }

                if (dataColumns == 4)
                {
                    binaryString.Append("1");
                    binaryString.Append(PDF417Tables.EncodingPatterns[offset + buffer[4]]);
                    binaryString.Append("1");
                }

                binaryString.Append(PDF417Tables.RowAddressPattern[rightRAP]);
                binaryString.Append("1"); // Stop.

                // The code string is a mixture of letters and numbers.
                bool latch = true;
                for (int i = 0; i < binaryString.Length; i++)
                {
                    if ((binaryString[i] >= '0') && (binaryString[i] <= '9'))
                    {
                        int value = (int)(binaryString[i] - '0');
                        bitPattern.AppendBits((latch) ? 0xffff : 0, value);
                        latch = !latch;
                    }

                    else
                    {
                        int position = PDF417Tables.PDFSet.IndexOf(binaryString[i]);
                        if (position >= 0 && position < 32)
                        {
                            bitPattern.AppendBits(position, 5);
                        }
                    }
                }

                int bitPatternLength = bitPattern.SizeInBits;
                if (hostSymbol == Symbology.Code128)
                {
                    if (linearWidth > bitPatternLength)
                    {
                        compositeShiftCount = (linearWidth - bitPatternLength) / 2;
                    }

                    else
                    {
                        compositeShiftCount = 0;
                    }
                }

                byte[] rowData = new byte[bitPatternLength + compositeShiftCount];
                for (int i = 0; i < bitPatternLength; i++)
                {
                    rowData[i + compositeShiftCount] = bitPattern[i];
                }

                SymbolData symbolData = new SymbolData(rowData, 2);
                encodedData.Insert(row, symbolData);

                // Clear data and set up RAPs and cluster for next row.
                binaryString.Clear();
                bitPattern.Clear();

                leftRAP++;
                centreRAP++;
                rightRAP++;
                cluster++;

                if (leftRAP == 53)
                {
                    leftRAP = 1;
                }

                if (centreRAP == 53)
                {
                    centreRAP = 1;
                }

                if (rightRAP == 53)
                {
                    rightRAP = 1;
                }

                if (cluster == 3)
                {
                    cluster = 0;
                }
            }
        }
Example #7
0
        private void PDF417()
        {
            int inputLength   = barcodeData.Length;
            int modeListCount = 0;
            int offset;
            int eccLevel;

            int[,] modeList = new int[2, inputLength];
            List <int> dataStream = new List <int>();

            int[] eccStream;

            for (int i = 0; i < inputLength; i++)
            {
                int mode = GetMode(barcodeData[i]);
                if (i == 0)
                {
                    modeList[1, modeListCount] = mode;
                    modeList[0, modeListCount]++;
                }

                else
                {
                    if (mode == modeList[1, modeListCount])
                    {
                        modeList[0, modeListCount]++;
                    }

                    else
                    {
                        modeListCount++;
                        modeList[1, modeListCount] = mode;
                        modeList[0, modeListCount]++;
                    }
                }
            }

            modeListCount++;
            SmoothPDF(ref modeListCount, modeList);

            // Compress the data.
            int dataIndex = 0;
            int dataStreamLength;

            for (int i = 0; i < modeListCount; i++)
            {
                switch (modeList[1, i])
                {
                case TEXT:
                    ProcessText(dataStream, dataIndex, modeList[0, i]);
                    break;

                case BYTE:
                    ProcessByte(dataStream, dataIndex, modeList[0, i]);
                    break;

                case NUMBER:
                    ProcessNumber(dataStream, dataIndex, modeList[0, i]);
                    break;
                }

                dataIndex += modeList[0, i];
            }

            // Now take care of the number of CWs per row.
            dataStreamLength = dataStream.Count;
            if (optionErrorCorrection < 0)
            {
                optionErrorCorrection = 6;
                if (dataStreamLength < 864)
                {
                    optionErrorCorrection = 5;
                }

                if (dataStreamLength < 321)
                {
                    optionErrorCorrection = 4;
                }

                if (dataStreamLength < 161)
                {
                    optionErrorCorrection = 3;
                }

                if (dataStreamLength < 41)
                {
                    optionErrorCorrection = 2;
                }
            }

            eccLevel = 1;
            for (int i = 1; i <= (optionErrorCorrection + 1); i++)
            {
                eccLevel *= 2;
            }

            if (optionDataColumns < 1)
            {
                optionDataColumns = (int)(0.5 + Math.Sqrt((dataStreamLength + eccLevel) / 3.0));
            }

            if (((dataStreamLength + eccLevel) / optionDataColumns) > 90)
            {
                // Stop the symbol from becoming too high by increasing the columns.
                optionDataColumns = optionDataColumns + 1;
            }

            if ((dataStreamLength + eccLevel) > 928)
            {
                throw new InvalidDataLengthException("PDF417: Input data too long.");
            }

            if (((dataStreamLength + eccLevel) / optionDataColumns) > 90)
            {
                throw new InvalidDataLengthException("PDF417: Input data too long for specified number of columns.");
            }

            // Padding calculation.
            int totalLength = dataStreamLength + eccLevel + 1;
            int padding     = 0;

            if ((totalLength / optionDataColumns) < 3)    // A bar code must have at least three rows.
            {
                padding = (optionDataColumns * 3) - totalLength;
            }

            else
            {
                if ((totalLength % optionDataColumns) > 0)
                {
                    padding = optionDataColumns - (totalLength % optionDataColumns);
                }
            }

            // Add the padding.
            while (padding > 0)
            {
                dataStream.Add(900);
                padding--;
            }

            // Insert the length descriptor.
            dataStream.Insert(0, dataStream.Count + 1);

            // We now take care of the Reed Solomon codes.
            if (optionErrorCorrection == 0)
            {
                offset = 0;
            }

            else
            {
                offset = eccLevel - 2;
            }

            dataStreamLength = dataStream.Count;
            eccStream        = new int[eccLevel];
            for (int i = 0; i < dataStreamLength; i++)
            {
                int total = (dataStream[i] + eccStream[eccLevel - 1]) % 929;
                for (int j = eccLevel - 1; j > 0; j--)
                {
                    eccStream[j] = ((eccStream[j - 1] + 929) - (total * PDF417Tables.Coefficients[offset + j]) % 929) % 929;
                }

                eccStream[0] = (929 - (total * PDF417Tables.Coefficients[offset]) % 929) % 929;
            }

            // Add the code words to the data stream.
            for (int i = eccLevel - 1; i >= 0; i--)
            {
                dataStream.Add((eccStream[i] != 0) ? 929 - eccStream[i] : 0);
            }

            dataStreamLength = dataStream.Count;
            int rowCount = dataStreamLength / optionDataColumns;

            if (dataStreamLength % optionDataColumns != 0)
            {
                rowCount++;
            }

            int c1 = (rowCount - 1) / 3;
            int c2 = (optionErrorCorrection * 3) + ((rowCount - 1) % 3);
            int c3 = optionDataColumns - 1;

            // Encode each row.
            StringBuilder codeString = new StringBuilder();
            BitVector     bitPattern = new BitVector();

            int[] buffer = new int[optionDataColumns + 2];

            for (int row = 0; row < rowCount; row++)
            {
                for (int i = 0; i < buffer.Length; i++)
                {
                    buffer[i] = 0;
                }

                for (int i = 0; i < optionDataColumns; i++)
                {
                    buffer[i + 1] = dataStream[row * optionDataColumns + i];
                }

                int errorCorrection = (row / 3) * 30;
                switch (row % 3)
                {
                /* Follows this codePattern from US Patent 5,243,655:
                 * Row 0: L0 (row #, # of rows)         R0 (row #, # of columns)
                 * Row 1: L1 (row #, security level)    R1 (row #, # of rows)
                 * Row 2: L2 (row #, # of columns)      R2 (row #, security level)
                 * Row 3: L3 (row #, # of rows)         R3 (row #, # of columns)
                 * etc. */
                case 0:
                    buffer[0] = errorCorrection + c1;
                    buffer[optionDataColumns + 1] = errorCorrection + c3;
                    break;

                case 1:
                    buffer[0] = errorCorrection + c2;
                    buffer[optionDataColumns + 1] = errorCorrection + c1;
                    break;

                case 2:
                    buffer[0] = errorCorrection + c3;
                    buffer[optionDataColumns + 1] = errorCorrection + c2;
                    break;
                }

                codeString.Append("+*");
                if (isTruncated)
                {
                    // Truncated PDF - remove the last 5 characters.
                    for (int j = 0; j <= optionDataColumns; j++)
                    {
                        switch (row % 3)
                        {
                        case 1:
                            offset = 929;
                            break;

                        case 2:
                            offset = 1858;
                            break;

                        default:
                            offset = 0;
                            break;
                        }

                        codeString.Append(PDF417Tables.EncodingPatterns[offset + buffer[j]]);
                        codeString.Append("*");
                    }
                }

                else
                {
                    // Normal PDF417 symbol.
                    for (int j = 0; j <= optionDataColumns + 1; j++)
                    {
                        switch (row % 3)
                        {
                        case 1:
                            offset = 929;
                            break;

                        case 2:
                            offset = 1858;
                            break;

                        default: offset = 0;
                            break;
                        }

                        codeString.Append(PDF417Tables.EncodingPatterns[offset + buffer[j]]);
                        codeString.Append("*");
                    }

                    codeString.Append("-");
                }

                for (int i = 0; i < codeString.Length; i++)
                {
                    int position = PDF417Tables.PDFSet.IndexOf(codeString[i]);
                    if (position >= 0 && position < 32)
                    {
                        bitPattern.AppendBits(position, 5);
                    }

                    else if (position == 32)
                    {
                        bitPattern.AppendBits(1, 2);
                    }

                    else if (position == 33)
                    {
                        bitPattern.AppendBits(0xff54, 16);
                    }

                    else
                    {
                        bitPattern.AppendBits(0x1fa29, 17);
                    }
                }

                int    size    = bitPattern.SizeInBits;
                byte[] rowData = new byte[size];
                for (int i = 0; i < size; i++)
                {
                    rowData[i] = bitPattern[i];
                }

                SymbolData symbolData = new SymbolData(rowData, optionElementHeight);
                Symbol.Add(symbolData);

                // Clear data ready for next row.
                codeString.Clear();
                bitPattern.Clear();
            }
        }
Example #8
0
        /// <summary>
        /// Generate a Micro PDF barcode.
        /// </summary>
        private void MicroPDF417()
        {
            int inputLength = barcodeData.Length;
            int offset;
            int modeListCount = 0;

            List <int> dataStream = new List <int>();

            int[] eccStream;

            // Encoding starts out the same as PDF417, so use the same code.
            int[,] modeList = new int[2, inputLength];
            for (int i = 0; i < inputLength; i++)
            {
                int mode = GetMode(barcodeData[i]);
                if (i == 0)     // First character.
                {
                    modeList[1, modeListCount] = mode;
                    modeList[0, modeListCount]++;
                }

                else
                {
                    // Next character same mode.
                    if (mode == modeList[1, modeListCount])
                    {
                        modeList[0, modeListCount]++;
                    }

                    else
                    {
                        // Next character a different mode.
                        modeListCount++;
                        modeList[1, modeListCount] = mode;
                        modeList[0, modeListCount]++;
                    }
                }
            }

            modeListCount++;
            SmoothPDF(ref modeListCount, modeList);

            // Compress the data.
            int dataIndex = 0;
            int dataStreamLength;

            for (int i = 0; i < modeListCount; i++)
            {
                switch (modeList[1, i])
                {
                case TEXT:
                    ProcessText(dataStream, dataIndex, modeList[0, i]);
                    break;

                case BYTE:
                    ProcessByte(dataStream, dataIndex, modeList[0, i]);
                    break;

                case NUMBER:
                    ProcessNumber(dataStream, dataIndex, modeList[0, i]);
                    break;
                }

                dataIndex += modeList[0, i];
            }

            //
            // This is where it all changes!
            //
            dataStreamLength = dataStream.Count;
            if (dataStreamLength > 126)
            {
                throw new InvalidDataLengthException();
            }

            if (optionDataColumns > 4)
            {
                optionDataColumns = 0;
            }

            // Now figure out which variant of the symbol to use and load values accordingly.
            int variant = 0;

            if ((optionDataColumns == 1) && (dataStreamLength > 20))
            {
                // The user specified 1 column but the data doesn't fit - go to automatic
                optionDataColumns = 0;
            }

            if ((optionDataColumns == 2) && (dataStreamLength > 37))
            {
                // The user specified 2 columns but the data doesn't fit - go to automatic
                optionDataColumns = 0;
            }

            if ((optionDataColumns == 3) && (dataStreamLength > 82))
            {
                // The user specified 3 columns but the data doesn't fit - go to automatic
                optionDataColumns = 0;
            }

            if (optionDataColumns == 1)
            {
                variant = 6;
                if (dataStreamLength <= 16)
                {
                    variant = 5;
                }

                if (dataStreamLength <= 12)
                {
                    variant = 4;
                }

                if (dataStreamLength <= 10)
                {
                    variant = 3;
                }

                if (dataStreamLength <= 7)
                {
                    variant = 2;
                }

                if (dataStreamLength <= 4)
                {
                    variant = 1;
                }
            }

            if (optionDataColumns == 2)
            {
                variant = 13;
                if (dataStreamLength <= 33)
                {
                    variant = 12;
                }

                if (dataStreamLength <= 29)
                {
                    variant = 11;
                }

                if (dataStreamLength <= 24)
                {
                    variant = 10;
                }

                if (dataStreamLength <= 19)
                {
                    variant = 9;
                }

                if (dataStreamLength <= 13)
                {
                    variant = 8;
                }

                if (dataStreamLength <= 8)
                {
                    variant = 7;
                }
            }

            if (optionDataColumns == 3)
            {
                // The user specified 3 columns and the data does fit
                variant = 23;
                if (dataStreamLength <= 70)
                {
                    variant = 22;
                }

                if (dataStreamLength <= 58)
                {
                    variant = 21;
                }

                if (dataStreamLength <= 46)
                {
                    variant = 20;
                }

                if (dataStreamLength <= 34)
                {
                    variant = 19;
                }

                if (dataStreamLength <= 24)
                {
                    variant = 18;
                }

                if (dataStreamLength <= 18)
                {
                    variant = 17;
                }

                if (dataStreamLength <= 14)
                {
                    variant = 16;
                }

                if (dataStreamLength <= 10)
                {
                    variant = 15;
                }

                if (dataStreamLength <= 6)
                {
                    variant = 14;
                }
            }

            if (optionDataColumns == 4)
            {
                // The user specified 4 columns and the data does fit.
                variant = 34;
                if (dataStreamLength <= 108)
                {
                    variant = 33;
                }

                if (dataStreamLength <= 90)
                {
                    variant = 32;
                }

                if (dataStreamLength <= 72)
                {
                    variant = 31;
                }

                if (dataStreamLength <= 54)
                {
                    variant = 30;
                }

                if (dataStreamLength <= 39)
                {
                    variant = 29;
                }

                if (dataStreamLength <= 30)
                {
                    variant = 28;
                }

                if (dataStreamLength <= 24)
                {
                    variant = 27;
                }

                if (dataStreamLength <= 18)
                {
                    variant = 26;
                }

                if (dataStreamLength <= 12)
                {
                    variant = 25;
                }

                if (dataStreamLength <= 8)
                {
                    variant = 24;
                }
            }

            if (variant == 0)
            {
                // Let ZintNET choose automatically from all available variations.
                for (int i = 27; i >= 0; i--)
                {
                    if (PDF417Tables.MicroAutoSize[i] >= dataStreamLength)
                    {
                        variant = PDF417Tables.MicroAutoSize[i + 28];
                    }
                }
            }

            // Now we have the variant we can load the data.
            variant--;
            optionDataColumns = PDF417Tables.MicroVariants[variant];            // columns
            int rowCount      = PDF417Tables.MicroVariants[variant + 34];       // row Count
            int eccCodewords  = PDF417Tables.MicroVariants[variant + 68];       // number of error correction CWs
            int dataCodewords = (optionDataColumns * rowCount) - eccCodewords;  // number of data CWs
            int padding       = dataCodewords - dataStreamLength;               // amount of padding required

            offset = PDF417Tables.MicroVariants[variant + 102];                 // coefficient offset

            // Add the padding
            while (padding > 0)
            {
                dataStream.Add(900);
                padding--;
            }

            // Reed-Solomon error correction
            dataStreamLength = dataStream.Count;
            eccStream        = new int[eccCodewords];
            for (int i = 0; i < dataStreamLength; i++)
            {
                int total = (dataStream[i] + eccStream[eccCodewords - 1]) % 929;
                for (int j = eccCodewords - 1; j > 0; j--)
                {
                    eccStream[j] = ((eccStream[j - 1] + 929) - (total * PDF417Tables.MicroCoefficients[offset + j]) % 929) % 929;
                }

                eccStream[0] = (929 - (total * PDF417Tables.MicroCoefficients[offset]) % 929) % 929;
            }

            for (int j = 0; j < eccCodewords; j++)
            {
                if (eccStream[j] != 0)
                {
                    eccStream[j] = 929 - eccStream[j];
                }
            }

            // Add the reed-solomon codewords to the data stream.
            for (int i = eccCodewords - 1; i >= 0; i--)
            {
                dataStream.Add(eccStream[i]);
            }

            // RAP (Row Address Pattern) start values
            int leftRAPStart   = PDF417Tables.RowAddressTable[variant];
            int centreRAPStart = PDF417Tables.RowAddressTable[variant + 34];
            int rightRAPStart  = PDF417Tables.RowAddressTable[variant + 68];
            int startCluster   = PDF417Tables.RowAddressTable[variant + 102] / 3;

            // Start encoding.
            int leftRAP   = leftRAPStart;
            int centreRAP = centreRAPStart;
            int rightRAP  = rightRAPStart;
            int cluster   = startCluster; // Cluster can be 0, 1 or 2 for Cluster(0), Cluster(3) and Cluster(6).

            StringBuilder codeString = new StringBuilder();
            BitVector     bitPattern = new BitVector();

            int[] buffer = new int[optionDataColumns + 1];
            for (int row = 0; row < rowCount; row++)
            {
                for (int i = 0; i < buffer.Length; i++)
                {
                    buffer[i] = 0;
                }

                for (int i = 0; i < optionDataColumns; i++)
                {
                    buffer[i + 1] = dataStream[row * optionDataColumns + i];
                }

                // Copy the data into code string.
                offset = 929 * cluster;
                codeString.Append(PDF417Tables.RowAddressPattern[leftRAP]);
                codeString.Append("1");
                codeString.Append(PDF417Tables.EncodingPatterns[offset + buffer[1]]);
                codeString.Append("1");

                if (optionDataColumns == 3)
                {
                    codeString.Append(PDF417Tables.CentreRowAddressPattern[centreRAP]);
                }

                if (optionDataColumns >= 2)
                {
                    codeString.Append("1");
                    codeString.Append(PDF417Tables.EncodingPatterns[offset + buffer[2]]);
                    codeString.Append("1");
                }

                if (optionDataColumns == 4)
                {
                    codeString.Append(PDF417Tables.CentreRowAddressPattern[centreRAP]);
                }

                if (optionDataColumns >= 3)
                {
                    codeString.Append("1");
                    codeString.Append(PDF417Tables.EncodingPatterns[offset + buffer[3]]);
                    codeString.Append("1");
                }

                if (optionDataColumns == 4)
                {
                    codeString.Append("1");
                    codeString.Append(PDF417Tables.EncodingPatterns[offset + buffer[4]]);
                    codeString.Append("1");
                }

                codeString.Append(PDF417Tables.RowAddressPattern[rightRAP]);
                codeString.Append("1"); // Stop.

                // Now codeString is a mixture of letters and numbers
                bool latch = true;
                int  value;
                for (int i = 0; i < codeString.Length; i++)
                {
                    if ((codeString[i] >= '0') && (codeString[i] <= '9'))
                    {
                        value = (int)(codeString[i] - '0');
                        bitPattern.AppendBits((latch) ? 0xfff : 0, value);
                        latch = !latch;
                    }

                    else
                    {
                        int position = PDF417Tables.PDFSet.IndexOf(codeString[i]);
                        if (position >= 0 && position < 32)
                        {
                            bitPattern.AppendBits(position, 5);
                        }
                    }
                }

                int    size    = bitPattern.SizeInBits;
                byte[] rowData = new byte[size];
                for (int i = 0; i < size; i++)
                {
                    rowData[i] = bitPattern[i];
                }

                SymbolData symbolData = new SymbolData(rowData, 2);
                Symbol.Add(symbolData);

                codeString.Clear();
                bitPattern.Clear();

                // Set up RAPs and Cluster for next row.
                leftRAP++;
                centreRAP++;
                rightRAP++;
                cluster++;

                if (leftRAP == 53)
                {
                    leftRAP = 1;
                }

                if (centreRAP == 53)
                {
                    centreRAP = 1;
                }

                if (rightRAP == 53)
                {
                    rightRAP = 1;
                }

                if (cluster == 3)
                {
                    cluster = 0;
                }
            }
        }