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 3 and return the penalty. Find consecutive cells of 00001011101 or /// 10111010000, and give penalty to them. If we find patterns like 000010111010000, we give /// penalties twice (i.e. 40 * 2). /// </summary> /// <param name="matrix">The matrix.</param> /// <returns></returns> public static int ApplyMaskPenaltyRule3(ByteMatrix matrix) { int numPenalties = 0; byte[][] array = matrix.Array; int width = matrix.Width; int height = matrix.Height; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { byte[] arrayY = array[y]; // We can at least optimize this access if (x + 6 < width && arrayY[x] == 1 && arrayY[x + 1] == 0 && arrayY[x + 2] == 1 && arrayY[x + 3] == 1 && arrayY[x + 4] == 1 && arrayY[x + 5] == 0 && arrayY[x + 6] == 1 && (IsWhiteHorizontal(arrayY, x - 4, x) || IsWhiteHorizontal(arrayY, x + 7, x + 11))) { numPenalties++; } if (y + 6 < height && array[y][x] == 1 && array[y + 1][x] == 0 && array[y + 2][x] == 1 && array[y + 3][x] == 1 && array[y + 4][x] == 1 && array[y + 5][x] == 0 && array[y + 6][x] == 1 && (IsWhiteVertical(array, x, y - 4, y) || IsWhiteVertical(array, x, y + 7, y + 11))) { numPenalties++; } } } return(numPenalties * N3); }
/// <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++) { var arrayY = array[y]; var arrayY1 = array[y + 1]; for (int x = 0; x < width - 1; x++) { int value = arrayY[x]; if (value == arrayY[x + 1] && value == arrayY1[x] && value == arrayY1[x + 1]) { penalty++; } } } return(N2 * penalty); }
/// <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> /// 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)); }
/// <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[] coordinates = TYPE_INFO_COORDINATES[i]; int x1 = coordinates[0]; int y1 = coordinates[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> /// 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> /// 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) { var encoding = DEFAULT_BYTE_MODE_ENCODING; var generateECI = !DEFAULT_BYTE_MODE_ENCODING.Equals(encoding); // 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. var mode = ChooseMode(content, encoding); // This will store the header information, like mode and // length, as well as "header" segments like an ECI segment. var headerBits = new BitArray(); // Append ECI segment if applicable if (mode == Mode.BYTE && generateECI) { var eci = CharacterSetECI.GetCharacterSetECIByName(encoding); if (eci != null) { 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. var dataBits = new BitArray(); AppendBytes(content, mode, dataBits, encoding); Version version = RecommendVersion(ecLevel, mode, headerBits, dataBits); var headerAndDataBits = new BitArray(); headerAndDataBits.AppendBitArray(headerBits); // Find "length" of main segment and write it var numLetters = mode == Mode.BYTE ? dataBits.SizeInBytes : content.Length; AppendLengthInfo(numLetters, version, mode, headerAndDataBits); // Put data together into the overall payload headerAndDataBits.AppendBitArray(dataBits); var ecBlocks = version.GetECBlocksForLevel(ecLevel); var numDataBytes = version.TotalCodewords - ecBlocks.TotalECCodewords; // Terminate the bits properly. TerminateBits(numDataBytes, headerAndDataBits); // Interleave data bits with error correction code. var finalBits = InterleaveWithECBytes(headerAndDataBits, version.TotalCodewords, numDataBytes, ecBlocks.NumBlocks); var qrCode = new QRCode { ECLevel = ecLevel, Mode = mode, Version = version }; // Choose the mask pattern and set to "qrCode". var dimension = version.DimensionForVersion; var matrix = new ByteMatrix(dimension, dimension); var 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; }
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; }