private static void embedTimingPatterns(ByteMatrix matrix) { // -8 is for skipping position detection patterns (size 7), and two horizontal/vertical // separation patterns (size 1). Thus, 8 = 7 + 1. for (int i = 8; i < matrix.Width - 8; ++i) { int bit = (i + 1) % 2; // Horizontal line. if (isEmpty(matrix[i, 6])) { matrix[i, 6] = bit; } // Vertical line. if (isEmpty(matrix[6, i])) { matrix[6, i] = bit; } } }
/// <summary> /// Apply mask penalty rule 2 and return the penalty. Find 2x2 blocks with the same color and give /// penalty to them. This is actually equivalent to the spec's rule, which is to find MxN blocks and give a /// penalty proportional to (M-1)x(N-1), because this is the number of 2x2 blocks inside such a block. /// </summary> /// <param name="matrix">The matrix.</param> /// <returns></returns> public static int applyMaskPenaltyRule2(ByteMatrix matrix) { int penalty = 0; var array = matrix.Array; int width = matrix.Width; int height = matrix.Height; for (int y = 0; y < height - 1; y++) { for (int x = 0; x < width - 1; x++) { int value = array[y][x]; if (value == array[y][x + 1] && value == array[y + 1][x] && value == array[y + 1][x + 1]) { penalty++; } } } return(N2 * penalty); }
private static int chooseMaskPattern(BitArray bits, ErrorCorrectionLevel ecLevel, Version version, ByteMatrix matrix) { int minPenalty = Int32.MaxValue; // Lower penalty is better. int bestMaskPattern = -1; // We try all mask patterns to choose the best one. for (int maskPattern = 0; maskPattern < QRCode.NUM_MASK_PATTERNS; maskPattern++) { MatrixUtil.buildMatrix(bits, ecLevel, version, maskPattern, matrix); int penalty = calculateMaskPenalty(matrix); if (penalty < minPenalty) { minPenalty = penalty; bestMaskPattern = maskPattern; } } return(bestMaskPattern); }
/// <summary> /// Apply mask penalty rule 4 and return the penalty. Calculate the ratio of dark cells and give /// penalty if the ratio is far from 50%. It gives 10 penalty for 5% distance. /// </summary> /// <param name="matrix">The matrix.</param> /// <returns></returns> public static int applyMaskPenaltyRule4(ByteMatrix matrix) { int numDarkCells = 0; var array = matrix.Array; int width = matrix.Width; int height = matrix.Height; for (int y = 0; y < height; y++) { var arrayY = array[y]; for (int x = 0; x < width; x++) { if (arrayY[x] == 1) { numDarkCells++; } } } var numTotalCells = matrix.Height * matrix.Width; var darkRatio = (double)numDarkCells / numTotalCells; var fivePercentVariances = (int)(Math.Abs(darkRatio - 0.5) * 20.0); // * 100.0 / 5.0 return(fivePercentVariances * N4); }
/// <summary> /// Encodes the specified content. /// </summary> /// <param name="content">The content.</param> /// <param name="ecLevel">The ec level.</param> /// <param name="hints">The hints.</param> /// <returns></returns> public static QRCode encode(String content, ErrorCorrectionLevel ecLevel, IDictionary <EncodeHintType, object> hints) { // Determine what character encoding has been specified by the caller, if any #if !SILVERLIGHT || WINDOWS_PHONE String encoding = hints == null || !hints.ContainsKey(EncodeHintType.CHARACTER_SET) ? null : (String)hints[EncodeHintType.CHARACTER_SET]; if (encoding == null) { encoding = DEFAULT_BYTE_MODE_ENCODING; } bool generateECI = !DEFAULT_BYTE_MODE_ENCODING.Equals(encoding); #else // Silverlight supports only UTF-8 and UTF-16 out-of-the-box const string encoding = "UTF-8"; // caller of the method can only control if the ECI segment should be written // character set is fixed to UTF-8; but some scanners doesn't like the ECI segment bool generateECI = (hints != null && hints.ContainsKey(EncodeHintType.CHARACTER_SET)); #endif // Pick an encoding mode appropriate for the content. Note that this will not attempt to use // multiple modes / segments even if that were more efficient. Twould be nice. Mode mode = chooseMode(content, encoding); // This will store the header information, like mode and // length, as well as "header" segments like an ECI segment. BitArray headerBits = new BitArray(); // Append ECI segment if applicable if (mode == Mode.BYTE && generateECI) { CharacterSetECI eci = CharacterSetECI.getCharacterSetECIByName(encoding); if (eci != null) { var eciIsExplicitDisabled = (hints != null && hints.ContainsKey(EncodeHintType.DISABLE_ECI) ? (bool)hints[EncodeHintType.DISABLE_ECI] : false); if (!eciIsExplicitDisabled) { appendECI(eci, headerBits); } } } // (With ECI in place,) Write the mode marker appendModeInfo(mode, headerBits); // Collect data within the main segment, separately, to count its size if needed. Don't add it to // main payload yet. BitArray dataBits = new BitArray(); appendBytes(content, mode, dataBits, encoding); // Hard part: need to know version to know how many bits length takes. But need to know how many // bits it takes to know version. First we take a guess at version by assuming version will be // the minimum, 1: int provisionalBitsNeeded = headerBits.Size + mode.getCharacterCountBits(Version.getVersionForNumber(1)) + dataBits.Size; Version provisionalVersion = chooseVersion(provisionalBitsNeeded, ecLevel); // Use that guess to calculate the right version. I am still not sure this works in 100% of cases. int bitsNeeded = headerBits.Size + mode.getCharacterCountBits(provisionalVersion) + dataBits.Size; Version version = chooseVersion(bitsNeeded, ecLevel); BitArray headerAndDataBits = new BitArray(); headerAndDataBits.appendBitArray(headerBits); // Find "length" of main segment and write it int numLetters = mode == Mode.BYTE ? dataBits.SizeInBytes : content.Length; appendLengthInfo(numLetters, version, mode, headerAndDataBits); // Put data together into the overall payload headerAndDataBits.appendBitArray(dataBits); Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel); int numDataBytes = version.TotalCodewords - ecBlocks.TotalECCodewords; // Terminate the bits properly. terminateBits(numDataBytes, headerAndDataBits); // Interleave data bits with error correction code. BitArray finalBits = interleaveWithECBytes(headerAndDataBits, version.TotalCodewords, numDataBytes, ecBlocks.NumBlocks); QRCode qrCode = new QRCode { ECLevel = ecLevel, Mode = mode, Version = version }; // Choose the mask pattern and set to "qrCode". int dimension = version.DimensionForVersion; ByteMatrix matrix = new ByteMatrix(dimension, dimension); int maskPattern = chooseMaskPattern(finalBits, ecLevel, version, matrix); qrCode.MaskPattern = maskPattern; // Build the matrix and set it to "qrCode". MatrixUtil.buildMatrix(finalBits, ecLevel, version, maskPattern, matrix); qrCode.Matrix = matrix; return(qrCode); }
/// <summary> /// Embed type information. On success, modify the matrix. /// </summary> /// <param name="ecLevel">The ec level.</param> /// <param name="maskPattern">The mask pattern.</param> /// <param name="matrix">The matrix.</param> public static void embedTypeInfo(ErrorCorrectionLevel ecLevel, int maskPattern, ByteMatrix matrix) { BitArray typeInfoBits = new BitArray(); makeTypeInfoBits(ecLevel, maskPattern, typeInfoBits); for (int i = 0; i < typeInfoBits.Size; ++i) { // Place bits in LSB to MSB order. LSB (least significant bit) is the last value in // "typeInfoBits". int bit = typeInfoBits[typeInfoBits.Size - 1 - i] ? 1 : 0; // Type info bits at the left top corner. See 8.9 of JISX0510:2004 (p.46). int x1 = TYPE_INFO_COORDINATES[i][0]; int y1 = TYPE_INFO_COORDINATES[i][1]; matrix[x1, y1] = bit; if (i < 8) { // Right top corner. int x2 = matrix.Width - i - 1; int y2 = 8; matrix[x2, y2] = bit; } else { // Left bottom corner. int x2 = 8; int y2 = matrix.Height - 7 + (i - 8); matrix[x2, y2] = bit; } } }
/// <summary> /// Build 2D matrix of QR Code from "dataBits" with "ecLevel", "version" and "getMaskPattern". On /// success, store the result in "matrix" and return true. /// </summary> /// <param name="dataBits">The data bits.</param> /// <param name="ecLevel">The ec level.</param> /// <param name="version">The version.</param> /// <param name="maskPattern">The mask pattern.</param> /// <param name="matrix">The matrix.</param> public static void buildMatrix(BitArray dataBits, ErrorCorrectionLevel ecLevel, Version version, int maskPattern, ByteMatrix matrix) { clearMatrix(matrix); embedBasicPatterns(version, matrix); // Type information appear with any version. embedTypeInfo(ecLevel, maskPattern, matrix); // Version info appear if version >= 7. maybeEmbedVersionInfo(version, matrix); // Data should be embedded at end. embedDataBits(dataBits, maskPattern, matrix); }
/// <summary> /// Set all cells to 2. 2 means that the cell is empty (not set yet). /// /// JAVAPORT: We shouldn't need to do this at all. The code should be rewritten to begin encoding /// with the ByteMatrix initialized all to zero. /// </summary> /// <param name="matrix">The matrix.</param> public static void clearMatrix(ByteMatrix matrix) { matrix.clear(2); }
/// <summary> /// Apply mask penalty rule 1 and return the penalty. Find repetitive cells with the same color and /// give penalty to them. Example: 00000 or 11111. /// </summary> /// <param name="matrix">The matrix.</param> /// <returns></returns> public static int applyMaskPenaltyRule1(ByteMatrix matrix) { return(applyMaskPenaltyRule1Internal(matrix, true) + applyMaskPenaltyRule1Internal(matrix, false)); }