private static BitArray generateCheckWords(BitArray stuffedBits, int totalSymbolBits, int wordSize) { var messageSizeInWords = (stuffedBits.Size + wordSize - 1) / wordSize; for (var i = messageSizeInWords * wordSize - stuffedBits.Size; i > 0; i--) { stuffedBits.appendBit(true); } var rs = new ReedSolomonEncoder(getGF(wordSize)); var totalSizeInFullWords = totalSymbolBits / wordSize; var messageWords = bitsToWords(stuffedBits, wordSize, totalSizeInFullWords); rs.encode(messageWords, totalSizeInFullWords - messageSizeInWords); var startPad = totalSymbolBits % wordSize; var messageBits = new BitArray(); messageBits.appendBits(0, startPad); foreach (var messageWord in messageWords) { messageBits.appendBits(messageWord, wordSize); } return(messageBits); }
private static BitArray generateCheckWords(BitArray bitArray, int totalBits, int wordSize) { if (bitArray.Size % wordSize != 0) { throw new InvalidOperationException("size of bit array is not a multiple of the word size"); } // bitArray is guaranteed to be a multiple of the wordSize, so no padding needed int messageSizeInWords = bitArray.Size / wordSize; var rs = new ReedSolomonEncoder(getGF(wordSize)); var totalWords = totalBits / wordSize; var messageWords = bitsToWords(bitArray, wordSize, totalWords); rs.encode(messageWords, totalWords - messageSizeInWords); var startPad = totalBits % wordSize; var messageBits = new BitArray(); messageBits.appendBits(0, startPad); foreach (var messageWord in messageWords) { messageBits.appendBits(messageWord, wordSize); } return(messageBits); }
/// <summary> /// Вызов метода кодирования для текущего выбранного алгоритма коррекции ошибок /// </summary> /// <param name="input">Входной поток данных</param> /// <param name="output">Выходной поток данных</param> public void Forward(Stream input, Stream output) { int codeSize = _codeSize; int dataSize = _dataSize; int twoS = Math.Abs(codeSize - dataSize); Debug.Assert(codeSize > dataSize); switch (_eccId) { case EccId.None: None.Forward(input, output); break; case EccId.ReedSolomon: var buffer = new byte[Math.Max(codeSize, dataSize)]; while (input.Read(buffer, 0, dataSize) > 0) { int[] array = buffer.Select(x => (int)x).ToArray(); RsEncoder.encode(array, twoS); output.Write(array.Select(x => (byte)x).ToArray(), 0, codeSize); } break; default: throw new NotImplementedException(); } }
private static void testEncodeDecodeRandom(GenericGF field, int dataSize, int ecSize) { Assert.IsTrue(dataSize > 0 && dataSize <= field.Size - 3, "Invalid data size for " + field); Assert.IsTrue(ecSize > 0 && ecSize + dataSize <= field.Size, "Invalid ECC size for " + field); ReedSolomonEncoder encoder = new ReedSolomonEncoder(field); int[] message = new int[dataSize + ecSize]; int[] dataWords = new int[dataSize]; int[] ecWords = new int[ecSize]; Random random = getPseudoRandom(); int iterations = field.Size > 256 ? 1 : DECODER_RANDOM_TEST_ITERATIONS; for (int i = 0; i < iterations; i++) { // generate random data for (int k = 0; k < dataSize; k++) { dataWords[k] = random.Next(field.Size); } // generate ECC words Array.Copy(dataWords, 0, message, 0, dataWords.Length); encoder.encode(message, ecWords.Length); Array.Copy(message, dataSize, ecWords, 0, ecSize); // check to see if Decoder can fix up to ecWords/2 random errors testDecoder(field, dataWords, ecWords); } }
public void testQRCodeVersusDecoder() { var random = getRandom(); var encoder = new ReedSolomonEncoder(GenericGF.QR_CODE_FIELD_256); var decoder = new ReedSolomonDecoder(GenericGF.QR_CODE_FIELD_256); for (var i = 0; i < 100; i++) { var size = 2 + random.Next(254); var toEncode = new int[size]; var ecBytes = 1 + random.Next(2 * (1 + size / 8)); ecBytes = Math.Min(ecBytes, size - 1); var dataBytes = size - ecBytes; for (int j = 0; j < dataBytes; j++) { toEncode[j] = random.Next(256); } var original = new int[dataBytes]; Array.Copy(toEncode, 0, original, 0, dataBytes); encoder.encode(toEncode, ecBytes); corrupt(toEncode, ecBytes / 2, random); Assert.IsTrue(decoder.decode(toEncode, ecBytes)); assertArraysEqual(original, 0, toEncode, 0, dataBytes); } }
private static void testEncoder(GenericGF field, int[] dataWords, int[] ecWords) { ReedSolomonEncoder encoder = new ReedSolomonEncoder(field); int[] messageExpected = new int[dataWords.Length + ecWords.Length]; int[] message = new int[dataWords.Length + ecWords.Length]; Array.Copy(dataWords, 0, messageExpected, 0, dataWords.Length); Array.Copy(ecWords, 0, messageExpected, dataWords.Length, ecWords.Length); Array.Copy(dataWords, 0, message, 0, dataWords.Length); encoder.encode(message, ecWords.Length); assertDataEquals("Encode in " + field + " (" + dataWords.Length + ',' + ecWords.Length + ") failed", messageExpected, message); }
public static bool[] MarshallInt(uint value) { int[] byteArray = new int[32]; byteArray[0] = (byte)(value % 256); byteArray[1] = (byte)((value >> 8) % 256); byteArray[2] = (byte)((value >> 16) % 256); byteArray[3] = (byte)((value >> 24) % 256); ReedSolomonEncoder rse = new ReedSolomonEncoder(GenericGF.QR_CODE_FIELD_256); rse.encode(byteArray, 28); return(UnpackByteArray(byteArray)); }
public byte[] Encode(byte[] data, int parity) { int[] intar = new int[data.Length + parity]; for (int i = 0; i < data.Length; i++) { intar[i] = data[i]; } encoder.encode(intar, parity); var result = new byte[intar.Length]; for (int i = 0; i < intar.Length; i++) { result[i] = (byte)intar[i]; } return(result); }
public int[] EncodeRawBytesArray(int[] data) { var length = data.Length * _messageLength / _informationLength; length += (255 - (length % 255)) % 255; var modifiedData = new int[length]; var processedBytes = 0; for (var i = 0; i < data.Length; i += _informationLength) { var tempData = new int[_messageLength]; var remainder = (data.Length - i < _informationLength) ? data.Length - i : _informationLength; for (var j = 0; j < remainder; j++) { tempData[j] = data[i + j]; } for (var j = remainder; j < tempData.Length; j++) { tempData[j] = 0; } _reedSolomonEncoder.encode(tempData, _correctionLength); remainder = remainder >= _informationLength ? _messageLength : modifiedData.Length - processedBytes; for (var j = 0; j < remainder; j++) { modifiedData[processedBytes + j] = tempData[j]; } processedBytes += _messageLength; } return(modifiedData); }
/// <summary> /// Encode using Reed-Solomon error correction (with n bytes added to the end of bits). </summary> public static Bits bitsReedSolomonEncode(Bits bits, int n) { int tmpSize = (bits.size() + 7) / 8 + n; int[] data = new int[tmpSize]; if (tmpSize > bits.Bytes.Length) { tmpSize = bits.Bytes.Length; } Array.Copy(bits.Bytes, 0, data, 0, tmpSize); ReedSolomonEncoder enc = new ReedSolomonEncoder(GenericGF.QR_CODE_FIELD_256); enc.encode(data, n); Bits result = new Bits(bits); for (int i = data.Length - n; i < data.Length; i++) { result.addValue(data[i], 8); } return(result); }
/// <summary> /// Encodes the given binary content as an Aztec symbol /// </summary> /// <param name="data">input data string</param> /// <param name="minECCPercent">minimal percentange of error check words (According to ISO/IEC 24778:2008, /// a minimum of 23% + 3 words is recommended)</param> /// <returns>Aztec symbol matrix with metadata</returns> public static AztecCode encode(byte[] data, int minECCPercent) { // High-level encode var bits = highLevelEncode(data); // stuff bits and choose symbol size int eccBits = bits.Size * minECCPercent / 100 + 11; int totalSizeBits = bits.Size + eccBits; int layers; int wordSize = 0; int totalSymbolBits = 0; BitArray stuffedBits = null; for (layers = 1; layers < NB_BITS_COMPACT.Length; layers++) { if (NB_BITS_COMPACT[layers] >= totalSizeBits) { if (wordSize != WORD_SIZE[layers]) { wordSize = WORD_SIZE[layers]; stuffedBits = stuffBits(bits, wordSize); } totalSymbolBits = NB_BITS_COMPACT[layers]; if (stuffedBits.Size + eccBits <= NB_BITS_COMPACT[layers]) { break; } } } bool compact = true; if (layers == NB_BITS_COMPACT.Length) { compact = false; for (layers = 1; layers < NB_BITS.Length; layers++) { if (NB_BITS[layers] >= totalSizeBits) { if (wordSize != WORD_SIZE[layers]) { wordSize = WORD_SIZE[layers]; stuffedBits = stuffBits(bits, wordSize); } totalSymbolBits = NB_BITS[layers]; if (stuffedBits.Size + eccBits <= NB_BITS[layers]) { break; } } } } if (layers == NB_BITS.Length) { throw new ArgumentException("Data too large for an Aztec code"); } // pad the end int messageSizeInWords = (stuffedBits.Size + wordSize - 1) / wordSize; for (int i = messageSizeInWords * wordSize - stuffedBits.Size; i > 0; i--) { stuffedBits.appendBit(true); } // generate check words var rs = new ReedSolomonEncoder(getGF(wordSize)); var totalSizeInFullWords = totalSymbolBits / wordSize; var messageWords = bitsToWords(stuffedBits, wordSize, totalSizeInFullWords); rs.encode(messageWords, totalSizeInFullWords - messageSizeInWords); // convert to bit array and pad in the beginning var startPad = totalSymbolBits % wordSize; var messageBits = new BitArray(); messageBits.appendBits(0, startPad); foreach (var messageWord in messageWords) { messageBits.appendBits(messageWord, wordSize); } // generate mode message var modeMessage = generateModeMessage(compact, layers, messageSizeInWords); // allocate symbol var baseMatrixSize = compact ? 11 + layers * 4 : 14 + layers * 4; // not including alignment lines var alignmentMap = new int[baseMatrixSize]; int matrixSize; if (compact) { // no alignment marks in compact mode, alignmentMap is a no-op matrixSize = baseMatrixSize; for (int i = 0; i < alignmentMap.Length; i++) { alignmentMap[i] = i; } } else { matrixSize = baseMatrixSize + 1 + 2 * ((baseMatrixSize / 2 - 1) / 15); int origCenter = baseMatrixSize / 2; int center = matrixSize / 2; for (int i = 0; i < origCenter; i++) { int newOffset = i + i / 15; alignmentMap[origCenter - i - 1] = center - newOffset - 1; alignmentMap[origCenter + i] = center + newOffset + 1; } } var matrix = new BitMatrix(matrixSize); // draw mode and data bits for (int i = 0, rowOffset = 0; i < layers; i++) { int rowSize = compact ? (layers - i) * 4 + 9 : (layers - i) * 4 + 12; for (int j = 0; j < rowSize; j++) { int columnOffset = j * 2; for (int k = 0; k < 2; k++) { if (messageBits[rowOffset + columnOffset + k]) { matrix[alignmentMap[i * 2 + k], alignmentMap[i * 2 + j]] = true; } if (messageBits[rowOffset + rowSize * 2 + columnOffset + k]) { matrix[alignmentMap[i * 2 + j], alignmentMap[baseMatrixSize - 1 - i * 2 - k]] = true; } if (messageBits[rowOffset + rowSize * 4 + columnOffset + k]) { matrix[alignmentMap[baseMatrixSize - 1 - i * 2 - k], alignmentMap[baseMatrixSize - 1 - i * 2 - j]] = true; } if (messageBits[rowOffset + rowSize * 6 + columnOffset + k]) { matrix[alignmentMap[baseMatrixSize - 1 - i * 2 - j], alignmentMap[i * 2 + k]] = true; } } } rowOffset += rowSize * 8; } drawModeMessage(matrix, compact, matrixSize, modeMessage); // draw alignment marks if (compact) { drawBullsEye(matrix, matrixSize / 2, 5); } else { drawBullsEye(matrix, matrixSize / 2, 7); for (int i = 0, j = 0; i < baseMatrixSize / 2 - 1; i += 15, j += 16) { for (int k = (matrixSize / 2) & 1; k < matrixSize; k += 2) { matrix[matrixSize / 2 - j, k] = true; matrix[matrixSize / 2 + j, k] = true; matrix[k, matrixSize / 2 - j] = true; matrix[k, matrixSize / 2 + j] = true; } } } return(new AztecCode { isCompact = compact, Size = matrixSize, Layers = layers, CodeWords = messageSizeInWords, Matrix = matrix }); }