/// <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) { var aztec = new AztecCode(); // 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; } } } aztec.isCompact = compact; aztec.Size = matrixSize; aztec.Layers = layers; aztec.CodeWords = messageSizeInWords; aztec.Matrix = matrix; return aztec; }
private static BitMatrix renderResult(AztecCode code, int width, int height) { var input = code.Matrix; if (input == null) { throw new InvalidOperationException("No input code matrix"); } int inputWidth = input.Width; int inputHeight = input.Height; int outputWidth = Math.Max(width, inputWidth); int outputHeight = Math.Max(height, inputHeight); int multiple = Math.Min(outputWidth / inputWidth, outputHeight / inputHeight); int leftPadding = (outputWidth - (inputWidth * multiple)) / 2; int topPadding = (outputHeight - (inputHeight * multiple)) / 2; var output = new BitMatrix(outputWidth, outputHeight); for (int inputY = 0, outputY = topPadding; inputY < inputHeight; inputY++, outputY += multiple) { // Write the contents of this row of the barcode for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) { if (input[inputX, inputY]) { output.setRegion(outputX, outputY, multiple, multiple); } } } return output; }
/// <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) { var aztec = new AztecCode(); // 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; } } } aztec.isCompact = compact; aztec.Size = matrixSize; aztec.Layers = layers; aztec.CodeWords = messageSizeInWords; aztec.Matrix = matrix; return(aztec); }