// // /// <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()); } }
/// <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()); } }
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, " "); }
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(); } }
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; } } }
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; } } }
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(); } }
/// <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; } } }