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); } }
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); }
/// <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 = new HighLevelEncoder(data).encode(); // 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 }; }
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; }
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; }